linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/7] UBIFS: split ubifs_rcvry_gc_commit
@ 2011-05-06 14:15 Artem Bityutskiy
  2011-05-06 14:15 ` [PATCH 2/7] UBIFS: refactor ubifs_rcvry_gc_commit Artem Bityutskiy
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2011-05-06 14:15 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

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

Split the 'ubifs_rcvry_gc_commit()' function and introduce a 'grab_empty_leb()'
heler. This cleans 'ubifs_rcvry_gc_commit()' a little and makes it a bit less
of spagetti.

Also, add a commentary which explains why it is crucial to first search for an
empty LEB and then run commit.

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

diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 3d2598d..11776ae 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -1070,6 +1070,53 @@ int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
 }
 
 /**
+ * grab_empty_leb - grab an empty LEB to use as GC LEB and run commit.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function for 'ubifs_rcvry_gc_commit()' which grabs an empty
+ * LEB to be used as GC LEB (@c->gc_lnum), and then runs the commit. Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+static int grab_empty_leb(struct ubifs_info *c)
+{
+	int lnum, err;
+
+	/*
+	 * Note, it is very important to first search for an empty LEB and then
+	 * run the commit, not vice-versa. The reason is that there might be
+	 * only one empty LEB at the moment, the one which has been the
+	 * @c->gc_lnum just before the power cut happened. During the regular
+	 * UBIFS operation (not now) @c->gc_lnum is marked as "taken", so no
+	 * one but GC can grab it. But at this moment this single empty LEB is
+	 * not marked as taken, so if we run commit - what happens? Right, the
+	 * commit will grab it and write the index there. Remember that the
+	 * index always expands as long as there is free space, and it only
+	 * starts consolidating when we run out of space.
+	 *
+	 * IOW, if we run commit now, we might not be able to find a free LEB
+	 * after this.
+	 */
+	lnum = ubifs_find_free_leb_for_idx(c);
+	if (lnum < 0) {
+		dbg_err("could not find an empty LEB");
+		dbg_dump_lprops(c);
+		dbg_dump_budg(c, &c->bi);
+		return lnum;
+	}
+
+	/* Reset the index flag */
+	err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
+				  LPROPS_INDEX, 0);
+	if (err)
+		return err;
+
+	c->gc_lnum = lnum;
+	dbg_rcvry("found empty LEB %d, run commit", lnum);
+
+	return ubifs_run_commit(c);
+}
+
+/**
  * ubifs_rcvry_gc_commit - recover the GC LEB number and run the commit.
  * @c: UBIFS file-system description object
  *
@@ -1096,7 +1143,7 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 	c->gc_lnum = -1;
 	if (wbuf->lnum == -1) {
 		dbg_rcvry("no GC head LEB");
-		goto find_free;
+		return grab_empty_leb(c);
 	}
 	/*
 	 * See whether the used space in the dirtiest LEB fits in the GC head
@@ -1104,7 +1151,7 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 	 */
 	if (wbuf->offs == c->leb_size) {
 		dbg_rcvry("no room in GC head LEB");
-		goto find_free;
+		return grab_empty_leb(c);
 	}
 	err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
 	if (err) {
@@ -1121,7 +1168,7 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 		 */
 		if (err == -ENOSPC) {
 			dbg_rcvry("could not find a dirty LEB");
-			goto find_free;
+			return grab_empty_leb(c);
 		}
 		return err;
 	}
@@ -1167,30 +1214,6 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 		return err;
 	dbg_rcvry("allocated LEB %d for GC", lnum);
 	return 0;
-
-find_free:
-	/*
-	 * There is no GC head LEB or the free space in the GC head LEB is too
-	 * small, or there are not dirty LEBs. Allocate gc_lnum by calling
-	 * 'ubifs_find_free_leb_for_idx()' so GC is not run.
-	 */
-	lnum = ubifs_find_free_leb_for_idx(c);
-	if (lnum < 0) {
-		dbg_err("could not find an empty LEB");
-		dbg_dump_lprops(c);
-		dbg_dump_budg(c, &c->bi);
-		return lnum;
-	}
-	/* And reset the index flag */
-	err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
-				  LPROPS_INDEX, 0);
-	if (err)
-		return err;
-	c->gc_lnum = lnum;
-	dbg_rcvry("allocated LEB %d for GC", lnum);
-	/* Run the commit */
-	dbg_rcvry("committing");
-	return ubifs_run_commit(c);
 }
 
 /**
-- 
1.7.2.3

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

* [PATCH 2/7] UBIFS: refactor ubifs_rcvry_gc_commit
  2011-05-06 14:15 [PATCH 1/7] UBIFS: split ubifs_rcvry_gc_commit Artem Bityutskiy
@ 2011-05-06 14:15 ` Artem Bityutskiy
  2011-05-06 14:15 ` [PATCH 3/7] UBIFS: fix debugging message Artem Bityutskiy
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2011-05-06 14:15 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

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

This commits refactors and cleans up 'ubifs_rcvry_gc_commit()' which was quite
untidy, also removes the commentary which was not 100% correct.

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

diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 11776ae..d28db1e 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -1138,44 +1138,26 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 {
 	struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
 	struct ubifs_lprops lp;
-	int lnum, err;
+	int err;
 
 	c->gc_lnum = -1;
-	if (wbuf->lnum == -1) {
-		dbg_rcvry("no GC head LEB");
-		return grab_empty_leb(c);
-	}
-	/*
-	 * See whether the used space in the dirtiest LEB fits in the GC head
-	 * LEB.
-	 */
-	if (wbuf->offs == c->leb_size) {
-		dbg_rcvry("no room in GC head LEB");
+	if (wbuf->lnum == -1 || wbuf->offs == c->leb_size) {
+		dbg_rcvry("no GC head: wbuf->lnum %d, wbuf->offs %d",
+			  wbuf->lnum, wbuf->offs);
 		return grab_empty_leb(c);
 	}
+
 	err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
 	if (err) {
-		/*
-		 * There are no dirty or empty LEBs subject to here being
-		 * enough for the index. Try to use
-		 * 'ubifs_find_free_leb_for_idx()', which will return any empty
-		 * LEBs (ignoring index requirements). If the index then
-		 * doesn't have enough LEBs the recovery commit will fail -
-		 * which is the  same result anyway i.e. recovery fails. So
-		 * there is no problem ignoring index  requirements and just
-		 * grabbing a free LEB since we have already established there
-		 * is not a dirty LEB we could have used instead.
-		 */
-		if (err == -ENOSPC) {
-			dbg_rcvry("could not find a dirty LEB");
-			return grab_empty_leb(c);
-		}
-		return err;
+		if (err != -ENOSPC)
+			return err;
+
+		dbg_rcvry("could not find a dirty LEB");
+		return grab_empty_leb(c);
 	}
 
 	ubifs_assert(!(lp.flags & LPROPS_INDEX));
 	ubifs_assert(lp.free + lp.dirty >= wbuf->offs);
-	lnum = lp.lnum;
 
 	/*
 	 * We run the commit before garbage collection otherwise subsequent
@@ -1185,11 +1167,8 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 	err = ubifs_run_commit(c);
 	if (err)
 		return err;
-	/*
-	 * The data in the dirtiest LEB fits in the GC head LEB, so do the GC
-	 * - use locking to keep 'ubifs_assert()' happy.
-	 */
-	dbg_rcvry("GC'ing LEB %d", lnum);
+
+	dbg_rcvry("GC'ing LEB %d", lp.lnum);
 	mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
 	err = ubifs_garbage_collect_leb(c, &lp);
 	if (err >= 0) {
@@ -1205,14 +1184,16 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 			err = -EINVAL;
 		return err;
 	}
-	if (err != LEB_RETAINED) {
-		dbg_err("GC returned %d", err);
+
+	ubifs_assert(err == LEB_RETAINED);
+	if (err != LEB_RETAINED)
 		return -EINVAL;
-	}
+
 	err = ubifs_leb_unmap(c, c->gc_lnum);
 	if (err)
 		return err;
-	dbg_rcvry("allocated LEB %d for GC", lnum);
+
+	dbg_rcvry("allocated LEB %d for GC", lp.lnum);
 	return 0;
 }
 
-- 
1.7.2.3

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

* [PATCH 3/7] UBIFS: fix debugging message
  2011-05-06 14:15 [PATCH 1/7] UBIFS: split ubifs_rcvry_gc_commit Artem Bityutskiy
  2011-05-06 14:15 ` [PATCH 2/7] UBIFS: refactor ubifs_rcvry_gc_commit Artem Bityutskiy
@ 2011-05-06 14:15 ` Artem Bityutskiy
  2011-05-06 14:15 ` [PATCH 4/7] UBIFS: remove an unneeded check Artem Bityutskiy
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2011-05-06 14:15 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

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

When recovering the inode size, one of the debugging messages was printed
incorrecly, this patches fixes it.

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

diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index d28db1e..596dede 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -1496,7 +1496,7 @@ int ubifs_recover_size(struct ubifs_info *c)
 				if (inode->i_size < e->d_size) {
 					dbg_rcvry("ino %lu size %lld -> %lld",
 						  (unsigned long)e->inum,
-						  e->d_size, inode->i_size);
+						  inode->i_size, e->d_size);
 					inode->i_size = e->d_size;
 					ubifs_inode(inode)->ui_size = e->d_size;
 					e->inode = inode;
-- 
1.7.2.3

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

* [PATCH 4/7] UBIFS: remove an unneeded check
  2011-05-06 14:15 [PATCH 1/7] UBIFS: split ubifs_rcvry_gc_commit Artem Bityutskiy
  2011-05-06 14:15 ` [PATCH 2/7] UBIFS: refactor ubifs_rcvry_gc_commit Artem Bityutskiy
  2011-05-06 14:15 ` [PATCH 3/7] UBIFS: fix debugging message Artem Bityutskiy
@ 2011-05-06 14:15 ` Artem Bityutskiy
  2011-05-06 14:15 ` [PATCH 5/7] UBIFS: fix debugging FS checking failure Artem Bityutskiy
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2011-05-06 14:15 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

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

In 'ubifs_recover_size()' we have an "if (!e->inode && c->ro_mount)" statement.
But if 'c->ro_mount' is true, then '!e->inode' must always be true as well. So
we can remove the unnecessary '!e->inode' test and put an
'ubifs_assert(!e->inode)' instead.

This patch also removes an extra trailing white-space in a debugging print,
as well as adds few empty lines to 'ubifs_recover_size()' to make it a bit more
readable.

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

diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 596dede..d6c8ce3 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -1436,7 +1436,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
 	err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
 	if (err)
 		goto out;
-	dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ",
+	dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
 		  (unsigned long)e->inum, lnum, offs, i_size, e->d_size);
 	return 0;
 
@@ -1485,11 +1485,14 @@ int ubifs_recover_size(struct ubifs_info *c)
 				e->i_size = le64_to_cpu(ino->size);
 			}
 		}
+
 		if (e->exists && e->i_size < e->d_size) {
-			if (!e->inode && c->ro_mount) {
+			if (c->ro_mount) {
 				/* Fix the inode size and pin it in memory */
 				struct inode *inode;
 
+				ubifs_assert(!e->inode);
+
 				inode = ubifs_iget(c->vfs_sb, e->inum);
 				if (IS_ERR(inode))
 					return PTR_ERR(inode);
@@ -1513,9 +1516,11 @@ int ubifs_recover_size(struct ubifs_info *c)
 					iput(e->inode);
 			}
 		}
+
 		this = rb_next(this);
 		rb_erase(&e->rb, &c->size_tree);
 		kfree(e);
 	}
+
 	return 0;
 }
-- 
1.7.2.3

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

* [PATCH 5/7] UBIFS: fix debugging FS checking failure
  2011-05-06 14:15 [PATCH 1/7] UBIFS: split ubifs_rcvry_gc_commit Artem Bityutskiy
                   ` (2 preceding siblings ...)
  2011-05-06 14:15 ` [PATCH 4/7] UBIFS: remove an unneeded check Artem Bityutskiy
@ 2011-05-06 14:15 ` Artem Bityutskiy
  2011-05-06 14:15 ` [PATCH 6/7] UBIFS: fix inode size debugging check failure Artem Bityutskiy
  2011-05-06 14:15 ` [PATCH 7/7] UBIFS: fix a rare memory leak in ro to rw remounting path Artem Bityutskiy
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2011-05-06 14:15 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

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

When the debugging self-checks are enabled, we go trough whole file-system
after mount and check/validate every single node referred to by the index.
This is implemented by the 'dbg_check_filesystem()' function. However, this
function fails if we mount "unclean" file-system, i.e., if we mount the
file-system after a power cut. It fails with the following symptoms:

UBIFS DBG (pid 8171): ubifs_recover_size: ino 937 size 3309925 -> 3317760
UBIFS: recovery deferred
UBIFS error (pid 8171): check_leaf: data node at LEB 1000:0 is not within inode size 3309925

The reason of failure is that recovery fixed up the inode size in memory, but
not on the flash so far. So the value on the flash is incorrect so far,
and would be corrected when we re-mount R/W. But 'check_leaf()' ignores
this fact and tries to validate the size of the on-flash inode, which is
incorrect, so it fails.

This patch teaches the checking code to look at the VFS inode cache first,
and if there is the inode in question, use that inode instead of the inode
on the flash media. This fixes the issue.

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

diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index f7515bd..b5ba2ea 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -1818,6 +1818,8 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
 	struct rb_node **p, *parent = NULL;
 	struct fsck_inode *fscki;
 	ino_t inum = key_inum_flash(c, &ino->key);
+	struct inode *inode;
+	struct ubifs_inode *ui;
 
 	p = &fsckd->inodes.rb_node;
 	while (*p) {
@@ -1841,19 +1843,46 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
 	if (!fscki)
 		return ERR_PTR(-ENOMEM);
 
+	inode = ilookup(c->vfs_sb, inum);
+
 	fscki->inum = inum;
-	fscki->nlink = le32_to_cpu(ino->nlink);
-	fscki->size = le64_to_cpu(ino->size);
-	fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
-	fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
-	fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
-	fscki->mode = le32_to_cpu(ino->mode);
+	/*
+	 * If the inode is present in the VFS inode cache, use it instead of
+	 * the on-flash inode which might be out-of-date. E.g., the size might
+	 * be out-of-date. If we do not do this, the following may happen, for
+	 * example:
+	 *   1. A power cut happens
+	 *   2. We mount the file-system R/O, the replay process fixes up the
+	 *      inode size in the VFS cache, but on on-flash.
+	 *   3. 'check_leaf()' fails because it hits a data node beyond inode
+	 *      size.
+	 */
+	if (!inode) {
+		fscki->nlink = le32_to_cpu(ino->nlink);
+		fscki->size = le64_to_cpu(ino->size);
+		fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
+		fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
+		fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
+		fscki->mode = le32_to_cpu(ino->mode);
+	} else {
+		ui = ubifs_inode(inode);
+		fscki->nlink = inode->i_nlink;
+		fscki->size = inode->i_size;
+		fscki->xattr_cnt = ui->xattr_cnt;
+		fscki->xattr_sz = ui->xattr_size;
+		fscki->xattr_nms = ui->xattr_names;
+		fscki->mode = inode->i_mode;
+		iput(inode);
+	}
+
 	if (S_ISDIR(fscki->mode)) {
 		fscki->calc_sz = UBIFS_INO_NODE_SZ;
 		fscki->calc_cnt = 2;
 	}
+
 	rb_link_node(&fscki->rb, parent, p);
 	rb_insert_color(&fscki->rb, &fsckd->inodes);
+
 	return fscki;
 }
 
-- 
1.7.2.3

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

* [PATCH 6/7] UBIFS: fix inode size debugging check failure
  2011-05-06 14:15 [PATCH 1/7] UBIFS: split ubifs_rcvry_gc_commit Artem Bityutskiy
                   ` (3 preceding siblings ...)
  2011-05-06 14:15 ` [PATCH 5/7] UBIFS: fix debugging FS checking failure Artem Bityutskiy
@ 2011-05-06 14:15 ` Artem Bityutskiy
  2011-05-06 14:15 ` [PATCH 7/7] UBIFS: fix a rare memory leak in ro to rw remounting path Artem Bityutskiy
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2011-05-06 14:15 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

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

This patch fixes a problem with the following symptoms:

UBIFS: deferred recovery completed
UBIFS error (pid 15676): dbg_check_synced_i_size: ui_size is 11481088, synced_i_size is 11459081, but inode is clean
UBIFS error (pid 15676): dbg_check_synced_i_size: i_ino 128, i_mode 0x81a4, i_size 11481088

It happens when additional debugging checks are enabled and we are recovering
from a power cut. When we fixup corrupted inode size during recovery, we change
them in-place and we change ui_size as well, but not synced_i_size, which
causes this failure. This patch makes sure we change both fields and fixes the
issue.

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

diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index d6c8ce3..3f41a0c 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -1490,18 +1490,22 @@ int ubifs_recover_size(struct ubifs_info *c)
 			if (c->ro_mount) {
 				/* Fix the inode size and pin it in memory */
 				struct inode *inode;
+				struct ubifs_inode *ui;
 
 				ubifs_assert(!e->inode);
 
 				inode = ubifs_iget(c->vfs_sb, e->inum);
 				if (IS_ERR(inode))
 					return PTR_ERR(inode);
+
+				ui = ubifs_inode(inode);
 				if (inode->i_size < e->d_size) {
 					dbg_rcvry("ino %lu size %lld -> %lld",
 						  (unsigned long)e->inum,
 						  inode->i_size, e->d_size);
 					inode->i_size = e->d_size;
-					ubifs_inode(inode)->ui_size = e->d_size;
+					ui->ui_size = e->d_size;
+					ui->synced_i_size = e->d_size;
 					e->inode = inode;
 					this = rb_next(this);
 					continue;
-- 
1.7.2.3

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

* [PATCH 7/7] UBIFS: fix a rare memory leak in ro to rw remounting path
  2011-05-06 14:15 [PATCH 1/7] UBIFS: split ubifs_rcvry_gc_commit Artem Bityutskiy
                   ` (4 preceding siblings ...)
  2011-05-06 14:15 ` [PATCH 6/7] UBIFS: fix inode size debugging check failure Artem Bityutskiy
@ 2011-05-06 14:15 ` Artem Bityutskiy
  5 siblings, 0 replies; 7+ messages in thread
From: Artem Bityutskiy @ 2011-05-06 14:15 UTC (permalink / raw)
  To: MTD list; +Cc: Adrian Hunter

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

When re-mounting from R/O mode to R/W mode and the LEB count in the superblock
is not up-to date, because for the underlying UBI volume became larger, we
re-write the superblock. We allocate RAM for these purposes, but never free it.
So this is a memory leak, although very rare one.

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

diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index bf31b47..cad60b5 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -475,7 +475,8 @@ failed:
  * @c: UBIFS file-system description object
  *
  * This function returns a pointer to the superblock node or a negative error
- * code.
+ * code. Note, the user of this function is responsible of kfree()'ing the
+ * returned superblock buffer.
  */
 struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
 {
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 407c064..575ea83 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1585,6 +1585,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
 		}
 		sup->leb_cnt = cpu_to_le32(c->leb_cnt);
 		err = ubifs_write_sb_node(c, sup);
+		kfree(sup);
 		if (err)
 			goto out;
 	}
-- 
1.7.2.3

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

end of thread, other threads:[~2011-05-06 14:11 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-06 14:15 [PATCH 1/7] UBIFS: split ubifs_rcvry_gc_commit Artem Bityutskiy
2011-05-06 14:15 ` [PATCH 2/7] UBIFS: refactor ubifs_rcvry_gc_commit Artem Bityutskiy
2011-05-06 14:15 ` [PATCH 3/7] UBIFS: fix debugging message Artem Bityutskiy
2011-05-06 14:15 ` [PATCH 4/7] UBIFS: remove an unneeded check Artem Bityutskiy
2011-05-06 14:15 ` [PATCH 5/7] UBIFS: fix debugging FS checking failure Artem Bityutskiy
2011-05-06 14:15 ` [PATCH 6/7] UBIFS: fix inode size debugging check failure Artem Bityutskiy
2011-05-06 14:15 ` [PATCH 7/7] UBIFS: fix a rare memory leak in ro to rw remounting path 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).