diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-20 12:19:03 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-20 12:19:03 -0400 |
| commit | 396b122f6af3d329df3b4d688f6e66de3e2a399a (patch) | |
| tree | 0b4185d529c1ba4c8eca1de23f14beecbe460323 /fs/ubifs/lpt_commit.c | |
| parent | ed402af3c23a4804b3f8899263e8d0f97c62ab49 (diff) | |
| parent | 54779aabb0183bbe049d2b52e96cd148366dfb0b (diff) | |
Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
* 'linux-next' of git://git.infradead.org/ubifs-2.6: (25 commits)
UBIFS: fix ubifs_compress commentary
UBIFS: amend printk
UBIFS: do not read unnecessary bytes when unpacking bits
UBIFS: check buffer length when scanning for LPT nodes
UBIFS: correct condition to eliminate unecessary assignment
UBIFS: add more debugging messages for LPT
UBIFS: fix bulk-read handling uptodate pages
UBIFS: improve garbage collection
UBIFS: allow for sync_fs when read-only
UBIFS: commit on sync_fs
UBIFS: correct comment for commit_on_unmount
UBIFS: update dbg_dump_inode
UBIFS: fix commentary
UBIFS: fix races in bit-fields
UBIFS: ensure data read beyond i_size is zeroed out correctly
UBIFS: correct key comparison
UBIFS: use bit-fields when possible
UBIFS: check data CRC when in error state
UBIFS: improve znode splitting rules
UBIFS: add no_chk_data_crc mount option
...
Diffstat (limited to 'fs/ubifs/lpt_commit.c')
| -rw-r--r-- | fs/ubifs/lpt_commit.c | 187 |
1 files changed, 177 insertions, 10 deletions
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c index 5f0b83e20af6..eed5a0025d63 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 | /** |
| @@ -1044,6 +1089,8 @@ static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len) | |||
| 1044 | int pos = 0, node_type, node_len; | 1089 | int pos = 0, node_type, node_len; |
| 1045 | uint16_t crc, calc_crc; | 1090 | uint16_t crc, calc_crc; |
| 1046 | 1091 | ||
| 1092 | if (len < UBIFS_LPT_CRC_BYTES + (UBIFS_LPT_TYPE_BITS + 7) / 8) | ||
| 1093 | return 0; | ||
| 1047 | node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS); | 1094 | node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS); |
| 1048 | if (node_type == UBIFS_LPT_NOT_A_NODE) | 1095 | if (node_type == UBIFS_LPT_NOT_A_NODE) |
| 1049 | return 0; | 1096 | return 0; |
| @@ -1156,6 +1203,9 @@ int ubifs_lpt_start_commit(struct ubifs_info *c) | |||
| 1156 | dbg_lp(""); | 1203 | dbg_lp(""); |
| 1157 | 1204 | ||
| 1158 | mutex_lock(&c->lp_mutex); | 1205 | mutex_lock(&c->lp_mutex); |
| 1206 | err = dbg_chk_lpt_free_spc(c); | ||
| 1207 | if (err) | ||
| 1208 | goto out; | ||
| 1159 | err = dbg_check_ltab(c); | 1209 | err = dbg_check_ltab(c); |
| 1160 | if (err) | 1210 | if (err) |
| 1161 | goto out; | 1211 | goto out; |
| @@ -1645,4 +1695,121 @@ int dbg_check_ltab(struct ubifs_info *c) | |||
| 1645 | return 0; | 1695 | return 0; |
| 1646 | } | 1696 | } |
| 1647 | 1697 | ||
| 1698 | /** | ||
| 1699 | * dbg_chk_lpt_free_spc - check LPT free space is enough to write entire LPT. | ||
| 1700 | * @c: the UBIFS file-system description object | ||
| 1701 | * | ||
| 1702 | * This function returns %0 on success and a negative error code on failure. | ||
| 1703 | */ | ||
| 1704 | int dbg_chk_lpt_free_spc(struct ubifs_info *c) | ||
| 1705 | { | ||
| 1706 | long long free = 0; | ||
| 1707 | int i; | ||
| 1708 | |||
| 1709 | for (i = 0; i < c->lpt_lebs; i++) { | ||
| 1710 | if (c->ltab[i].tgc || c->ltab[i].cmt) | ||
| 1711 | continue; | ||
| 1712 | if (i + c->lpt_first == c->nhead_lnum) | ||
| 1713 | free += c->leb_size - c->nhead_offs; | ||
| 1714 | else if (c->ltab[i].free == c->leb_size) | ||
| 1715 | free += c->leb_size; | ||
| 1716 | } | ||
| 1717 | if (free < c->lpt_sz) { | ||
| 1718 | dbg_err("LPT space error: free %lld lpt_sz %lld", | ||
| 1719 | free, c->lpt_sz); | ||
| 1720 | dbg_dump_lpt_info(c); | ||
| 1721 | return -EINVAL; | ||
| 1722 | } | ||
| 1723 | return 0; | ||
| 1724 | } | ||
| 1725 | |||
| 1726 | /** | ||
| 1727 | * dbg_chk_lpt_sz - check LPT does not write more than LPT size. | ||
| 1728 | * @c: the UBIFS file-system description object | ||
| 1729 | * @action: action | ||
| 1730 | * @len: length written | ||
| 1731 | * | ||
| 1732 | * This function returns %0 on success and a negative error code on failure. | ||
| 1733 | */ | ||
| 1734 | int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len) | ||
| 1735 | { | ||
| 1736 | long long chk_lpt_sz, lpt_sz; | ||
| 1737 | int err = 0; | ||
| 1738 | |||
| 1739 | switch (action) { | ||
| 1740 | case 0: | ||
| 1741 | c->chk_lpt_sz = 0; | ||
| 1742 | c->chk_lpt_sz2 = 0; | ||
| 1743 | c->chk_lpt_lebs = 0; | ||
| 1744 | c->chk_lpt_wastage = 0; | ||
| 1745 | if (c->dirty_pn_cnt > c->pnode_cnt) { | ||
| 1746 | dbg_err("dirty pnodes %d exceed max %d", | ||
| 1747 | c->dirty_pn_cnt, c->pnode_cnt); | ||
| 1748 | err = -EINVAL; | ||
| 1749 | } | ||
| 1750 | if (c->dirty_nn_cnt > c->nnode_cnt) { | ||
| 1751 | dbg_err("dirty nnodes %d exceed max %d", | ||
| 1752 | c->dirty_nn_cnt, c->nnode_cnt); | ||
| 1753 | err = -EINVAL; | ||
| 1754 | } | ||
| 1755 | return err; | ||
| 1756 | case 1: | ||
| 1757 | c->chk_lpt_sz += len; | ||
| 1758 | return 0; | ||
| 1759 | case 2: | ||
| 1760 | c->chk_lpt_sz += len; | ||
| 1761 | c->chk_lpt_wastage += len; | ||
| 1762 | c->chk_lpt_lebs += 1; | ||
| 1763 | return 0; | ||
| 1764 | case 3: | ||
| 1765 | chk_lpt_sz = c->leb_size; | ||
| 1766 | chk_lpt_sz *= c->chk_lpt_lebs; | ||
| 1767 | chk_lpt_sz += len - c->nhead_offs; | ||
| 1768 | if (c->chk_lpt_sz != chk_lpt_sz) { | ||
| 1769 | dbg_err("LPT wrote %lld but space used was %lld", | ||
| 1770 | c->chk_lpt_sz, chk_lpt_sz); | ||
| 1771 | err = -EINVAL; | ||
| 1772 | } | ||
| 1773 | if (c->chk_lpt_sz > c->lpt_sz) { | ||
| 1774 | dbg_err("LPT wrote %lld but lpt_sz is %lld", | ||
| 1775 | c->chk_lpt_sz, c->lpt_sz); | ||
| 1776 | err = -EINVAL; | ||
| 1777 | } | ||
| 1778 | if (c->chk_lpt_sz2 && c->chk_lpt_sz != c->chk_lpt_sz2) { | ||
| 1779 | dbg_err("LPT layout size %lld but wrote %lld", | ||
| 1780 | c->chk_lpt_sz, c->chk_lpt_sz2); | ||
| 1781 | err = -EINVAL; | ||
| 1782 | } | ||
| 1783 | if (c->chk_lpt_sz2 && c->new_nhead_offs != len) { | ||
| 1784 | dbg_err("LPT new nhead offs: expected %d was %d", | ||
| 1785 | c->new_nhead_offs, len); | ||
| 1786 | err = -EINVAL; | ||
| 1787 | } | ||
| 1788 | lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; | ||
| 1789 | lpt_sz += (long long)c->nnode_cnt * c->nnode_sz; | ||
| 1790 | lpt_sz += c->ltab_sz; | ||
| 1791 | if (c->big_lpt) | ||
| 1792 | lpt_sz += c->lsave_sz; | ||
| 1793 | if (c->chk_lpt_sz - c->chk_lpt_wastage > lpt_sz) { | ||
| 1794 | dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld", | ||
| 1795 | c->chk_lpt_sz, c->chk_lpt_wastage, lpt_sz); | ||
| 1796 | err = -EINVAL; | ||
| 1797 | } | ||
| 1798 | if (err) | ||
| 1799 | dbg_dump_lpt_info(c); | ||
| 1800 | c->chk_lpt_sz2 = c->chk_lpt_sz; | ||
| 1801 | c->chk_lpt_sz = 0; | ||
| 1802 | c->chk_lpt_wastage = 0; | ||
| 1803 | c->chk_lpt_lebs = 0; | ||
| 1804 | c->new_nhead_offs = len; | ||
| 1805 | return err; | ||
| 1806 | case 4: | ||
| 1807 | c->chk_lpt_sz += len; | ||
| 1808 | c->chk_lpt_wastage += len; | ||
| 1809 | return 0; | ||
| 1810 | default: | ||
| 1811 | return -EINVAL; | ||
| 1812 | } | ||
| 1813 | } | ||
| 1814 | |||
| 1648 | #endif /* CONFIG_UBIFS_FS_DEBUG */ | 1815 | #endif /* CONFIG_UBIFS_FS_DEBUG */ |
