Skip to content

Commit

Permalink
jffs2: Fix page lock / f->sem deadlock
Browse files Browse the repository at this point in the history
With this fix, all code paths should now be obtaining the page lock before
f->sem.

Reported-by: Szabó Tamás <sztomi89@gmail.com>
Tested-by: Thomas Betker <thomas.betker@rohde-schwarz.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Cc: stable@vger.kernel.org
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Feb 25, 2016
1 parent 157078f commit 49e91e7
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 11 deletions.
5 changes: 1 addition & 4 deletions fs/jffs2/README.Locking
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
JFFS2 LOCKING DOCUMENTATION
---------------------------

At least theoretically, JFFS2 does not require the Big Kernel Lock
(BKL), which was always helpfully obtained for it by Linux 2.4 VFS
code. It has its own locking, as described below.

This document attempts to describe the existing locking rules for
JFFS2. It is not expected to remain perfectly up to date, but ought to
be fairly close.
Expand Down Expand Up @@ -69,6 +65,7 @@ Ordering constraints:
any f->sem held.
2. Never attempt to lock two file mutexes in one thread.
No ordering rules have been made for doing so.
3. Never lock a page cache page with f->sem held.


erase_completion_lock spinlock
Expand Down
17 changes: 10 additions & 7 deletions fs/jffs2/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1296,14 +1296,17 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
BUG_ON(start > orig_start);
}

/* First, use readpage() to read the appropriate page into the page cache */
/* Q: What happens if we actually try to GC the _same_ page for which commit_write()
* triggered garbage collection in the first place?
* A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the
* page OK. We'll actually write it out again in commit_write, which is a little
* suboptimal, but at least we're correct.
*/
/* The rules state that we must obtain the page lock *before* f->sem, so
* drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's
* actually going to *change* so we're safe; we only allow reading.
*
* It is important to note that jffs2_write_begin() will ensure that its
* page is marked Uptodate before allocating space. That means that if we
* end up here trying to GC the *same* page that jffs2_write_begin() is
* trying to write out, read_cache_page() will not deadlock. */
mutex_unlock(&f->sem);
pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
mutex_lock(&f->sem);

if (IS_ERR(pg_ptr)) {
pr_warn("read_cache_page() returned error: %ld\n",
Expand Down

0 comments on commit 49e91e7

Please sign in to comment.