aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2008-04-22 20:17:51 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2008-04-22 20:24:17 -0400
commit85a62db6245a82f07a31b387915ee2180b9ea11a (patch)
tree9de37a0f9267f92aac41e817c5e8fec6887400a1
parent014b164e1392a166fe96e003d2f0e7ad2e2a0bb7 (diff)
[JFFS2] Add paranoia debugging for superblock counts
The problem fixed in commit 014b164e1392a166fe96e003d2f0e7ad2e2a0bb7 (space leak with in-band cleanmarkers) would have been caught a lot quicker if our paranoid debugging mode had included adding up the size counts from all the eraseblocks and comparing the totals with the counts in the superblock. Add that. Make jffs2_mark_erased_block() file the newly-erased block on the free_list before calling the debug function, to make it happy. Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r--fs/jffs2/debug.c132
-rw-r--r--fs/jffs2/erase.c7
2 files changed, 136 insertions, 3 deletions
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c
index 660793107e92..590bdd6e0147 100644
--- a/fs/jffs2/debug.c
+++ b/fs/jffs2/debug.c
@@ -153,6 +153,135 @@ __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
153 kfree(buf); 153 kfree(buf);
154} 154}
155 155
156void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c)
157{
158 struct jffs2_eraseblock *jeb;
159 uint32_t free = 0, dirty = 0, used = 0, wasted = 0,
160 erasing = 0, bad = 0, unchecked = 0;
161 int nr_counted = 0;
162 int dump = 0;
163
164 if (c->gcblock) {
165 nr_counted++;
166 free += c->gcblock->free_size;
167 dirty += c->gcblock->dirty_size;
168 used += c->gcblock->used_size;
169 wasted += c->gcblock->wasted_size;
170 unchecked += c->gcblock->unchecked_size;
171 }
172 if (c->nextblock) {
173 nr_counted++;
174 free += c->nextblock->free_size;
175 dirty += c->nextblock->dirty_size;
176 used += c->nextblock->used_size;
177 wasted += c->nextblock->wasted_size;
178 unchecked += c->nextblock->unchecked_size;
179 }
180 list_for_each_entry(jeb, &c->clean_list, list) {
181 nr_counted++;
182 free += jeb->free_size;
183 dirty += jeb->dirty_size;
184 used += jeb->used_size;
185 wasted += jeb->wasted_size;
186 unchecked += jeb->unchecked_size;
187 }
188 list_for_each_entry(jeb, &c->very_dirty_list, list) {
189 nr_counted++;
190 free += jeb->free_size;
191 dirty += jeb->dirty_size;
192 used += jeb->used_size;
193 wasted += jeb->wasted_size;
194 unchecked += jeb->unchecked_size;
195 }
196 list_for_each_entry(jeb, &c->dirty_list, list) {
197 nr_counted++;
198 free += jeb->free_size;
199 dirty += jeb->dirty_size;
200 used += jeb->used_size;
201 wasted += jeb->wasted_size;
202 unchecked += jeb->unchecked_size;
203 }
204 list_for_each_entry(jeb, &c->erasable_list, list) {
205 nr_counted++;
206 free += jeb->free_size;
207 dirty += jeb->dirty_size;
208 used += jeb->used_size;
209 wasted += jeb->wasted_size;
210 unchecked += jeb->unchecked_size;
211 }
212 list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) {
213 nr_counted++;
214 free += jeb->free_size;
215 dirty += jeb->dirty_size;
216 used += jeb->used_size;
217 wasted += jeb->wasted_size;
218 unchecked += jeb->unchecked_size;
219 }
220 list_for_each_entry(jeb, &c->erase_pending_list, list) {
221 nr_counted++;
222 free += jeb->free_size;
223 dirty += jeb->dirty_size;
224 used += jeb->used_size;
225 wasted += jeb->wasted_size;
226 unchecked += jeb->unchecked_size;
227 }
228 list_for_each_entry(jeb, &c->free_list, list) {
229 nr_counted++;
230 free += jeb->free_size;
231 dirty += jeb->dirty_size;
232 used += jeb->used_size;
233 wasted += jeb->wasted_size;
234 unchecked += jeb->unchecked_size;
235 }
236 list_for_each_entry(jeb, &c->bad_used_list, list) {
237 nr_counted++;
238 free += jeb->free_size;
239 dirty += jeb->dirty_size;
240 used += jeb->used_size;
241 wasted += jeb->wasted_size;
242 unchecked += jeb->unchecked_size;
243 }
244
245 list_for_each_entry(jeb, &c->erasing_list, list) {
246 nr_counted++;
247 erasing += c->sector_size;
248 }
249 list_for_each_entry(jeb, &c->erase_complete_list, list) {
250 nr_counted++;
251 erasing += c->sector_size;
252 }
253 list_for_each_entry(jeb, &c->bad_list, list) {
254 nr_counted++;
255 bad += c->sector_size;
256 }
257
258#define check(sz) \
259 if (sz != c->sz##_size) { \
260 printk(KERN_WARNING #sz "_size mismatch counted 0x%x, c->" #sz "_size 0x%x\n", \
261 sz, c->sz##_size); \
262 dump = 1; \
263 }
264 check(free);
265 check(dirty);
266 check(used);
267 check(wasted);
268 check(unchecked);
269 check(bad);
270 check(erasing);
271#undef check
272
273 if (nr_counted != c->nr_blocks) {
274 printk(KERN_WARNING "%s counted only 0x%x blocks of 0x%x. Where are the others?\n",
275 __func__, nr_counted, c->nr_blocks);
276 dump = 1;
277 }
278
279 if (dump) {
280 __jffs2_dbg_dump_block_lists_nolock(c);
281 BUG();
282 }
283}
284
156/* 285/*
157 * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'. 286 * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
158 */ 287 */
@@ -229,6 +358,9 @@ __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
229 } 358 }
230#endif 359#endif
231 360
361 if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING)))
362 __jffs2_dbg_superblock_counts(c);
363
232 return; 364 return;
233 365
234error: 366error:
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index bdc6a7bec802..65d91943fc2d 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -460,12 +460,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
460 if (c->cleanmarker_size && !jffs2_cleanmarker_oob(c)) 460 if (c->cleanmarker_size && !jffs2_cleanmarker_oob(c))
461 jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); 461 jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL);
462 462
463 jffs2_dbg_acct_sanity_check_nolock(c,jeb);
464 jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
465
466 list_add_tail(&jeb->list, &c->free_list); 463 list_add_tail(&jeb->list, &c->free_list);
467 c->nr_erasing_blocks--; 464 c->nr_erasing_blocks--;
468 c->nr_free_blocks++; 465 c->nr_free_blocks++;
466
467 jffs2_dbg_acct_sanity_check_nolock(c, jeb);
468 jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
469
469 spin_unlock(&c->erase_completion_lock); 470 spin_unlock(&c->erase_completion_lock);
470 mutex_unlock(&c->erase_free_sem); 471 mutex_unlock(&c->erase_free_sem);
471 wake_up(&c->erase_wait); 472 wake_up(&c->erase_wait);