Commit 49e91e70 authored by David Woodhouse's avatar David Woodhouse

jffs2: Fix page lock / f->sem deadlock

With this fix, all code paths should now be obtaining the page lock before
f->sem.
Reported-by: default avatarSzabó Tamás <sztomi89@gmail.com>
Tested-by: default avatarThomas Betker <thomas.betker@rohde-schwarz.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
Cc: stable@vger.kernel.org
parent 157078f6
...@@ -2,10 +2,6 @@ ...@@ -2,10 +2,6 @@
JFFS2 LOCKING DOCUMENTATION 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 This document attempts to describe the existing locking rules for
JFFS2. It is not expected to remain perfectly up to date, but ought to JFFS2. It is not expected to remain perfectly up to date, but ought to
be fairly close. be fairly close.
...@@ -69,6 +65,7 @@ Ordering constraints: ...@@ -69,6 +65,7 @@ Ordering constraints:
any f->sem held. any f->sem held.
2. Never attempt to lock two file mutexes in one thread. 2. Never attempt to lock two file mutexes in one thread.
No ordering rules have been made for doing so. No ordering rules have been made for doing so.
3. Never lock a page cache page with f->sem held.
erase_completion_lock spinlock erase_completion_lock spinlock
......
...@@ -1296,14 +1296,17 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era ...@@ -1296,14 +1296,17 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
BUG_ON(start > orig_start); BUG_ON(start > orig_start);
} }
/* First, use readpage() to read the appropriate page into the page cache */ /* The rules state that we must obtain the page lock *before* f->sem, so
/* Q: What happens if we actually try to GC the _same_ page for which commit_write() * drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's
* triggered garbage collection in the first place? * actually going to *change* so we're safe; we only allow reading.
* 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 * It is important to note that jffs2_write_begin() will ensure that its
* suboptimal, but at least we're correct. * 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); pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
mutex_lock(&f->sem);
if (IS_ERR(pg_ptr)) { if (IS_ERR(pg_ptr)) {
pr_warn("read_cache_page() returned error: %ld\n", pr_warn("read_cache_page() returned error: %ld\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment