[JFFS2] fix mount crash caused by removed nodes

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Thu Feb 26 14:59:02 EST 2009


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=4c41bd0ec953954158f92bed5d3062645062b98e
Commit:     4c41bd0ec953954158f92bed5d3062645062b98e
Parent:     efab0b5d3eed6aa71f8e3233e4e11774eedc04dc
Author:     Thomas Gleixner <tglx at linutronix.de>
AuthorDate: Mon Feb 16 21:29:31 2009 +0100
Committer:  David Woodhouse <David.Woodhouse at intel.com>
CommitDate: Sat Feb 21 11:09:29 2009 +0100

    [JFFS2] fix mount crash caused by removed nodes
    
    At scan time we observed following scenario:
    
       node A inserted
       node B inserted
       node C inserted -> sets overlapped flag on node B
    
       node A is removed due to CRC failure -> overlapped flag on node B remains
    
       while (tn->overlapped)
       	 tn = tn_prev(tn);
    
       ==> crash, when tn_prev(B) is referenced.
    
    When the ultimate node is removed at scan time and the overlapped flag
    is set on the penultimate node, then nothing updates the overlapped
    flag of that node. The overlapped iterators blindly expect that the
    ultimate node does not have the overlapped flag set, which causes the
    scan code to crash.
    
    It would be a huge overhead to go through the node chain on node
    removal and fix up the overlapped flags, so detecting such a case on
    the fly in the overlapped iterators is a simpler and reliable
    solution.
    
    Cc: stable at kernel.org
    Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
    Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>
---
 fs/jffs2/readinode.c |   42 +++++++++++++++++++++++++++++++++---------
 1 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 6ca08ad..1fc1e92 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -220,7 +220,7 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
 				struct jffs2_tmp_dnode_info *tn)
 {
 	uint32_t fn_end = tn->fn->ofs + tn->fn->size;
-	struct jffs2_tmp_dnode_info *this;
+	struct jffs2_tmp_dnode_info *this, *ptn;
 
 	dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw));
 
@@ -251,11 +251,18 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
 	if (this) {
 		/* If the node is coincident with another at a lower address,
 		   back up until the other node is found. It may be relevant */
-		while (this->overlapped)
-			this = tn_prev(this);
-
-		/* First node should never be marked overlapped */
-		BUG_ON(!this);
+		while (this->overlapped) {
+			ptn = tn_prev(this);
+			if (!ptn) {
+				/*
+				 * We killed a node which set the overlapped
+				 * flags during the scan. Fix it up.
+				 */
+				this->overlapped = 0;
+				break;
+			}
+			this = ptn;
+		}
 		dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
 	}
 
@@ -360,7 +367,17 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
 			}
 			if (!this->overlapped)
 				break;
-			this = tn_prev(this);
+
+			ptn = tn_prev(this);
+			if (!ptn) {
+				/*
+				 * We killed a node which set the overlapped
+				 * flags during the scan. Fix it up.
+				 */
+				this->overlapped = 0;
+				break;
+			}
+			this = ptn;
 		}
 	}
 
@@ -456,8 +473,15 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c,
 		eat_last(&rii->tn_root, &last->rb);
 		ver_insert(&ver_root, last);
 
-		if (unlikely(last->overlapped))
-			continue;
+		if (unlikely(last->overlapped)) {
+			if (pen)
+				continue;
+			/*
+			 * We killed a node which set the overlapped
+			 * flags during the scan. Fix it up.
+			 */
+			last->overlapped = 0;
+		}
 
 		/* Now we have a bunch of nodes in reverse version
 		   order, in the tree at ver_root. Most of the time,



More information about the linux-mtd-cvs mailing list