Revert "jffs2: Fix lock acquisition order bug in jffs2_write_begin"

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Thu Feb 25 03:59:02 PST 2016


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=157078f64b8a9cd7011b6b900b2f2498df850748
Commit:     157078f64b8a9cd7011b6b900b2f2498df850748
Parent:     38714fbd299f992080a11b977f609136ec8530c2
Author:     Thomas Betker <thomas.betker at rohde-schwarz.com>
AuthorDate: Tue Nov 10 22:18:15 2015 +0100
Committer:  David Woodhouse <David.Woodhouse at intel.com>
CommitDate: Thu Feb 25 11:11:25 2016 +0000

    Revert "jffs2: Fix lock acquisition order bug in jffs2_write_begin"
    
    This reverts commit 5ffd3412ae55
    ("jffs2: Fix lock acquisition order bug in jffs2_write_begin").
    
    The commit modified jffs2_write_begin() to remove a deadlock with
    jffs2_garbage_collect_live(), but this introduced new deadlocks found
    by multiple users. page_lock() actually has to be called before
    mutex_lock(&c->alloc_sem) or mutex_lock(&f->sem) because
    jffs2_write_end() and jffs2_readpage() are called with the page locked,
    and they acquire c->alloc_sem and f->sem, resp.
    
    In other words, the lock order in jffs2_write_begin() was correct, and
    it is the jffs2_garbage_collect_live() path that has to be changed.
    
    Revert the commit to get rid of the new deadlocks, and to clear the way
    for a better fix of the original deadlock.
    
    Reported-by: Deng Chao <deng.chao1 at zte.com.cn>
    Reported-by: Ming Liu <liu.ming50 at gmail.com>
    Reported-by: wangzaiwei <wangzaiwei at top-vision.cn>
    Signed-off-by: Thomas Betker <thomas.betker at rohde-schwarz.com>
    Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>
    Cc: stable at vger.kernel.org
---
 fs/jffs2/file.c | 39 ++++++++++++++++++---------------------
 1 file changed, 18 insertions(+), 21 deletions(-)

diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index c5ac594..cad86ba 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -137,39 +137,33 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
 	struct page *pg;
 	struct inode *inode = mapping->host;
 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-	struct jffs2_raw_inode ri;
-	uint32_t alloc_len = 0;
 	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
 	uint32_t pageofs = index << PAGE_CACHE_SHIFT;
 	int ret = 0;
 
-	jffs2_dbg(1, "%s()\n", __func__);
-
-	if (pageofs > inode->i_size) {
-		ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
-					  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
-		if (ret)
-			return ret;
-	}
-
-	mutex_lock(&f->sem);
 	pg = grab_cache_page_write_begin(mapping, index, flags);
-	if (!pg) {
-		if (alloc_len)
-			jffs2_complete_reservation(c);
-		mutex_unlock(&f->sem);
+	if (!pg)
 		return -ENOMEM;
-	}
 	*pagep = pg;
 
-	if (alloc_len) {
+	jffs2_dbg(1, "%s()\n", __func__);
+
+	if (pageofs > inode->i_size) {
 		/* Make new hole frag from old EOF to new page */
+		struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+		struct jffs2_raw_inode ri;
 		struct jffs2_full_dnode *fn;
+		uint32_t alloc_len;
 
 		jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
 			  (unsigned int)inode->i_size, pageofs);
 
+		ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
+					  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
+		if (ret)
+			goto out_page;
+
+		mutex_lock(&f->sem);
 		memset(&ri, 0, sizeof(ri));
 
 		ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -196,6 +190,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
 		if (IS_ERR(fn)) {
 			ret = PTR_ERR(fn);
 			jffs2_complete_reservation(c);
+			mutex_unlock(&f->sem);
 			goto out_page;
 		}
 		ret = jffs2_add_full_dnode_to_inode(c, f, fn);
@@ -210,10 +205,12 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
 			jffs2_mark_node_obsolete(c, fn->raw);
 			jffs2_free_full_dnode(fn);
 			jffs2_complete_reservation(c);
+			mutex_unlock(&f->sem);
 			goto out_page;
 		}
 		jffs2_complete_reservation(c);
 		inode->i_size = pageofs;
+		mutex_unlock(&f->sem);
 	}
 
 	/*
@@ -222,18 +219,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
 	 * case of a short-copy.
 	 */
 	if (!PageUptodate(pg)) {
+		mutex_lock(&f->sem);
 		ret = jffs2_do_readpage_nolock(inode, pg);
+		mutex_unlock(&f->sem);
 		if (ret)
 			goto out_page;
 	}
-	mutex_unlock(&f->sem);
 	jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags);
 	return ret;
 
 out_page:
 	unlock_page(pg);
 	page_cache_release(pg);
-	mutex_unlock(&f->sem);
 	return ret;
 }
 



More information about the linux-mtd-cvs mailing list