diff options
-rw-r--r-- | fs/jffs2/erase.c | 21 | ||||
-rw-r--r-- | fs/jffs2/jffs2_fs_sb.h | 3 | ||||
-rw-r--r-- | fs/jffs2/malloc.c | 75 | ||||
-rw-r--r-- | fs/jffs2/nodelist.c | 93 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 31 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 51 | ||||
-rw-r--r-- | fs/jffs2/os-linux.h | 1 | ||||
-rw-r--r-- | fs/jffs2/summary.c | 14 | ||||
-rw-r--r-- | fs/jffs2/wbuf.c | 287 |
9 files changed, 351 insertions, 225 deletions
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index c8386b256831..1862e8bc101d 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -285,20 +285,25 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, | |||
285 | 285 | ||
286 | void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | 286 | void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) |
287 | { | 287 | { |
288 | struct jffs2_raw_node_ref *ref; | 288 | struct jffs2_raw_node_ref *block, *ref; |
289 | D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset)); | 289 | D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset)); |
290 | while(jeb->first_node) { | ||
291 | ref = jeb->first_node; | ||
292 | jeb->first_node = ref->next_phys; | ||
293 | 290 | ||
294 | /* Remove from the inode-list */ | 291 | block = ref = jeb->first_node; |
295 | if (ref->next_in_ino) | 292 | |
293 | while (ref) { | ||
294 | if (ref->flash_offset == REF_LINK_NODE) { | ||
295 | ref = ref->next_in_ino; | ||
296 | jffs2_free_refblock(block); | ||
297 | block = ref; | ||
298 | continue; | ||
299 | } | ||
300 | if (ref->flash_offset != REF_EMPTY_NODE && ref->next_in_ino) | ||
296 | jffs2_remove_node_refs_from_ino_list(c, ref, jeb); | 301 | jffs2_remove_node_refs_from_ino_list(c, ref, jeb); |
297 | /* else it was a non-inode node or already removed, so don't bother */ | 302 | /* else it was a non-inode node or already removed, so don't bother */ |
298 | 303 | ||
299 | __jffs2_free_raw_node_ref(ref); | 304 | ref++; |
300 | } | 305 | } |
301 | jeb->last_node = NULL; | 306 | jeb->first_node = jeb->last_node = NULL; |
302 | } | 307 | } |
303 | 308 | ||
304 | static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset) | 309 | static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset) |
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 67529f0a44dd..272fbea55192 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h | |||
@@ -26,9 +26,6 @@ struct jffs2_inodirty; | |||
26 | struct jffs2_sb_info { | 26 | struct jffs2_sb_info { |
27 | struct mtd_info *mtd; | 27 | struct mtd_info *mtd; |
28 | 28 | ||
29 | struct jffs2_raw_node_ref *refs; | ||
30 | int reserved_refs; | ||
31 | |||
32 | uint32_t highest_ino; | 29 | uint32_t highest_ino; |
33 | uint32_t checked_ino; | 30 | uint32_t checked_ino; |
34 | 31 | ||
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 171483ef0e4d..4889d0700c0e 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c | |||
@@ -57,8 +57,8 @@ int __init jffs2_create_slab_caches(void) | |||
57 | if (!tmp_dnode_info_slab) | 57 | if (!tmp_dnode_info_slab) |
58 | goto err; | 58 | goto err; |
59 | 59 | ||
60 | raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", | 60 | raw_node_ref_slab = kmem_cache_create("jffs2_refblock", |
61 | sizeof(struct jffs2_raw_node_ref), | 61 | sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1), |
62 | 0, 0, NULL, NULL); | 62 | 0, 0, NULL, NULL); |
63 | if (!raw_node_ref_slab) | 63 | if (!raw_node_ref_slab) |
64 | goto err; | 64 | goto err; |
@@ -190,38 +190,65 @@ void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) | |||
190 | kmem_cache_free(tmp_dnode_info_slab, x); | 190 | kmem_cache_free(tmp_dnode_info_slab, x); |
191 | } | 191 | } |
192 | 192 | ||
193 | struct jffs2_raw_node_ref *jffs2_alloc_refblock(void) | ||
194 | { | ||
195 | struct jffs2_raw_node_ref *ret; | ||
196 | |||
197 | ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); | ||
198 | if (ret) { | ||
199 | int i = 0; | ||
200 | for (i=0; i < REFS_PER_BLOCK; i++) { | ||
201 | ret[i].flash_offset = REF_EMPTY_NODE; | ||
202 | ret[i].next_in_ino = NULL; | ||
203 | } | ||
204 | ret[i].flash_offset = REF_LINK_NODE; | ||
205 | ret[i].next_in_ino = NULL; | ||
206 | } | ||
207 | return ret; | ||
208 | } | ||
209 | |||
193 | int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, | 210 | int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, |
194 | struct jffs2_eraseblock *jeb, int nr) | 211 | struct jffs2_eraseblock *jeb, int nr) |
195 | { | 212 | { |
196 | struct jffs2_raw_node_ref *p = c->refs; | 213 | struct jffs2_raw_node_ref **p, *ref; |
214 | int i = nr; | ||
197 | 215 | ||
198 | dbg_memalloc("%d\n", nr); | 216 | dbg_memalloc("%d\n", nr); |
199 | 217 | ||
200 | while (nr && p) { | 218 | p = &jeb->last_node; |
201 | p = p->next_in_ino; | 219 | ref = *p; |
202 | nr--; | 220 | |
203 | } | 221 | dbg_memalloc("Reserving %d refs for block @0x%08x\n", nr, jeb->offset); |
204 | while (nr) { | 222 | |
205 | p = __jffs2_alloc_raw_node_ref(); | 223 | /* If jeb->last_node is really a valid node then skip over it */ |
206 | if (!p) | 224 | if (ref && ref->flash_offset != REF_EMPTY_NODE) |
207 | return -ENOMEM; | 225 | ref++; |
208 | p->next_in_ino = c->refs; | 226 | |
209 | c->refs = p; | 227 | while (i) { |
210 | nr--; | 228 | if (!ref) { |
229 | dbg_memalloc("Allocating new refblock linked from %p\n", p); | ||
230 | ref = *p = jffs2_alloc_refblock(); | ||
231 | if (!ref) | ||
232 | return -ENOMEM; | ||
233 | } | ||
234 | if (ref->flash_offset == REF_LINK_NODE) { | ||
235 | p = &ref->next_in_ino; | ||
236 | ref = *p; | ||
237 | continue; | ||
238 | } | ||
239 | i--; | ||
240 | ref++; | ||
211 | } | 241 | } |
212 | c->reserved_refs = nr; | 242 | jeb->allocated_refs = nr; |
213 | return 0; | ||
214 | } | ||
215 | 243 | ||
216 | struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void) | 244 | dbg_memalloc("Reserved %d refs for block @0x%08x, last_node is %p (%08x,%p)\n", |
217 | { | 245 | nr, jeb->offset, jeb->last_node, jeb->last_node->flash_offset, |
218 | struct jffs2_raw_node_ref *ret; | 246 | jeb->last_node->next_in_ino); |
219 | ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); | 247 | |
220 | dbg_memalloc("%p\n", ret); | 248 | return 0; |
221 | return ret; | ||
222 | } | 249 | } |
223 | 250 | ||
224 | void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) | 251 | void jffs2_free_refblock(struct jffs2_raw_node_ref *x) |
225 | { | 252 | { |
226 | dbg_memalloc("%p\n", x); | 253 | dbg_memalloc("%p\n", x); |
227 | kmem_cache_free(raw_node_ref_slab, x); | 254 | kmem_cache_free(raw_node_ref_slab, x); |
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 0e82979c741c..5d36e9b4d7c5 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c | |||
@@ -954,18 +954,16 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) | |||
954 | for (i=0; i<c->nr_blocks; i++) { | 954 | for (i=0; i<c->nr_blocks; i++) { |
955 | this = c->blocks[i].first_node; | 955 | this = c->blocks[i].first_node; |
956 | while (this) { | 956 | while (this) { |
957 | next = this->next_phys; | 957 | if (this[REFS_PER_BLOCK].flash_offset == REF_LINK_NODE) |
958 | __jffs2_free_raw_node_ref(this); | 958 | next = this[REFS_PER_BLOCK].next_in_ino; |
959 | else | ||
960 | next = NULL; | ||
961 | |||
962 | jffs2_free_refblock(this); | ||
959 | this = next; | 963 | this = next; |
960 | } | 964 | } |
961 | c->blocks[i].first_node = c->blocks[i].last_node = NULL; | 965 | c->blocks[i].first_node = c->blocks[i].last_node = NULL; |
962 | } | 966 | } |
963 | this = c->refs; | ||
964 | while (this) { | ||
965 | next = this->next_in_ino; | ||
966 | __jffs2_free_raw_node_ref(this); | ||
967 | this = next; | ||
968 | } | ||
969 | } | 967 | } |
970 | 968 | ||
971 | struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) | 969 | struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) |
@@ -1060,32 +1058,37 @@ struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, | |||
1060 | { | 1058 | { |
1061 | struct jffs2_raw_node_ref *ref; | 1059 | struct jffs2_raw_node_ref *ref; |
1062 | 1060 | ||
1063 | /* These will be preallocated _very_ shortly. */ | 1061 | BUG_ON(!jeb->allocated_refs); |
1064 | ref = c->refs; | 1062 | jeb->allocated_refs--; |
1065 | if (!c->refs) { | 1063 | |
1066 | JFFS2_WARNING("Using non-preallocated refs!\n"); | 1064 | ref = jeb->last_node; |
1067 | ref = __jffs2_alloc_raw_node_ref(); | 1065 | |
1068 | BUG_ON(!ref); | 1066 | dbg_noderef("Last node at %p is (%08x,%p)\n", ref, ref->flash_offset, |
1069 | WARN_ON(1); | 1067 | ref->next_in_ino); |
1070 | } else { | 1068 | |
1071 | c->refs = ref->next_in_ino; | 1069 | while (ref->flash_offset != REF_EMPTY_NODE) { |
1070 | if (ref->flash_offset == REF_LINK_NODE) | ||
1071 | ref = ref->next_in_ino; | ||
1072 | else | ||
1073 | ref++; | ||
1072 | } | 1074 | } |
1073 | 1075 | ||
1074 | ref->next_phys = NULL; | 1076 | dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref, |
1077 | ref->flash_offset, ofs, ref->next_in_ino, len); | ||
1078 | |||
1075 | ref->flash_offset = ofs; | 1079 | ref->flash_offset = ofs; |
1076 | 1080 | ||
1077 | if (!jeb->first_node) | 1081 | if (!jeb->first_node) { |
1078 | jeb->first_node = ref; | 1082 | jeb->first_node = ref; |
1079 | if (jeb->last_node) { | 1083 | BUG_ON(ref_offset(ref) != jeb->offset); |
1080 | jeb->last_node->next_phys = ref; | 1084 | } else if (unlikely(ref_offset(ref) != jeb->offset + c->sector_size - jeb->free_size)) { |
1081 | #ifdef TEST_TOTLEN | 1085 | uint32_t last_len = ref_totlen(c, jeb, jeb->last_node); |
1082 | if (ref_offset(jeb->last_node) + jeb->last_node->__totlen != ref_offset(ref)) { | 1086 | |
1083 | printk(KERN_CRIT "Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n", | 1087 | JFFS2_ERROR("Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n", |
1084 | ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, | 1088 | ref, ref_offset(ref), ref_offset(ref)+len, |
1085 | ref_offset(jeb->last_node), ref_offset(jeb->last_node)+jeb->last_node->__totlen); | 1089 | ref_offset(jeb->last_node), |
1086 | WARN_ON(1); | 1090 | ref_offset(jeb->last_node)+last_len); |
1087 | } | 1091 | BUG(); |
1088 | #endif | ||
1089 | } | 1092 | } |
1090 | jeb->last_node = ref; | 1093 | jeb->last_node = ref; |
1091 | 1094 | ||
@@ -1130,12 +1133,13 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb | |||
1130 | { | 1133 | { |
1131 | if (!size) | 1134 | if (!size) |
1132 | return 0; | 1135 | return 0; |
1133 | if (size > c->sector_size - jeb->used_size) { | 1136 | if (unlikely(size > jeb->free_size)) { |
1134 | printk(KERN_CRIT "Dirty space 0x%x larger then used_size 0x%x (wasted 0x%x)\n", | 1137 | printk(KERN_CRIT "Dirty space 0x%x larger then free_size 0x%x (wasted 0x%x)\n", |
1135 | size, jeb->used_size, jeb->wasted_size); | 1138 | size, jeb->free_size, jeb->wasted_size); |
1136 | BUG(); | 1139 | BUG(); |
1137 | } | 1140 | } |
1138 | if (jeb->last_node && ref_obsolete(jeb->last_node)) { | 1141 | /* REF_EMPTY_NODE is !obsolete, so that works OK */ |
1142 | if (ref_obsolete(jeb->last_node)) { | ||
1139 | #ifdef TEST_TOTLEN | 1143 | #ifdef TEST_TOTLEN |
1140 | jeb->last_node->__totlen += size; | 1144 | jeb->last_node->__totlen += size; |
1141 | #endif | 1145 | #endif |
@@ -1168,7 +1172,7 @@ static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, | |||
1168 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | 1172 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; |
1169 | 1173 | ||
1170 | /* Last node in block. Use free_space */ | 1174 | /* Last node in block. Use free_space */ |
1171 | if (ref != jeb->last_node) { | 1175 | if (unlikely(ref != jeb->last_node)) { |
1172 | printk(KERN_CRIT "ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n", | 1176 | printk(KERN_CRIT "ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n", |
1173 | ref, ref_offset(ref), jeb->last_node, jeb->last_node?ref_offset(jeb->last_node):0); | 1177 | ref, ref_offset(ref), jeb->last_node, jeb->last_node?ref_offset(jeb->last_node):0); |
1174 | BUG(); | 1178 | BUG(); |
@@ -1183,17 +1187,13 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je | |||
1183 | { | 1187 | { |
1184 | uint32_t ret; | 1188 | uint32_t ret; |
1185 | 1189 | ||
1186 | #if CONFIG_JFFS2_FS_DEBUG > 0 | ||
1187 | if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) { | ||
1188 | printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n", | ||
1189 | jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref)); | ||
1190 | BUG(); | ||
1191 | } | ||
1192 | #endif | ||
1193 | |||
1194 | ret = __ref_totlen(c, jeb, ref); | 1190 | ret = __ref_totlen(c, jeb, ref); |
1191 | |||
1195 | #ifdef TEST_TOTLEN | 1192 | #ifdef TEST_TOTLEN |
1196 | if (ret != ref->__totlen) { | 1193 | if (unlikely(ret != ref->__totlen)) { |
1194 | if (!jeb) | ||
1195 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | ||
1196 | |||
1197 | printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n", | 1197 | printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n", |
1198 | ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, | 1198 | ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, |
1199 | ret, ref->__totlen); | 1199 | ret, ref->__totlen); |
@@ -1204,13 +1204,14 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je | |||
1204 | printk(KERN_CRIT "No next ref. jeb->last_node is %p\n", jeb->last_node); | 1204 | printk(KERN_CRIT "No next ref. jeb->last_node is %p\n", jeb->last_node); |
1205 | 1205 | ||
1206 | printk(KERN_CRIT "jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n", jeb->wasted_size, jeb->dirty_size, jeb->used_size, jeb->free_size); | 1206 | printk(KERN_CRIT "jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n", jeb->wasted_size, jeb->dirty_size, jeb->used_size, jeb->free_size); |
1207 | ret = ref->__totlen; | 1207 | |
1208 | if (!jeb) | ||
1209 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | ||
1210 | #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) | 1208 | #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) |
1211 | __jffs2_dbg_dump_node_refs_nolock(c, jeb); | 1209 | __jffs2_dbg_dump_node_refs_nolock(c, jeb); |
1212 | #endif | 1210 | #endif |
1211 | |||
1213 | WARN_ON(1); | 1212 | WARN_ON(1); |
1213 | |||
1214 | ret = ref->__totlen; | ||
1214 | } | 1215 | } |
1215 | #endif /* TEST_TOTLEN */ | 1216 | #endif /* TEST_TOTLEN */ |
1216 | return ret; | 1217 | return ret; |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 6c92dc46fe9e..7ad8ee043880 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
@@ -80,7 +80,6 @@ struct jffs2_raw_node_ref | |||
80 | for this object. If this _is_ the last, it points to the inode_cache, | 80 | for this object. If this _is_ the last, it points to the inode_cache, |
81 | xattr_ref or xattr_datum instead. The common part of those structures | 81 | xattr_ref or xattr_datum instead. The common part of those structures |
82 | has NULL in the first word. See jffs2_raw_ref_to_ic() below */ | 82 | has NULL in the first word. See jffs2_raw_ref_to_ic() below */ |
83 | struct jffs2_raw_node_ref *next_phys; | ||
84 | uint32_t flash_offset; | 83 | uint32_t flash_offset; |
85 | #define TEST_TOTLEN | 84 | #define TEST_TOTLEN |
86 | #ifdef TEST_TOTLEN | 85 | #ifdef TEST_TOTLEN |
@@ -88,7 +87,29 @@ struct jffs2_raw_node_ref | |||
88 | #endif | 87 | #endif |
89 | }; | 88 | }; |
90 | 89 | ||
91 | #define ref_next(r) ((r)->next_phys) | 90 | #define REF_LINK_NODE ((int32_t)-1) |
91 | #define REF_EMPTY_NODE ((int32_t)-2) | ||
92 | |||
93 | /* Use blocks of about 256 bytes */ | ||
94 | #define REFS_PER_BLOCK ((255/sizeof(struct jffs2_raw_node_ref))-1) | ||
95 | |||
96 | static inline struct jffs2_raw_node_ref *ref_next(struct jffs2_raw_node_ref *ref) | ||
97 | { | ||
98 | ref++; | ||
99 | |||
100 | /* Link to another block of refs */ | ||
101 | if (ref->flash_offset == REF_LINK_NODE) { | ||
102 | ref = ref->next_in_ino; | ||
103 | if (!ref) | ||
104 | return ref; | ||
105 | } | ||
106 | |||
107 | /* End of chain */ | ||
108 | if (ref->flash_offset == REF_EMPTY_NODE) | ||
109 | return NULL; | ||
110 | |||
111 | return ref; | ||
112 | } | ||
92 | 113 | ||
93 | static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw) | 114 | static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw) |
94 | { | 115 | { |
@@ -234,6 +255,7 @@ struct jffs2_eraseblock | |||
234 | uint32_t wasted_size; | 255 | uint32_t wasted_size; |
235 | uint32_t free_size; /* Note that sector_size - free_size | 256 | uint32_t free_size; /* Note that sector_size - free_size |
236 | is the address of the first free space */ | 257 | is the address of the first free space */ |
258 | uint32_t allocated_refs; | ||
237 | struct jffs2_raw_node_ref *first_node; | 259 | struct jffs2_raw_node_ref *first_node; |
238 | struct jffs2_raw_node_ref *last_node; | 260 | struct jffs2_raw_node_ref *last_node; |
239 | 261 | ||
@@ -378,10 +400,9 @@ struct jffs2_raw_inode *jffs2_alloc_raw_inode(void); | |||
378 | void jffs2_free_raw_inode(struct jffs2_raw_inode *); | 400 | void jffs2_free_raw_inode(struct jffs2_raw_inode *); |
379 | struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void); | 401 | struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void); |
380 | void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *); | 402 | void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *); |
381 | int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, | 403 | int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, |
382 | struct jffs2_eraseblock *jeb, int nr); | 404 | struct jffs2_eraseblock *jeb, int nr); |
383 | struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void); | 405 | void jffs2_free_refblock(struct jffs2_raw_node_ref *); |
384 | void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *); | ||
385 | struct jffs2_node_frag *jffs2_alloc_node_frag(void); | 406 | struct jffs2_node_frag *jffs2_alloc_node_frag(void); |
386 | void jffs2_free_node_frag(struct jffs2_node_frag *); | 407 | void jffs2_free_node_frag(struct jffs2_node_frag *); |
387 | struct jffs2_inode_cache *jffs2_alloc_inode_cache(void); | 408 | struct jffs2_inode_cache *jffs2_alloc_inode_cache(void); |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 73a06d01db48..71d1630609a5 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -458,14 +458,13 @@ static inline int on_list(struct list_head *obj, struct list_head *head) | |||
458 | void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) | 458 | void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) |
459 | { | 459 | { |
460 | struct jffs2_eraseblock *jeb; | 460 | struct jffs2_eraseblock *jeb; |
461 | struct jffs2_raw_node_ref *next_ref; | ||
462 | int blocknr; | 461 | int blocknr; |
463 | struct jffs2_unknown_node n; | 462 | struct jffs2_unknown_node n; |
464 | int ret, addedsize; | 463 | int ret, addedsize; |
465 | size_t retlen; | 464 | size_t retlen; |
466 | uint32_t freed_len; | 465 | uint32_t freed_len; |
467 | 466 | ||
468 | if(!ref) { | 467 | if(unlikely(!ref)) { |
469 | printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); | 468 | printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); |
470 | return; | 469 | return; |
471 | } | 470 | } |
@@ -683,54 +682,6 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
683 | spin_unlock(&c->erase_completion_lock); | 682 | spin_unlock(&c->erase_completion_lock); |
684 | } | 683 | } |
685 | 684 | ||
686 | |||
687 | /* Merge with the next node in the physical list, if there is one | ||
688 | and if it's also obsolete and if it doesn't belong to any inode */ | ||
689 | next_ref = ref_next(ref); | ||
690 | |||
691 | if (next_ref && ref_obsolete(next_ref) && !next_ref->next_in_ino) { | ||
692 | spin_lock(&c->erase_completion_lock); | ||
693 | |||
694 | #ifdef TEST_TOTLEN | ||
695 | ref->__totlen += next_ref->__totlen; | ||
696 | #endif | ||
697 | ref->next_phys = ref_next(next_ref); | ||
698 | if (jeb->last_node == next_ref) jeb->last_node = ref; | ||
699 | if (jeb->gc_node == next_ref) { | ||
700 | /* gc will be happy continuing gc on this node */ | ||
701 | jeb->gc_node=ref; | ||
702 | } | ||
703 | spin_unlock(&c->erase_completion_lock); | ||
704 | |||
705 | __jffs2_free_raw_node_ref(next_ref); | ||
706 | } | ||
707 | |||
708 | /* Also merge with the previous node in the list, if there is one | ||
709 | and that one is obsolete */ | ||
710 | if (ref != jeb->first_node ) { | ||
711 | struct jffs2_raw_node_ref *p = jeb->first_node; | ||
712 | |||
713 | spin_lock(&c->erase_completion_lock); | ||
714 | |||
715 | while ((next_ref = ref_next(ref)) != ref) | ||
716 | p = next_ref; | ||
717 | |||
718 | if (ref_obsolete(p) && !ref->next_in_ino) { | ||
719 | #ifdef TEST_TOTLEN | ||
720 | p->__totlen += ref->__totlen; | ||
721 | #endif | ||
722 | if (jeb->last_node == ref) { | ||
723 | jeb->last_node = p; | ||
724 | } | ||
725 | if (jeb->gc_node == ref) { | ||
726 | /* gc will be happy continuing gc on this node */ | ||
727 | jeb->gc_node=p; | ||
728 | } | ||
729 | p->next_phys = ref_next(ref); | ||
730 | __jffs2_free_raw_node_ref(ref); | ||
731 | } | ||
732 | spin_unlock(&c->erase_completion_lock); | ||
733 | } | ||
734 | out_erase_sem: | 685 | out_erase_sem: |
735 | up(&c->erase_free_sem); | 686 | up(&c->erase_free_sem); |
736 | } | 687 | } |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 743c9e52152d..cd4021bcb944 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -95,6 +95,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
95 | #define jffs2_dataflash(c) (0) | 95 | #define jffs2_dataflash(c) (0) |
96 | #define jffs2_dataflash_setup(c) (0) | 96 | #define jffs2_dataflash_setup(c) (0) |
97 | #define jffs2_dataflash_cleanup(c) do {} while (0) | 97 | #define jffs2_dataflash_cleanup(c) do {} while (0) |
98 | #define jffs2_nor_wbuf_flash(c) (0) | ||
98 | #define jffs2_nor_wbuf_flash_setup(c) (0) | 99 | #define jffs2_nor_wbuf_flash_setup(c) (0) |
99 | #define jffs2_nor_wbuf_flash_cleanup(c) do {} while (0) | 100 | #define jffs2_nor_wbuf_flash_cleanup(c) do {} while (0) |
100 | 101 | ||
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 523a8f330ef5..00e856e4fdbe 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c | |||
@@ -511,7 +511,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
511 | spr = (struct jffs2_sum_xref_flash *)sp; | 511 | spr = (struct jffs2_sum_xref_flash *)sp; |
512 | dbg_summary("xref at %#08x-%#08x\n", | 512 | dbg_summary("xref at %#08x-%#08x\n", |
513 | jeb->offset + je32_to_cpu(spr->offset), | 513 | jeb->offset + je32_to_cpu(spr->offset), |
514 | jeb->offset + je32_to_cpu(spr->offset) + PAD(sizeof(struct jffs2_raw_xref))); | 514 | jeb->offset + je32_to_cpu(spr->offset) + |
515 | (uint32_t)PAD(sizeof(struct jffs2_raw_xref))); | ||
515 | 516 | ||
516 | ref = jffs2_alloc_xattr_ref(); | 517 | ref = jffs2_alloc_xattr_ref(); |
517 | if (!ref) { | 518 | if (!ref) { |
@@ -787,10 +788,12 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
787 | JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n", | 788 | JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n", |
788 | infosize, sum_ofs, ret, retlen); | 789 | infosize, sum_ofs, ret, retlen); |
789 | 790 | ||
790 | /* Waste remaining space */ | 791 | if (retlen) { |
791 | spin_lock(&c->erase_completion_lock); | 792 | /* Waste remaining space */ |
792 | jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL); | 793 | spin_lock(&c->erase_completion_lock); |
793 | spin_unlock(&c->erase_completion_lock); | 794 | jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL); |
795 | spin_unlock(&c->erase_completion_lock); | ||
796 | } | ||
794 | 797 | ||
795 | c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; | 798 | c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; |
796 | 799 | ||
@@ -836,6 +839,7 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) | |||
836 | jffs2_sum_disable_collecting(c->summary); | 839 | jffs2_sum_disable_collecting(c->summary); |
837 | 840 | ||
838 | JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize); | 841 | JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize); |
842 | spin_lock(&c->erase_completion_lock); | ||
839 | return 0; | 843 | return 0; |
840 | } | 844 | } |
841 | 845 | ||
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index e16e45ea0474..2febece89062 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -156,72 +156,126 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
156 | jffs2_erase_pending_trigger(c); | 156 | jffs2_erase_pending_trigger(c); |
157 | } | 157 | } |
158 | 158 | ||
159 | /* Adjust its size counts accordingly */ | 159 | if (!jffs2_prealloc_raw_node_refs(c, jeb, 1)) { |
160 | c->wasted_size += jeb->free_size; | 160 | uint32_t oldfree = jeb->free_size; |
161 | c->free_size -= jeb->free_size; | 161 | |
162 | jeb->wasted_size += jeb->free_size; | 162 | jffs2_link_node_ref(c, jeb, |
163 | jeb->free_size = 0; | 163 | (jeb->offset+c->sector_size-oldfree) | REF_OBSOLETE, |
164 | oldfree, NULL); | ||
165 | /* convert to wasted */ | ||
166 | c->wasted_size += oldfree; | ||
167 | jeb->wasted_size += oldfree; | ||
168 | c->dirty_size -= oldfree; | ||
169 | jeb->dirty_size -= oldfree; | ||
170 | } | ||
164 | 171 | ||
165 | jffs2_dbg_dump_block_lists_nolock(c); | 172 | jffs2_dbg_dump_block_lists_nolock(c); |
166 | jffs2_dbg_acct_sanity_check_nolock(c,jeb); | 173 | jffs2_dbg_acct_sanity_check_nolock(c,jeb); |
167 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | 174 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
168 | } | 175 | } |
169 | 176 | ||
177 | static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info *c, | ||
178 | struct jffs2_inode_info *f, | ||
179 | struct jffs2_raw_node_ref *raw, | ||
180 | union jffs2_node_union *node) | ||
181 | { | ||
182 | struct jffs2_node_frag *frag; | ||
183 | struct jffs2_full_dirent *fd; | ||
184 | |||
185 | dbg_noderef("incore_replace_raw: node at %p is {%04x,%04x}\n", | ||
186 | node, je16_to_cpu(node->u.magic), je16_to_cpu(node->u.nodetype)); | ||
187 | |||
188 | BUG_ON(je16_to_cpu(node->u.magic) != 0x1985 && | ||
189 | je16_to_cpu(node->u.magic) != 0); | ||
190 | |||
191 | switch (je16_to_cpu(node->u.nodetype)) { | ||
192 | case JFFS2_NODETYPE_INODE: | ||
193 | frag = jffs2_lookup_node_frag(&f->fragtree, je32_to_cpu(node->i.offset)); | ||
194 | BUG_ON(!frag); | ||
195 | /* Find a frag which refers to the full_dnode we want to modify */ | ||
196 | while (!frag->node || frag->node->raw != raw) { | ||
197 | frag = frag_next(frag); | ||
198 | BUG_ON(!frag); | ||
199 | } | ||
200 | dbg_noderef("Will replace ->raw in full_dnode at %p\n", frag->node); | ||
201 | return &frag->node->raw; | ||
202 | break; | ||
203 | |||
204 | case JFFS2_NODETYPE_DIRENT: | ||
205 | for (fd = f->dents; fd; fd = fd->next) { | ||
206 | if (fd->raw == raw) { | ||
207 | dbg_noderef("Will replace ->raw in full_dirent at %p\n", fd); | ||
208 | return &fd->raw; | ||
209 | } | ||
210 | } | ||
211 | BUG(); | ||
212 | default: | ||
213 | dbg_noderef("Don't care about replacing raw for nodetype %x\n", | ||
214 | je16_to_cpu(node->u.nodetype)); | ||
215 | break; | ||
216 | } | ||
217 | return NULL; | ||
218 | } | ||
219 | |||
170 | /* Recover from failure to write wbuf. Recover the nodes up to the | 220 | /* Recover from failure to write wbuf. Recover the nodes up to the |
171 | * wbuf, not the one which we were starting to try to write. */ | 221 | * wbuf, not the one which we were starting to try to write. */ |
172 | 222 | ||
173 | static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | 223 | static void jffs2_wbuf_recover(struct jffs2_sb_info *c) |
174 | { | 224 | { |
175 | struct jffs2_eraseblock *jeb, *new_jeb; | 225 | struct jffs2_eraseblock *jeb, *new_jeb; |
176 | struct jffs2_raw_node_ref **first_raw, **raw; | 226 | struct jffs2_raw_node_ref *raw, *next, *first_raw = NULL; |
177 | size_t retlen; | 227 | size_t retlen; |
178 | int ret; | 228 | int ret; |
229 | int nr_refile = 0; | ||
179 | unsigned char *buf; | 230 | unsigned char *buf; |
180 | uint32_t start, end, ofs, len; | 231 | uint32_t start, end, ofs, len; |
181 | 232 | ||
182 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; | 233 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; |
183 | 234 | ||
184 | if (jffs2_prealloc_raw_node_refs(c, jeb, c->reserved_refs + 1)) | ||
185 | return; | ||
186 | |||
187 | spin_lock(&c->erase_completion_lock); | 235 | spin_lock(&c->erase_completion_lock); |
188 | |||
189 | jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); | 236 | jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); |
237 | spin_unlock(&c->erase_completion_lock); | ||
238 | |||
239 | BUG_ON(!ref_obsolete(jeb->last_node)); | ||
190 | 240 | ||
191 | /* Find the first node to be recovered, by skipping over every | 241 | /* Find the first node to be recovered, by skipping over every |
192 | node which ends before the wbuf starts, or which is obsolete. */ | 242 | node which ends before the wbuf starts, or which is obsolete. */ |
193 | first_raw = &jeb->first_node; | 243 | for (next = raw = jeb->first_node; next; raw = next) { |
194 | while (*first_raw && | 244 | next = ref_next(raw); |
195 | (ref_obsolete(*first_raw) || | 245 | |
196 | (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) { | 246 | if (ref_obsolete(raw) || |
197 | D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", | 247 | (next && ref_offset(next) <= c->wbuf_ofs)) { |
198 | ref_offset(*first_raw), ref_flags(*first_raw), | 248 | dbg_noderef("Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", |
199 | (ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw)), | 249 | ref_offset(raw), ref_flags(raw), |
200 | c->wbuf_ofs)); | 250 | (ref_offset(raw) + ref_totlen(c, jeb, raw)), |
201 | first_raw = &(*first_raw)->next_phys; | 251 | c->wbuf_ofs); |
252 | continue; | ||
253 | } | ||
254 | dbg_noderef("First node to be recovered is at 0x%08x(%d)-0x%08x\n", | ||
255 | ref_offset(raw), ref_flags(raw), | ||
256 | (ref_offset(raw) + ref_totlen(c, jeb, raw))); | ||
257 | |||
258 | first_raw = raw; | ||
259 | break; | ||
202 | } | 260 | } |
203 | 261 | ||
204 | if (!*first_raw) { | 262 | if (!first_raw) { |
205 | /* All nodes were obsolete. Nothing to recover. */ | 263 | /* All nodes were obsolete. Nothing to recover. */ |
206 | D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n")); | 264 | D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n")); |
207 | spin_unlock(&c->erase_completion_lock); | 265 | c->wbuf_len = 0; |
208 | return; | 266 | return; |
209 | } | 267 | } |
210 | 268 | ||
211 | start = ref_offset(*first_raw); | 269 | start = ref_offset(first_raw); |
212 | end = ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw); | 270 | end = ref_offset(jeb->last_node); |
271 | nr_refile = 1; | ||
213 | 272 | ||
214 | /* Find the last node to be recovered */ | 273 | /* Count the number of refs which need to be copied */ |
215 | raw = first_raw; | 274 | while ((raw = ref_next(raw)) != jeb->last_node) |
216 | while ((*raw)) { | 275 | nr_refile++; |
217 | if (!ref_obsolete(*raw)) | ||
218 | end = ref_offset(*raw) + ref_totlen(c, jeb, *raw); | ||
219 | 276 | ||
220 | raw = &(*raw)->next_phys; | 277 | dbg_noderef("wbuf recover %08x-%08x (%d bytes in %d nodes)\n", |
221 | } | 278 | start, end, end - start, nr_refile); |
222 | spin_unlock(&c->erase_completion_lock); | ||
223 | |||
224 | D1(printk(KERN_DEBUG "wbuf recover %08x-%08x\n", start, end)); | ||
225 | 279 | ||
226 | buf = NULL; | 280 | buf = NULL; |
227 | if (start < c->wbuf_ofs) { | 281 | if (start < c->wbuf_ofs) { |
@@ -248,13 +302,24 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
248 | kfree(buf); | 302 | kfree(buf); |
249 | buf = NULL; | 303 | buf = NULL; |
250 | read_failed: | 304 | read_failed: |
251 | first_raw = &(*first_raw)->next_phys; | 305 | first_raw = ref_next(first_raw); |
306 | nr_refile--; | ||
307 | while (first_raw && ref_obsolete(first_raw)) { | ||
308 | first_raw = ref_next(first_raw); | ||
309 | nr_refile--; | ||
310 | } | ||
311 | |||
252 | /* If this was the only node to be recovered, give up */ | 312 | /* If this was the only node to be recovered, give up */ |
253 | if (!(*first_raw)) | 313 | if (!first_raw) { |
314 | c->wbuf_len = 0; | ||
254 | return; | 315 | return; |
316 | } | ||
255 | 317 | ||
256 | /* It wasn't. Go on and try to recover nodes complete in the wbuf */ | 318 | /* It wasn't. Go on and try to recover nodes complete in the wbuf */ |
257 | start = ref_offset(*first_raw); | 319 | start = ref_offset(first_raw); |
320 | dbg_noderef("wbuf now recover %08x-%08x (%d bytes in %d nodes)\n", | ||
321 | start, end, end - start, nr_refile); | ||
322 | |||
258 | } else { | 323 | } else { |
259 | /* Read succeeded. Copy the remaining data from the wbuf */ | 324 | /* Read succeeded. Copy the remaining data from the wbuf */ |
260 | memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs); | 325 | memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs); |
@@ -263,7 +328,6 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
263 | /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards. | 328 | /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards. |
264 | Either 'buf' contains the data, or we find it in the wbuf */ | 329 | Either 'buf' contains the data, or we find it in the wbuf */ |
265 | 330 | ||
266 | |||
267 | /* ... and get an allocation of space from a shiny new block instead */ | 331 | /* ... and get an allocation of space from a shiny new block instead */ |
268 | ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE); | 332 | ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE); |
269 | if (ret) { | 333 | if (ret) { |
@@ -271,6 +335,14 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
271 | kfree(buf); | 335 | kfree(buf); |
272 | return; | 336 | return; |
273 | } | 337 | } |
338 | |||
339 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile); | ||
340 | if (ret) { | ||
341 | printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n"); | ||
342 | kfree(buf); | ||
343 | return; | ||
344 | } | ||
345 | |||
274 | ofs = write_ofs(c); | 346 | ofs = write_ofs(c); |
275 | 347 | ||
276 | if (end-start >= c->wbuf_pagesize) { | 348 | if (end-start >= c->wbuf_pagesize) { |
@@ -304,7 +376,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
304 | kfree(buf); | 376 | kfree(buf); |
305 | 377 | ||
306 | if (retlen) | 378 | if (retlen) |
307 | jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, *first_raw), NULL); | 379 | jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, first_raw), NULL); |
308 | 380 | ||
309 | return; | 381 | return; |
310 | } | 382 | } |
@@ -314,12 +386,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
314 | c->wbuf_ofs = ofs + towrite; | 386 | c->wbuf_ofs = ofs + towrite; |
315 | memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); | 387 | memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); |
316 | /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ | 388 | /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ |
317 | kfree(buf); | ||
318 | } else { | 389 | } else { |
319 | /* OK, now we're left with the dregs in whichever buffer we're using */ | 390 | /* OK, now we're left with the dregs in whichever buffer we're using */ |
320 | if (buf) { | 391 | if (buf) { |
321 | memcpy(c->wbuf, buf, end-start); | 392 | memcpy(c->wbuf, buf, end-start); |
322 | kfree(buf); | ||
323 | } else { | 393 | } else { |
324 | memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start); | 394 | memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start); |
325 | } | 395 | } |
@@ -331,62 +401,111 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
331 | new_jeb = &c->blocks[ofs / c->sector_size]; | 401 | new_jeb = &c->blocks[ofs / c->sector_size]; |
332 | 402 | ||
333 | spin_lock(&c->erase_completion_lock); | 403 | spin_lock(&c->erase_completion_lock); |
334 | if (new_jeb->first_node) { | 404 | for (raw = first_raw; raw != jeb->last_node; raw = ref_next(raw)) { |
335 | /* Odd, but possible with ST flash later maybe */ | 405 | uint32_t rawlen = ref_totlen(c, jeb, raw); |
336 | new_jeb->last_node->next_phys = *first_raw; | 406 | struct jffs2_inode_cache *ic; |
337 | } else { | 407 | struct jffs2_raw_node_ref *new_ref; |
338 | new_jeb->first_node = *first_raw; | 408 | struct jffs2_raw_node_ref **adjust_ref = NULL; |
339 | } | 409 | struct jffs2_inode_info *f = NULL; |
340 | |||
341 | raw = first_raw; | ||
342 | while (*raw) { | ||
343 | uint32_t rawlen = ref_totlen(c, jeb, *raw); | ||
344 | 410 | ||
345 | D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n", | 411 | D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n", |
346 | rawlen, ref_offset(*raw), ref_flags(*raw), ofs)); | 412 | rawlen, ref_offset(raw), ref_flags(raw), ofs)); |
413 | |||
414 | ic = jffs2_raw_ref_to_ic(raw); | ||
415 | |||
416 | /* Ick. This XATTR mess should be fixed shortly... */ | ||
417 | if (ic && ic->class == RAWNODE_CLASS_XATTR_DATUM) { | ||
418 | struct jffs2_xattr_datum *xd = (void *)ic; | ||
419 | BUG_ON(xd->node != raw); | ||
420 | adjust_ref = &xd->node; | ||
421 | raw->next_in_ino = NULL; | ||
422 | ic = NULL; | ||
423 | } else if (ic && ic->class == RAWNODE_CLASS_XATTR_REF) { | ||
424 | struct jffs2_xattr_datum *xr = (void *)ic; | ||
425 | BUG_ON(xr->node != raw); | ||
426 | adjust_ref = &xr->node; | ||
427 | raw->next_in_ino = NULL; | ||
428 | ic = NULL; | ||
429 | } else if (ic && ic->class == RAWNODE_CLASS_INODE_CACHE) { | ||
430 | struct jffs2_raw_node_ref **p = &ic->nodes; | ||
431 | |||
432 | /* Remove the old node from the per-inode list */ | ||
433 | while (*p && *p != (void *)ic) { | ||
434 | if (*p == raw) { | ||
435 | (*p) = (raw->next_in_ino); | ||
436 | raw->next_in_ino = NULL; | ||
437 | break; | ||
438 | } | ||
439 | p = &((*p)->next_in_ino); | ||
440 | } | ||
347 | 441 | ||
348 | if (ref_obsolete(*raw)) { | 442 | if (ic->state == INO_STATE_PRESENT && !ref_obsolete(raw)) { |
349 | /* Shouldn't really happen much */ | 443 | /* If it's an in-core inode, then we have to adjust any |
350 | new_jeb->dirty_size += rawlen; | 444 | full_dirent or full_dnode structure to point to the |
351 | new_jeb->free_size -= rawlen; | 445 | new version instead of the old */ |
352 | c->dirty_size += rawlen; | 446 | f = jffs2_gc_fetch_inode(c, ic->ino, ic->nlink); |
353 | } else { | 447 | if (IS_ERR(f)) { |
354 | new_jeb->used_size += rawlen; | 448 | /* Should never happen; it _must_ be present */ |
355 | new_jeb->free_size -= rawlen; | 449 | JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n", |
450 | ic->ino, PTR_ERR(f)); | ||
451 | BUG(); | ||
452 | } | ||
453 | /* We don't lock f->sem. There's a number of ways we could | ||
454 | end up in here with it already being locked, and nobody's | ||
455 | going to modify it on us anyway because we hold the | ||
456 | alloc_sem. We're only changing one ->raw pointer too, | ||
457 | which we can get away with without upsetting readers. */ | ||
458 | adjust_ref = jffs2_incore_replace_raw(c, f, raw, | ||
459 | (void *)(buf?:c->wbuf) + (ref_offset(raw) - start)); | ||
460 | } else if (unlikely(ic->state != INO_STATE_PRESENT && | ||
461 | ic->state != INO_STATE_CHECKEDABSENT && | ||
462 | ic->state != INO_STATE_GC)) { | ||
463 | JFFS2_ERROR("Inode #%u is in strange state %d!\n", ic->ino, ic->state); | ||
464 | BUG(); | ||
465 | } | ||
466 | } | ||
467 | |||
468 | new_ref = jffs2_link_node_ref(c, new_jeb, ofs | ref_flags(raw), rawlen, ic); | ||
469 | |||
470 | if (adjust_ref) { | ||
471 | BUG_ON(*adjust_ref != raw); | ||
472 | *adjust_ref = new_ref; | ||
473 | } | ||
474 | if (f) | ||
475 | jffs2_gc_release_inode(c, f); | ||
476 | |||
477 | if (!ref_obsolete(raw)) { | ||
356 | jeb->dirty_size += rawlen; | 478 | jeb->dirty_size += rawlen; |
357 | jeb->used_size -= rawlen; | 479 | jeb->used_size -= rawlen; |
358 | c->dirty_size += rawlen; | 480 | c->dirty_size += rawlen; |
481 | c->used_size -= rawlen; | ||
482 | raw->flash_offset = ref_offset(raw) | REF_OBSOLETE; | ||
483 | BUG_ON(raw->next_in_ino); | ||
359 | } | 484 | } |
360 | c->free_size -= rawlen; | ||
361 | (*raw)->flash_offset = ofs | ref_flags(*raw); | ||
362 | ofs += rawlen; | 485 | ofs += rawlen; |
363 | new_jeb->last_node = *raw; | ||
364 | |||
365 | raw = &(*raw)->next_phys; | ||
366 | } | 486 | } |
367 | 487 | ||
488 | kfree(buf); | ||
489 | |||
368 | /* Fix up the original jeb now it's on the bad_list */ | 490 | /* Fix up the original jeb now it's on the bad_list */ |
369 | *first_raw = NULL; | 491 | if (first_raw == jeb->first_node) { |
370 | if (first_raw == &jeb->first_node) { | ||
371 | jeb->last_node = NULL; | ||
372 | D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset)); | 492 | D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset)); |
373 | list_del(&jeb->list); | 493 | list_del(&jeb->list); |
374 | list_add(&jeb->list, &c->erase_pending_list); | 494 | list_add(&jeb->list, &c->erase_pending_list); |
375 | c->nr_erasing_blocks++; | 495 | c->nr_erasing_blocks++; |
376 | jffs2_erase_pending_trigger(c); | 496 | jffs2_erase_pending_trigger(c); |
377 | } | 497 | } |
378 | else | ||
379 | jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys); | ||
380 | 498 | ||
381 | jffs2_dbg_acct_sanity_check_nolock(c, jeb); | 499 | jffs2_dbg_acct_sanity_check_nolock(c, jeb); |
382 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | 500 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); |
383 | 501 | ||
384 | jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); | 502 | jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); |
385 | jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); | 503 | jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); |
386 | 504 | ||
387 | spin_unlock(&c->erase_completion_lock); | 505 | spin_unlock(&c->erase_completion_lock); |
388 | 506 | ||
389 | D1(printk(KERN_DEBUG "wbuf recovery completed OK\n")); | 507 | D1(printk(KERN_DEBUG "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n", c->wbuf_ofs, c->wbuf_len)); |
508 | |||
390 | } | 509 | } |
391 | 510 | ||
392 | /* Meaning of pad argument: | 511 | /* Meaning of pad argument: |
@@ -400,6 +519,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
400 | 519 | ||
401 | static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | 520 | static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) |
402 | { | 521 | { |
522 | struct jffs2_eraseblock *wbuf_jeb; | ||
403 | int ret; | 523 | int ret; |
404 | size_t retlen; | 524 | size_t retlen; |
405 | 525 | ||
@@ -417,7 +537,8 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
417 | if (!c->wbuf_len) /* already checked c->wbuf above */ | 537 | if (!c->wbuf_len) /* already checked c->wbuf above */ |
418 | return 0; | 538 | return 0; |
419 | 539 | ||
420 | if (jffs2_prealloc_raw_node_refs(c, c->nextblock, c->reserved_refs + 1)) | 540 | wbuf_jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; |
541 | if (jffs2_prealloc_raw_node_refs(c, wbuf_jeb, c->nextblock->allocated_refs + 1)) | ||
421 | return -ENOMEM; | 542 | return -ENOMEM; |
422 | 543 | ||
423 | /* claim remaining space on the page | 544 | /* claim remaining space on the page |
@@ -473,32 +594,29 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
473 | 594 | ||
474 | /* Adjust free size of the block if we padded. */ | 595 | /* Adjust free size of the block if we padded. */ |
475 | if (pad) { | 596 | if (pad) { |
476 | struct jffs2_eraseblock *jeb; | ||
477 | uint32_t waste = c->wbuf_pagesize - c->wbuf_len; | 597 | uint32_t waste = c->wbuf_pagesize - c->wbuf_len; |
478 | 598 | ||
479 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; | ||
480 | |||
481 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", | 599 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", |
482 | (jeb==c->nextblock)?"next":"", jeb->offset)); | 600 | (wbuf_jeb==c->nextblock)?"next":"", wbuf_jeb->offset)); |
483 | 601 | ||
484 | /* wbuf_pagesize - wbuf_len is the amount of space that's to be | 602 | /* wbuf_pagesize - wbuf_len is the amount of space that's to be |
485 | padded. If there is less free space in the block than that, | 603 | padded. If there is less free space in the block than that, |
486 | something screwed up */ | 604 | something screwed up */ |
487 | if (jeb->free_size < waste) { | 605 | if (wbuf_jeb->free_size < waste) { |
488 | printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n", | 606 | printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n", |
489 | c->wbuf_ofs, c->wbuf_len, waste); | 607 | c->wbuf_ofs, c->wbuf_len, waste); |
490 | printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n", | 608 | printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n", |
491 | jeb->offset, jeb->free_size); | 609 | wbuf_jeb->offset, wbuf_jeb->free_size); |
492 | BUG(); | 610 | BUG(); |
493 | } | 611 | } |
494 | 612 | ||
495 | spin_lock(&c->erase_completion_lock); | 613 | spin_lock(&c->erase_completion_lock); |
496 | 614 | ||
497 | jffs2_link_node_ref(c, jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); | 615 | jffs2_link_node_ref(c, wbuf_jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); |
498 | /* FIXME: that made it count as dirty. Convert to wasted */ | 616 | /* FIXME: that made it count as dirty. Convert to wasted */ |
499 | jeb->dirty_size -= waste; | 617 | wbuf_jeb->dirty_size -= waste; |
500 | c->dirty_size -= waste; | 618 | c->dirty_size -= waste; |
501 | jeb->wasted_size += waste; | 619 | wbuf_jeb->wasted_size += waste; |
502 | c->wasted_size += waste; | 620 | c->wasted_size += waste; |
503 | } else | 621 | } else |
504 | spin_lock(&c->erase_completion_lock); | 622 | spin_lock(&c->erase_completion_lock); |
@@ -758,7 +876,8 @@ outerr: | |||
758 | * This is the entry for flash write. | 876 | * This is the entry for flash write. |
759 | * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev | 877 | * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev |
760 | */ | 878 | */ |
761 | int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf) | 879 | int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, |
880 | size_t *retlen, const u_char *buf) | ||
762 | { | 881 | { |
763 | struct kvec vecs[1]; | 882 | struct kvec vecs[1]; |
764 | 883 | ||
@@ -953,7 +1072,7 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
953 | } | 1072 | } |
954 | D1(if (retval == 1) { | 1073 | D1(if (retval == 1) { |
955 | printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset); | 1074 | printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset); |
956 | printk(KERN_WARNING "OOB at %08x was ", offset); | 1075 | printk(KERN_WARNING "OOB at %08zx was ", offset); |
957 | for (i=0; i < oob_size; i++) { | 1076 | for (i=0; i < oob_size; i++) { |
958 | printk("%02x ", buf[i]); | 1077 | printk("%02x ", buf[i]); |
959 | } | 1078 | } |