diff options
author | Adrian Hunter <ext-adrian.hunter@nokia.com> | 2008-09-12 11:13:31 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-09-30 04:12:59 -0400 |
commit | 73944a6de048c2c49422e9063e57198256efd23e (patch) | |
tree | 048789b4d3228dcf6e0f33a446bdbf423ebf5b6f /fs | |
parent | 5c0013c16bd2ee08ffef1a1365622556a57218f5 (diff) |
UBIFS: add more debugging messages for LPT
Also add debugging checks for LPT size and separate
out c->check_lpt_free from unrelated bitfields.
Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ubifs/debug.c | 37 | ||||
-rw-r--r-- | fs/ubifs/debug.h | 6 | ||||
-rw-r--r-- | fs/ubifs/lpt.c | 3 | ||||
-rw-r--r-- | fs/ubifs/lpt_commit.c | 185 | ||||
-rw-r--r-- | fs/ubifs/ubifs.h | 10 |
5 files changed, 228 insertions, 13 deletions
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 32071ec87cd7..7186400750e7 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c | |||
@@ -655,6 +655,43 @@ void dbg_dump_lprops(struct ubifs_info *c) | |||
655 | } | 655 | } |
656 | } | 656 | } |
657 | 657 | ||
658 | void dbg_dump_lpt_info(struct ubifs_info *c) | ||
659 | { | ||
660 | int i; | ||
661 | |||
662 | spin_lock(&dbg_lock); | ||
663 | printk(KERN_DEBUG "\tlpt_sz: %lld\n", c->lpt_sz); | ||
664 | printk(KERN_DEBUG "\tpnode_sz: %d\n", c->pnode_sz); | ||
665 | printk(KERN_DEBUG "\tnnode_sz: %d\n", c->nnode_sz); | ||
666 | printk(KERN_DEBUG "\tltab_sz: %d\n", c->ltab_sz); | ||
667 | printk(KERN_DEBUG "\tlsave_sz: %d\n", c->lsave_sz); | ||
668 | printk(KERN_DEBUG "\tbig_lpt: %d\n", c->big_lpt); | ||
669 | printk(KERN_DEBUG "\tlpt_hght: %d\n", c->lpt_hght); | ||
670 | printk(KERN_DEBUG "\tpnode_cnt: %d\n", c->pnode_cnt); | ||
671 | printk(KERN_DEBUG "\tnnode_cnt: %d\n", c->nnode_cnt); | ||
672 | printk(KERN_DEBUG "\tdirty_pn_cnt: %d\n", c->dirty_pn_cnt); | ||
673 | printk(KERN_DEBUG "\tdirty_nn_cnt: %d\n", c->dirty_nn_cnt); | ||
674 | printk(KERN_DEBUG "\tlsave_cnt: %d\n", c->lsave_cnt); | ||
675 | printk(KERN_DEBUG "\tspace_bits: %d\n", c->space_bits); | ||
676 | printk(KERN_DEBUG "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits); | ||
677 | printk(KERN_DEBUG "\tlpt_offs_bits: %d\n", c->lpt_offs_bits); | ||
678 | printk(KERN_DEBUG "\tlpt_spc_bits: %d\n", c->lpt_spc_bits); | ||
679 | printk(KERN_DEBUG "\tpcnt_bits: %d\n", c->pcnt_bits); | ||
680 | printk(KERN_DEBUG "\tlnum_bits: %d\n", c->lnum_bits); | ||
681 | printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs); | ||
682 | printk(KERN_DEBUG "\tLPT head is at %d:%d\n", | ||
683 | c->nhead_lnum, c->nhead_offs); | ||
684 | printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n", c->ltab_lnum, c->ltab_offs); | ||
685 | if (c->big_lpt) | ||
686 | printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n", | ||
687 | c->lsave_lnum, c->lsave_offs); | ||
688 | for (i = 0; i < c->lpt_lebs; i++) | ||
689 | printk(KERN_DEBUG "\tLPT LEB %d free %d dirty %d tgc %d " | ||
690 | "cmt %d\n", i + c->lpt_first, c->ltab[i].free, | ||
691 | c->ltab[i].dirty, c->ltab[i].tgc, c->ltab[i].cmt); | ||
692 | spin_unlock(&dbg_lock); | ||
693 | } | ||
694 | |||
658 | void dbg_dump_leb(const struct ubifs_info *c, int lnum) | 695 | void dbg_dump_leb(const struct ubifs_info *c, int lnum) |
659 | { | 696 | { |
660 | struct ubifs_scan_leb *sleb; | 697 | struct ubifs_scan_leb *sleb; |
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 50315fc57185..33d6b95071e4 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h | |||
@@ -224,6 +224,7 @@ void dbg_dump_lstats(const struct ubifs_lp_stats *lst); | |||
224 | void dbg_dump_budg(struct ubifs_info *c); | 224 | void dbg_dump_budg(struct ubifs_info *c); |
225 | void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp); | 225 | void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp); |
226 | void dbg_dump_lprops(struct ubifs_info *c); | 226 | void dbg_dump_lprops(struct ubifs_info *c); |
227 | void dbg_dump_lpt_info(struct ubifs_info *c); | ||
227 | void dbg_dump_leb(const struct ubifs_info *c, int lnum); | 228 | void dbg_dump_leb(const struct ubifs_info *c, int lnum); |
228 | void dbg_dump_znode(const struct ubifs_info *c, | 229 | void dbg_dump_znode(const struct ubifs_info *c, |
229 | const struct ubifs_znode *znode); | 230 | const struct ubifs_znode *znode); |
@@ -249,6 +250,8 @@ int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot); | |||
249 | int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot); | 250 | int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot); |
250 | int dbg_check_cats(struct ubifs_info *c); | 251 | int dbg_check_cats(struct ubifs_info *c); |
251 | int dbg_check_ltab(struct ubifs_info *c); | 252 | int dbg_check_ltab(struct ubifs_info *c); |
253 | int dbg_chk_lpt_free_spc(struct ubifs_info *c); | ||
254 | int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len); | ||
252 | int dbg_check_synced_i_size(struct inode *inode); | 255 | int dbg_check_synced_i_size(struct inode *inode); |
253 | int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir); | 256 | int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir); |
254 | int dbg_check_tnc(struct ubifs_info *c, int extra); | 257 | int dbg_check_tnc(struct ubifs_info *c, int extra); |
@@ -367,6 +370,7 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum, | |||
367 | #define dbg_dump_budg(c) ({}) | 370 | #define dbg_dump_budg(c) ({}) |
368 | #define dbg_dump_lprop(c, lp) ({}) | 371 | #define dbg_dump_lprop(c, lp) ({}) |
369 | #define dbg_dump_lprops(c) ({}) | 372 | #define dbg_dump_lprops(c) ({}) |
373 | #define dbg_dump_lpt_info(c) ({}) | ||
370 | #define dbg_dump_leb(c, lnum) ({}) | 374 | #define dbg_dump_leb(c, lnum) ({}) |
371 | #define dbg_dump_znode(c, znode) ({}) | 375 | #define dbg_dump_znode(c, znode) ({}) |
372 | #define dbg_dump_heap(c, heap, cat) ({}) | 376 | #define dbg_dump_heap(c, heap, cat) ({}) |
@@ -379,6 +383,8 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum, | |||
379 | #define dbg_check_old_index(c, zroot) 0 | 383 | #define dbg_check_old_index(c, zroot) 0 |
380 | #define dbg_check_cats(c) 0 | 384 | #define dbg_check_cats(c) 0 |
381 | #define dbg_check_ltab(c) 0 | 385 | #define dbg_check_ltab(c) 0 |
386 | #define dbg_chk_lpt_free_spc(c) 0 | ||
387 | #define dbg_chk_lpt_sz(c, action, len) 0 | ||
382 | #define dbg_check_synced_i_size(inode) 0 | 388 | #define dbg_check_synced_i_size(inode) 0 |
383 | #define dbg_check_dir_size(c, dir) 0 | 389 | #define dbg_check_dir_size(c, dir) 0 |
384 | #define dbg_check_tnc(c, x) 0 | 390 | #define dbg_check_tnc(c, x) 0 |
diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c index 9ff2463177e5..cd11b23a1875 100644 --- a/fs/ubifs/lpt.c +++ b/fs/ubifs/lpt.c | |||
@@ -109,7 +109,8 @@ static void do_calc_lpt_geom(struct ubifs_info *c) | |||
109 | c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; | 109 | c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; |
110 | c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz; | 110 | c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz; |
111 | c->lpt_sz += c->ltab_sz; | 111 | c->lpt_sz += c->ltab_sz; |
112 | c->lpt_sz += c->lsave_sz; | 112 | if (c->big_lpt) |
113 | c->lpt_sz += c->lsave_sz; | ||
113 | 114 | ||
114 | /* Add wastage */ | 115 | /* Add wastage */ |
115 | sz = c->lpt_sz; | 116 | sz = c->lpt_sz; |
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c index 5f0b83e20af6..8546865a9104 100644 --- a/fs/ubifs/lpt_commit.c +++ b/fs/ubifs/lpt_commit.c | |||
@@ -177,8 +177,6 @@ static int alloc_lpt_leb(struct ubifs_info *c, int *lnum) | |||
177 | return 0; | 177 | return 0; |
178 | } | 178 | } |
179 | } | 179 | } |
180 | dbg_err("last LEB %d", *lnum); | ||
181 | dump_stack(); | ||
182 | return -ENOSPC; | 180 | return -ENOSPC; |
183 | } | 181 | } |
184 | 182 | ||
@@ -193,6 +191,9 @@ static int layout_cnodes(struct ubifs_info *c) | |||
193 | int lnum, offs, len, alen, done_lsave, done_ltab, err; | 191 | int lnum, offs, len, alen, done_lsave, done_ltab, err; |
194 | struct ubifs_cnode *cnode; | 192 | struct ubifs_cnode *cnode; |
195 | 193 | ||
194 | err = dbg_chk_lpt_sz(c, 0, 0); | ||
195 | if (err) | ||
196 | return err; | ||
196 | cnode = c->lpt_cnext; | 197 | cnode = c->lpt_cnext; |
197 | if (!cnode) | 198 | if (!cnode) |
198 | return 0; | 199 | return 0; |
@@ -206,6 +207,7 @@ static int layout_cnodes(struct ubifs_info *c) | |||
206 | c->lsave_lnum = lnum; | 207 | c->lsave_lnum = lnum; |
207 | c->lsave_offs = offs; | 208 | c->lsave_offs = offs; |
208 | offs += c->lsave_sz; | 209 | offs += c->lsave_sz; |
210 | dbg_chk_lpt_sz(c, 1, c->lsave_sz); | ||
209 | } | 211 | } |
210 | 212 | ||
211 | if (offs + c->ltab_sz <= c->leb_size) { | 213 | if (offs + c->ltab_sz <= c->leb_size) { |
@@ -213,6 +215,7 @@ static int layout_cnodes(struct ubifs_info *c) | |||
213 | c->ltab_lnum = lnum; | 215 | c->ltab_lnum = lnum; |
214 | c->ltab_offs = offs; | 216 | c->ltab_offs = offs; |
215 | offs += c->ltab_sz; | 217 | offs += c->ltab_sz; |
218 | dbg_chk_lpt_sz(c, 1, c->ltab_sz); | ||
216 | } | 219 | } |
217 | 220 | ||
218 | do { | 221 | do { |
@@ -226,9 +229,10 @@ static int layout_cnodes(struct ubifs_info *c) | |||
226 | while (offs + len > c->leb_size) { | 229 | while (offs + len > c->leb_size) { |
227 | alen = ALIGN(offs, c->min_io_size); | 230 | alen = ALIGN(offs, c->min_io_size); |
228 | upd_ltab(c, lnum, c->leb_size - alen, alen - offs); | 231 | upd_ltab(c, lnum, c->leb_size - alen, alen - offs); |
232 | dbg_chk_lpt_sz(c, 2, alen - offs); | ||
229 | err = alloc_lpt_leb(c, &lnum); | 233 | err = alloc_lpt_leb(c, &lnum); |
230 | if (err) | 234 | if (err) |
231 | return err; | 235 | goto no_space; |
232 | offs = 0; | 236 | offs = 0; |
233 | ubifs_assert(lnum >= c->lpt_first && | 237 | ubifs_assert(lnum >= c->lpt_first && |
234 | lnum <= c->lpt_last); | 238 | lnum <= c->lpt_last); |
@@ -238,6 +242,7 @@ static int layout_cnodes(struct ubifs_info *c) | |||
238 | c->lsave_lnum = lnum; | 242 | c->lsave_lnum = lnum; |
239 | c->lsave_offs = offs; | 243 | c->lsave_offs = offs; |
240 | offs += c->lsave_sz; | 244 | offs += c->lsave_sz; |
245 | dbg_chk_lpt_sz(c, 1, c->lsave_sz); | ||
241 | continue; | 246 | continue; |
242 | } | 247 | } |
243 | if (!done_ltab) { | 248 | if (!done_ltab) { |
@@ -245,6 +250,7 @@ static int layout_cnodes(struct ubifs_info *c) | |||
245 | c->ltab_lnum = lnum; | 250 | c->ltab_lnum = lnum; |
246 | c->ltab_offs = offs; | 251 | c->ltab_offs = offs; |
247 | offs += c->ltab_sz; | 252 | offs += c->ltab_sz; |
253 | dbg_chk_lpt_sz(c, 1, c->ltab_sz); | ||
248 | continue; | 254 | continue; |
249 | } | 255 | } |
250 | break; | 256 | break; |
@@ -257,6 +263,7 @@ static int layout_cnodes(struct ubifs_info *c) | |||
257 | c->lpt_offs = offs; | 263 | c->lpt_offs = offs; |
258 | } | 264 | } |
259 | offs += len; | 265 | offs += len; |
266 | dbg_chk_lpt_sz(c, 1, len); | ||
260 | cnode = cnode->cnext; | 267 | cnode = cnode->cnext; |
261 | } while (cnode && cnode != c->lpt_cnext); | 268 | } while (cnode && cnode != c->lpt_cnext); |
262 | 269 | ||
@@ -265,9 +272,10 @@ static int layout_cnodes(struct ubifs_info *c) | |||
265 | if (offs + c->lsave_sz > c->leb_size) { | 272 | if (offs + c->lsave_sz > c->leb_size) { |
266 | alen = ALIGN(offs, c->min_io_size); | 273 | alen = ALIGN(offs, c->min_io_size); |
267 | upd_ltab(c, lnum, c->leb_size - alen, alen - offs); | 274 | upd_ltab(c, lnum, c->leb_size - alen, alen - offs); |
275 | dbg_chk_lpt_sz(c, 2, alen - offs); | ||
268 | err = alloc_lpt_leb(c, &lnum); | 276 | err = alloc_lpt_leb(c, &lnum); |
269 | if (err) | 277 | if (err) |
270 | return err; | 278 | goto no_space; |
271 | offs = 0; | 279 | offs = 0; |
272 | ubifs_assert(lnum >= c->lpt_first && | 280 | ubifs_assert(lnum >= c->lpt_first && |
273 | lnum <= c->lpt_last); | 281 | lnum <= c->lpt_last); |
@@ -276,6 +284,7 @@ static int layout_cnodes(struct ubifs_info *c) | |||
276 | c->lsave_lnum = lnum; | 284 | c->lsave_lnum = lnum; |
277 | c->lsave_offs = offs; | 285 | c->lsave_offs = offs; |
278 | offs += c->lsave_sz; | 286 | offs += c->lsave_sz; |
287 | dbg_chk_lpt_sz(c, 1, c->lsave_sz); | ||
279 | } | 288 | } |
280 | 289 | ||
281 | /* Make sure to place LPT's own lprops table */ | 290 | /* Make sure to place LPT's own lprops table */ |
@@ -283,9 +292,10 @@ static int layout_cnodes(struct ubifs_info *c) | |||
283 | if (offs + c->ltab_sz > c->leb_size) { | 292 | if (offs + c->ltab_sz > c->leb_size) { |
284 | alen = ALIGN(offs, c->min_io_size); | 293 | alen = ALIGN(offs, c->min_io_size); |
285 | upd_ltab(c, lnum, c->leb_size - alen, alen - offs); | 294 | upd_ltab(c, lnum, c->leb_size - alen, alen - offs); |
295 | dbg_chk_lpt_sz(c, 2, alen - offs); | ||
286 | err = alloc_lpt_leb(c, &lnum); | 296 | err = alloc_lpt_leb(c, &lnum); |
287 | if (err) | 297 | if (err) |
288 | return err; | 298 | goto no_space; |
289 | offs = 0; | 299 | offs = 0; |
290 | ubifs_assert(lnum >= c->lpt_first && | 300 | ubifs_assert(lnum >= c->lpt_first && |
291 | lnum <= c->lpt_last); | 301 | lnum <= c->lpt_last); |
@@ -294,11 +304,23 @@ static int layout_cnodes(struct ubifs_info *c) | |||
294 | c->ltab_lnum = lnum; | 304 | c->ltab_lnum = lnum; |
295 | c->ltab_offs = offs; | 305 | c->ltab_offs = offs; |
296 | offs += c->ltab_sz; | 306 | offs += c->ltab_sz; |
307 | dbg_chk_lpt_sz(c, 1, c->ltab_sz); | ||
297 | } | 308 | } |
298 | 309 | ||
299 | alen = ALIGN(offs, c->min_io_size); | 310 | alen = ALIGN(offs, c->min_io_size); |
300 | upd_ltab(c, lnum, c->leb_size - alen, alen - offs); | 311 | upd_ltab(c, lnum, c->leb_size - alen, alen - offs); |
312 | dbg_chk_lpt_sz(c, 4, alen - offs); | ||
313 | err = dbg_chk_lpt_sz(c, 3, alen); | ||
314 | if (err) | ||
315 | return err; | ||
301 | return 0; | 316 | return 0; |
317 | |||
318 | no_space: | ||
319 | ubifs_err("LPT out of space"); | ||
320 | dbg_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, " | ||
321 | "done_lsave %d", lnum, offs, len, done_ltab, done_lsave); | ||
322 | dbg_dump_lpt_info(c); | ||
323 | return err; | ||
302 | } | 324 | } |
303 | 325 | ||
304 | /** | 326 | /** |
@@ -333,8 +355,6 @@ static int realloc_lpt_leb(struct ubifs_info *c, int *lnum) | |||
333 | *lnum = i + c->lpt_first; | 355 | *lnum = i + c->lpt_first; |
334 | return 0; | 356 | return 0; |
335 | } | 357 | } |
336 | dbg_err("last LEB %d", *lnum); | ||
337 | dump_stack(); | ||
338 | return -ENOSPC; | 358 | return -ENOSPC; |
339 | } | 359 | } |
340 | 360 | ||
@@ -369,12 +389,14 @@ static int write_cnodes(struct ubifs_info *c) | |||
369 | done_lsave = 1; | 389 | done_lsave = 1; |
370 | ubifs_pack_lsave(c, buf + offs, c->lsave); | 390 | ubifs_pack_lsave(c, buf + offs, c->lsave); |
371 | offs += c->lsave_sz; | 391 | offs += c->lsave_sz; |
392 | dbg_chk_lpt_sz(c, 1, c->lsave_sz); | ||
372 | } | 393 | } |
373 | 394 | ||
374 | if (offs + c->ltab_sz <= c->leb_size) { | 395 | if (offs + c->ltab_sz <= c->leb_size) { |
375 | done_ltab = 1; | 396 | done_ltab = 1; |
376 | ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); | 397 | ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); |
377 | offs += c->ltab_sz; | 398 | offs += c->ltab_sz; |
399 | dbg_chk_lpt_sz(c, 1, c->ltab_sz); | ||
378 | } | 400 | } |
379 | 401 | ||
380 | /* Loop for each cnode */ | 402 | /* Loop for each cnode */ |
@@ -392,10 +414,12 @@ static int write_cnodes(struct ubifs_info *c) | |||
392 | alen, UBI_SHORTTERM); | 414 | alen, UBI_SHORTTERM); |
393 | if (err) | 415 | if (err) |
394 | return err; | 416 | return err; |
417 | dbg_chk_lpt_sz(c, 4, alen - wlen); | ||
395 | } | 418 | } |
419 | dbg_chk_lpt_sz(c, 2, 0); | ||
396 | err = realloc_lpt_leb(c, &lnum); | 420 | err = realloc_lpt_leb(c, &lnum); |
397 | if (err) | 421 | if (err) |
398 | return err; | 422 | goto no_space; |
399 | offs = 0; | 423 | offs = 0; |
400 | from = 0; | 424 | from = 0; |
401 | ubifs_assert(lnum >= c->lpt_first && | 425 | ubifs_assert(lnum >= c->lpt_first && |
@@ -408,12 +432,14 @@ static int write_cnodes(struct ubifs_info *c) | |||
408 | done_lsave = 1; | 432 | done_lsave = 1; |
409 | ubifs_pack_lsave(c, buf + offs, c->lsave); | 433 | ubifs_pack_lsave(c, buf + offs, c->lsave); |
410 | offs += c->lsave_sz; | 434 | offs += c->lsave_sz; |
435 | dbg_chk_lpt_sz(c, 1, c->lsave_sz); | ||
411 | continue; | 436 | continue; |
412 | } | 437 | } |
413 | if (!done_ltab) { | 438 | if (!done_ltab) { |
414 | done_ltab = 1; | 439 | done_ltab = 1; |
415 | ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); | 440 | ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); |
416 | offs += c->ltab_sz; | 441 | offs += c->ltab_sz; |
442 | dbg_chk_lpt_sz(c, 1, c->ltab_sz); | ||
417 | continue; | 443 | continue; |
418 | } | 444 | } |
419 | break; | 445 | break; |
@@ -435,6 +461,7 @@ static int write_cnodes(struct ubifs_info *c) | |||
435 | clear_bit(COW_ZNODE, &cnode->flags); | 461 | clear_bit(COW_ZNODE, &cnode->flags); |
436 | smp_mb__after_clear_bit(); | 462 | smp_mb__after_clear_bit(); |
437 | offs += len; | 463 | offs += len; |
464 | dbg_chk_lpt_sz(c, 1, len); | ||
438 | cnode = cnode->cnext; | 465 | cnode = cnode->cnext; |
439 | } while (cnode && cnode != c->lpt_cnext); | 466 | } while (cnode && cnode != c->lpt_cnext); |
440 | 467 | ||
@@ -448,9 +475,10 @@ static int write_cnodes(struct ubifs_info *c) | |||
448 | UBI_SHORTTERM); | 475 | UBI_SHORTTERM); |
449 | if (err) | 476 | if (err) |
450 | return err; | 477 | return err; |
478 | dbg_chk_lpt_sz(c, 2, alen - wlen); | ||
451 | err = realloc_lpt_leb(c, &lnum); | 479 | err = realloc_lpt_leb(c, &lnum); |
452 | if (err) | 480 | if (err) |
453 | return err; | 481 | goto no_space; |
454 | offs = 0; | 482 | offs = 0; |
455 | ubifs_assert(lnum >= c->lpt_first && | 483 | ubifs_assert(lnum >= c->lpt_first && |
456 | lnum <= c->lpt_last); | 484 | lnum <= c->lpt_last); |
@@ -461,6 +489,7 @@ static int write_cnodes(struct ubifs_info *c) | |||
461 | done_lsave = 1; | 489 | done_lsave = 1; |
462 | ubifs_pack_lsave(c, buf + offs, c->lsave); | 490 | ubifs_pack_lsave(c, buf + offs, c->lsave); |
463 | offs += c->lsave_sz; | 491 | offs += c->lsave_sz; |
492 | dbg_chk_lpt_sz(c, 1, c->lsave_sz); | ||
464 | } | 493 | } |
465 | 494 | ||
466 | /* Make sure to place LPT's own lprops table */ | 495 | /* Make sure to place LPT's own lprops table */ |
@@ -473,9 +502,10 @@ static int write_cnodes(struct ubifs_info *c) | |||
473 | UBI_SHORTTERM); | 502 | UBI_SHORTTERM); |
474 | if (err) | 503 | if (err) |
475 | return err; | 504 | return err; |
505 | dbg_chk_lpt_sz(c, 2, alen - wlen); | ||
476 | err = realloc_lpt_leb(c, &lnum); | 506 | err = realloc_lpt_leb(c, &lnum); |
477 | if (err) | 507 | if (err) |
478 | return err; | 508 | goto no_space; |
479 | offs = 0; | 509 | offs = 0; |
480 | ubifs_assert(lnum >= c->lpt_first && | 510 | ubifs_assert(lnum >= c->lpt_first && |
481 | lnum <= c->lpt_last); | 511 | lnum <= c->lpt_last); |
@@ -486,6 +516,7 @@ static int write_cnodes(struct ubifs_info *c) | |||
486 | done_ltab = 1; | 516 | done_ltab = 1; |
487 | ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); | 517 | ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); |
488 | offs += c->ltab_sz; | 518 | offs += c->ltab_sz; |
519 | dbg_chk_lpt_sz(c, 1, c->ltab_sz); | ||
489 | } | 520 | } |
490 | 521 | ||
491 | /* Write remaining data in buffer */ | 522 | /* Write remaining data in buffer */ |
@@ -495,6 +526,12 @@ static int write_cnodes(struct ubifs_info *c) | |||
495 | err = ubifs_leb_write(c, lnum, buf + from, from, alen, UBI_SHORTTERM); | 526 | err = ubifs_leb_write(c, lnum, buf + from, from, alen, UBI_SHORTTERM); |
496 | if (err) | 527 | if (err) |
497 | return err; | 528 | return err; |
529 | |||
530 | dbg_chk_lpt_sz(c, 4, alen - wlen); | ||
531 | err = dbg_chk_lpt_sz(c, 3, ALIGN(offs, c->min_io_size)); | ||
532 | if (err) | ||
533 | return err; | ||
534 | |||
498 | c->nhead_lnum = lnum; | 535 | c->nhead_lnum = lnum; |
499 | c->nhead_offs = ALIGN(offs, c->min_io_size); | 536 | c->nhead_offs = ALIGN(offs, c->min_io_size); |
500 | 537 | ||
@@ -503,7 +540,15 @@ static int write_cnodes(struct ubifs_info *c) | |||
503 | dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs); | 540 | dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs); |
504 | if (c->big_lpt) | 541 | if (c->big_lpt) |
505 | dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); | 542 | dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); |
543 | |||
506 | return 0; | 544 | return 0; |
545 | |||
546 | no_space: | ||
547 | ubifs_err("LPT out of space mismatch"); | ||
548 | dbg_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab " | ||
549 | "%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave); | ||
550 | dbg_dump_lpt_info(c); | ||
551 | return err; | ||
507 | } | 552 | } |
508 | 553 | ||
509 | /** | 554 | /** |
@@ -1156,6 +1201,9 @@ int ubifs_lpt_start_commit(struct ubifs_info *c) | |||
1156 | dbg_lp(""); | 1201 | dbg_lp(""); |
1157 | 1202 | ||
1158 | mutex_lock(&c->lp_mutex); | 1203 | mutex_lock(&c->lp_mutex); |
1204 | err = dbg_chk_lpt_free_spc(c); | ||
1205 | if (err) | ||
1206 | goto out; | ||
1159 | err = dbg_check_ltab(c); | 1207 | err = dbg_check_ltab(c); |
1160 | if (err) | 1208 | if (err) |
1161 | goto out; | 1209 | goto out; |
@@ -1645,4 +1693,121 @@ int dbg_check_ltab(struct ubifs_info *c) | |||
1645 | return 0; | 1693 | return 0; |
1646 | } | 1694 | } |
1647 | 1695 | ||
1696 | /** | ||
1697 | * dbg_chk_lpt_free_spc - check LPT free space is enough to write entire LPT. | ||
1698 | * @c: the UBIFS file-system description object | ||
1699 | * | ||
1700 | * This function returns %0 on success and a negative error code on failure. | ||
1701 | */ | ||
1702 | int dbg_chk_lpt_free_spc(struct ubifs_info *c) | ||
1703 | { | ||
1704 | long long free = 0; | ||
1705 | int i; | ||
1706 | |||
1707 | for (i = 0; i < c->lpt_lebs; i++) { | ||
1708 | if (c->ltab[i].tgc || c->ltab[i].cmt) | ||
1709 | continue; | ||
1710 | if (i + c->lpt_first == c->nhead_lnum) | ||
1711 | free += c->leb_size - c->nhead_offs; | ||
1712 | else if (c->ltab[i].free == c->leb_size) | ||
1713 | free += c->leb_size; | ||
1714 | } | ||
1715 | if (free < c->lpt_sz) { | ||
1716 | dbg_err("LPT space error: free %lld lpt_sz %lld", | ||
1717 | free, c->lpt_sz); | ||
1718 | dbg_dump_lpt_info(c); | ||
1719 | return -EINVAL; | ||
1720 | } | ||
1721 | return 0; | ||
1722 | } | ||
1723 | |||
1724 | /** | ||
1725 | * dbg_chk_lpt_sz - check LPT does not write more than LPT size. | ||
1726 | * @c: the UBIFS file-system description object | ||
1727 | * @action: action | ||
1728 | * @len: length written | ||
1729 | * | ||
1730 | * This function returns %0 on success and a negative error code on failure. | ||
1731 | */ | ||
1732 | int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len) | ||
1733 | { | ||
1734 | long long chk_lpt_sz, lpt_sz; | ||
1735 | int err = 0; | ||
1736 | |||
1737 | switch (action) { | ||
1738 | case 0: | ||
1739 | c->chk_lpt_sz = 0; | ||
1740 | c->chk_lpt_sz2 = 0; | ||
1741 | c->chk_lpt_lebs = 0; | ||
1742 | c->chk_lpt_wastage = 0; | ||
1743 | if (c->dirty_pn_cnt > c->pnode_cnt) { | ||
1744 | dbg_err("dirty pnodes %d exceed max %d", | ||
1745 | c->dirty_pn_cnt, c->pnode_cnt); | ||
1746 | err = -EINVAL; | ||
1747 | } | ||
1748 | if (c->dirty_nn_cnt > c->nnode_cnt) { | ||
1749 | dbg_err("dirty nnodes %d exceed max %d", | ||
1750 | c->dirty_nn_cnt, c->nnode_cnt); | ||
1751 | err = -EINVAL; | ||
1752 | } | ||
1753 | return err; | ||
1754 | case 1: | ||
1755 | c->chk_lpt_sz += len; | ||
1756 | return 0; | ||
1757 | case 2: | ||
1758 | c->chk_lpt_sz += len; | ||
1759 | c->chk_lpt_wastage += len; | ||
1760 | c->chk_lpt_lebs += 1; | ||
1761 | return 0; | ||
1762 | case 3: | ||
1763 | chk_lpt_sz = c->leb_size; | ||
1764 | chk_lpt_sz *= c->chk_lpt_lebs; | ||
1765 | chk_lpt_sz += len - c->nhead_offs; | ||
1766 | if (c->chk_lpt_sz != chk_lpt_sz) { | ||
1767 | dbg_err("LPT wrote %lld but space used was %lld", | ||
1768 | c->chk_lpt_sz, chk_lpt_sz); | ||
1769 | err = -EINVAL; | ||
1770 | } | ||
1771 | if (c->chk_lpt_sz > c->lpt_sz) { | ||
1772 | dbg_err("LPT wrote %lld but lpt_sz is %lld", | ||
1773 | c->chk_lpt_sz, c->lpt_sz); | ||
1774 | err = -EINVAL; | ||
1775 | } | ||
1776 | if (c->chk_lpt_sz2 && c->chk_lpt_sz != c->chk_lpt_sz2) { | ||
1777 | dbg_err("LPT layout size %lld but wrote %lld", | ||
1778 | c->chk_lpt_sz, c->chk_lpt_sz2); | ||
1779 | err = -EINVAL; | ||
1780 | } | ||
1781 | if (c->chk_lpt_sz2 && c->new_nhead_offs != len) { | ||
1782 | dbg_err("LPT new nhead offs: expected %d was %d", | ||
1783 | c->new_nhead_offs, len); | ||
1784 | err = -EINVAL; | ||
1785 | } | ||
1786 | lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; | ||
1787 | lpt_sz += (long long)c->nnode_cnt * c->nnode_sz; | ||
1788 | lpt_sz += c->ltab_sz; | ||
1789 | if (c->big_lpt) | ||
1790 | lpt_sz += c->lsave_sz; | ||
1791 | if (c->chk_lpt_sz - c->chk_lpt_wastage > lpt_sz) { | ||
1792 | dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld", | ||
1793 | c->chk_lpt_sz, c->chk_lpt_wastage, lpt_sz); | ||
1794 | err = -EINVAL; | ||
1795 | } | ||
1796 | if (err) | ||
1797 | dbg_dump_lpt_info(c); | ||
1798 | c->chk_lpt_sz2 = c->chk_lpt_sz; | ||
1799 | c->chk_lpt_sz = 0; | ||
1800 | c->chk_lpt_wastage = 0; | ||
1801 | c->chk_lpt_lebs = 0; | ||
1802 | c->new_nhead_offs = len; | ||
1803 | return err; | ||
1804 | case 4: | ||
1805 | c->chk_lpt_sz += len; | ||
1806 | c->chk_lpt_wastage += len; | ||
1807 | return 0; | ||
1808 | default: | ||
1809 | return -EINVAL; | ||
1810 | } | ||
1811 | } | ||
1812 | |||
1648 | #endif /* CONFIG_UBIFS_FS_DEBUG */ | 1813 | #endif /* CONFIG_UBIFS_FS_DEBUG */ |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 49b06c9f675a..a7bd32fa15b9 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
@@ -943,7 +943,6 @@ struct ubifs_mount_opts { | |||
943 | * | 943 | * |
944 | * @fast_unmount: do not run journal commit before un-mounting | 944 | * @fast_unmount: do not run journal commit before un-mounting |
945 | * @big_lpt: flag that LPT is too big to write whole during commit | 945 | * @big_lpt: flag that LPT is too big to write whole during commit |
946 | * @check_lpt_free: flag that indicates LPT GC may be needed | ||
947 | * @no_chk_data_crc: do not check CRCs when reading data nodes (except during | 946 | * @no_chk_data_crc: do not check CRCs when reading data nodes (except during |
948 | * recovery) | 947 | * recovery) |
949 | * @bulk_read: enable bulk-reads | 948 | * @bulk_read: enable bulk-reads |
@@ -1102,6 +1101,7 @@ struct ubifs_mount_opts { | |||
1102 | * @lpt_drty_flgs: dirty flags for LPT special nodes e.g. ltab | 1101 | * @lpt_drty_flgs: dirty flags for LPT special nodes e.g. ltab |
1103 | * @dirty_nn_cnt: number of dirty nnodes | 1102 | * @dirty_nn_cnt: number of dirty nnodes |
1104 | * @dirty_pn_cnt: number of dirty pnodes | 1103 | * @dirty_pn_cnt: number of dirty pnodes |
1104 | * @check_lpt_free: flag that indicates LPT GC may be needed | ||
1105 | * @lpt_sz: LPT size | 1105 | * @lpt_sz: LPT size |
1106 | * @lpt_nod_buf: buffer for an on-flash nnode or pnode | 1106 | * @lpt_nod_buf: buffer for an on-flash nnode or pnode |
1107 | * @lpt_buf: buffer of LEB size used by LPT | 1107 | * @lpt_buf: buffer of LEB size used by LPT |
@@ -1191,7 +1191,6 @@ struct ubifs_info { | |||
1191 | 1191 | ||
1192 | unsigned int fast_unmount:1; | 1192 | unsigned int fast_unmount:1; |
1193 | unsigned int big_lpt:1; | 1193 | unsigned int big_lpt:1; |
1194 | unsigned int check_lpt_free:1; | ||
1195 | unsigned int no_chk_data_crc:1; | 1194 | unsigned int no_chk_data_crc:1; |
1196 | unsigned int bulk_read:1; | 1195 | unsigned int bulk_read:1; |
1197 | 1196 | ||
@@ -1340,6 +1339,7 @@ struct ubifs_info { | |||
1340 | int lpt_drty_flgs; | 1339 | int lpt_drty_flgs; |
1341 | int dirty_nn_cnt; | 1340 | int dirty_nn_cnt; |
1342 | int dirty_pn_cnt; | 1341 | int dirty_pn_cnt; |
1342 | int check_lpt_free; | ||
1343 | long long lpt_sz; | 1343 | long long lpt_sz; |
1344 | void *lpt_nod_buf; | 1344 | void *lpt_nod_buf; |
1345 | void *lpt_buf; | 1345 | void *lpt_buf; |
@@ -1394,6 +1394,12 @@ struct ubifs_info { | |||
1394 | unsigned long fail_timeout; | 1394 | unsigned long fail_timeout; |
1395 | unsigned int fail_cnt; | 1395 | unsigned int fail_cnt; |
1396 | unsigned int fail_cnt_max; | 1396 | unsigned int fail_cnt_max; |
1397 | long long chk_lpt_sz; | ||
1398 | long long chk_lpt_sz2; | ||
1399 | long long chk_lpt_wastage; | ||
1400 | int chk_lpt_lebs; | ||
1401 | int new_nhead_lnum; | ||
1402 | int new_nhead_offs; | ||
1397 | #endif | 1403 | #endif |
1398 | }; | 1404 | }; |
1399 | 1405 | ||