diff options
Diffstat (limited to 'fs/ubifs/replay.c')
-rw-r--r-- | fs/ubifs/replay.c | 75 |
1 files changed, 71 insertions, 4 deletions
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index 0f50fbfe630f..6617280d1679 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c | |||
@@ -473,6 +473,65 @@ int ubifs_validate_entry(struct ubifs_info *c, | |||
473 | } | 473 | } |
474 | 474 | ||
475 | /** | 475 | /** |
476 | * is_last_bud - check if the bud is the last in the journal head. | ||
477 | * @c: UBIFS file-system description object | ||
478 | * @bud: bud description object | ||
479 | * | ||
480 | * This function checks if bud @bud is the last bud in its journal head. This | ||
481 | * information is then used by 'replay_bud()' to decide whether the bud can | ||
482 | * have corruptions or not. Indeed, only last buds can be corrupted by power | ||
483 | * cuts. Returns %1 if this is the last bud, and %0 if not. | ||
484 | */ | ||
485 | static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud) | ||
486 | { | ||
487 | struct ubifs_jhead *jh = &c->jheads[bud->jhead]; | ||
488 | struct ubifs_bud *next; | ||
489 | uint32_t data; | ||
490 | int err; | ||
491 | |||
492 | if (list_is_last(&bud->list, &jh->buds_list)) | ||
493 | return 1; | ||
494 | |||
495 | /* | ||
496 | * The following is a quirk to make sure we work correctly with UBIFS | ||
497 | * images used with older UBIFS. | ||
498 | * | ||
499 | * Normally, the last bud will be the last in the journal head's list | ||
500 | * of bud. However, there is one exception if the UBIFS image belongs | ||
501 | * to older UBIFS. This is fairly unlikely: one would need to use old | ||
502 | * UBIFS, then have a power cut exactly at the right point, and then | ||
503 | * try to mount this image with new UBIFS. | ||
504 | * | ||
505 | * The exception is: it is possible to have 2 buds A and B, A goes | ||
506 | * before B, and B is the last, bud B is contains no data, and bud A is | ||
507 | * corrupted at the end. The reason is that in older versions when the | ||
508 | * journal code switched the next bud (from A to B), it first added a | ||
509 | * log reference node for the new bud (B), and only after this it | ||
510 | * synchronized the write-buffer of current bud (A). But later this was | ||
511 | * changed and UBIFS started to always synchronize the write-buffer of | ||
512 | * the bud (A) before writing the log reference for the new bud (B). | ||
513 | * | ||
514 | * But because older UBIFS always synchronized A's write-buffer before | ||
515 | * writing to B, we can recognize this exceptional situation but | ||
516 | * checking the contents of bud B - if it is empty, then A can be | ||
517 | * treated as the last and we can recover it. | ||
518 | * | ||
519 | * TODO: remove this piece of code in a couple of years (today it is | ||
520 | * 16.05.2011). | ||
521 | */ | ||
522 | next = list_entry(bud->list.next, struct ubifs_bud, list); | ||
523 | if (!list_is_last(&next->list, &jh->buds_list)) | ||
524 | return 0; | ||
525 | |||
526 | err = ubi_read(c->ubi, next->lnum, (char *)&data, | ||
527 | next->start, 4); | ||
528 | if (err) | ||
529 | return 0; | ||
530 | |||
531 | return data == 0xFFFFFFFF; | ||
532 | } | ||
533 | |||
534 | /** | ||
476 | * replay_bud - replay a bud logical eraseblock. | 535 | * replay_bud - replay a bud logical eraseblock. |
477 | * @c: UBIFS file-system description object | 536 | * @c: UBIFS file-system description object |
478 | * @b: bud entry which describes the bud | 537 | * @b: bud entry which describes the bud |
@@ -483,15 +542,23 @@ int ubifs_validate_entry(struct ubifs_info *c, | |||
483 | */ | 542 | */ |
484 | static int replay_bud(struct ubifs_info *c, struct bud_entry *b) | 543 | static int replay_bud(struct ubifs_info *c, struct bud_entry *b) |
485 | { | 544 | { |
545 | int is_last = is_last_bud(c, b->bud); | ||
486 | int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start; | 546 | int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start; |
487 | int jhead = b->bud->jhead; | ||
488 | struct ubifs_scan_leb *sleb; | 547 | struct ubifs_scan_leb *sleb; |
489 | struct ubifs_scan_node *snod; | 548 | struct ubifs_scan_node *snod; |
490 | 549 | ||
491 | dbg_mnt("replay bud LEB %d, head %d, offs %d", lnum, jhead, offs); | 550 | dbg_mnt("replay bud LEB %d, head %d, offs %d, is_last %d", |
551 | lnum, b->bud->jhead, offs, is_last); | ||
492 | 552 | ||
493 | if (c->need_recovery) | 553 | if (c->need_recovery && is_last) |
494 | sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD); | 554 | /* |
555 | * Recover only last LEBs in the journal heads, because power | ||
556 | * cuts may cause corruptions only in these LEBs, because only | ||
557 | * these LEBs could possibly be written to at the power cut | ||
558 | * time. | ||
559 | */ | ||
560 | sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, | ||
561 | b->bud->jhead != GCHD); | ||
495 | else | 562 | else |
496 | sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0); | 563 | sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0); |
497 | if (IS_ERR(sleb)) | 564 | if (IS_ERR(sleb)) |