linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/20] UBIFS: last changes
@ 2011-05-16  7:44 Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 01/20] UBIFS: improve debugging lprops scanning a little Artem Bityutskiy
                   ` (19 more replies)
  0 siblings, 20 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

Hi,

here are the last UBIFS changes which I have not sent to the mailing list yet.
The 20-patch series is _not_ a one improvement or fix, it is just a set of last
20 patches in the ubifs-2.6.git tree, dumped to the mailing list for review.
Since no one usually comments on patches, I'm saving time and do not split the
20 patches on several independent series. But if you want this, please, let me
know.

So, in these series:

1. Various fixes and improvements in the debugging code, to make sure that
   UBIFS extra debugging checks work fine in case of power cuts. I've made the
   changes when testing with 'integck' in power cut emulation mode with all the
   extra checks enabled.

2. Just random simplifications and clean-ups spotted while reading the code.

3. A lot of replay code simplifications, also spotted while reading the code
   and trying to figure out how it works.

4. A recovery improvement - now we recover only the last bud LEBs, not all of
   them, because power cuts can cause corruptions only in the last bud.

5. The free space fix-up code from Matthew - it deals with the situation when
   UBIFS is flashed with a dumb flasher and free space is unusable. So one can
   ask mkfs.ubifs to put a special flag to the UBIFS super-block and UBIFS will
   fix-up all the free space on the first mount. I will take time, though, so
   using a smarter flasher is more preferable. However, I'm still waiting for
   mkfs.ubifs changes from Matthew, as well as a piece of documentation for
   this space fix-up thing.

I'm going to send these changes upstream the next merge window.

Artem.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 01/20] UBIFS: improve debugging lprops scanning a little
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 02/20] UBIFS: simplify error path in lprops debugging check Artem Bityutskiy
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

When doing the lprops extra check ('dbg_check_lprops()') we scan whole media.
We even scan empty and freeable LEBs which may contain garbage, which we handle
after scanning. This patch teach the lprops checking function
('scan_check_cb()') to avoid scanning for free and freeable LEBs and save time.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/lprops.c |   42 ++++++++++++++++++------------------------
 1 files changed, 18 insertions(+), 24 deletions(-)

diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index 0ee0847..ce9fe39 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -1100,32 +1100,26 @@ static int scan_check_cb(struct ubifs_info *c,
 		goto out;
 	}
 
+	/*
+	 * After an unclean unmount, empty and freeable LEBs
+	 * may contain garbage - do not scan them.
+	 */
+	if (lp->free == c->leb_size) {
+		lst->empty_lebs += 1;
+		lst->total_free += c->leb_size;
+		lst->total_dark += ubifs_calc_dark(c, c->leb_size);
+		return LPT_SCAN_CONTINUE;
+	}
+	if (lp->free + lp->dirty == c->leb_size &&
+	    !(lp->flags & LPROPS_INDEX)) {
+		lst->total_free  += lp->free;
+		lst->total_dirty += lp->dirty;
+		lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
+		return LPT_SCAN_CONTINUE;
+	}
+
 	sleb = ubifs_scan(c, lnum, 0, buf, 0);
 	if (IS_ERR(sleb)) {
-		/*
-		 * After an unclean unmount, empty and freeable LEBs
-		 * may contain garbage.
-		 */
-		if (lp->free == c->leb_size) {
-			ubifs_err("scan errors were in empty LEB "
-				  "- continuing checking");
-			lst->empty_lebs += 1;
-			lst->total_free += c->leb_size;
-			lst->total_dark += ubifs_calc_dark(c, c->leb_size);
-			ret = LPT_SCAN_CONTINUE;
-			goto exit;
-		}
-
-		if (lp->free + lp->dirty == c->leb_size &&
-		    !(lp->flags & LPROPS_INDEX)) {
-			ubifs_err("scan errors were in freeable LEB "
-				  "- continuing checking");
-			lst->total_free  += lp->free;
-			lst->total_dirty += lp->dirty;
-			lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
-			ret = LPT_SCAN_CONTINUE;
-			goto exit;
-		}
 		data->err = PTR_ERR(sleb);
 		ret = LPT_SCAN_STOP;
 		goto exit;
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 02/20] UBIFS: simplify error path in lprops debugging check
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 01/20] UBIFS: improve debugging lprops scanning a little Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 03/20] UBIFS: simplify " Artem Bityutskiy
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

Simplify error path in 'scan_check_cb()' and stop using the special 'data->err'
field, but instead return the error code directly.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/lprops.c |   25 ++++++++++---------------
 1 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index ce9fe39..ac4521a 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -1044,7 +1044,7 @@ static int scan_check_cb(struct ubifs_info *c,
 		if (cat != (lp->flags & LPROPS_CAT_MASK)) {
 			ubifs_err("bad LEB category %d expected %d",
 				  (lp->flags & LPROPS_CAT_MASK), cat);
-			goto out;
+			return -EINVAL;
 		}
 	}
 
@@ -1078,7 +1078,7 @@ static int scan_check_cb(struct ubifs_info *c,
 			}
 			if (!found) {
 				ubifs_err("bad LPT list (category %d)", cat);
-				goto out;
+				return -EINVAL;
 			}
 		}
 	}
@@ -1090,15 +1090,13 @@ static int scan_check_cb(struct ubifs_info *c,
 		if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
 		    lp != heap->arr[lp->hpos]) {
 			ubifs_err("bad LPT heap (category %d)", cat);
-			goto out;
+			return -EINVAL;
 		}
 	}
 
 	buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
-	if (!buf) {
-		ubifs_err("cannot allocate memory to scan LEB %d", lnum);
-		goto out;
-	}
+	if (!buf)
+		return -ENOMEM;
 
 	/*
 	 * After an unclean unmount, empty and freeable LEBs
@@ -1120,9 +1118,8 @@ static int scan_check_cb(struct ubifs_info *c,
 
 	sleb = ubifs_scan(c, lnum, 0, buf, 0);
 	if (IS_ERR(sleb)) {
-		data->err = PTR_ERR(sleb);
-		ret = LPT_SCAN_STOP;
-		goto exit;
+		ret = PTR_ERR(sleb);
+		goto out;
 	}
 
 	is_idx = -1;
@@ -1240,10 +1237,8 @@ static int scan_check_cb(struct ubifs_info *c,
 	}
 
 	ubifs_scan_destroy(sleb);
-	ret = LPT_SCAN_CONTINUE;
-exit:
 	vfree(buf);
-	return ret;
+	return LPT_SCAN_CONTINUE;
 
 out_print:
 	ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, "
@@ -1252,10 +1247,10 @@ out_print:
 	dbg_dump_leb(c, lnum);
 out_destroy:
 	ubifs_scan_destroy(sleb);
+	ret = -EINVAL;
 out:
 	vfree(buf);
-	data->err = -EINVAL;
-	return LPT_SCAN_STOP;
+	return ret;
 }
 
 /**
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 03/20] UBIFS: simplify lprops debugging check
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 01/20] UBIFS: improve debugging lprops scanning a little Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 02/20] UBIFS: simplify error path in lprops debugging check Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 04/20] UBIFS: dump more in the " Artem Bityutskiy
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

Now we return all errors from 'scan_check_cb()' directly, so we do not need
'struct scan_check_data' any more, and this patch removes it.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/lprops.c |   48 +++++++++++++++---------------------------------
 1 files changed, 15 insertions(+), 33 deletions(-)

diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index ac4521a..77c541b 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -1007,21 +1007,11 @@ out:
 }
 
 /**
- * struct scan_check_data - data provided to scan callback function.
- * @lst: LEB properties statistics
- * @err: error code
- */
-struct scan_check_data {
-	struct ubifs_lp_stats lst;
-	int err;
-};
-
-/**
  * scan_check_cb - scan callback.
  * @c: the UBIFS file-system description object
  * @lp: LEB properties to scan
  * @in_tree: whether the LEB properties are in main memory
- * @data: information passed to and from the caller of the scan
+ * @lst: lprops statistics to update
  *
  * This function returns a code that indicates whether the scan should continue
  * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
@@ -1030,11 +1020,10 @@ struct scan_check_data {
  */
 static int scan_check_cb(struct ubifs_info *c,
 			 const struct ubifs_lprops *lp, int in_tree,
-			 struct scan_check_data *data)
+			 struct ubifs_lp_stats *lst)
 {
 	struct ubifs_scan_leb *sleb;
 	struct ubifs_scan_node *snod;
-	struct ubifs_lp_stats *lst = &data->lst;
 	int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
 	void *buf = NULL;
 
@@ -1267,8 +1256,7 @@ out:
 int dbg_check_lprops(struct ubifs_info *c)
 {
 	int i, err;
-	struct scan_check_data data;
-	struct ubifs_lp_stats *lst = &data.lst;
+	struct ubifs_lp_stats lst;
 
 	if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
 		return 0;
@@ -1283,29 +1271,23 @@ int dbg_check_lprops(struct ubifs_info *c)
 			return err;
 	}
 
-	memset(lst, 0, sizeof(struct ubifs_lp_stats));
-
-	data.err = 0;
+	memset(&lst, 0, sizeof(struct ubifs_lp_stats));
 	err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
 				    (ubifs_lpt_scan_callback)scan_check_cb,
-				    &data);
+				    &lst);
 	if (err && err != -ENOSPC)
 		goto out;
-	if (data.err) {
-		err = data.err;
-		goto out;
-	}
 
-	if (lst->empty_lebs != c->lst.empty_lebs ||
-	    lst->idx_lebs != c->lst.idx_lebs ||
-	    lst->total_free != c->lst.total_free ||
-	    lst->total_dirty != c->lst.total_dirty ||
-	    lst->total_used != c->lst.total_used) {
+	if (lst.empty_lebs != c->lst.empty_lebs ||
+	    lst.idx_lebs != c->lst.idx_lebs ||
+	    lst.total_free != c->lst.total_free ||
+	    lst.total_dirty != c->lst.total_dirty ||
+	    lst.total_used != c->lst.total_used) {
 		ubifs_err("bad overall accounting");
 		ubifs_err("calculated: empty_lebs %d, idx_lebs %d, "
 			  "total_free %lld, total_dirty %lld, total_used %lld",
-			  lst->empty_lebs, lst->idx_lebs, lst->total_free,
-			  lst->total_dirty, lst->total_used);
+			  lst.empty_lebs, lst.idx_lebs, lst.total_free,
+			  lst.total_dirty, lst.total_used);
 		ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, "
 			  "total_free %lld, total_dirty %lld, total_used %lld",
 			  c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
@@ -1314,11 +1296,11 @@ int dbg_check_lprops(struct ubifs_info *c)
 		goto out;
 	}
 
-	if (lst->total_dead != c->lst.total_dead ||
-	    lst->total_dark != c->lst.total_dark) {
+	if (lst.total_dead != c->lst.total_dead ||
+	    lst.total_dark != c->lst.total_dark) {
 		ubifs_err("bad dead/dark space accounting");
 		ubifs_err("calculated: total_dead %lld, total_dark %lld",
-			  lst->total_dead, lst->total_dark);
+			  lst.total_dead, lst.total_dark);
 		ubifs_err("read from lprops: total_dead %lld, total_dark %lld",
 			  c->lst.total_dead, c->lst.total_dark);
 		err = -EINVAL;
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 04/20] UBIFS: dump more in the lprops debugging check
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (2 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 03/20] UBIFS: simplify " Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 05/20] UBIFS: improve debugging messages Artem Bityutskiy
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/lprops.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index 77c541b..667884f 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -1108,6 +1108,10 @@ static int scan_check_cb(struct ubifs_info *c,
 	sleb = ubifs_scan(c, lnum, 0, buf, 0);
 	if (IS_ERR(sleb)) {
 		ret = PTR_ERR(sleb);
+		if (ret == -EUCLEAN) {
+			dbg_dump_lprops(c);
+			dbg_dump_budg(c, &c->bi);
+		}
 		goto out;
 	}
 
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 05/20] UBIFS: improve debugging messages
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (3 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 04/20] UBIFS: dump more in the " Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 06/20] UBIFS: improve commentary Artem Bityutskiy
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

Print a bit more information is some recovery and replay paths.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/recovery.c |    7 +++----
 fs/ubifs/replay.c   |    3 ++-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 3f41a0c..42b4512 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -1140,12 +1140,11 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 	struct ubifs_lprops lp;
 	int err;
 
+	dbg_rcvry("GC head LEB %d, offs %d", wbuf->lnum, wbuf->offs);
+
 	c->gc_lnum = -1;
-	if (wbuf->lnum == -1 || wbuf->offs == c->leb_size) {
-		dbg_rcvry("no GC head: wbuf->lnum %d, wbuf->offs %d",
-			  wbuf->lnum, wbuf->offs);
+	if (wbuf->lnum == -1 || wbuf->offs == c->leb_size)
 		return grab_empty_leb(c);
-	}
 
 	err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
 	if (err) {
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index c29c468..0052663 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -509,7 +509,7 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
 	struct ubifs_scan_node *snod;
 	struct ubifs_bud *bud;
 
-	dbg_mnt("replay bud LEB %d, head %d", lnum, jhead);
+	dbg_mnt("replay bud LEB %d, head %d, offs %d", lnum, jhead, offs);
 	if (c->need_recovery)
 		sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
 	else
@@ -636,6 +636,7 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
 
 	*dirty = sleb->endpt - offs - used;
 	*free = c->leb_size - sleb->endpt;
+	dbg_mnt("bud LEB %d replied: dirty %d, free %d", lnum, *dirty, *free);
 
 out:
 	ubifs_scan_destroy(sleb);
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 06/20] UBIFS: improve commentary
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (4 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 05/20] UBIFS: improve debugging messages Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 07/20] UBIFS: make 2 functions static Artem Bityutskiy
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

This is a tiny clean-up patch which improves replay commentaries.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/replay.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 0052663..e27346f 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -125,10 +125,11 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
 		 * zero which means the LEB must have been empty. The LEB
 		 * property values should be lp->free == c->leb_size and
 		 * lp->dirty == 0, but that is not the case. The reason is that
-		 * the LEB was garbage collected. The garbage collector resets
-		 * the free and dirty space without recording it anywhere except
-		 * lprops, so if there is not a commit then lprops does not have
-		 * that information next time the file system is mounted.
+		 * the LEB had been garbage collected before it became the bud,
+		 * and there was not commit inbetween. The garbage collector
+		 * resets the free and dirty space without recording it
+		 * anywhere except lprops, so if there was no commit then
+		 * lprops does not have that information.
 		 *
 		 * We do not need to adjust free space because the scan has told
 		 * us the exact value which is recorded in the replay entry as
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 07/20] UBIFS: make 2 functions static
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (5 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 06/20] UBIFS: improve commentary Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 08/20] UBIFS: double check that buds are replied in order Artem Bityutskiy
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

This is a minor change which makes 2 functions static because they
are not used outside the gc.c file: 'data_nodes_cmp()' and
'nondata_nodes_cmp()'.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/gc.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index 082d21b..d70937b 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -118,7 +118,7 @@ static int switch_gc_head(struct ubifs_info *c)
  * This function compares data nodes @a and @b. Returns %1 if @a has greater
  * inode or block number, and %-1 otherwise.
  */
-int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+static int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 {
 	ino_t inuma, inumb;
 	struct ubifs_info *c = priv;
@@ -161,7 +161,8 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
  * first and sorted by length in descending order. Directory entry nodes go
  * after inode nodes and are sorted in ascending hash valuer order.
  */
-int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+static int nondata_nodes_cmp(void *priv, struct list_head *a,
+			     struct list_head *b)
 {
 	ino_t inuma, inumb;
 	struct ubifs_info *c = priv;
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 08/20] UBIFS: double check that buds are replied in order
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (6 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 07/20] UBIFS: make 2 functions static Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 09/20] UBIFS: remove unnecessary stack variable Artem Bityutskiy
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

Commit 52c6e6f990669deac3f370f1603815adb55a1dbd provides misleading infomation
in the commit messages - buds are replied in order. And the real reason why
that fix helped is probably because it made sure we seek head even in read-only
mode (so deferred recovery will have seeked heads).

This patch adds an assertion which will fire if we reply buds out of order.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/replay.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index e27346f..5e81503 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -713,6 +713,7 @@ static int replay_buds(struct ubifs_info *c)
 {
 	struct bud_entry *b;
 	int err, uninitialized_var(free), uninitialized_var(dirty);
+	unsigned long long prev_sqnum = 0;
 
 	list_for_each_entry(b, &c->replay_buds, list) {
 		err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
@@ -723,6 +724,9 @@ static int replay_buds(struct ubifs_info *c)
 				      free, dirty, b->bud->jhead);
 		if (err)
 			return err;
+
+		ubifs_assert(b->sqnum > prev_sqnum);
+		prev_sqnum = b->sqnum;
 	}
 
 	return 0;
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 09/20] UBIFS: remove unnecessary stack variable
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (7 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 08/20] UBIFS: double check that buds are replied in order Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 10/20] UBIFS: store free and dirty space in the bud replay entry Artem Bityutskiy
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

This is patch removes an unnecessary 'offs' variable from 'ubifs_wbuf_write_nolock()'
- we can just keep 'wbuf->offs' up-to-date instead. This patch is very minor
the only motivation for it was that it is cleaner to keep wbuf->offs up-to-date
by the time we call 'ubifs_leb_write()'.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/io.c |   17 ++++++++---------
 1 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index 6cc0931..67bbde3 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -573,7 +573,7 @@ out_timers:
 int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
 {
 	struct ubifs_info *c = wbuf->c;
-	int err, written, n, aligned_len = ALIGN(len, 8), offs;
+	int err, written, n, aligned_len = ALIGN(len, 8);
 
 	dbg_io("%d bytes (%s) to jhead %s wbuf at LEB %d:%d", len,
 	       dbg_ntype(((struct ubifs_ch *)buf)->node_type),
@@ -636,7 +636,6 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
 		goto exit;
 	}
 
-	offs = wbuf->offs;
 	written = 0;
 
 	if (wbuf->used) {
@@ -653,7 +652,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
 		if (err)
 			goto out;
 
-		offs += wbuf->size;
+		wbuf->offs += wbuf->size;
 		len -= wbuf->avail;
 		aligned_len -= wbuf->avail;
 		written += wbuf->avail;
@@ -672,7 +671,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
 		if (err)
 			goto out;
 
-		offs += wbuf->size;
+		wbuf->offs += wbuf->size;
 		len -= wbuf->size;
 		aligned_len -= wbuf->size;
 		written += wbuf->size;
@@ -687,12 +686,13 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
 	n = aligned_len >> c->max_write_shift;
 	if (n) {
 		n <<= c->max_write_shift;
-		dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, offs);
-		err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, offs, n,
-				    wbuf->dtype);
+		dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
+		       wbuf->offs);
+		err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written,
+				    wbuf->offs, n, wbuf->dtype);
 		if (err)
 			goto out;
-		offs += n;
+		wbuf->offs += n;
 		aligned_len -= n;
 		len -= n;
 		written += n;
@@ -707,7 +707,6 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
 		 */
 		memcpy(wbuf->buf, buf + written, len);
 
-	wbuf->offs = offs;
 	if (c->leb_size - wbuf->offs >= c->max_write_size)
 		wbuf->size = c->max_write_size;
 	else
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 10/20] UBIFS: store free and dirty space in the bud replay entry
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (8 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 09/20] UBIFS: remove unnecessary stack variable Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 11/20] UBIFS: simplify replay Artem Bityutskiy
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

This is just a small preparation patch which adds 'free' and 'drity' fields to
'struct bud_entry'. They will be used to set bud lprops.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/replay.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 5e81503..ee2f0b2 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -90,14 +90,16 @@ struct replay_entry {
  * struct bud_entry - entry in the list of buds to replay.
  * @list: next bud in the list
  * @bud: bud description object
- * @free: free bytes in the bud
  * @sqnum: reference node sequence number
+ * @free: free bytes in the bud
+ * @dirty: dirty bytes in the bud
  */
 struct bud_entry {
 	struct list_head list;
 	struct ubifs_bud *bud;
-	int free;
 	unsigned long long sqnum;
+	int free;
+	int dirty;
 };
 
 /**
@@ -720,6 +722,8 @@ static int replay_buds(struct ubifs_info *c)
 				 &free, &dirty);
 		if (err)
 			return err;
+		b->free = free;
+		b->dirty = dirty;
 		err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
 				      free, dirty, b->bud->jhead);
 		if (err)
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 11/20] UBIFS: simplify replay
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (9 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 10/20] UBIFS: store free and dirty space in the bud replay entry Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 12/20] UBIFS: substitute the replay tree with a replay list Artem Bityutskiy
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

This patch simplifies the replay code and makes it smaller. First of all, we
can notice that we do not really need to create bud replay entries and insert
them to the replay tree, because the only reason we do this is to set buds
lprops correctly at the end. Instead, we can just walk the list of buds at the
very end and set lprops for each bud. This allows us to get rid of whole
'insert_ref_node()' function, the 'REPLAY_REF' flag, and several fields in
'struct replay_entry'. Then we can also notice that we do not need the 'flags'
'struct replay_entry' field, because there is only one flag -
'REPLAY_DELETION'. Instead, we can just add a 'deletion' bit fields. As a
result, this patch deletes much more lines that in adds.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/replay.c |  167 +++++++++++++++++++----------------------------------
 1 files changed, 59 insertions(+), 108 deletions(-)

diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index ee2f0b2..08f5036 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -34,32 +34,18 @@
 
 #include "ubifs.h"
 
-/*
- * Replay flags.
- *
- * REPLAY_DELETION: node was deleted
- * REPLAY_REF: node is a reference node
- */
-enum {
-	REPLAY_DELETION = 1,
-	REPLAY_REF = 2,
-};
-
 /**
  * struct replay_entry - replay tree entry.
  * @lnum: logical eraseblock number of the node
  * @offs: node offset
  * @len: node length
+ * @deletion: non-zero if this entry corresponds to a node deletion
  * @sqnum: node sequence number
- * @flags: replay flags
  * @rb: links the replay tree
  * @key: node key
  * @nm: directory entry name
  * @old_size: truncation old size
  * @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.
@@ -68,8 +54,8 @@ struct replay_entry {
 	int lnum;
 	int offs;
 	int len;
+	unsigned int deletion:1;
 	unsigned long long sqnum;
-	int flags;
 	struct rb_node rb;
 	union ubifs_key key;
 	union {
@@ -78,11 +64,6 @@ struct replay_entry {
 			loff_t old_size;
 			loff_t new_size;
 		};
-		struct {
-			int free;
-			int dirty;
-			int jhead;
-		};
 	};
 };
 
@@ -105,28 +86,32 @@ struct bud_entry {
 /**
  * set_bud_lprops - set free and dirty space used by a bud.
  * @c: UBIFS file-system description object
- * @r: replay entry of bud
+ * @b: bud entry which describes the bud
+ *
+ * This function makes sure the LEB properties of bud @b are set correctly
+ * after the replay. Returns zero in case of success and a negative error code
+ * in case of failure.
  */
-static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
+static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
 {
 	const struct ubifs_lprops *lp;
 	int err = 0, dirty;
 
 	ubifs_get_lprops(c);
 
-	lp = ubifs_lpt_lookup_dirty(c, r->lnum);
+	lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum);
 	if (IS_ERR(lp)) {
 		err = PTR_ERR(lp);
 		goto out;
 	}
 
 	dirty = lp->dirty;
-	if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
+	if (b->bud->start == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
 		/*
 		 * The LEB was added to the journal with a starting offset of
 		 * zero which means the LEB must have been empty. The LEB
-		 * property values should be lp->free == c->leb_size and
-		 * lp->dirty == 0, but that is not the case. The reason is that
+		 * property values should be @lp->free == @c->leb_size and
+		 * @lp->dirty == 0, but that is not the case. The reason is that
 		 * the LEB had been garbage collected before it became the bud,
 		 * and there was not commit inbetween. The garbage collector
 		 * resets the free and dirty space without recording it
@@ -135,15 +120,15 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
 		 *
 		 * We do not need to adjust free space because the scan has told
 		 * us the exact value which is recorded in the replay entry as
-		 * r->free.
+		 * @b->free.
 		 *
 		 * However we do need to subtract from the dirty space the
 		 * amount of space that the garbage collector reclaimed, which
 		 * is the whole LEB minus the amount of space that was free.
 		 */
-		dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
+		dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
 			lp->free, lp->dirty);
-		dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
+		dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
 			lp->free, lp->dirty);
 		dirty -= c->leb_size - lp->free;
 		/*
@@ -155,10 +140,10 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
 		 */
 		if (dirty != 0)
 			dbg_msg("LEB %d lp: %d free %d dirty "
-				"replay: %d free %d dirty", r->lnum, lp->free,
-				lp->dirty, r->free, r->dirty);
+				"replay: %d free %d dirty", b->bud->lnum,
+				lp->free, lp->dirty, b->free, b->dirty);
 	}
-	lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty,
+	lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty,
 			     lp->flags | LPROPS_TAKEN, 0);
 	if (IS_ERR(lp)) {
 		err = PTR_ERR(lp);
@@ -166,8 +151,9 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
 	}
 
 	/* 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);
+	err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf,
+				     b->bud->lnum, c->leb_size - b->free,
+				     UBI_SHORTTERM);
 
 out:
 	ubifs_release_lprops(c);
@@ -175,6 +161,27 @@ out:
 }
 
 /**
+ * set_buds_lprops - set free and dirty space for all replayed buds.
+ * @c: UBIFS file-system description object
+ *
+ * This function sets LEB properties for all replayed buds. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+static int set_buds_lprops(struct ubifs_info *c)
+{
+	struct bud_entry *b;
+	int err;
+
+	list_for_each_entry(b, &c->replay_buds, list) {
+		err = set_bud_lprops(c, b);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
  * trun_remove_range - apply a replay entry for a truncation to the TNC.
  * @c: UBIFS file-system description object
  * @r: replay entry of truncation
@@ -210,24 +217,22 @@ static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
  */
 static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
 {
-	int err, deletion = ((r->flags & REPLAY_DELETION) != 0);
+	int err;
 
-	dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum,
-		r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key));
+	dbg_mnt("LEB %d:%d len %d deletion %d sqnum %llu %s", r->lnum,
+		r->offs, r->len, r->deletion, r->sqnum, DBGKEY(&r->key));
 
 	/* Set c->replay_sqnum to help deal with dangling branches. */
 	c->replay_sqnum = r->sqnum;
 
-	if (r->flags & REPLAY_REF)
-		err = set_bud_lprops(c, r);
-	else if (is_hash_key(c, &r->key)) {
-		if (deletion)
+	if (is_hash_key(c, &r->key)) {
+		if (r->deletion)
 			err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
 		else
 			err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
 					       r->len, &r->nm);
 	} else {
-		if (deletion)
+		if (r->deletion)
 			switch (key_type(c, &r->key)) {
 			case UBIFS_INO_KEY:
 			{
@@ -250,7 +255,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
 			return err;
 
 		if (c->need_recovery)
-			err = ubifs_recover_size_accum(c, &r->key, deletion,
+			err = ubifs_recover_size_accum(c, &r->key, r->deletion,
 						       r->new_size);
 	}
 
@@ -373,11 +378,11 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
 	r->lnum = lnum;
 	r->offs = offs;
 	r->len = len;
+	r->deletion = !!deletion;
 	r->sqnum = sqnum;
-	r->flags = (deletion ? REPLAY_DELETION : 0);
+	key_copy(c, key, &r->key);
 	r->old_size = old_size;
 	r->new_size = new_size;
-	key_copy(c, key, &r->key);
 
 	rb_link_node(&r->rb, parent, p);
 	rb_insert_color(&r->rb, &c->replay_tree);
@@ -445,13 +450,13 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
 	r->lnum = lnum;
 	r->offs = offs;
 	r->len = len;
+	r->deletion = !!deletion;
 	r->sqnum = sqnum;
+	key_copy(c, key, &r->key);
 	r->nm.len = nlen;
 	memcpy(nbuf, name, nlen);
 	nbuf[nlen] = '\0';
 	r->nm.name = nbuf;
-	r->flags = (deletion ? REPLAY_DELETION : 0);
-	key_copy(c, key, &r->key);
 
 	ubifs_assert(!*p);
 	rb_link_node(&r->rb, parent, p);
@@ -653,58 +658,6 @@ out_dump:
 }
 
 /**
- * insert_ref_node - insert a reference node to the replay tree.
- * @c: UBIFS file-system description object
- * @lnum: node logical eraseblock number
- * @offs: node offset
- * @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,
-			   int jhead)
-{
-	struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
-	struct replay_entry *r;
-
-	dbg_mnt("add ref LEB %d:%d", lnum, offs);
-	while (*p) {
-		parent = *p;
-		r = rb_entry(parent, struct replay_entry, rb);
-		if (sqnum < r->sqnum) {
-			p = &(*p)->rb_left;
-			continue;
-		} else if (sqnum > r->sqnum) {
-			p = &(*p)->rb_right;
-			continue;
-		}
-		ubifs_err("duplicate sqnum in replay tree");
-		return -EINVAL;
-	}
-
-	r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
-	if (!r)
-		return -ENOMEM;
-
-	r->lnum = lnum;
-	r->offs = offs;
-	r->sqnum = sqnum;
-	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);
-	return 0;
-}
-
-/**
  * replay_buds - replay all buds.
  * @c: UBIFS file-system description object
  *
@@ -714,18 +667,12 @@ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
 static int replay_buds(struct ubifs_info *c)
 {
 	struct bud_entry *b;
-	int err, uninitialized_var(free), uninitialized_var(dirty);
+	int err;
 	unsigned long long prev_sqnum = 0;
 
 	list_for_each_entry(b, &c->replay_buds, list) {
 		err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
-				 &free, &dirty);
-		if (err)
-			return err;
-		b->free = free;
-		b->dirty = dirty;
-		err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
-				      free, dirty, b->bud->jhead);
+				 &b->free, &b->dirty);
 		if (err)
 			return err;
 
@@ -1074,6 +1021,10 @@ int ubifs_replay_journal(struct ubifs_info *c)
 	if (err)
 		goto out;
 
+	err = set_buds_lprops(c);
+	if (err)
+		goto out;
+
 	/*
 	 * UBIFS budgeting calculations use @c->bi.uncommitted_idx variable
 	 * to roughly estimate index growth. Things like @c->bi.min_idx_lebs
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 12/20] UBIFS: substitute the replay tree with a replay list
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (10 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 11/20] UBIFS: simplify replay Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 13/20] UBIFS: change bud replay function conventions Artem Bityutskiy
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

This patch simplifies replay even further - it removes the replay tree and
adds the replay list instead. Indeed, we just do not need to use a tree here -
all we need to do is to add all nodes to the list and then sort it. Using
RB-tree is an overkill - more code and slower. And since we replay buds in
order, we expect the nodes to follow in _mostly_ sorted order, so the merge
sort becomes much cheaper in average than an RB-tree.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/replay.c |  172 +++++++++++++++++++++++------------------------------
 fs/ubifs/ubifs.h  |    2 -
 2 files changed, 74 insertions(+), 100 deletions(-)

diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 08f5036..47915a7 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -33,22 +33,24 @@
  */
 
 #include "ubifs.h"
+#include <linux/list_sort.h>
 
 /**
- * struct replay_entry - replay tree entry.
+ * struct replay_entry - replay list entry.
  * @lnum: logical eraseblock number of the node
  * @offs: node offset
  * @len: node length
  * @deletion: non-zero if this entry corresponds to a node deletion
  * @sqnum: node sequence number
- * @rb: links the replay tree
+ * @list: links the replay list
  * @key: node key
  * @nm: directory entry name
  * @old_size: truncation old size
  * @new_size: truncation new size
  *
- * UBIFS journal replay must compare node sequence numbers, which means it must
- * build a tree of node information to insert into the TNC.
+ * The replay process first scans all buds and builds the replay list, then
+ * sorts the replay list in nodes sequence number order, and then inserts all
+ * the replay entries to the TNC.
  */
 struct replay_entry {
 	int lnum;
@@ -56,7 +58,7 @@ struct replay_entry {
 	int len;
 	unsigned int deletion:1;
 	unsigned long long sqnum;
-	struct rb_node rb;
+	struct list_head list;
 	union ubifs_key key;
 	union {
 		struct qstr nm;
@@ -263,68 +265,77 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
 }
 
 /**
- * destroy_replay_tree - destroy the replay.
- * @c: UBIFS file-system description object
+ * replay_entries_cmp - compare 2 replay entries.
+ * @priv: UBIFS file-system description object
+ * @a: first replay entry
+ * @a: second replay entry
  *
- * Destroy the replay tree.
+ * This is a comparios function for 'list_sort()' which compares 2 replay
+ * entries @a and @b by comparing their sequence numer.  Returns %1 if @a has
+ * greater sequence number and %-1 otherwise.
  */
-static void destroy_replay_tree(struct ubifs_info *c)
+static int replay_entries_cmp(void *priv, struct list_head *a,
+			      struct list_head *b)
 {
-	struct rb_node *this = c->replay_tree.rb_node;
-	struct replay_entry *r;
-
-	while (this) {
-		if (this->rb_left) {
-			this = this->rb_left;
-			continue;
-		} else if (this->rb_right) {
-			this = this->rb_right;
-			continue;
-		}
-		r = rb_entry(this, struct replay_entry, rb);
-		this = rb_parent(this);
-		if (this) {
-			if (this->rb_left == &r->rb)
-				this->rb_left = NULL;
-			else
-				this->rb_right = NULL;
-		}
-		if (is_hash_key(c, &r->key))
-			kfree(r->nm.name);
-		kfree(r);
-	}
-	c->replay_tree = RB_ROOT;
+	struct replay_entry *ra, *rb;
+
+	cond_resched();
+	if (a == b)
+		return 0;
+
+	ra = list_entry(a, struct replay_entry, list);
+	rb = list_entry(b, struct replay_entry, list);
+	ubifs_assert(ra->sqnum != rb->sqnum);
+	if (ra->sqnum > rb->sqnum)
+		return 1;
+	return -1;
 }
 
 /**
- * apply_replay_tree - apply the replay tree to the TNC.
+ * apply_replay_list - apply the replay list to the TNC.
  * @c: UBIFS file-system description object
  *
- * Apply the replay tree.
- * Returns zero in case of success and a negative error code in case of
- * failure.
+ * Apply all entries in the replay list to the TNC. Returns zero in case of
+ * success and a negative error code in case of failure.
  */
-static int apply_replay_tree(struct ubifs_info *c)
+static int apply_replay_list(struct ubifs_info *c)
 {
-	struct rb_node *this = rb_first(&c->replay_tree);
+	struct replay_entry *r;
+	int err;
 
-	while (this) {
-		struct replay_entry *r;
-		int err;
+	list_sort(c, &c->replay_list, &replay_entries_cmp);
 
+	list_for_each_entry(r, &c->replay_list, list) {
 		cond_resched();
 
-		r = rb_entry(this, struct replay_entry, rb);
 		err = apply_replay_entry(c, r);
 		if (err)
 			return err;
-		this = rb_next(this);
 	}
+
 	return 0;
 }
 
 /**
- * insert_node - insert a node to the replay tree.
+ * destroy_replay_list - destroy the replay.
+ * @c: UBIFS file-system description object
+ *
+ * Destroy the replay list.
+ */
+static void destroy_replay_list(struct ubifs_info *c)
+{
+	struct replay_entry *r, *tmp;
+
+	list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
+		if (is_hash_key(c, &r->key))
+			kfree(r->nm.name);
+		list_del(&r->list);
+		kfree(r);
+	}
+}
+
+/**
+ * insert_node - insert a node to the replay list
  * @c: UBIFS file-system description object
  * @lnum: node logical eraseblock number
  * @offs: node offset
@@ -336,39 +347,25 @@ static int apply_replay_tree(struct ubifs_info *c)
  * @old_size: truncation old size
  * @new_size: truncation new size
  *
- * This function inserts a scanned non-direntry node to the replay tree. The
- * replay tree is an RB-tree containing @struct replay_entry elements which are
- * indexed by the sequence number. The replay tree is applied at the very end
- * of the replay process. Since the tree is sorted in sequence number order,
- * the older modifications are applied first. This function returns zero in
- * case of success and a negative error code in case of failure.
+ * This function inserts a scanned non-direntry node to the replay list. The
+ * replay list contains @struct replay_entry elements, and we sort this list in
+ * sequence number order before applying it. The replay list is applied at the
+ * very end of the replay process. Since the list is sorted in sequence number
+ * order, the older modifications are applied first. This function returns zero
+ * in case of success and a negative error code in case of failure.
  */
 static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
 		       union ubifs_key *key, unsigned long long sqnum,
 		       int deletion, int *used, loff_t old_size,
 		       loff_t new_size)
 {
-	struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
 	struct replay_entry *r;
 
+	dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+
 	if (key_inum(c, key) >= c->highest_inum)
 		c->highest_inum = key_inum(c, key);
 
-	dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
-	while (*p) {
-		parent = *p;
-		r = rb_entry(parent, struct replay_entry, rb);
-		if (sqnum < r->sqnum) {
-			p = &(*p)->rb_left;
-			continue;
-		} else if (sqnum > r->sqnum) {
-			p = &(*p)->rb_right;
-			continue;
-		}
-		ubifs_err("duplicate sqnum in replay");
-		return -EINVAL;
-	}
-
 	r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
 	if (!r)
 		return -ENOMEM;
@@ -384,13 +381,12 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
 	r->old_size = old_size;
 	r->new_size = new_size;
 
-	rb_link_node(&r->rb, parent, p);
-	rb_insert_color(&r->rb, &c->replay_tree);
+	list_add_tail(&r->list, &c->replay_list);
 	return 0;
 }
 
 /**
- * insert_dent - insert a directory entry node into the replay tree.
+ * insert_dent - insert a directory entry node into the replay list.
  * @c: UBIFS file-system description object
  * @lnum: node logical eraseblock number
  * @offs: node offset
@@ -402,43 +398,25 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
  * @deletion: non-zero if this is a deletion
  * @used: number of bytes in use in a LEB
  *
- * This function inserts a scanned directory entry node to the replay tree.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- *
- * This function is also used for extended attribute entries because they are
- * implemented as directory entry nodes.
+ * This function inserts a scanned directory entry node or an extended
+ * attribute entry to the replay list. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
 static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
 		       union ubifs_key *key, const char *name, int nlen,
 		       unsigned long long sqnum, int deletion, int *used)
 {
-	struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
 	struct replay_entry *r;
 	char *nbuf;
 
+	dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
 	if (key_inum(c, key) >= c->highest_inum)
 		c->highest_inum = key_inum(c, key);
 
-	dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
-	while (*p) {
-		parent = *p;
-		r = rb_entry(parent, struct replay_entry, rb);
-		if (sqnum < r->sqnum) {
-			p = &(*p)->rb_left;
-			continue;
-		}
-		if (sqnum > r->sqnum) {
-			p = &(*p)->rb_right;
-			continue;
-		}
-		ubifs_err("duplicate sqnum in replay");
-		return -EINVAL;
-	}
-
 	r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
 	if (!r)
 		return -ENOMEM;
+
 	nbuf = kmalloc(nlen + 1, GFP_KERNEL);
 	if (!nbuf) {
 		kfree(r);
@@ -458,9 +436,7 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
 	nbuf[nlen] = '\0';
 	r->nm.name = nbuf;
 
-	ubifs_assert(!*p);
-	rb_link_node(&r->rb, parent, p);
-	rb_insert_color(&r->rb, &c->replay_tree);
+	list_add_tail(&r->list, &c->replay_list);
 	return 0;
 }
 
@@ -1017,7 +993,7 @@ int ubifs_replay_journal(struct ubifs_info *c)
 	if (err)
 		goto out;
 
-	err = apply_replay_tree(c);
+	err = apply_replay_list(c);
 	if (err)
 		goto out;
 
@@ -1039,7 +1015,7 @@ int ubifs_replay_journal(struct ubifs_info *c)
 		"highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,
 		(unsigned long)c->highest_inum);
 out:
-	destroy_replay_tree(c);
+	destroy_replay_list(c);
 	destroy_bud_list(c);
 	c->replaying = 0;
 	return err;
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 26a7ebe..a2f9d4e 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1205,7 +1205,6 @@ struct ubifs_debug_info;
  * @replaying: %1 during journal replay
  * @mounting: %1 while mounting
  * @remounting_rw: %1 while re-mounting from R/O mode to R/W mode
- * @replay_tree: temporary tree used during journal replay
  * @replay_list: temporary list used during journal replay
  * @replay_buds: list of buds to replay
  * @cs_sqnum: sequence number of first node in the log (commit start node)
@@ -1435,7 +1434,6 @@ struct ubifs_info {
 	unsigned int replaying:1;
 	unsigned int mounting:1;
 	unsigned int remounting_rw:1;
-	struct rb_root replay_tree;
 	struct list_head replay_list;
 	struct list_head replay_buds;
 	unsigned long long cs_sqnum;
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 13/20] UBIFS: change bud replay function conventions
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (11 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 12/20] UBIFS: substitute the replay tree with a replay list Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 14/20] UBIFS: remove BUG statement Artem Bityutskiy
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

This is a minor preparation patch which changes 'replay_bud()' interface -
instead of passing bud lnum, offs, jhead, etc directly, pass a pointer to the
bud entry which contains all the information. The bud entry will be also needed
in one of the following patches.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/replay.c |   28 ++++++++++++----------------
 1 files changed, 12 insertions(+), 16 deletions(-)

diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 47915a7..4378baa 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -475,25 +475,22 @@ int ubifs_validate_entry(struct ubifs_info *c,
 /**
  * replay_bud - replay a bud logical eraseblock.
  * @c: UBIFS file-system description object
- * @lnum: bud logical eraseblock number to replay
- * @offs: bud start offset
- * @jhead: journal head to which this bud belongs
- * @free: amount of free space in the bud is returned here
- * @dirty: amount of dirty space from padding and deletion nodes is returned
- * here
+ * @b: bud entry which describes the bud
  *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function replays bud @bud, recovers it if needed, and adds all nodes
+ * from this bud to the replay list. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
-static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
-		      int *free, int *dirty)
+static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
 {
-	int err = 0, used = 0;
+	int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start;
+	int jhead = b->bud->jhead;
 	struct ubifs_scan_leb *sleb;
 	struct ubifs_scan_node *snod;
 	struct ubifs_bud *bud;
 
 	dbg_mnt("replay bud LEB %d, head %d, offs %d", lnum, jhead, offs);
+
 	if (c->need_recovery)
 		sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
 	else
@@ -618,9 +615,9 @@ 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);
 
-	*dirty = sleb->endpt - offs - used;
-	*free = c->leb_size - sleb->endpt;
-	dbg_mnt("bud LEB %d replied: dirty %d, free %d", lnum, *dirty, *free);
+	b->dirty = sleb->endpt - offs - used;
+	b->free = c->leb_size - sleb->endpt;
+	dbg_mnt("bud LEB %d replied: dirty %d, free %d", lnum, b->dirty, b->free);
 
 out:
 	ubifs_scan_destroy(sleb);
@@ -647,8 +644,7 @@ static int replay_buds(struct ubifs_info *c)
 	unsigned long long prev_sqnum = 0;
 
 	list_for_each_entry(b, &c->replay_buds, list) {
-		err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
-				 &b->free, &b->dirty);
+		err = replay_bud(c, b);
 		if (err)
 			return err;
 
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 14/20] UBIFS: remove BUG statement
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (12 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 13/20] UBIFS: change bud replay function conventions Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 15/20] UBIFS: synchronize write-buffer before switching to the next bud Artem Bityutskiy
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

Remove a 'BUG()' statement when we are unable to find a bud and add a
similar 'ubifs_assert()' statement instead.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/replay.c |    6 +-----
 1 files changed, 1 insertions(+), 5 deletions(-)

diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 4378baa..0f50fbf 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -487,7 +487,6 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
 	int jhead = b->bud->jhead;
 	struct ubifs_scan_leb *sleb;
 	struct ubifs_scan_node *snod;
-	struct ubifs_bud *bud;
 
 	dbg_mnt("replay bud LEB %d, head %d, offs %d", lnum, jhead, offs);
 
@@ -608,10 +607,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
 			goto out;
 	}
 
-	bud = ubifs_search_bud(c, lnum);
-	if (!bud)
-		BUG();
-
+	ubifs_assert(ubifs_search_bud(c, lnum));
 	ubifs_assert(sleb->endpt - offs >= used);
 	ubifs_assert(sleb->endpt % c->min_io_size == 0);
 
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 15/20] UBIFS: synchronize write-buffer before switching to the next bud
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (13 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 14/20] UBIFS: remove BUG statement Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 16/20] UBIFS: expect corruption only in last journal head LEBs Artem Bityutskiy
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

Currently when UBIFS fills up the current bud (which is the last in the journal
head) and switches to the next bud, it first writes the log reference node for
the next bud and only after this synchronizes the write-buffer of the previous
bud. This is not a big deal, but an unclean power cut may lead to a situation
when we have corruption in a next-to-last bud, although it is much more logical
that we have to have corruption only in the last bud.

This patch also removes write-buffer synchronization from
'ubifs_wbuf_seek_nolock()' because this is not needed anymore (we synchronize
the write-buffer explicitly everywhere now) and also because this is just
prone to various errors.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/gc.c      |    4 ++++
 fs/ubifs/io.c      |   12 +++---------
 fs/ubifs/journal.c |   25 +++++++++++++++----------
 3 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index d70937b..ded29f6 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -100,6 +100,10 @@ static int switch_gc_head(struct ubifs_info *c)
 	if (err)
 		return err;
 
+	err = ubifs_wbuf_sync_nolock(wbuf);
+	if (err)
+		return err;
+
 	err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
 	if (err)
 		return err;
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index 67bbde3..166951e 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -452,8 +452,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
  * @dtype: data type
  *
  * This function targets the write-buffer to logical eraseblock @lnum:@offs.
- * The write-buffer is synchronized if it is not empty. Returns zero in case of
- * success and a negative error code in case of failure.
+ * The write-buffer has to be empty. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
 int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
 			   int dtype)
@@ -465,13 +465,7 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
 	ubifs_assert(offs >= 0 && offs <= c->leb_size);
 	ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
 	ubifs_assert(lnum != wbuf->lnum);
-
-	if (wbuf->used > 0) {
-		int err = ubifs_wbuf_sync_nolock(wbuf);
-
-		if (err)
-			return err;
-	}
+	ubifs_assert(wbuf->used == 0);
 
 	spin_lock(&wbuf->lock);
 	wbuf->lnum = lnum;
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index ce55a48..34b1679 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -141,14 +141,8 @@ again:
 	 * LEB with some empty space.
 	 */
 	lnum = ubifs_find_free_space(c, len, &offs, squeeze);
-	if (lnum >= 0) {
-		/* Found an LEB, add it to the journal head */
-		err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
-		if (err)
-			goto out_return;
-		/* A new bud was successfully allocated and added to the log */
+	if (lnum >= 0)
 		goto out;
-	}
 
 	err = lnum;
 	if (err != -ENOSPC)
@@ -203,12 +197,23 @@ again:
 		return 0;
 	}
 
-	err = ubifs_add_bud_to_log(c, jhead, lnum, 0);
-	if (err)
-		goto out_return;
 	offs = 0;
 
 out:
+	/*
+	 * Make sure we synchronize the write-buffer before we add the new bud
+	 * to the log. Otherwise we may have a power cut after the log
+	 * reference node for the last bud (@lnum) is written but before the
+	 * write-buffer data are written to the next-to-last bud
+	 * (@wbuf->lnum). And the effect would be that the recovery would see
+	 * that there is corruption in the next-to-last bud.
+	 */
+	err = ubifs_wbuf_sync_nolock(wbuf);
+	if (err)
+		goto out_return;
+	err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
+	if (err)
+		goto out_return;
 	err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, wbuf->dtype);
 	if (err)
 		goto out_unlock;
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 16/20] UBIFS: expect corruption only in last journal head LEBs
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (14 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 15/20] UBIFS: synchronize write-buffer before switching to the next bud Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16 10:48   ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 17/20] UBIFS: share the next_log_lnum helper Artem Bityutskiy
                   ` (3 subsequent siblings)
  19 siblings, 1 reply; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

This patch improves UBIFS recovery and teaches it to expect corruption only
in the last buds. Indeed, currently we just recover all buds, which is
incorrect because only the last buds can have corruptions in case of a power
cut. So it is inconsistent with the rest of the recovery strategy which tries
hard to distinguish between corruptions cause by power cuts and other types of
corruptions.

This patch also adds one quirk - a bit older UBIFS was could have corruption in
the next to last bud because of the way it switched buds: when bud A is full,
it first searched for the next bud B, the wrote a reference node to the log
about B, and then synchronized the write-buffer of A. So we could end up with
buds A and B, where B is the last, but A had corruption. The UBIFS behavior
was fixed, though, so currently it always first synchronizes A's write-buffer
and only after this adds B to the log. However, to be make sure that we handle
unclean (after a power cut) UBIFS images belonging to older UBIFS - we need to
add a quirk and keep it for some time: we need to check for the situation
described above.

Thankfully, it is easy to check for that situation. When UBIFS adds B to the
log, it always first unmaps B, then maps it, and then syncs A's write-buffer.
Thus, in that situation we can check that B is empty, in which case it is OK to
have corruption in A. To check that B is empty it is enough to just read the
first few bytes of the bud and compare them with 0xFFs. This quirk may be
removed in a couple of years.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/replay.c |   66 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 0f50fbf..bc2b64a 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -472,6 +472,56 @@ int ubifs_validate_entry(struct ubifs_info *c,
 	return 0;
 }
 
+/* TODO: comment */
+static int is_last_bud(struct ubifs_info *c, struct bud_entry *b)
+{
+	struct ubifs_jhead *jh = &c->jheads[b->bud->jhead];
+	struct ubifs_bud *next;
+	uint32_t data;
+	int err;
+
+	if (list_is_last(&b->bud->list, &jh->buds_list))
+		return 1;
+
+	/*
+	 * The following is a quirk to make sure we work correctly with UBIFS
+	 * images used with older UBIFS.
+	 *
+	 * Normally, the last bud will be the last in the journal head's list
+	 * of bud. However, there is one exception if the UBIFS image belongs
+	 * to older UBIFS. This is fairly unlikely: one would need to use old
+	 * UBIFS, then have a power cut exactly at the right point, and then
+	 * try to mount this image with new UBIFS.
+	 *
+	 * The exception is: it is possible to have 2 buds A and B, A goes
+	 * before B, and B is the last, bud B is contains no data, and bud A is
+	 * corrupted at the end. The reason is that in older versions when the
+	 * journal code switched the next bud (from A to B), it first added a
+	 * log reference node for the new bud (B), and only after this it
+	 * synchronized the write-buffer of current bud (A). But later this was
+	 * changed and UBIFS started to always synchronize the write-buffer of
+	 * the bud (A) before writing the log reference for the new bud (B).
+	 *
+	 * But because older UBIFS always synchronized A's write-buffer before
+	 * writing to B, we can recognize this exceptional situation but
+	 * checking the contents of bud B - if it is empty, then A can be
+	 * treated as the last and we can recover it.
+	 *
+	 * TODO: remove this piece of code in a couple of years (today it is
+	 * 16.05.2011).
+	 */
+	next = list_entry(b->bud->list.next, struct ubifs_bud, list);
+	if (!list_is_last(&next->list, &jh->buds_list))
+		return 0;
+
+	err = ubi_read(c->ubi, next->lnum, (char *)&data,
+		       next->start, 4);
+	if (err)
+		return 0;
+
+	return data == 0xFFFFFFFF;
+}
+
 /**
  * replay_bud - replay a bud logical eraseblock.
  * @c: UBIFS file-system description object
@@ -483,15 +533,23 @@ int ubifs_validate_entry(struct ubifs_info *c,
  */
 static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
 {
+	int is_last = is_last_bud(c, b);
 	int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start;
-	int jhead = b->bud->jhead;
 	struct ubifs_scan_leb *sleb;
 	struct ubifs_scan_node *snod;
 
-	dbg_mnt("replay bud LEB %d, head %d, offs %d", lnum, jhead, offs);
+	dbg_mnt("replay bud LEB %d, head %d, offs %d, is_last %d",
+		lnum, b->bud->jhead, offs, is_last);
 
-	if (c->need_recovery)
-		sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
+	if (c->need_recovery && is_last)
+		/*
+		 * Recover only last LEBs in the journal heads, because power
+		 * cuts may cause corruptions only in these LEBs, because only
+		 * these LEBs could possibly be written to at the power cut
+		 * time.
+		 */
+		sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf,
+					 b->bud->jhead != GCHD);
 	else
 		sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0);
 	if (IS_ERR(sleb))
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 17/20] UBIFS: share the next_log_lnum helper
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (15 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 16/20] UBIFS: expect corruption only in last journal head LEBs Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 18/20] UBIFS: add a superblock flag for free space fix-up Artem Bityutskiy
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

We'll need to use the 'next_log_lnum()' helper function from log.c in the fixup
code, so let's move it to misc.h. IOW, this is a preparation to the following
free space fixup changes.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/log.c  |   28 +++++++---------------------
 fs/ubifs/misc.h |   17 +++++++++++++++++
 2 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
index 40fa780..affea94 100644
--- a/fs/ubifs/log.c
+++ b/fs/ubifs/log.c
@@ -100,20 +100,6 @@ struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum)
 }
 
 /**
- * next_log_lnum - switch to the next log LEB.
- * @c: UBIFS file-system description object
- * @lnum: current log LEB
- */
-static inline int next_log_lnum(const struct ubifs_info *c, int lnum)
-{
-	lnum += 1;
-	if (lnum > c->log_last)
-		lnum = UBIFS_LOG_LNUM;
-
-	return lnum;
-}
-
-/**
  * empty_log_bytes - calculate amount of empty space in the log.
  * @c: UBIFS file-system description object
  */
@@ -257,7 +243,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
 	ref->jhead = cpu_to_le32(jhead);
 
 	if (c->lhead_offs > c->leb_size - c->ref_node_alsz) {
-		c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
+		c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
 		c->lhead_offs = 0;
 	}
 
@@ -425,7 +411,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
 
 	/* Switch to the next log LEB */
 	if (c->lhead_offs) {
-		c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
+		c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
 		c->lhead_offs = 0;
 	}
 
@@ -446,7 +432,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
 
 	c->lhead_offs += len;
 	if (c->lhead_offs == c->leb_size) {
-		c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
+		c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
 		c->lhead_offs = 0;
 	}
 
@@ -533,7 +519,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
 	}
 	mutex_lock(&c->log_mutex);
 	for (lnum = old_ltail_lnum; lnum != c->ltail_lnum;
-	     lnum = next_log_lnum(c, lnum)) {
+	     lnum = ubifs_next_log_lnum(c, lnum)) {
 		dbg_log("unmap log LEB %d", lnum);
 		err = ubifs_leb_unmap(c, lnum);
 		if (err)
@@ -642,7 +628,7 @@ static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs,
 		err = ubifs_leb_change(c, *lnum, buf, sz, UBI_SHORTTERM);
 		if (err)
 			return err;
-		*lnum = next_log_lnum(c, *lnum);
+		*lnum = ubifs_next_log_lnum(c, *lnum);
 		*offs = 0;
 	}
 	memcpy(buf + *offs, node, len);
@@ -712,7 +698,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
 		ubifs_scan_destroy(sleb);
 		if (lnum == c->lhead_lnum)
 			break;
-		lnum = next_log_lnum(c, lnum);
+		lnum = ubifs_next_log_lnum(c, lnum);
 	}
 	if (offs) {
 		int sz = ALIGN(offs, c->min_io_size);
@@ -732,7 +718,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
 	/* Unmap remaining LEBs */
 	lnum = write_lnum;
 	do {
-		lnum = next_log_lnum(c, lnum);
+		lnum = ubifs_next_log_lnum(c, lnum);
 		err = ubifs_leb_unmap(c, lnum);
 		if (err)
 			return err;
diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
index c3de04d..0b5296a 100644
--- a/fs/ubifs/misc.h
+++ b/fs/ubifs/misc.h
@@ -340,4 +340,21 @@ static inline void ubifs_release_lprops(struct ubifs_info *c)
 	mutex_unlock(&c->lp_mutex);
 }
 
+/**
+ * ubifs_next_log_lnum - switch to the next log LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: current log LEB
+ *
+ * This helper function returns the log LEB number which goes next after LEB
+ * 'lnum'.
+ */
+static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
+{
+	lnum += 1;
+	if (lnum > c->log_last)
+		lnum = UBIFS_LOG_LNUM;
+
+	return lnum;
+}
+
 #endif /* __UBIFS_MISC_H__ */
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 18/20] UBIFS: add a superblock flag for free space fix-up
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (16 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 17/20] UBIFS: share the next_log_lnum helper Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 19/20] UBIFS: add the fixup function Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 20/20] UBIFS: fix-up free space on mount if flag is set Artem Bityutskiy
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Matthew L. Creech <mlcreech@gmail.com>

The 'space_fixup' flag can be set in the superblock of a new filesystem by
mkfs.ubifs to indicate that any eraseblocks with free space remaining should be
fixed-up the first time it's mounted (after which the flag is un-set). This
means that the UBIFS image has been flashed by a "dumb" flasher and the free
space has been actually programmed (writing all 0xFFs), so this free space
cannot be used. UBIFS fixes the free space up by re-writing the contents of all
LEBs with free space using the atomic LEB change UBI operation.

Artem: improved commit message, add some more commentaries to the code.

Signed-off-by: Matthew L. Creech <mlcreech@gmail.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/debug.c       |    2 ++
 fs/ubifs/sb.c          |    1 +
 fs/ubifs/ubifs-media.h |    2 ++
 fs/ubifs/ubifs.h       |    2 ++
 4 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index b5ba2ea..f46d77e 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -316,6 +316,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
 		printk(KERN_DEBUG "\tflags          %#x\n", sup_flags);
 		printk(KERN_DEBUG "\t  big_lpt      %u\n",
 		       !!(sup_flags & UBIFS_FLG_BIGLPT));
+		printk(KERN_DEBUG "\t  space_fixup  %u\n",
+		       !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
 		printk(KERN_DEBUG "\tmin_io_size    %u\n",
 		       le32_to_cpu(sup->min_io_size));
 		printk(KERN_DEBUG "\tleb_size       %u\n",
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index cad60b5..93d6928 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -617,6 +617,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
 	c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
 	memcpy(&c->uuid, &sup->uuid, 16);
 	c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
+	c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
 
 	/* Automatically increase file system size to the maximum size */
 	c->old_leb_cnt = c->leb_cnt;
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index b922f03..e24380c 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -408,9 +408,11 @@ enum {
  * Superblock flags.
  *
  * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
+ * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
  */
 enum {
 	UBIFS_FLG_BIGLPT = 0x02,
+	UBIFS_FLG_SPACE_FIXUP = 0x04,
 };
 
 /**
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index a2f9d4e..8e27553 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1014,6 +1014,7 @@ struct ubifs_debug_info;
  * @cmt_wq: wait queue to sleep on if the log is full and a commit is running
  *
  * @big_lpt: flag that LPT is too big to write whole during commit
+ * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
  * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
  *                   recovery)
  * @bulk_read: enable bulk-reads
@@ -1253,6 +1254,7 @@ struct ubifs_info {
 	wait_queue_head_t cmt_wq;
 
 	unsigned int big_lpt:1;
+	unsigned int space_fixup:1;
 	unsigned int no_chk_data_crc:1;
 	unsigned int bulk_read:1;
 	unsigned int default_compr:2;
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 19/20] UBIFS: add the fixup function
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (17 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 18/20] UBIFS: add a superblock flag for free space fix-up Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  2011-05-16  7:44 ` [PATCH 20/20] UBIFS: fix-up free space on mount if flag is set Artem Bityutskiy
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Matthew L. Creech <mlcreech@gmail.com>

This patch adds the 'ubifs_fixup_free_space()' function which scans all
LEBs in the filesystem for those that are in-use but have one or more
empty pages, then re-maps the LEBs in order to erase the empty portions.
Afterward it removes the "space_fixup" flag from the UBIFS superblock.

Artem: massaged the patch

Signed-off-by: Matthew L. Creech <mlcreech@gmail.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/sb.c    |  149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ubifs/ubifs.h |    1 +
 2 files changed, 150 insertions(+), 0 deletions(-)

diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index 93d6928..c606f01 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -652,3 +652,152 @@ out:
 	kfree(sup);
 	return err;
 }
+
+/**
+ * fixup_leb - fixup/unmap an LEB containing free space.
+ * @c: UBIFS file-system description object
+ * @lnum: the LEB number to fix up
+ * @len: number of used bytes in LEB (starting at offset 0)
+ *
+ * This function reads the contents of the given LEB number @lnum, then fixes
+ * it up, so that empty min. I/O units in the end of LEB are actually erased on
+ * flash (rather than being just all-0xff real data). If the LEB is completely
+ * empty, it is simply unmapped.
+ */
+static int fixup_leb(struct ubifs_info *c, int lnum, int len)
+{
+	int err;
+
+	ubifs_assert(len >= 0);
+	ubifs_assert(len % c->min_io_size == 0);
+	ubifs_assert(len < c->leb_size);
+
+	if (len == 0) {
+		dbg_mnt("unmap empty LEB %d", lnum);
+		return ubi_leb_unmap(c->ubi, lnum);
+	}
+
+	dbg_mnt("fixup LEB %d, data len %d", lnum, len);
+	err = ubi_read(c->ubi, lnum, c->sbuf, 0, len);
+	if (err)
+		return err;
+
+	return ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
+}
+
+/**
+ * fixup_free_space - find & remap all LEBs containing free space.
+ * @c: UBIFS file-system description object
+ *
+ * This function walks through all LEBs in the filesystem and fiexes up those
+ * containing free/empty space.
+ */
+static int fixup_free_space(struct ubifs_info *c)
+{
+	int lnum, err = 0;
+	struct ubifs_lprops *lprops;
+
+	ubifs_get_lprops(c);
+
+	/* Fixup LEBs in the master area */
+	for (lnum = UBIFS_MST_LNUM; lnum < UBIFS_LOG_LNUM; lnum++) {
+		err = fixup_leb(c, lnum, c->mst_offs + c->mst_node_alsz);
+		if (err)
+			goto out;
+	}
+
+	/* Unmap unused log LEBs */
+	lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+	while (lnum != c->ltail_lnum) {
+		err = fixup_leb(c, lnum, 0);
+		if (err)
+			goto out;
+		lnum = ubifs_next_log_lnum(c, lnum);
+	}
+
+	/* Fixup the current log head */
+	err = fixup_leb(c, c->lhead_lnum, c->lhead_offs);
+	if (err)
+		goto out;
+
+	/* Fixup LEBs in the LPT area */
+	for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
+		int free = c->ltab[lnum - c->lpt_first].free;
+
+		if (free > 0) {
+			err = fixup_leb(c, lnum, c->leb_size - free);
+			if (err)
+				goto out;
+		}
+	}
+
+	/* Unmap LEBs in the orphans area */
+	for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
+		err = fixup_leb(c, lnum, 0);
+		if (err)
+			goto out;
+	}
+
+	/* Fixup LEBs in the main area */
+	for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
+		lprops = ubifs_lpt_lookup(c, lnum);
+		if (IS_ERR(lprops)) {
+			err = PTR_ERR(lprops);
+			goto out;
+		}
+
+		if (lprops->free > 0) {
+			err = fixup_leb(c, lnum, c->leb_size - lprops->free);
+			if (err)
+				goto out;
+		}
+	}
+
+out:
+	ubifs_release_lprops(c);
+	return err;
+}
+
+/**
+ * ubifs_fixup_free_space - find & fix all LEBs with free space.
+ * @c: UBIFS file-system description object
+ *
+ * This function fixes up LEBs containing free space on first mount, if the
+ * appropriate flag was set when the FS was created. Each LEB with one or more
+ * empty min. I/O unit (i.e. free-space-count > 0) is re-written, to make sure
+ * the free space is actually erased. E.g., this is necessary for some NAND
+ * chips, since the free space may have been programmed like real "0xff" data
+ * (generating a non-0xff ECC), causing future writes to the not-really-erased
+ * NAND pages to behave badly. After the space is fixed up, the superblock flag
+ * is cleared, so that this is skipped for all future mounts.
+ */
+int ubifs_fixup_free_space(struct ubifs_info *c)
+{
+	int err;
+	struct ubifs_sb_node *sup;
+
+	ubifs_assert(c->space_fixup);
+	ubifs_assert(!c->ro_mount);
+
+	ubifs_msg("start fixing up free space");
+
+	err = fixup_free_space(c);
+	if (err)
+		return err;
+
+	sup = ubifs_read_sb_node(c);
+	if (IS_ERR(sup))
+		return PTR_ERR(sup);
+
+	/* Free-space fixup is no longer required */
+	c->space_fixup = 0;
+	sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP);
+
+	err = ubifs_write_sb_node(c, sup);
+	kfree(sup);
+	if (err)
+		return err;
+
+	ubifs_msg("free space fixup complete");
+	return err;
+}
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 8e27553..93d1412 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1633,6 +1633,7 @@ int ubifs_write_master(struct ubifs_info *c);
 int ubifs_read_superblock(struct ubifs_info *c);
 struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
 int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
+int ubifs_fixup_free_space(struct ubifs_info *c);
 
 /* replay.c */
 int ubifs_validate_entry(struct ubifs_info *c,
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 20/20] UBIFS: fix-up free space on mount if flag is set
  2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
                   ` (18 preceding siblings ...)
  2011-05-16  7:44 ` [PATCH 19/20] UBIFS: add the fixup function Artem Bityutskiy
@ 2011-05-16  7:44 ` Artem Bityutskiy
  19 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16  7:44 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

From: Matthew L. Creech <mlcreech@gmail.com>

If a UBIFS filesystem is being mounted read-write, or is being remounted
from read-only to read-write, check for the "space_fixup" flag and fix
all LEBs containing empty space if necessary.

Artem: tweaked the patch a bit

Signed-off-by: Matthew L. Creech <mlcreech@gmail.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/super.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 575ea83..6db0bdaa 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1396,6 +1396,12 @@ static int mount_ubifs(struct ubifs_info *c)
 	} else
 		ubifs_assert(c->lst.taken_empty_lebs > 0);
 
+	if (!c->ro_mount && c->space_fixup) {
+		err = ubifs_fixup_free_space(c);
+		if (err)
+			goto out_infos;
+	}
+
 	err = dbg_check_filesystem(c);
 	if (err)
 		goto out_infos;
@@ -1686,6 +1692,13 @@ static int ubifs_remount_rw(struct ubifs_info *c)
 		 */
 		err = dbg_check_space_info(c);
 	}
+
+	if (c->space_fixup) {
+		err = ubifs_fixup_free_space(c);
+		if (err)
+			goto out;
+	}
+
 	mutex_unlock(&c->umount_mutex);
 	return err;
 
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH 16/20] UBIFS: expect corruption only in last journal head LEBs
  2011-05-16  7:44 ` [PATCH 16/20] UBIFS: expect corruption only in last journal head LEBs Artem Bityutskiy
@ 2011-05-16 10:48   ` Artem Bityutskiy
  0 siblings, 0 replies; 22+ messages in thread
From: Artem Bityutskiy @ 2011-05-16 10:48 UTC (permalink / raw)
  To: MTD list

On Mon, 2011-05-16 at 10:44 +0300, Artem Bityutskiy wrote:
> +/* TODO: comment */
> +static int is_last_bud(struct ubifs_info *c, struct bud_entry *b)

Oh, forgot to add a comment
-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2011-05-16 10:52 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-16  7:44 [PATCH 00/20] UBIFS: last changes Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 01/20] UBIFS: improve debugging lprops scanning a little Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 02/20] UBIFS: simplify error path in lprops debugging check Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 03/20] UBIFS: simplify " Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 04/20] UBIFS: dump more in the " Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 05/20] UBIFS: improve debugging messages Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 06/20] UBIFS: improve commentary Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 07/20] UBIFS: make 2 functions static Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 08/20] UBIFS: double check that buds are replied in order Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 09/20] UBIFS: remove unnecessary stack variable Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 10/20] UBIFS: store free and dirty space in the bud replay entry Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 11/20] UBIFS: simplify replay Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 12/20] UBIFS: substitute the replay tree with a replay list Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 13/20] UBIFS: change bud replay function conventions Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 14/20] UBIFS: remove BUG statement Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 15/20] UBIFS: synchronize write-buffer before switching to the next bud Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 16/20] UBIFS: expect corruption only in last journal head LEBs Artem Bityutskiy
2011-05-16 10:48   ` Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 17/20] UBIFS: share the next_log_lnum helper Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 18/20] UBIFS: add a superblock flag for free space fix-up Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 19/20] UBIFS: add the fixup function Artem Bityutskiy
2011-05-16  7:44 ` [PATCH 20/20] UBIFS: fix-up free space on mount if flag is set 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).