aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2011-04-25 11:17:09 -0400
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2011-05-02 12:23:36 -0400
commitb50b9f408502a2ea90459ae36ba8cdc9cc005cfe (patch)
tree07c53213eaa3017282a5876eb34037fcff4a9441 /fs
parent8e10cd74342c7f5ce259cceca36f6eba084f5d58 (diff)
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
Diffstat (limited to 'fs')
-rw-r--r--fs/ubifs/log.c20
-rw-r--r--fs/ubifs/super.c15
2 files changed, 4 insertions, 31 deletions
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
index 4d0cb1241460..40fa780ebea7 100644
--- a/fs/ubifs/log.c
+++ b/fs/ubifs/log.c
@@ -175,26 +175,6 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
175} 175}
176 176
177/** 177/**
178 * ubifs_create_buds_lists - create journal head buds lists for remount rw.
179 * @c: UBIFS file-system description object
180 */
181void 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. 178 * ubifs_add_bud_to_log - add a new bud to the log.
199 * @c: UBIFS file-system description object 179 * @c: UBIFS file-system description object
200 * @jhead: journal head the bud belongs to 180 * @jhead: journal head the bud belongs to
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index be6c7b008f38..04ad07f4fcc3 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1257,12 +1257,12 @@ static int mount_ubifs(struct ubifs_info *c)
1257 goto out_free; 1257 goto out_free;
1258 } 1258 }
1259 1259
1260 err = alloc_wbufs(c);
1261 if (err)
1262 goto out_cbuf;
1263
1260 sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id); 1264 sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
1261 if (!c->ro_mount) { 1265 if (!c->ro_mount) {
1262 err = alloc_wbufs(c);
1263 if (err)
1264 goto out_cbuf;
1265
1266 /* Create background thread */ 1266 /* Create background thread */
1267 c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); 1267 c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
1268 if (IS_ERR(c->bgt)) { 1268 if (IS_ERR(c->bgt)) {
@@ -1631,12 +1631,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
1631 if (err) 1631 if (err)
1632 goto out; 1632 goto out;
1633 1633
1634 err = alloc_wbufs(c);
1635 if (err)
1636 goto out;
1637
1638 ubifs_create_buds_lists(c);
1639
1640 /* Create background thread */ 1634 /* Create background thread */
1641 c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); 1635 c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
1642 if (IS_ERR(c->bgt)) { 1636 if (IS_ERR(c->bgt)) {
@@ -1744,7 +1738,6 @@ static void ubifs_remount_ro(struct ubifs_info *c)
1744 if (err) 1738 if (err)
1745 ubifs_ro_mode(c, err); 1739 ubifs_ro_mode(c, err);
1746 1740
1747 free_wbufs(c);
1748 vfree(c->orph_buf); 1741 vfree(c->orph_buf);
1749 c->orph_buf = NULL; 1742 c->orph_buf = NULL;
1750 kfree(c->write_reserve_buf); 1743 kfree(c->write_reserve_buf);