UBIFS: seek journal heads to the latest bud in replay

This is the second fix of the following symptom:

UBIFS error (pid 34456): could not find an empty LEB

which sometimes happens after power cuts when we mount the file-system - UBIFS
refuses it with the above error message which comes from the
'ubifs_rcvry_gc_commit()' function. I can reproduce this using the integck test
with the UBIFS power cut emulation enabled.

Analysis of the problem.

Currently UBIFS replay seeks the journal heads to the last _replayed_ bud.
But the buds are replayed out-of-order, so the replay basically seeks journal
heads to the "random" bud belonging to this head, and not to the _last_ one.

The result of this is that the GC head may be seeked to a full LEB with no free
space, or very little free space. And 'ubifs_rcvry_gc_commit()' tries to find a
fully or mostly dirty LEB to match the current GC head (because we need to
garbage-collect that dirty LEB at one go, because we do not have @c->gc_lnum).
So 'ubifs_find_dirty_leb()' fails and we fall back to finding an empty LEB and
also fail. As a result - recovery fails and mounting fails.

This patch teaches the replay to initialize the GC heads exactly to the latest
buds, i.e. the buds which have the largest sequence number in corresponding
log reference nodes.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Cc: stable@kernel.org

+12 -6
+12 -6
fs/ubifs/replay.c
··· 59 * @new_size: truncation new size 60 * @free: amount of free space in a bud 61 * @dirty: amount of dirty space in a bud from padding and deletion nodes 62 * 63 * UBIFS journal replay must compare node sequence numbers, which means it must 64 * build a tree of node information to insert into the TNC. ··· 81 struct { 82 int free; 83 int dirty; 84 }; 85 }; 86 }; ··· 161 err = PTR_ERR(lp); 162 goto out; 163 } 164 out: 165 ubifs_release_lprops(c); 166 return err; ··· 634 ubifs_assert(sleb->endpt - offs >= used); 635 ubifs_assert(sleb->endpt % c->min_io_size == 0); 636 637 - if (sleb->endpt + c->min_io_size <= c->leb_size && !c->ro_mount) 638 - err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum, 639 - sleb->endpt, UBI_SHORTTERM); 640 - 641 *dirty = sleb->endpt - offs - used; 642 *free = c->leb_size - sleb->endpt; 643 ··· 656 * @sqnum: sequence number 657 * @free: amount of free space in bud 658 * @dirty: amount of dirty space from padding and deletion nodes 659 * 660 * This function inserts a reference node to the replay tree and returns zero 661 * in case of success or a negative error code in case of failure. 662 */ 663 static int insert_ref_node(struct ubifs_info *c, int lnum, int offs, 664 - unsigned long long sqnum, int free, int dirty) 665 { 666 struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; 667 struct replay_entry *r; ··· 693 r->flags = REPLAY_REF; 694 r->free = free; 695 r->dirty = dirty; 696 697 rb_link_node(&r->rb, parent, p); 698 rb_insert_color(&r->rb, &c->replay_tree); ··· 718 if (err) 719 return err; 720 err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum, 721 - free, dirty); 722 if (err) 723 return err; 724 }
··· 59 * @new_size: truncation new size 60 * @free: amount of free space in a bud 61 * @dirty: amount of dirty space in a bud from padding and deletion nodes 62 + * @jhead: journal head number of the bud 63 * 64 * UBIFS journal replay must compare node sequence numbers, which means it must 65 * build a tree of node information to insert into the TNC. ··· 80 struct { 81 int free; 82 int dirty; 83 + int jhead; 84 }; 85 }; 86 }; ··· 159 err = PTR_ERR(lp); 160 goto out; 161 } 162 + 163 + /* Make sure the journal head points to the latest bud */ 164 + err = ubifs_wbuf_seek_nolock(&c->jheads[r->jhead].wbuf, r->lnum, 165 + c->leb_size - r->free, UBI_SHORTTERM); 166 + 167 out: 168 ubifs_release_lprops(c); 169 return err; ··· 627 ubifs_assert(sleb->endpt - offs >= used); 628 ubifs_assert(sleb->endpt % c->min_io_size == 0); 629 630 *dirty = sleb->endpt - offs - used; 631 *free = c->leb_size - sleb->endpt; 632 ··· 653 * @sqnum: sequence number 654 * @free: amount of free space in bud 655 * @dirty: amount of dirty space from padding and deletion nodes 656 + * @jhead: journal head number for the bud 657 * 658 * This function inserts a reference node to the replay tree and returns zero 659 * in case of success or a negative error code in case of failure. 660 */ 661 static int insert_ref_node(struct ubifs_info *c, int lnum, int offs, 662 + unsigned long long sqnum, int free, int dirty, 663 + int jhead) 664 { 665 struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; 666 struct replay_entry *r; ··· 688 r->flags = REPLAY_REF; 689 r->free = free; 690 r->dirty = dirty; 691 + r->jhead = jhead; 692 693 rb_link_node(&r->rb, parent, p); 694 rb_insert_color(&r->rb, &c->replay_tree); ··· 712 if (err) 713 return err; 714 err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum, 715 + free, dirty, b->bud->jhead); 716 if (err) 717 return err; 718 }