diff mbox

[2/6] Btrfs: build up error handling for merge_reloc_roots

Message ID 1362414341-17306-3-git-send-email-bo.li.liu@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Liu Bo March 4, 2013, 4:25 p.m. UTC
We first use btrfs_std_error hook to replace with BUG_ON, and we
also need to cleanup what is left, including reloc roots rbtree
and reloc roots list.
Here we use a helper function to cleanup both rbtree and list, and
since this function can also be used in the balance recover path,
we also make the change as well to keep code simple.

Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
---
 fs/btrfs/relocation.c |   47 +++++++++++++++++++++++++++++++++++------------
 1 files changed, 35 insertions(+), 12 deletions(-)

Comments

David Sterba March 18, 2013, 2:16 p.m. UTC | #1
On Tue, Mar 05, 2013 at 12:25:37AM +0800, Liu Bo wrote:
> We first use btrfs_std_error hook to replace with BUG_ON, and we
> also need to cleanup what is left, including reloc roots rbtree
> and reloc roots list.
> Here we use a helper function to cleanup both rbtree and list, and
> since this function can also be used in the balance recover path,
> we also make the change as well to keep code simple.

I've noticed that return value from merge_reloc_roots is never checked
in the callers. Did you verify that this is ok?

For example when called from btrfs_recover_relocation, is it possible
that the reloc-to-be-recovered is still left unprocessed but the
filesystem is going to be silently mounted read-write?

The mount and remount callpaths check for recover_relocation errors and
do not proceed otherwise. In RO mount, it's not called.

So, either merge_reloc_roots callers should catch the errors or there
are none by design (ie. the whole reloc operation is restartable).

david
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Liu Bo March 19, 2013, 12:16 p.m. UTC | #2
On Mon, Mar 18, 2013 at 03:16:12PM +0100, David Sterba wrote:
> On Tue, Mar 05, 2013 at 12:25:37AM +0800, Liu Bo wrote:
> > We first use btrfs_std_error hook to replace with BUG_ON, and we
> > also need to cleanup what is left, including reloc roots rbtree
> > and reloc roots list.
> > Here we use a helper function to cleanup both rbtree and list, and
> > since this function can also be used in the balance recover path,
> > we also make the change as well to keep code simple.
> 
> I've noticed that return value from merge_reloc_roots is never checked
> in the callers. Did you verify that this is ok?

Yeah, it's fine.

Actually we set fs to RO once we get error here, as we have recorded a balance
item and , balance can start over again the next time.

> 
> For example when called from btrfs_recover_relocation, is it possible
> that the reloc-to-be-recovered is still left unprocessed but the
> filesystem is going to be silently mounted read-write?

hmm, I'm not able to picture such a case...

> 
> The mount and remount callpaths check for recover_relocation errors and
> do not proceed otherwise. In RO mount, it's not called.
> 
> So, either merge_reloc_roots callers should catch the errors or there
> are none by design (ie. the whole reloc operation is restartable).
> 

it's desigend to be always ready for a crash or a power off.

thanks,
liubo
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Sterba March 28, 2013, 2:15 p.m. UTC | #3
On Tue, Mar 19, 2013 at 08:16:41PM +0800, Liu Bo wrote:
> On Mon, Mar 18, 2013 at 03:16:12PM +0100, David Sterba wrote:
> > I've noticed that return value from merge_reloc_roots is never checked
> > in the callers. Did you verify that this is ok?
> 
> Yeah, it's fine.

Then it's ok to change return value to 'void' so it does not look like
an unhandled errorcode.

> Actually we set fs to RO once we get error here, as we have recorded a balance
> item and , balance can start over again the next time.

Yeah, if we get there via transaction abort. My background motivation is
to implement a (much) more responsive balance cancel. This is different
from the poweroff "cancel", because it does not keep any in-memory
state.

david
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index d9be73b..8608afb 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -2240,13 +2240,28 @@  again:
 }
 
 static noinline_for_stack
+void free_reloc_roots(struct list_head *list)
+{
+	struct btrfs_root *reloc_root;
+
+	while (!list_empty(list)) {
+		reloc_root = list_entry(list->next, struct btrfs_root,
+					root_list);
+		__update_reloc_root(reloc_root, 1);
+		free_extent_buffer(reloc_root->node);
+		free_extent_buffer(reloc_root->commit_root);
+		kfree(reloc_root);
+	}
+}
+
+static noinline_for_stack
 int merge_reloc_roots(struct reloc_control *rc)
 {
 	struct btrfs_root *root;
 	struct btrfs_root *reloc_root;
 	LIST_HEAD(reloc_roots);
 	int found = 0;
-	int ret;
+	int ret = 0;
 again:
 	root = rc->extent_root;
 
@@ -2272,20 +2287,33 @@  again:
 			BUG_ON(root->reloc_root != reloc_root);
 
 			ret = merge_reloc_root(rc, root);
-			BUG_ON(ret);
+			if (ret)
+				goto out;
 		} else {
 			list_del_init(&reloc_root->root_list);
 		}
 		ret = btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1);
-		BUG_ON(ret < 0);
+		if (ret < 0) {
+			if (list_empty(&reloc_root->root_list))
+				list_add_tail(&reloc_root->root_list,
+					      &reloc_roots);
+			goto out;
+		}
 	}
 
 	if (found) {
 		found = 0;
 		goto again;
 	}
+out:
+	if (ret) {
+		btrfs_std_error(root->fs_info, ret);
+		if (!list_empty(&reloc_roots))
+			free_reloc_roots(&reloc_roots);
+	}
+
 	BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root));
-	return 0;
+	return ret;
 }
 
 static void free_block_list(struct rb_root *blocks)
@@ -4266,14 +4294,9 @@  int btrfs_recover_relocation(struct btrfs_root *root)
 out_free:
 	kfree(rc);
 out:
-	while (!list_empty(&reloc_roots)) {
-		reloc_root = list_entry(reloc_roots.next,
-					struct btrfs_root, root_list);
-		list_del(&reloc_root->root_list);
-		free_extent_buffer(reloc_root->node);
-		free_extent_buffer(reloc_root->commit_root);
-		kfree(reloc_root);
-	}
+	if (!list_empty(&reloc_roots))
+		free_reloc_roots(&reloc_roots);
+
 	btrfs_free_path(path);
 
 	if (err == 0) {