diff options
author | Artem B. Bityuckiy <dedekind@infradead.org> | 2005-04-09 06:47:03 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 07:16:47 -0400 |
commit | 8557fd51c22e4c2109f062decd19de439061ceae (patch) | |
tree | 66884a832e912decd06a8441db05fd78ec8e3e6e /fs | |
parent | abc37e6771ec92bb4c531d218ad572afbef6aa21 (diff) |
[JFFS2] Fix race in garbage collector
Fix the race problem described here:
http://lists.infradead.org/pipermail/linux-mtd/2005-April/012361.html
Signed-off-by: Artem B. Bityuckiy <dedekind@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/jffs2/gc.c | 30 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 14 |
2 files changed, 37 insertions, 7 deletions
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 694bc90ad779..7086cd634503 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: gc.c,v 1.147 2005/03/20 21:43:22 dedekind Exp $ | 10 | * $Id: gc.c,v 1.148 2005/04/09 10:47:00 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -669,9 +669,10 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ | |||
669 | { | 669 | { |
670 | struct jffs2_full_dnode *new_fn; | 670 | struct jffs2_full_dnode *new_fn; |
671 | struct jffs2_raw_inode ri; | 671 | struct jffs2_raw_inode ri; |
672 | struct jffs2_node_frag *last_frag; | ||
672 | jint16_t dev; | 673 | jint16_t dev; |
673 | char *mdata = NULL, mdatalen = 0; | 674 | char *mdata = NULL, mdatalen = 0; |
674 | uint32_t alloclen, phys_ofs; | 675 | uint32_t alloclen, phys_ofs, ilen; |
675 | int ret; | 676 | int ret; |
676 | 677 | ||
677 | if (S_ISBLK(JFFS2_F_I_MODE(f)) || | 678 | if (S_ISBLK(JFFS2_F_I_MODE(f)) || |
@@ -707,6 +708,14 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ | |||
707 | goto out; | 708 | goto out; |
708 | } | 709 | } |
709 | 710 | ||
711 | last_frag = frag_last(&f->fragtree); | ||
712 | if (last_frag) | ||
713 | /* Fetch the inode length from the fragtree rather then | ||
714 | * from i_size since i_size may have not been updated yet */ | ||
715 | ilen = last_frag->ofs + last_frag->size; | ||
716 | else | ||
717 | ilen = JFFS2_F_I_SIZE(f); | ||
718 | |||
710 | memset(&ri, 0, sizeof(ri)); | 719 | memset(&ri, 0, sizeof(ri)); |
711 | ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 720 | ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
712 | ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); | 721 | ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); |
@@ -718,7 +727,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ | |||
718 | ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); | 727 | ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); |
719 | ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); | 728 | ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); |
720 | ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); | 729 | ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); |
721 | ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); | 730 | ri.isize = cpu_to_je32(ilen); |
722 | ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); | 731 | ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); |
723 | ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); | 732 | ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); |
724 | ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); | 733 | ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); |
@@ -898,7 +907,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
898 | struct jffs2_raw_inode ri; | 907 | struct jffs2_raw_inode ri; |
899 | struct jffs2_node_frag *frag; | 908 | struct jffs2_node_frag *frag; |
900 | struct jffs2_full_dnode *new_fn; | 909 | struct jffs2_full_dnode *new_fn; |
901 | uint32_t alloclen, phys_ofs; | 910 | uint32_t alloclen, phys_ofs, ilen; |
902 | int ret; | 911 | int ret; |
903 | 912 | ||
904 | D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", | 913 | D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", |
@@ -958,10 +967,19 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
958 | ri.csize = cpu_to_je32(0); | 967 | ri.csize = cpu_to_je32(0); |
959 | ri.compr = JFFS2_COMPR_ZERO; | 968 | ri.compr = JFFS2_COMPR_ZERO; |
960 | } | 969 | } |
970 | |||
971 | frag = frag_last(&f->fragtree); | ||
972 | if (frag) | ||
973 | /* Fetch the inode length from the fragtree rather then | ||
974 | * from i_size since i_size may have not been updated yet */ | ||
975 | ilen = frag->ofs + frag->size; | ||
976 | else | ||
977 | ilen = JFFS2_F_I_SIZE(f); | ||
978 | |||
961 | ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); | 979 | ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); |
962 | ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); | 980 | ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); |
963 | ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); | 981 | ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); |
964 | ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); | 982 | ri.isize = cpu_to_je32(ilen); |
965 | ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); | 983 | ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); |
966 | ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); | 984 | ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); |
967 | ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); | 985 | ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); |
@@ -1168,7 +1186,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era | |||
1168 | D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", | 1186 | D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", |
1169 | orig_start, orig_end, start, end)); | 1187 | orig_start, orig_end, start, end)); |
1170 | 1188 | ||
1171 | BUG_ON(end > JFFS2_F_I_SIZE(f)); | 1189 | D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size)); |
1172 | BUG_ON(end < orig_end); | 1190 | BUG_ON(end < orig_end); |
1173 | BUG_ON(start > orig_start); | 1191 | BUG_ON(start > orig_start); |
1174 | } | 1192 | } |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 57f675c2c97f..a65539f28b06 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: nodelist.h,v 1.128 2005/02/27 23:01:32 dwmw2 Exp $ | 10 | * $Id: nodelist.h,v 1.130 2005/04/09 10:46:59 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -363,6 +363,18 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root) | |||
363 | node = node->rb_left; | 363 | node = node->rb_left; |
364 | return rb_entry(node, struct jffs2_node_frag, rb); | 364 | return rb_entry(node, struct jffs2_node_frag, rb); |
365 | } | 365 | } |
366 | |||
367 | static inline struct jffs2_node_frag *frag_last(struct rb_root *root) | ||
368 | { | ||
369 | struct rb_node *node = root->rb_node; | ||
370 | |||
371 | if (!node) | ||
372 | return NULL; | ||
373 | while(node->rb_right) | ||
374 | node = node->rb_right; | ||
375 | return rb_entry(node, struct jffs2_node_frag, rb); | ||
376 | } | ||
377 | |||
366 | #define rb_parent(rb) ((rb)->rb_parent) | 378 | #define rb_parent(rb) ((rb)->rb_parent) |
367 | #define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb) | 379 | #define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb) |
368 | #define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb) | 380 | #define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb) |