* [PATCH 1/2] UBIFS: do not free write-buffers when in R/O mode
@ 2011-04-25 16:55 Artem Bityutskiy
0 siblings, 0 replies; 4+ messages in thread
From: Artem Bityutskiy @ 2011-04-25 16:55 UTC (permalink / raw)
To: MTD list; +Cc: Adrian Hunter
From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
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. Namely, I've noticed them when trying to fix and clean-up the
monster 'ubifs_rcvry_gc_commit()' function.
When mounting R/W, the reply process sets journal heads to some buds, but when
mounting R/O - it does not, because the write-buffers are not allocated. So
'ubifs_rcvry_gc_commit()' works completely differently 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 first case, we have journal heads seeked to some buds, in the second
case, they are always non-seeked (wbuf->lnum == -1).
And this is an obstacle for me to fix 'ubifs_rcvry_gc_commit()' because things
are already quite complicated there, and this additional subtle difference
causes more complications.
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.
This patch is actually a preparation for further 'ubifs_rcvry_gc_commit()'
fixes and clean-ups.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
fs/ubifs/log.c | 20 --------------------
fs/ubifs/super.c | 15 ++++-----------
2 files changed, 4 insertions(+), 31 deletions(-)
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
index 4d0cb12..40fa780 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)
}
/**
- * ubifs_create_buds_lists - create journal head buds lists for remount rw.
- * @c: UBIFS file-system description object
- */
-void ubifs_create_buds_lists(struct ubifs_info *c)
-{
- struct rb_node *p;
-
- spin_lock(&c->buds_lock);
- p = rb_first(&c->buds);
- while (p) {
- struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb);
- struct ubifs_jhead *jhead = &c->jheads[bud->jhead];
-
- list_add_tail(&bud->list, &jhead->buds_list);
- p = rb_next(p);
- }
- spin_unlock(&c->buds_lock);
-}
-
-/**
* ubifs_add_bud_to_log - add a new bud to the log.
* @c: UBIFS file-system description object
* @jhead: journal head the bud belongs to
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 459d8c6..1f049ae 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1257,12 +1257,12 @@ static int mount_ubifs(struct ubifs_info *c)
goto out_free;
}
+ err = alloc_wbufs(c);
+ if (err)
+ goto out_cbuf;
+
sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
if (!c->ro_mount) {
- err = alloc_wbufs(c);
- if (err)
- goto out_cbuf;
-
/* Create background thread */
c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
if (IS_ERR(c->bgt)) {
@@ -1632,12 +1632,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
if (err)
goto out;
- err = alloc_wbufs(c);
- if (err)
- goto out;
-
- ubifs_create_buds_lists(c);
-
/* Create background thread */
c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
if (IS_ERR(c->bgt)) {
@@ -1745,7 +1739,6 @@ static void ubifs_remount_ro(struct ubifs_info *c)
if (err)
ubifs_ro_mode(c, err);
- free_wbufs(c);
vfree(c->orph_buf);
c->orph_buf = NULL;
kfree(c->write_reserve_buf);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 0/2] UBIFS: fix recovery mounting
@ 2011-05-02 16:22 Artem Bityutskiy
2011-05-02 16:22 ` [PATCH 1/2] UBIFS: do not free write-buffers when in R/O mode Artem Bityutskiy
2011-05-02 16:22 ` [PATCH 2/2] UBIFS: seek journal heads to the latest bud in replay Artem Bityutskiy
0 siblings, 2 replies; 4+ messages in thread
From: Artem Bityutskiy @ 2011-05-02 16:22 UTC (permalink / raw)
To: MTD list; +Cc: Adrian Hunter
From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Hi,
I've sent these patches here already, but now I've re-written the commit
message, tested them, see that recovery does not fail anymore, and I am
going to merge them upstream and to the -stable trees.
Artem.
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/2] UBIFS: do not free write-buffers when in R/O mode
2011-05-02 16:22 [PATCH 0/2] UBIFS: fix recovery mounting Artem Bityutskiy
@ 2011-05-02 16:22 ` Artem Bityutskiy
2011-05-02 16:22 ` [PATCH 2/2] UBIFS: seek journal heads to the latest bud in replay Artem Bityutskiy
1 sibling, 0 replies; 4+ messages in thread
From: Artem Bityutskiy @ 2011-05-02 16:22 UTC (permalink / raw)
To: MTD list; +Cc: Adrian Hunter
From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
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
---
fs/ubifs/log.c | 20 --------------------
fs/ubifs/super.c | 15 ++++-----------
2 files changed, 4 insertions(+), 31 deletions(-)
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
index 4d0cb12..40fa780 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)
}
/**
- * ubifs_create_buds_lists - create journal head buds lists for remount rw.
- * @c: UBIFS file-system description object
- */
-void ubifs_create_buds_lists(struct ubifs_info *c)
-{
- struct rb_node *p;
-
- spin_lock(&c->buds_lock);
- p = rb_first(&c->buds);
- while (p) {
- struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb);
- struct ubifs_jhead *jhead = &c->jheads[bud->jhead];
-
- list_add_tail(&bud->list, &jhead->buds_list);
- p = rb_next(p);
- }
- spin_unlock(&c->buds_lock);
-}
-
-/**
* ubifs_add_bud_to_log - add a new bud to the log.
* @c: UBIFS file-system description object
* @jhead: journal head the bud belongs to
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 459d8c6..1f049ae 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1257,12 +1257,12 @@ static int mount_ubifs(struct ubifs_info *c)
goto out_free;
}
+ err = alloc_wbufs(c);
+ if (err)
+ goto out_cbuf;
+
sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
if (!c->ro_mount) {
- err = alloc_wbufs(c);
- if (err)
- goto out_cbuf;
-
/* Create background thread */
c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
if (IS_ERR(c->bgt)) {
@@ -1632,12 +1632,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
if (err)
goto out;
- err = alloc_wbufs(c);
- if (err)
- goto out;
-
- ubifs_create_buds_lists(c);
-
/* Create background thread */
c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
if (IS_ERR(c->bgt)) {
@@ -1745,7 +1739,6 @@ static void ubifs_remount_ro(struct ubifs_info *c)
if (err)
ubifs_ro_mode(c, err);
- free_wbufs(c);
vfree(c->orph_buf);
c->orph_buf = NULL;
kfree(c->write_reserve_buf);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] UBIFS: seek journal heads to the latest bud in replay
2011-05-02 16:22 [PATCH 0/2] UBIFS: fix recovery mounting Artem Bityutskiy
2011-05-02 16:22 ` [PATCH 1/2] UBIFS: do not free write-buffers when in R/O mode Artem Bityutskiy
@ 2011-05-02 16:22 ` Artem Bityutskiy
1 sibling, 0 replies; 4+ messages in thread
From: Artem Bityutskiy @ 2011-05-02 16:22 UTC (permalink / raw)
To: MTD list; +Cc: Adrian Hunter
From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
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
---
fs/ubifs/replay.c | 18 ++++++++++++------
1 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index b716a18..c29c468 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -59,6 +59,7 @@ enum {
* @new_size: truncation new size
* @free: amount of free space in a bud
* @dirty: amount of dirty space in a bud from padding and deletion nodes
+ * @jhead: journal head number of the bud
*
* UBIFS journal replay must compare node sequence numbers, which means it must
* build a tree of node information to insert into the TNC.
@@ -80,6 +81,7 @@ struct replay_entry {
struct {
int free;
int dirty;
+ int jhead;
};
};
};
@@ -159,6 +161,11 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
err = PTR_ERR(lp);
goto out;
}
+
+ /* Make sure the journal head points to the latest bud */
+ err = ubifs_wbuf_seek_nolock(&c->jheads[r->jhead].wbuf, r->lnum,
+ c->leb_size - r->free, UBI_SHORTTERM);
+
out:
ubifs_release_lprops(c);
return err;
@@ -627,10 +634,6 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
ubifs_assert(sleb->endpt - offs >= used);
ubifs_assert(sleb->endpt % c->min_io_size == 0);
- if (sleb->endpt + c->min_io_size <= c->leb_size && !c->ro_mount)
- err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum,
- sleb->endpt, UBI_SHORTTERM);
-
*dirty = sleb->endpt - offs - used;
*free = c->leb_size - sleb->endpt;
@@ -653,12 +656,14 @@ out_dump:
* @sqnum: sequence number
* @free: amount of free space in bud
* @dirty: amount of dirty space from padding and deletion nodes
+ * @jhead: journal head number for the bud
*
* This function inserts a reference node to the replay tree and returns zero
* in case of success or a negative error code in case of failure.
*/
static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
- unsigned long long sqnum, int free, int dirty)
+ unsigned long long sqnum, int free, int dirty,
+ int jhead)
{
struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
struct replay_entry *r;
@@ -688,6 +693,7 @@ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
r->flags = REPLAY_REF;
r->free = free;
r->dirty = dirty;
+ r->jhead = jhead;
rb_link_node(&r->rb, parent, p);
rb_insert_color(&r->rb, &c->replay_tree);
@@ -712,7 +718,7 @@ static int replay_buds(struct ubifs_info *c)
if (err)
return err;
err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
- free, dirty);
+ free, dirty, b->bud->jhead);
if (err)
return err;
}
--
1.7.2.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2011-05-02 16:18 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-02 16:22 [PATCH 0/2] UBIFS: fix recovery mounting Artem Bityutskiy
2011-05-02 16:22 ` [PATCH 1/2] UBIFS: do not free write-buffers when in R/O mode Artem Bityutskiy
2011-05-02 16:22 ` [PATCH 2/2] UBIFS: seek journal heads to the latest bud in replay Artem Bityutskiy
-- strict thread matches above, loose matches on Subject: below --
2011-04-25 16:55 [PATCH 1/2] UBIFS: do not free write-buffers when in R/O mode Artem Bityutskiy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).