summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2009-02-16 21:29:31 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2009-03-16 17:52:44 -0700
commit662f8bb08ee7875c6f25047256b2336104e3e98f (patch)
treeadb684f2db6545a82107d40ee2eb77d1a7ed567c /fs
parentfbb38fcb8e793f5df68be9992354d9d50cbd41ea (diff)
JFFS2: fix mount crash caused by removed nodes
commit 4c41bd0ec953954158f92bed5d3062645062b98e upstream. 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. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/jffs2/readinode.c42
1 files changed, 33 insertions, 9 deletions
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 6ca08ad887c0..1fc1e92356ee 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,