linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv2 0/9] UBIFS: recent patches
@ 2010-08-08  9:57 Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 1/9] UBIFS: switch to RO mode after synchronizing Artem Bityutskiy
                   ` (8 more replies)
  0 siblings, 9 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08  9:57 UTC (permalink / raw)
  To: linux-mtd; +Cc: Matthieu CASTET, Adrian Hunter

Hi,

here are re-workded patches. The GC fix patch is thrown out because it is
"ballocs". The scanning code is fixed. And I found out the real reason of
assertions in 'list_sort()'s 'cmp()' function. This vesrsion should be
better.

Pushed to ubifs-2.6.git / master.

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

* [PATCHv2 1/9] UBIFS: switch to RO mode after synchronizing
  2010-08-08  9:57 [PATCHv2 0/9] UBIFS: recent patches Artem Bityutskiy
@ 2010-08-08  9:57 ` Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 2/9] UBIFS: do not treat ENOSPC specially Artem Bityutskiy
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08  9:57 UTC (permalink / raw)
  To: linux-mtd; +Cc: Matthieu CASTET, Adrian Hunter

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

In 'ubifs_garbage_collect()' on error path, we first switch to R/O mode, and
then synchronize write-buffers (to make sure no data are lost). But the GC
write-buffer synchronization will fail, because we are already in R/O mode.
This patch re-orders this and makes sure we first synchronize the write-buffer,
and then switch to R/O mode.

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

diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index 918d158..f89a422 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -774,8 +774,8 @@ out_unlock:
 out:
 	ubifs_assert(ret < 0);
 	ubifs_assert(ret != -ENOSPC && ret != -EAGAIN);
-	ubifs_ro_mode(c, ret);
 	ubifs_wbuf_sync_nolock(wbuf);
+	ubifs_ro_mode(c, ret);
 	mutex_unlock(&wbuf->io_mutex);
 	ubifs_return_leb(c, lp.lnum);
 	return ret;
-- 
1.7.1.1

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

* [PATCHv2 2/9] UBIFS: do not treat ENOSPC specially
  2010-08-08  9:57 [PATCHv2 0/9] UBIFS: recent patches Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 1/9] UBIFS: switch to RO mode after synchronizing Artem Bityutskiy
@ 2010-08-08  9:57 ` Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 3/9] UBIFS: fix assertion warning Artem Bityutskiy
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08  9:57 UTC (permalink / raw)
  To: linux-mtd; +Cc: Matthieu CASTET, Adrian Hunter

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

'ubifs_garbage_collect_leb()' should never return '-ENOSPC', and if it
does, this is an error. Thus, do not treat this error code specially.
'-EAGAIN' is a special error code, but not '-ENOSPC'.

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

diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index f89a422..29ce1b3 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -677,7 +677,7 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
 
 		ret = ubifs_garbage_collect_leb(c, &lp);
 		if (ret < 0) {
-			if (ret == -EAGAIN || ret == -ENOSPC) {
+			if (ret == -EAGAIN) {
 				/*
 				 * These codes are not errors, so we have to
 				 * return the LEB to lprops. But if the
-- 
1.7.1.1

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

* [PATCHv2 3/9] UBIFS: fix assertion warning
  2010-08-08  9:57 [PATCHv2 0/9] UBIFS: recent patches Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 1/9] UBIFS: switch to RO mode after synchronizing Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 2/9] UBIFS: do not treat ENOSPC specially Artem Bityutskiy
@ 2010-08-08  9:57 ` Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 4/9] UBIFS: do not look up truncation nodes Artem Bityutskiy
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08  9:57 UTC (permalink / raw)
  To: linux-mtd; +Cc: Matthieu CASTET, Adrian Hunter

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

This patch fixes the following false assertion warning:

UBIFS assert failed in data_nodes_cmp at 130 (pid 15107)

The assertion was wrong because it did not take into account that the
node can be an xentry.

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

diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index 29ce1b3..d060c62 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -178,7 +178,8 @@ int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 	if (typeb == UBIFS_INO_KEY)
 		return 1;
 
-	ubifs_assert(typea == UBIFS_DENT_KEY && typeb == UBIFS_DENT_KEY);
+	ubifs_assert(typea == UBIFS_DENT_KEY || typea == UBIFS_XENT_KEY);
+	ubifs_assert(typeb == UBIFS_DENT_KEY || typeb == UBIFS_XENT_KEY);
 	inuma = key_inum(c, &sa->key);
 	inumb = key_inum(c, &sb->key);
 
-- 
1.7.1.1

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

* [PATCHv2 4/9] UBIFS: do not look up truncation nodes
  2010-08-08  9:57 [PATCHv2 0/9] UBIFS: recent patches Artem Bityutskiy
                   ` (2 preceding siblings ...)
  2010-08-08  9:57 ` [PATCHv2 3/9] UBIFS: fix assertion warning Artem Bityutskiy
@ 2010-08-08  9:57 ` Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 5/9] UBIFS: do not use key type in list_sort Artem Bityutskiy
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08  9:57 UTC (permalink / raw)
  To: linux-mtd; +Cc: Matthieu CASTET, Adrian Hunter

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

When moving nodes in GC, do not try to look up truncation nodes in TNC,
because they do not exist there. This would be harmless, because the TNC
look-up would fail, if we did not have bug 'ubifs_add_snod()' which reads
garbage into 'snod->key'. But in any case, it is less error prone to
explicitly ignore everything but inode, data, dentry and xentry nodes.

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

diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index d060c62..fd944fe 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -233,9 +233,26 @@ static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 	list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
 		int err;
 
-		ubifs_assert(snod->type != UBIFS_IDX_NODE);
-		ubifs_assert(snod->type != UBIFS_REF_NODE);
-		ubifs_assert(snod->type != UBIFS_CS_NODE);
+		ubifs_assert(snod->type == UBIFS_INO_NODE  ||
+			     snod->type == UBIFS_DATA_NODE ||
+			     snod->type == UBIFS_DENT_NODE ||
+			     snod->type == UBIFS_XENT_NODE ||
+			     snod->type == UBIFS_TRUN_NODE);
+
+		if (snod->type != UBIFS_INO_NODE  &&
+		    snod->type != UBIFS_DATA_NODE &&
+		    snod->type != UBIFS_DENT_NODE &&
+		    snod->type != UBIFS_XENT_NODE) {
+			/* Probably truncation node, zap it */
+			list_del(&snod->list);
+			kfree(snod);
+			continue;
+		}
+
+		ubifs_assert(key_type(c, &snod->key) == UBIFS_DATA_KEY ||
+			     key_type(c, &snod->key) == UBIFS_INO_KEY  ||
+			     key_type(c, &snod->key) == UBIFS_DENT_KEY ||
+			     key_type(c, &snod->key) == UBIFS_XENT_KEY);
 
 		err = ubifs_tnc_has_node(c, &snod->key, 0, sleb->lnum,
 					 snod->offs, 0);
-- 
1.7.1.1

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

* [PATCHv2 5/9] UBIFS: do not use key type in list_sort
  2010-08-08  9:57 [PATCHv2 0/9] UBIFS: recent patches Artem Bityutskiy
                   ` (3 preceding siblings ...)
  2010-08-08  9:57 ` [PATCHv2 4/9] UBIFS: do not look up truncation nodes Artem Bityutskiy
@ 2010-08-08  9:57 ` Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 6/9] UBIFS: improve assertion in node comparison functions Artem Bityutskiy
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08  9:57 UTC (permalink / raw)
  To: linux-mtd; +Cc: Matthieu CASTET, Adrian Hunter

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

In comparison function for 'list_sort()' we use key type to distinguish between
node types. However, we have a bit easier way to detect node type -
'snod->type'. This is a bit easier and more logical to use, comparing to
decoding key types. Also allows to get rid of 2 local variables.

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

diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index fd944fe..f2be055 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -157,7 +157,6 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
  */
 int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 {
-	int typea, typeb;
 	ino_t inuma, inumb;
 	struct ubifs_info *c = priv;
 	struct ubifs_scan_node *sa, *sb;
@@ -165,21 +164,22 @@ int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 	cond_resched();
 	sa = list_entry(a, struct ubifs_scan_node, list);
 	sb = list_entry(b, struct ubifs_scan_node, list);
-	typea = key_type(c, &sa->key);
-	typeb = key_type(c, &sb->key);
-	ubifs_assert(typea != UBIFS_DATA_KEY && typeb != UBIFS_DATA_KEY);
+	ubifs_assert(sa->type != UBIFS_DATA_NODE &&
+		     sb->type != UBIFS_DATA_NODE);
 
 	/* Inodes go before directory entries */
-	if (typea == UBIFS_INO_KEY) {
-		if (typeb == UBIFS_INO_KEY)
+	if (sa->type == UBIFS_INO_NODE) {
+		if (sb->type == UBIFS_INO_NODE)
 			return sb->len - sa->len;
 		return -1;
 	}
-	if (typeb == UBIFS_INO_KEY)
+	if (sb->type == UBIFS_INO_NODE)
 		return 1;
 
-	ubifs_assert(typea == UBIFS_DENT_KEY || typea == UBIFS_XENT_KEY);
-	ubifs_assert(typeb == UBIFS_DENT_KEY || typeb == UBIFS_XENT_KEY);
+	ubifs_assert(sa->type == UBIFS_DENT_NODE ||
+		     sa->type == UBIFS_XENT_NODE);
+	ubifs_assert(sb->type == UBIFS_DENT_NODE ||
+		     sb->type == UBIFS_XENT_NODE);
 	inuma = key_inum(c, &sa->key);
 	inumb = key_inum(c, &sb->key);
 
-- 
1.7.1.1

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

* [PATCHv2 6/9] UBIFS: improve assertion in node comparison functions
  2010-08-08  9:57 [PATCHv2 0/9] UBIFS: recent patches Artem Bityutskiy
                   ` (4 preceding siblings ...)
  2010-08-08  9:57 ` [PATCHv2 5/9] UBIFS: do not use key type in list_sort Artem Bityutskiy
@ 2010-08-08  9:57 ` Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 7/9] UBIFS: do not write rubbish into truncation scanning node Artem Bityutskiy
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08  9:57 UTC (permalink / raw)
  To: linux-mtd; +Cc: Matthieu CASTET, Adrian Hunter

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

Improve assertions in gc.c in the comparison functions for 'list_sort()': check
key types _and_ node types.

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

diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index f2be055..8dbe36f 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -127,8 +127,11 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 	cond_resched();
 	sa = list_entry(a, struct ubifs_scan_node, list);
 	sb = list_entry(b, struct ubifs_scan_node, list);
+
 	ubifs_assert(key_type(c, &sa->key) == UBIFS_DATA_KEY);
 	ubifs_assert(key_type(c, &sb->key) == UBIFS_DATA_KEY);
+	ubifs_assert(sa->type == UBIFS_DATA_NODE);
+	ubifs_assert(sb->type == UBIFS_DATA_NODE);
 
 	inuma = key_inum(c, &sa->key);
 	inumb = key_inum(c, &sb->key);
@@ -164,6 +167,9 @@ int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 	cond_resched();
 	sa = list_entry(a, struct ubifs_scan_node, list);
 	sb = list_entry(b, struct ubifs_scan_node, list);
+
+	ubifs_assert(key_type(c, &sa->key) != UBIFS_DATA_KEY &&
+		     key_type(c, &sb->key) != UBIFS_DATA_KEY);
 	ubifs_assert(sa->type != UBIFS_DATA_NODE &&
 		     sb->type != UBIFS_DATA_NODE);
 
@@ -176,10 +182,15 @@ int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 	if (sb->type == UBIFS_INO_NODE)
 		return 1;
 
+	ubifs_assert(key_type(c, &sa->key) == UBIFS_DENT_KEY ||
+		     key_type(c, &sa->key) == UBIFS_XENT_KEY);
+	ubifs_assert(key_type(c, &sb->key) == UBIFS_DENT_KEY ||
+		     key_type(c, &sb->key) == UBIFS_XENT_KEY);
 	ubifs_assert(sa->type == UBIFS_DENT_NODE ||
 		     sa->type == UBIFS_XENT_NODE);
 	ubifs_assert(sb->type == UBIFS_DENT_NODE ||
 		     sb->type == UBIFS_XENT_NODE);
+
 	inuma = key_inum(c, &sa->key);
 	inumb = key_inum(c, &sb->key);
 
-- 
1.7.1.1

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

* [PATCHv2 7/9] UBIFS: do not write rubbish into truncation scanning node
  2010-08-08  9:57 [PATCHv2 0/9] UBIFS: recent patches Artem Bityutskiy
                   ` (5 preceding siblings ...)
  2010-08-08  9:57 ` [PATCHv2 6/9] UBIFS: improve assertion in node comparison functions Artem Bityutskiy
@ 2010-08-08  9:57 ` Artem Bityutskiy
  2010-08-08 11:03   ` Adrian Hunter
  2010-08-08  9:57 ` [PATCHv2 8/9] UBIFS: fix assertion warnings in comparison function Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 9/9] UBIFS: introduce list sorting debugging checks Artem Bityutskiy
  8 siblings, 1 reply; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08  9:57 UTC (permalink / raw)
  To: linux-mtd; +Cc: Matthieu CASTET, Adrian Hunter

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

In the scanning code, in 'ubifs_add_snod()', we write rubbish into
'snod->key', because we assume that on-flash truncation nodes have a key, but
they do not. If the other parts of UBIFS then mistakenly try to look-up
the truncation node key (they should not do this, but may do because of a bug),
we can succeed and corrupt TNC. It looks like we did have such a situation in
'sort_nodes()' in gc.c.

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

diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
index 96c5253..a0a305c 100644
--- a/fs/ubifs/scan.c
+++ b/fs/ubifs/scan.c
@@ -212,7 +212,6 @@ int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 	case UBIFS_DENT_NODE:
 	case UBIFS_XENT_NODE:
 	case UBIFS_DATA_NODE:
-	case UBIFS_TRUN_NODE:
 		/*
 		 * The key is in the same place in all keyed
 		 * nodes.
-- 
1.7.1.1

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

* [PATCHv2 8/9] UBIFS: fix assertion warnings in comparison function
  2010-08-08  9:57 [PATCHv2 0/9] UBIFS: recent patches Artem Bityutskiy
                   ` (6 preceding siblings ...)
  2010-08-08  9:57 ` [PATCHv2 7/9] UBIFS: do not write rubbish into truncation scanning node Artem Bityutskiy
@ 2010-08-08  9:57 ` Artem Bityutskiy
  2010-08-08  9:57 ` [PATCHv2 9/9] UBIFS: introduce list sorting debugging checks Artem Bityutskiy
  8 siblings, 0 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08  9:57 UTC (permalink / raw)
  To: linux-mtd; +Cc: Matthieu CASTET, Adrian Hunter

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

When running the integrity test ('integck' from mtd-utils) on current
UBIFS on 2.6.35, I see that assertions in UBIFS 'list_sort()' comparison
functions trigger sometimes, e.g.:

UBIFS assert failed in data_nodes_cmp at 132 (pid 28311)

My investigation showed that this happens when 'list_sort()' calls the 'cmp()'
function with equivalent arguments. In this case, the 'struct list_head'
parameter, passed to 'cmp()' is bogus, and it does not belong to any element in
the original list.

And this issue seems to be introduced by commit:

commit 835cc0c8477fdbc59e0217891d6f11061b1ac4e2
Author: Don Mullis <don.mullis@gmail.com>
Date:   Fri Mar 5 13:43:15 2010 -0800

It is easy to work around the issue by doing:

if (a == b)
	return 0;

in UBIFS. It works, but 'lib_sort()' should nevertheless be fixed. Although it
is harmless to have this piece of code in UBIFS.

This patch adds that code to both UBIFS 'cmp()' functions:
'data_nodes_cmp()' and 'nondata_nodes_cmp()'.

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

diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index 8dbe36f..84ab9aa 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -125,6 +125,9 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 	struct ubifs_scan_node *sa, *sb;
 
 	cond_resched();
+	if (a == b)
+		return 0;
+
 	sa = list_entry(a, struct ubifs_scan_node, list);
 	sb = list_entry(b, struct ubifs_scan_node, list);
 
@@ -165,6 +168,9 @@ int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 	struct ubifs_scan_node *sa, *sb;
 
 	cond_resched();
+	if (a == b)
+		return 0;
+
 	sa = list_entry(a, struct ubifs_scan_node, list);
 	sb = list_entry(b, struct ubifs_scan_node, list);
 
-- 
1.7.1.1

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

* [PATCHv2 9/9] UBIFS: introduce list sorting debugging checks
  2010-08-08  9:57 [PATCHv2 0/9] UBIFS: recent patches Artem Bityutskiy
                   ` (7 preceding siblings ...)
  2010-08-08  9:57 ` [PATCHv2 8/9] UBIFS: fix assertion warnings in comparison function Artem Bityutskiy
@ 2010-08-08  9:57 ` Artem Bityutskiy
  8 siblings, 0 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08  9:57 UTC (permalink / raw)
  To: linux-mtd; +Cc: Matthieu CASTET, Adrian Hunter

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

The UBIFS bug in the GC list sorting comparison functions inspired
me to write internal debugging check functions which verify that
the list of nodes is sorted properly.

So, this patch implements 2 new debugging functions:
 o 'dbg_check_data_nodes_order()' - check order of data nodes list
 o 'dbg_check_nondata_nodes_order()' - check order of non-data nodes list

The debugging functions are executed only if general UBIFS debugging checks are
enabled. And they are compiled out if UBIFS debugging is disabled.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/debug.c |  156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ubifs/debug.h |    4 ++
 fs/ubifs/gc.c    |   10 +++-
 3 files changed, 168 insertions(+), 2 deletions(-)

diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index c2a68ba..1f00d77 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -2239,6 +2239,162 @@ out_free:
 	return err;
 }
 
+/**
+ * dbg_check_data_nodes_order - check that list of data nodes is sorted.
+ * @c: UBIFS file-system description object
+ * @head: the list of nodes ('struct ubifs_scan_node' objects)
+ *
+ * This function returns zero if the list of data nodes is sorted correctly,
+ * and %-EINVAL if not.
+ */
+int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
+{
+	struct list_head *cur;
+	struct ubifs_scan_node *sa, *sb;
+
+	if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
+		return 0;
+
+	for (cur = head->next; cur->next != head; cur = cur->next) {
+		ino_t inuma, inumb;
+		uint32_t blka, blkb;
+
+		cond_reshed();
+		sa = container_of(cur, struct ubifs_scan_node, list);
+		sb = container_of(cur->next, struct ubifs_scan_node, list);
+
+		if (sa->type != UBIFS_DATA_NODE) {
+			ubifs_err("bad node type %d", sa->type);
+			dbg_dump_node(c, sa->node);
+			return -EINVAL;
+		}
+		if (sb->type != UBIFS_DATA_NODE) {
+			ubifs_err("bad node type %d", sb->type);
+			dbg_dump_node(c, sb->node);
+			return -EINVAL;
+		}
+
+		inuma = key_inum(c, &sa->key);
+		inumb = key_inum(c, &sb->key);
+
+		if (inuma < inumb)
+			continue;
+		if (inuma > inumb) {
+			ubifs_err("larger inum %lu goes before inum %lu",
+				  (unsigned long)inuma, (unsigned long)inumb);
+			goto error_dump;
+		}
+
+		blka = key_block(c, &sa->key);
+		blkb = key_block(c, &sb->key);
+
+		if (blka > blkb) {
+			ubifs_err("larger block %u goes before %u", blka, blkb);
+			goto error_dump;
+		}
+		if (blka == blkb) {
+			ubifs_err("two data nodes for the same block");
+			goto error_dump;
+		}
+	}
+
+	return 0;
+
+error_dump:
+	dbg_dump_node(c, sa->node);
+	dbg_dump_node(c, sb->node);
+	return -EINVAL;
+}
+
+/**
+ * dbg_check_nondata_nodes_order - check that list of data nodes is sorted.
+ * @c: UBIFS file-system description object
+ * @head: the list of nodes ('struct ubifs_scan_node' objects)
+ *
+ * This function returns zero if the list of non-data nodes is sorted correctly,
+ * and %-EINVAL if not.
+ */
+int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
+{
+	struct list_head *cur;
+	struct ubifs_scan_node *sa, *sb;
+
+	if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
+		return 0;
+
+	for (cur = head->next; cur->next != head; cur = cur->next) {
+		ino_t inuma, inumb;
+		uint32_t hasha, hashb;
+
+		cond_reshed();
+		sa = container_of(cur, struct ubifs_scan_node, list);
+		sb = container_of(cur->next, struct ubifs_scan_node, list);
+
+		if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
+		    sa->type != UBIFS_XENT_NODE) {
+			ubifs_err("bad node type %d", sa->type);
+			dbg_dump_node(c, sa->node);
+			return -EINVAL;
+		}
+		if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
+		    sa->type != UBIFS_XENT_NODE) {
+			ubifs_err("bad node type %d", sb->type);
+			dbg_dump_node(c, sb->node);
+			return -EINVAL;
+		}
+
+		if (sa->type != UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) {
+			ubifs_err("non-inode node goes before inode node");
+			goto error_dump;
+		}
+
+		if (sa->type == UBIFS_INO_NODE && sb->type != UBIFS_INO_NODE)
+			continue;
+
+		if (sa->type == UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) {
+			/* Inode nodes are sorted in descending size order */
+			if (sa->len < sb->len) {
+				ubifs_err("smaller inode node goes first");
+				goto error_dump;
+			}
+			continue;
+		}
+
+		/*
+		 * This is either a dentry or xentry, which should be sorted in
+		 * ascending (parent ino, hash) order.
+		 */
+		inuma = key_inum(c, &sa->key);
+		inumb = key_inum(c, &sb->key);
+
+		if (inuma < inumb)
+			continue;
+		if (inuma > inumb) {
+			ubifs_err("larger inum %lu goes before inum %lu",
+				  (unsigned long)inuma, (unsigned long)inumb);
+			goto error_dump;
+		}
+
+		hasha = key_block(c, &sa->key);
+		hashb = key_block(c, &sb->key);
+
+		if (hasha > hashb) {
+			ubifs_err("larger hash %u goes before %u", hasha, hashb);
+			goto error_dump;
+		}
+	}
+
+	return 0;
+
+error_dump:
+	ubifs_msg("dumping first node");
+	dbg_dump_node(c, sa->node);
+	ubifs_msg("dumping second node");
+	dbg_dump_node(c, sb->node);
+	return -EINVAL;
+	return 0;
+}
+
 static int invocation_cnt;
 
 int dbg_force_in_the_gaps(void)
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index 29d9601..69ebe47 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -324,6 +324,8 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
 			int row, int col);
 int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
 			 loff_t size);
+int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
+int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
 
 /* Force the use of in-the-gaps method for testing */
 
@@ -465,6 +467,8 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
 #define dbg_check_lprops(c)                        0
 #define dbg_check_lpt_nodes(c, cnode, row, col)    0
 #define dbg_check_inode_size(c, inode, size)       0
+#define dbg_check_data_nodes_order(c, head)        0
+#define dbg_check_nondata_nodes_order(c, head)     0
 #define dbg_force_in_the_gaps_enabled              0
 #define dbg_force_in_the_gaps()                    0
 #define dbg_failure_mode                           0
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index 84ab9aa..95317a9 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -242,14 +242,13 @@ int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 		      struct list_head *nondata, int *min)
 {
+	int err;
 	struct ubifs_scan_node *snod, *tmp;
 
 	*min = INT_MAX;
 
 	/* Separate data nodes and non-data nodes */
 	list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
-		int err;
-
 		ubifs_assert(snod->type == UBIFS_INO_NODE  ||
 			     snod->type == UBIFS_DATA_NODE ||
 			     snod->type == UBIFS_DENT_NODE ||
@@ -293,6 +292,13 @@ static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 	/* Sort data and non-data nodes */
 	list_sort(c, &sleb->nodes, &data_nodes_cmp);
 	list_sort(c, nondata, &nondata_nodes_cmp);
+
+	err = dbg_check_data_nodes_order(c, &sleb->nodes);
+	if (err)
+		return err;
+	err = dbg_check_nondata_nodes_order(c, nondata);
+	if (err)
+		return err;
 	return 0;
 }
 
-- 
1.7.1.1

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

* Re: [PATCHv2 7/9] UBIFS: do not write rubbish into truncation scanning node
  2010-08-08  9:57 ` [PATCHv2 7/9] UBIFS: do not write rubbish into truncation scanning node Artem Bityutskiy
@ 2010-08-08 11:03   ` Adrian Hunter
  2010-08-08 11:08     ` Adrian Hunter
  0 siblings, 1 reply; 14+ messages in thread
From: Adrian Hunter @ 2010-08-08 11:03 UTC (permalink / raw)
  To: Artem Bityutskiy; +Cc: linux-mtd@lists.infradead.org, Matthieu CASTET

Artem Bityutskiy wrote:
> From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
> 
> In the scanning code, in 'ubifs_add_snod()', we write rubbish into
> 'snod->key', because we assume that on-flash truncation nodes have a key, but
> they do not. If the other parts of UBIFS then mistakenly try to look-up
> the truncation node key (they should not do this, but may do because of a bug),
> we can succeed and corrupt TNC. It looks like we did have such a situation in
> 'sort_nodes()' in gc.c.
> 
> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
> ---
>  fs/ubifs/scan.c |    1 -
>  1 files changed, 0 insertions(+), 1 deletions(-)
> 
> diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
> index 96c5253..a0a305c 100644
> --- a/fs/ubifs/scan.c
> +++ b/fs/ubifs/scan.c
> @@ -212,7 +212,6 @@ int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
>  	case UBIFS_DENT_NODE:
>  	case UBIFS_XENT_NODE:
>  	case UBIFS_DATA_NODE:
> -	case UBIFS_TRUN_NODE:

There is another bug in ubifs_recover_size_accum() that expects a truncate node
to have a key.  That would be fixed by using trun_key_init() here.

>  		/*
>  		 * The key is in the same place in all keyed
>  		 * nodes.

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

* Re: [PATCHv2 7/9] UBIFS: do not write rubbish into truncation scanning node
  2010-08-08 11:03   ` Adrian Hunter
@ 2010-08-08 11:08     ` Adrian Hunter
  2010-08-08 13:59       ` Artem Bityutskiy
  2010-08-22  4:25       ` Artem Bityutskiy
  0 siblings, 2 replies; 14+ messages in thread
From: Adrian Hunter @ 2010-08-08 11:08 UTC (permalink / raw)
  To: Artem Bityutskiy; +Cc: linux-mtd@lists.infradead.org, Matthieu CASTET

Adrian Hunter wrote:
> Artem Bityutskiy wrote:
>> From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
>>
>> In the scanning code, in 'ubifs_add_snod()', we write rubbish into
>> 'snod->key', because we assume that on-flash truncation nodes have a key, but
>> they do not. If the other parts of UBIFS then mistakenly try to look-up
>> the truncation node key (they should not do this, but may do because of a bug),
>> we can succeed and corrupt TNC. It looks like we did have such a situation in
>> 'sort_nodes()' in gc.c.
>>
>> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
>> ---
>>  fs/ubifs/scan.c |    1 -
>>  1 files changed, 0 insertions(+), 1 deletions(-)
>>
>> diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
>> index 96c5253..a0a305c 100644
>> --- a/fs/ubifs/scan.c
>> +++ b/fs/ubifs/scan.c
>> @@ -212,7 +212,6 @@ int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
>>  	case UBIFS_DENT_NODE:
>>  	case UBIFS_XENT_NODE:
>>  	case UBIFS_DATA_NODE:
>> -	case UBIFS_TRUN_NODE:
> 
> There is another bug in ubifs_recover_size_accum() that expects a truncate node
> to have a key.  That would be fixed by using trun_key_init() here.

No I was wrong, the key in ubifs_recover_size_accum() is already created using
trun_key_init()

Still, trun_key_init might be better here because the all-zeroes key has a key-type
of UBIFS_INO_KEY.  What do you think?

> 
>>  		/*
>>  		 * The key is in the same place in all keyed
>>  		 * nodes.
> 
> 

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

* Re: [PATCHv2 7/9] UBIFS: do not write rubbish into truncation scanning node
  2010-08-08 11:08     ` Adrian Hunter
@ 2010-08-08 13:59       ` Artem Bityutskiy
  2010-08-22  4:25       ` Artem Bityutskiy
  1 sibling, 0 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-08 13:59 UTC (permalink / raw)
  To: Adrian Hunter; +Cc: linux-mtd@lists.infradead.org, Matthieu CASTET

On Sun, 2010-08-08 at 14:08 +0300, Adrian Hunter wrote:
> No I was wrong, the key in ubifs_recover_size_accum() is already created using
> trun_key_init()
> 
> Still, trun_key_init might be better here because the all-zeroes key has a key-type
> of UBIFS_INO_KEY.  What do you think?

Did not really think, but off the top of my head it is probably good to
initialize ->key to something invalid of all other nodes then.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

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

* Re: [PATCHv2 7/9] UBIFS: do not write rubbish into truncation scanning node
  2010-08-08 11:08     ` Adrian Hunter
  2010-08-08 13:59       ` Artem Bityutskiy
@ 2010-08-22  4:25       ` Artem Bityutskiy
  1 sibling, 0 replies; 14+ messages in thread
From: Artem Bityutskiy @ 2010-08-22  4:25 UTC (permalink / raw)
  To: Adrian Hunter; +Cc: linux-mtd@lists.infradead.org, Matthieu CASTET

On Sun, 2010-08-08 at 14:08 +0300, Adrian Hunter wrote:
> Still, trun_key_init might be better here because the all-zeroes key has a key-type
> of UBIFS_INO_KEY.  What do you think?

I've left this patch as it is, since it is the simplest fix for the
issue. But on top of it I've applied the patch below. I've also amended
comments in patch 2/7, as Vitaly Wool suggested. Pushed to
ubifs-2.6.git / master. Only compile-tested the last series so far.

From: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Subject: [PATCH] UBIFS: mark unused key objects as invalid

When scanning the flash, UBIFS builds a list of flash nodes of type
'struct ubifs_scan_node'. Each scanned node has a 'snod->key' field. This field
is valid for most of the nodes, but invalid for some node type, e.g., truncation
nodes. It is safer to explicitly initialize such keys to something invalid,
rather than leaving them initialized to all zeros, which has key type of
UBIFS_INO_KEY.

This patch introduces new "fake" key type UBIFS_INVALID_KEY and initializes
unused 'snod->key' objects to this type. It also adds debugging assertions in
the TNC code to make sure no one ever tries to look these nodes up in the TNC.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
---
 fs/ubifs/key.h   |   14 ++++++++++++++
 fs/ubifs/scan.c  |    5 ++++-
 fs/ubifs/tnc.c   |    5 ++++-
 fs/ubifs/ubifs.h |    6 +++++-
 4 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/fs/ubifs/key.h b/fs/ubifs/key.h
index 0f530c6..92a8491 100644
--- a/fs/ubifs/key.h
+++ b/fs/ubifs/key.h
@@ -306,6 +306,20 @@ static inline void trun_key_init(const struct ubifs_info *c,
 }
 
 /**
+ * invalid_key_init - initialize invalid node key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ *
+ * This is a helper function which marks a @key object as invalid.
+ */
+static inline void invalid_key_init(const struct ubifs_info *c,
+				    union ubifs_key *key)
+{
+	key->u32[0] = 0xDEADBEAF;
+	key->u32[1] = UBIFS_INVALID_KEY;
+}
+
+/**
  * key_type - get key type.
  * @c: UBIFS file-system description object
  * @key: key to get type of
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
index a0a305c..3e1ee57 100644
--- a/fs/ubifs/scan.c
+++ b/fs/ubifs/scan.c
@@ -197,7 +197,7 @@ int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 	struct ubifs_ino_node *ino = buf;
 	struct ubifs_scan_node *snod;
 
-	snod = kzalloc(sizeof(struct ubifs_scan_node), GFP_NOFS);
+	snod = kmalloc(sizeof(struct ubifs_scan_node), GFP_NOFS);
 	if (!snod)
 		return -ENOMEM;
 
@@ -218,6 +218,9 @@ int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 		 */
 		key_read(c, &ino->key, &snod->key);
 		break;
+	default:
+		invalid_key_init(c, &snod->key);
+		break;
 	}
 	list_add_tail(&snod->list, &sleb->nodes);
 	sleb->nodes_cnt += 1;
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 2194915..ad9cf01 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -1177,6 +1177,7 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
 	unsigned long time = get_seconds();
 
 	dbg_tnc("search key %s", DBGKEY(key));
+	ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
 
 	znode = c->zroot.znode;
 	if (unlikely(!znode)) {
@@ -2966,7 +2967,7 @@ static struct ubifs_znode *right_znode(struct ubifs_info *c,
  *
  * This function searches an indexing node by its first key @key and its
  * address @lnum:@offs. It looks up the indexing tree by pulling all indexing
- * nodes it traverses to TNC. This function is called fro indexing nodes which
+ * nodes it traverses to TNC. This function is called for indexing nodes which
  * were found on the media by scanning, for example when garbage-collecting or
  * when doing in-the-gaps commit. This means that the indexing node which is
  * looked for does not have to have exactly the same leftmost key @key, because
@@ -2988,6 +2989,8 @@ static struct ubifs_znode *lookup_znode(struct ubifs_info *c,
 	struct ubifs_znode *znode, *zn;
 	int n, nn;
 
+	ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
+
 	/*
 	 * The arguments have probably been read off flash, so don't assume
 	 * they are valid.
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 0431087..a5928b1 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -119,8 +119,12 @@
  * in TNC. However, when replaying, it is handy to introduce fake "truncation"
  * keys for truncation nodes because the code becomes simpler. So we define
  * %UBIFS_TRUN_KEY type.
+ *
+ * But otherwise, out of the journal reply scope, the truncation keys are
+ * invalid.
  */
-#define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT
+#define UBIFS_TRUN_KEY    UBIFS_KEY_TYPES_CNT
+#define UBIFS_INVALID_KEY UBIFS_KEY_TYPES_CNT
 
 /*
  * How much a directory entry/extended attribute entry adds to the parent/host
-- 
1.7.2.1

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

end of thread, other threads:[~2010-08-22  4:25 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-08-08  9:57 [PATCHv2 0/9] UBIFS: recent patches Artem Bityutskiy
2010-08-08  9:57 ` [PATCHv2 1/9] UBIFS: switch to RO mode after synchronizing Artem Bityutskiy
2010-08-08  9:57 ` [PATCHv2 2/9] UBIFS: do not treat ENOSPC specially Artem Bityutskiy
2010-08-08  9:57 ` [PATCHv2 3/9] UBIFS: fix assertion warning Artem Bityutskiy
2010-08-08  9:57 ` [PATCHv2 4/9] UBIFS: do not look up truncation nodes Artem Bityutskiy
2010-08-08  9:57 ` [PATCHv2 5/9] UBIFS: do not use key type in list_sort Artem Bityutskiy
2010-08-08  9:57 ` [PATCHv2 6/9] UBIFS: improve assertion in node comparison functions Artem Bityutskiy
2010-08-08  9:57 ` [PATCHv2 7/9] UBIFS: do not write rubbish into truncation scanning node Artem Bityutskiy
2010-08-08 11:03   ` Adrian Hunter
2010-08-08 11:08     ` Adrian Hunter
2010-08-08 13:59       ` Artem Bityutskiy
2010-08-22  4:25       ` Artem Bityutskiy
2010-08-08  9:57 ` [PATCHv2 8/9] UBIFS: fix assertion warnings in comparison function Artem Bityutskiy
2010-08-08  9:57 ` [PATCHv2 9/9] UBIFS: introduce list sorting debugging checks 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).