Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=61c4b23770d1b0cef7c06a23378ab544eb0c64b4
Commit:     61c4b23770d1b0cef7c06a23378ab544eb0c64b4
Parent:     c00c310eac04a28d2143368ae988716792ed53ce
Author:     David Woodhouse <[EMAIL PROTECTED]>
AuthorDate: Wed Apr 25 17:04:23 2007 +0100
Committer:  David Woodhouse <[EMAIL PROTECTED]>
CommitDate: Wed Apr 25 17:04:23 2007 +0100

    [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 <[EMAIL PROTECTED]>
---
 fs/jffs2/nodelist.c  |   18 ++++++++++++------
 fs/jffs2/nodelist.h  |    2 +-
 fs/jffs2/readinode.c |    9 +++++++--
 3 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index ac2a4c4..4bf8608 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
        *prev = new;
 }
 
-void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, 
uint32_t size)
+uint32_t jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root 
*list, uint32_t size)
 {
        struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
 
@@ -74,18 +74,24 @@ void jffs2_truncate_fragtree(struct jffs2_sb_info *c, 
struct rb_root *list, uint
        }
 
        if (size == 0)
-               return;
+               return 0;
 
-       /*
-        * If the last fragment starts at the RAM page boundary, it is
-        * REF_PRISTINE irrespective of its size.
-        */
        frag = frag_last(list);
+
+       /* Sanity check for truncation to longer than we started with... */
+       if (!frag)
+               return 0;
+       if (frag->ofs + frag->size < size)
+               return frag->ofs + frag->size;
+
+       /* If the last fragment starts at the RAM page boundary, it is
+        * REF_PRISTINE irrespective of its size. */
        if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) {
                dbg_fragtree2("marking the last fragment 0x%08x-0x%08x 
REF_PRISTINE.\n",
                        frag->ofs, frag->ofs + frag->size);
                frag->node->raw->flash_offset = ref_offset(frag->node->raw) | 
REF_PRISTINE;
        }
+       return size;
 }
 
 static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c,
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index cb34cac..25126a0 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -362,7 +362,7 @@ struct rb_node *rb_next(struct rb_node *);
 struct rb_node *rb_prev(struct rb_node *);
 void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct 
rb_root *root);
 int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct 
jffs2_inode_info *f, struct jffs2_full_dnode *fn);
-void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, 
uint32_t size);
+uint32_t jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root 
*list, uint32_t size);
 struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c,
                                               struct jffs2_eraseblock *jeb,
                                               uint32_t ofs, uint32_t len,
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index a42ffba..6aff389 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,
                                        struct jffs2_raw_inode *latest_node)
 {
        struct jffs2_readinode_info rii;
-       uint32_t crc;
+       uint32_t crc, new_size;
        size_t retlen;
        int ret;
 
@@ -1233,7 +1233,12 @@ static int jffs2_do_read_inode_internal(struct 
jffs2_sb_info *c,
 
        case S_IFREG:
                /* If it was a regular file, truncate it to the latest node's 
isize */
-               jffs2_truncate_fragtree(c, &f->fragtree, 
je32_to_cpu(latest_node->isize));
+               new_size = jffs2_truncate_fragtree(c, &f->fragtree, 
je32_to_cpu(latest_node->isize));
+               if (new_size != je32_to_cpu(latest_node->isize)) {
+                       JFFS2_WARNING("Truncating ino #%u to %d bytes failed 
because it only had %d bytes to start with!\n",
+                                     f->inocache->ino, 
je32_to_cpu(latest_node->isize), new_size);
+                       latest_node->isize = cpu_to_je32(new_size);
+               }
                break;
 
        case S_IFLNK:
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to