diff options
Diffstat (limited to 'fs/jffs2')
-rw-r--r-- | fs/jffs2/nodelist.c | 18 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 2 | ||||
-rw-r--r-- | 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 ac2a4c422e3..4bf86088b3a 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 cb34cac5d0f..25126a062ca 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 a42ffba2ed1..6aff38930b5 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: |