UBIFS: do not free write-buffers when in R/O mode

Currently UBIFS has a small optimization - it frees write-buffers when it is
re-mounted from R/W mode to R/O mode. Of course, when it is mounted R/O, it
does not allocate write-buffers as well.

This optimization is nice but it leads to subtle problems and complications
in recovery, which I can reproduce using the integck test. The symptoms are
that after a power cut the file-system cannot be mounted if we first mount
it R/O, and then re-mount R/W - 'ubifs_rcvry_gc_commit()' prints:

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

Analysis of the problem.

When mounting R/W, the reply process sets journal heads to buds [1], but
when mounting R/O - it does not do this, because the write-buffers are not
allocated. So 'ubifs_rcvry_gc_commit()' works completely differently for the
same file-system but for the following 2 cases:

1. mounting R/W after a power cut and recover
2. mounting R/O after a power cut, re-mounting R/W and run deferred recovery

In the former case, we have journal heads seeked to the a bud, in the latter
case, they are non-seeked (wbuf->lnum == -1). So in the latter case we do not
try to recover the GC LEB by garbage-collecting to the GC head, but we just
try to find an empty LEB, and there may be no empty LEBs, so we just fail.
On the other hand, in the former case (mount R/W), we are able to make a GC LEB
(@c->gc_lnum) by garbage-collecting.

Thus, let's remove this small nice optimization and always allocate
write-buffers. This should not make too big difference - we have only 3
of them, each of max. write unit size, which is usually 2KiB. So this is
about 6KiB of RAM for the typical case, and only when mounted R/O.

[1]: Note, currently the replay process is setting (seeking) the journal heads
to _some_ buds, not necessarily to the buds which had been the journal heads
before the power cut happened. This will be fixed separately.

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

+4 -31
-20
fs/ubifs/log.c
··· 175 } 176 177 /** 178 - * ubifs_create_buds_lists - create journal head buds lists for remount rw. 179 - * @c: UBIFS file-system description object 180 - */ 181 - void ubifs_create_buds_lists(struct ubifs_info *c) 182 - { 183 - struct rb_node *p; 184 - 185 - spin_lock(&c->buds_lock); 186 - p = rb_first(&c->buds); 187 - while (p) { 188 - struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb); 189 - struct ubifs_jhead *jhead = &c->jheads[bud->jhead]; 190 - 191 - list_add_tail(&bud->list, &jhead->buds_list); 192 - p = rb_next(p); 193 - } 194 - spin_unlock(&c->buds_lock); 195 - } 196 - 197 - /** 198 * ubifs_add_bud_to_log - add a new bud to the log. 199 * @c: UBIFS file-system description object 200 * @jhead: journal head the bud belongs to
··· 175 } 176 177 /** 178 * ubifs_add_bud_to_log - add a new bud to the log. 179 * @c: UBIFS file-system description object 180 * @jhead: journal head the bud belongs to
+4 -11
fs/ubifs/super.c
··· 1257 goto out_free; 1258 } 1259 1260 sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id); 1261 if (!c->ro_mount) { 1262 - err = alloc_wbufs(c); 1263 - if (err) 1264 - goto out_cbuf; 1265 - 1266 /* Create background thread */ 1267 c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); 1268 if (IS_ERR(c->bgt)) { ··· 1631 if (err) 1632 goto out; 1633 1634 - err = alloc_wbufs(c); 1635 - if (err) 1636 - goto out; 1637 - 1638 - ubifs_create_buds_lists(c); 1639 - 1640 /* Create background thread */ 1641 c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); 1642 if (IS_ERR(c->bgt)) { ··· 1738 if (err) 1739 ubifs_ro_mode(c, err); 1740 1741 - free_wbufs(c); 1742 vfree(c->orph_buf); 1743 c->orph_buf = NULL; 1744 kfree(c->write_reserve_buf);
··· 1257 goto out_free; 1258 } 1259 1260 + err = alloc_wbufs(c); 1261 + if (err) 1262 + goto out_cbuf; 1263 + 1264 sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id); 1265 if (!c->ro_mount) { 1266 /* Create background thread */ 1267 c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); 1268 if (IS_ERR(c->bgt)) { ··· 1631 if (err) 1632 goto out; 1633 1634 /* Create background thread */ 1635 c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); 1636 if (IS_ERR(c->bgt)) { ··· 1744 if (err) 1745 ubifs_ro_mode(c, err); 1746 1747 vfree(c->orph_buf); 1748 c->orph_buf = NULL; 1749 kfree(c->write_reserve_buf);