summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
*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 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 *);
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 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,
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: