aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-04-25 12:04:23 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-04-25 12:04:23 -0400
commit61c4b23770d1b0cef7c06a23378ab544eb0c64b4 (patch)
treeb4cf1e784621d2f60a3494ded1d5852934107c22
parentc00c310eac04a28d2143368ae988716792ed53ce (diff)
[JFFS2] Handle inodes with only a single metadata node with non-zero isize
This should never happen unless there's corruption on the medium and the actual data nodes go missing. But the failure mode (an oops when we assume the fragtree isn't empty and go looking for its last node) isn't useful. Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r--fs/jffs2/nodelist.c18
-rw-r--r--fs/jffs2/nodelist.h2
-rw-r--r--fs/jffs2/readinode.c9
3 files changed, 20 insertions, 9 deletions
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index ac2a4c422e32..4bf86088b3ae 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -52,7 +52,7 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new
52 *prev = new; 52 *prev = new;
53} 53}
54 54
55void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) 55uint32_t jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
56{ 56{
57 struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); 57 struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
58 58
@@ -74,18 +74,24 @@ void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint
74 } 74 }
75 75
76 if (size == 0) 76 if (size == 0)
77 return; 77 return 0;
78 78
79 /*
80 * If the last fragment starts at the RAM page boundary, it is
81 * REF_PRISTINE irrespective of its size.
82 */
83 frag = frag_last(list); 79 frag = frag_last(list);
80
81 /* Sanity check for truncation to longer than we started with... */
82 if (!frag)
83 return 0;
84 if (frag->ofs + frag->size < size)
85 return frag->ofs + frag->size;
86
87 /* If the last fragment starts at the RAM page boundary, it is
88 * REF_PRISTINE irrespective of its size. */
84 if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) { 89 if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) {
85 dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n", 90 dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n",
86 frag->ofs, frag->ofs + frag->size); 91 frag->ofs, frag->ofs + frag->size);
87 frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE; 92 frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE;
88 } 93 }
94 return size;
89} 95}
90 96
91static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, 97static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c,
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index cb34cac5d0f8..25126a062cae 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -362,7 +362,7 @@ struct rb_node *rb_next(struct rb_node *);
362struct rb_node *rb_prev(struct rb_node *); 362struct rb_node *rb_prev(struct rb_node *);
363void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); 363void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
364int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); 364int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
365void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); 365uint32_t jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
366struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, 366struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c,
367 struct jffs2_eraseblock *jeb, 367 struct jffs2_eraseblock *jeb,
368 uint32_t ofs, uint32_t len, 368 uint32_t ofs, uint32_t len,
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index a42ffba2ed17..6aff38930b50 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -1132,7 +1132,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
1132 struct jffs2_raw_inode *latest_node) 1132 struct jffs2_raw_inode *latest_node)
1133{ 1133{
1134 struct jffs2_readinode_info rii; 1134 struct jffs2_readinode_info rii;
1135 uint32_t crc; 1135 uint32_t crc, new_size;
1136 size_t retlen; 1136 size_t retlen;
1137 int ret; 1137 int ret;
1138 1138
@@ -1233,7 +1233,12 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
1233 1233
1234 case S_IFREG: 1234 case S_IFREG:
1235 /* If it was a regular file, truncate it to the latest node's isize */ 1235 /* If it was a regular file, truncate it to the latest node's isize */
1236 jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize)); 1236 new_size = jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize));
1237 if (new_size != je32_to_cpu(latest_node->isize)) {
1238 JFFS2_WARNING("Truncating ino #%u to %d bytes failed because it only had %d bytes to start with!\n",
1239 f->inocache->ino, je32_to_cpu(latest_node->isize), new_size);
1240 latest_node->isize = cpu_to_je32(new_size);
1241 }
1237 break; 1242 break;
1238 1243
1239 case S_IFLNK: 1244 case S_IFLNK: