linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Restriper restore bugfix
@ 2012-06-22 18:24 Ilya Dryomov
  2012-06-22 18:24 ` [PATCH 1/2] Btrfs: restore restriper state on all mounts Ilya Dryomov
  2012-06-22 18:24 ` [PATCH 2/2] Btrfs: resume balance on rw (re)mounts properly Ilya Dryomov
  0 siblings, 2 replies; 5+ messages in thread
From: Ilya Dryomov @ 2012-06-22 18:24 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Chris Mason, idryomov

This fixes restriper restore bug which triggered asserts for users with
interrupted balances on rootfs btrfs.

Thanks,

		Ilya


Ilya Dryomov (2):
  Btrfs: restore restriper state on all mounts
  Btrfs: resume balance on rw (re)mounts properly

 fs/btrfs/disk-io.c |   39 ++++++++++++++++++----------
 fs/btrfs/super.c   |    4 +++
 fs/btrfs/volumes.c |   73 ++++++++++++++++++++++++++++++++--------------------
 fs/btrfs/volumes.h |    3 +-
 4 files changed, 76 insertions(+), 43 deletions(-)

-- 
1.7.9.1


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

* [PATCH 1/2] Btrfs: restore restriper state on all mounts
  2012-06-22 18:24 [PATCH 0/2] Restriper restore bugfix Ilya Dryomov
@ 2012-06-22 18:24 ` Ilya Dryomov
  2012-06-26 16:17   ` David Sterba
  2012-06-22 18:24 ` [PATCH 2/2] Btrfs: resume balance on rw (re)mounts properly Ilya Dryomov
  1 sibling, 1 reply; 5+ messages in thread
From: Ilya Dryomov @ 2012-06-22 18:24 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Chris Mason, idryomov

Fix a bug that triggered asserts in btrfs_balance() in both normal and
resume modes -- restriper state was not properly restored on read-only
mounts.  This factors out resuming code from btrfs_restore_balance(),
which is now also called earlier in the mount sequence to avoid the
problem of some early writes getting the old profile.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
 fs/btrfs/disk-io.c |   15 ++++++++++-----
 fs/btrfs/volumes.c |   39 +++++++++++++++++++--------------------
 fs/btrfs/volumes.h |    2 +-
 3 files changed, 30 insertions(+), 26 deletions(-)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 77872da..dae7cd6 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2354,17 +2354,22 @@ retry_root_backup:
 				  BTRFS_CSUM_TREE_OBJECTID, csum_root);
 	if (ret)
 		goto recovery_tree_root;
-
 	csum_root->track_dirty = 1;
 
 	fs_info->generation = generation;
 	fs_info->last_trans_committed = generation;
 
+	ret = btrfs_recover_balance(fs_info);
+	if (ret) {
+		printk(KERN_WARNING "btrfs: failed to recover balance\n");
+		goto fail_tree_roots;
+	}
+
 	ret = btrfs_init_dev_stats(fs_info);
 	if (ret) {
 		printk(KERN_ERR "btrfs: failed to init dev_stats: %d\n",
 		       ret);
-		goto fail_block_groups;
+		goto fail_balance_ctl;
 	}
 
 	ret = btrfs_init_space_info(fs_info);
@@ -2492,9 +2497,6 @@ retry_root_backup:
 			err = btrfs_orphan_cleanup(fs_info->tree_root);
 		up_read(&fs_info->cleanup_work_sem);
 
-		if (!err)
-			err = btrfs_recover_balance(fs_info->tree_root);
-
 		if (err) {
 			close_ctree(tree_root);
 			return err;
@@ -2518,6 +2520,9 @@ fail_cleaner:
 fail_block_groups:
 	btrfs_free_block_groups(fs_info);
 
+fail_balance_ctl:
+	kfree(fs_info->balance_ctl);
+
 fail_tree_roots:
 	free_root_pointers(fs_info, 1);
 
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 8a3d259..f7649b9 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2867,9 +2867,8 @@ static int balance_kthread(void *data)
 	return ret;
 }
 
-int btrfs_recover_balance(struct btrfs_root *tree_root)
+int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
 {
-	struct task_struct *tsk;
 	struct btrfs_balance_control *bctl;
 	struct btrfs_balance_item *item;
 	struct btrfs_disk_balance_args disk_bargs;
@@ -2882,29 +2881,30 @@ int btrfs_recover_balance(struct btrfs_root *tree_root)
 	if (!path)
 		return -ENOMEM;
 
-	bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
-	if (!bctl) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
 	key.objectid = BTRFS_BALANCE_OBJECTID;
 	key.type = BTRFS_BALANCE_ITEM_KEY;
 	key.offset = 0;
 
-	ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
+	ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0);
 	if (ret < 0)
-		goto out_bctl;
+		goto out;
 	if (ret > 0) { /* ret = -ENOENT; */
 		ret = 0;
-		goto out_bctl;
+		goto out;
+	}
+
+	bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
+	if (!bctl) {
+		ret = -ENOMEM;
+		goto out;
 	}
 
 	leaf = path->nodes[0];
 	item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item);
 
-	bctl->fs_info = tree_root->fs_info;
-	bctl->flags = btrfs_balance_flags(leaf, item) | BTRFS_BALANCE_RESUME;
+	bctl->fs_info = fs_info;
+	bctl->flags = btrfs_balance_flags(leaf, item);
+	bctl->flags |= BTRFS_BALANCE_RESUME;
 
 	btrfs_balance_data(leaf, item, &disk_bargs);
 	btrfs_disk_balance_args_to_cpu(&bctl->data, &disk_bargs);
@@ -2913,14 +2913,13 @@ int btrfs_recover_balance(struct btrfs_root *tree_root)
 	btrfs_balance_sys(leaf, item, &disk_bargs);
 	btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs);
 
-	tsk = kthread_run(balance_kthread, bctl, "btrfs-balance");
-	if (IS_ERR(tsk))
-		ret = PTR_ERR(tsk);
-	else
-		goto out;
+	mutex_lock(&fs_info->volume_mutex);
+	mutex_lock(&fs_info->balance_mutex);
 
-out_bctl:
-	kfree(bctl);
+	set_balance_control(bctl);
+
+	mutex_unlock(&fs_info->balance_mutex);
+	mutex_unlock(&fs_info->volume_mutex);
 out:
 	btrfs_free_path(path);
 	return ret;
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 74366f2..e1b1a64 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -281,7 +281,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
 int btrfs_init_new_device(struct btrfs_root *root, char *path);
 int btrfs_balance(struct btrfs_balance_control *bctl,
 		  struct btrfs_ioctl_balance_args *bargs);
-int btrfs_recover_balance(struct btrfs_root *tree_root);
+int btrfs_recover_balance(struct btrfs_fs_info *fs_info);
 int btrfs_pause_balance(struct btrfs_fs_info *fs_info);
 int btrfs_cancel_balance(struct btrfs_fs_info *fs_info);
 int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
-- 
1.7.9.1


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

* [PATCH 2/2] Btrfs: resume balance on rw (re)mounts properly
  2012-06-22 18:24 [PATCH 0/2] Restriper restore bugfix Ilya Dryomov
  2012-06-22 18:24 ` [PATCH 1/2] Btrfs: restore restriper state on all mounts Ilya Dryomov
@ 2012-06-22 18:24 ` Ilya Dryomov
  1 sibling, 0 replies; 5+ messages in thread
From: Ilya Dryomov @ 2012-06-22 18:24 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Chris Mason, idryomov

This introduces btrfs_resume_balance_async(), which, given that
restriper state was recovered earlier by btrfs_recover_balance(),
resumes balance in btrfs-balance kthread.

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
 fs/btrfs/disk-io.c |   24 +++++++++++++++---------
 fs/btrfs/super.c   |    4 ++++
 fs/btrfs/volumes.c |   36 +++++++++++++++++++++++++++---------
 fs/btrfs/volumes.h |    1 +
 4 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index dae7cd6..e863f58 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2490,17 +2490,23 @@ retry_root_backup:
 		goto fail_trans_kthread;
 	}
 
-	if (!(sb->s_flags & MS_RDONLY)) {
-		down_read(&fs_info->cleanup_work_sem);
-		err = btrfs_orphan_cleanup(fs_info->fs_root);
-		if (!err)
-			err = btrfs_orphan_cleanup(fs_info->tree_root);
+	if (sb->s_flags & MS_RDONLY)
+		return 0;
+
+	down_read(&fs_info->cleanup_work_sem);
+	if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) ||
+	    (ret = btrfs_orphan_cleanup(fs_info->tree_root))) {
 		up_read(&fs_info->cleanup_work_sem);
+		close_ctree(tree_root);
+		return ret;
+	}
+	up_read(&fs_info->cleanup_work_sem);
 
-		if (err) {
-			close_ctree(tree_root);
-			return err;
-		}
+	ret = btrfs_resume_balance_async(fs_info);
+	if (ret) {
+		printk(KERN_WARNING "btrfs: failed to resume balance\n");
+		close_ctree(tree_root);
+		return ret;
 	}
 
 	return 0;
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 0eb9a4d..e239915 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1187,6 +1187,10 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 		if (ret)
 			goto restore;
 
+		ret = btrfs_resume_balance_async(fs_info);
+		if (ret)
+			goto restore;
+
 		sb->s_flags &= ~MS_RDONLY;
 	}
 
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index f7649b9..0f1778c 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2845,28 +2845,46 @@ out:
 
 static int balance_kthread(void *data)
 {
-	struct btrfs_balance_control *bctl =
-			(struct btrfs_balance_control *)data;
-	struct btrfs_fs_info *fs_info = bctl->fs_info;
+	struct btrfs_fs_info *fs_info = data;
 	int ret = 0;
 
 	mutex_lock(&fs_info->volume_mutex);
 	mutex_lock(&fs_info->balance_mutex);
 
-	set_balance_control(bctl);
-
-	if (btrfs_test_opt(fs_info->tree_root, SKIP_BALANCE)) {
-		printk(KERN_INFO "btrfs: force skipping balance\n");
-	} else {
+	if (fs_info->balance_ctl) {
 		printk(KERN_INFO "btrfs: continuing balance\n");
-		ret = btrfs_balance(bctl, NULL);
+		ret = btrfs_balance(fs_info->balance_ctl, NULL);
 	}
 
 	mutex_unlock(&fs_info->balance_mutex);
 	mutex_unlock(&fs_info->volume_mutex);
+
 	return ret;
 }
 
+int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info)
+{
+	struct task_struct *tsk;
+
+	spin_lock(&fs_info->balance_lock);
+	if (!fs_info->balance_ctl) {
+		spin_unlock(&fs_info->balance_lock);
+		return 0;
+	}
+	spin_unlock(&fs_info->balance_lock);
+
+	if (btrfs_test_opt(fs_info->tree_root, SKIP_BALANCE)) {
+		printk(KERN_INFO "btrfs: force skipping balance\n");
+		return 0;
+	}
+
+	tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance");
+	if (IS_ERR(tsk))
+		return PTR_ERR(tsk);
+
+	return 0;
+}
+
 int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
 {
 	struct btrfs_balance_control *bctl;
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index e1b1a64..95f6637 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -281,6 +281,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
 int btrfs_init_new_device(struct btrfs_root *root, char *path);
 int btrfs_balance(struct btrfs_balance_control *bctl,
 		  struct btrfs_ioctl_balance_args *bargs);
+int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info);
 int btrfs_recover_balance(struct btrfs_fs_info *fs_info);
 int btrfs_pause_balance(struct btrfs_fs_info *fs_info);
 int btrfs_cancel_balance(struct btrfs_fs_info *fs_info);
-- 
1.7.9.1


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

* Re: [PATCH 1/2] Btrfs: restore restriper state on all mounts
  2012-06-22 18:24 ` [PATCH 1/2] Btrfs: restore restriper state on all mounts Ilya Dryomov
@ 2012-06-26 16:17   ` David Sterba
  2012-06-26 17:35     ` Ilya Dryomov
  0 siblings, 1 reply; 5+ messages in thread
From: David Sterba @ 2012-06-26 16:17 UTC (permalink / raw)
  To: Ilya Dryomov; +Cc: linux-btrfs, Chris Mason

On Fri, Jun 22, 2012 at 09:24:12PM +0300, Ilya Dryomov wrote:
> Fix a bug that triggered asserts in btrfs_balance() in both normal and
> resume modes -- restriper state was not properly restored on read-only
> mounts.  This factors out resuming code from btrfs_restore_balance(),
> which is now also called earlier in the mount sequence to avoid the
> problem of some early writes getting the old profile.
> 
> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
> ---
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index 77872da..dae7cd6 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -2492,9 +2497,6 @@ retry_root_backup:
>  			err = btrfs_orphan_cleanup(fs_info->tree_root);
>  		up_read(&fs_info->cleanup_work_sem);
>  
> -		if (!err)
> -			err = btrfs_recover_balance(fs_info->tree_root);
> -
>  		if (err) {
>  			close_ctree(tree_root);
>  			return err;
> @@ -2518,6 +2520,9 @@ fail_cleaner:
>  fail_block_groups:
>  	btrfs_free_block_groups(fs_info);
>  
> +fail_balance_ctl:
> +	kfree(fs_info->balance_ctl);

I think you need to set fs_info->balance_ctl to NULL, otherwise this
could lead to double free from free_fs_info. I was looking along the
call paths and didn't see free_fs_info called on the mount failure path:

vfs->mount
  btrfs_mount
    btrfs_fill_super
      open_ctree
        (recover balance fails, frees ctl)

error is propagated back to vfs, no other fs callback is done (like
kill_super which does call free_fs_info).

The only exit path that is not going through free_fs_info is after error
from btrfs_fill_super, and this can fail from various reasons.

Either I'm missing something, or we leak a btrfs_fs_info every time a
mount fails ...


Back to your patch, apart from the balance_ctl pointer reset, both are
ok and given the number of bug reports [useless padding text here]

  this should go to 3.5-rc.


david

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

* Re: [PATCH 1/2] Btrfs: restore restriper state on all mounts
  2012-06-26 16:17   ` David Sterba
@ 2012-06-26 17:35     ` Ilya Dryomov
  0 siblings, 0 replies; 5+ messages in thread
From: Ilya Dryomov @ 2012-06-26 17:35 UTC (permalink / raw)
  To: linux-btrfs, Chris Mason

First of all, thanks for reviewing!

On Tue, Jun 26, 2012 at 06:17:39PM +0200, David Sterba wrote:
> On Fri, Jun 22, 2012 at 09:24:12PM +0300, Ilya Dryomov wrote:
> > Fix a bug that triggered asserts in btrfs_balance() in both normal and
> > resume modes -- restriper state was not properly restored on read-only
> > mounts.  This factors out resuming code from btrfs_restore_balance(),
> > which is now also called earlier in the mount sequence to avoid the
> > problem of some early writes getting the old profile.
> > 
> > Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
> > ---
> > diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> > index 77872da..dae7cd6 100644
> > --- a/fs/btrfs/disk-io.c
> > +++ b/fs/btrfs/disk-io.c
> > @@ -2492,9 +2497,6 @@ retry_root_backup:
> >  			err = btrfs_orphan_cleanup(fs_info->tree_root);
> >  		up_read(&fs_info->cleanup_work_sem);
> >  
> > -		if (!err)
> > -			err = btrfs_recover_balance(fs_info->tree_root);
> > -
> >  		if (err) {
> >  			close_ctree(tree_root);
> >  			return err;
> > @@ -2518,6 +2520,9 @@ fail_cleaner:
> >  fail_block_groups:
> >  	btrfs_free_block_groups(fs_info);
> >  
> > +fail_balance_ctl:
> > +	kfree(fs_info->balance_ctl);
> 
> I think you need to set fs_info->balance_ctl to NULL, otherwise this
> could lead to double free from free_fs_info. I was looking along the

Yes, I do.  I meant to call unset_balance_control(fs_info) there, but
changed it to kfree(), because of the BUG_ON() in the former.

unset_balance_control(), of course, sets ->balance_ctl to NULL ;)

> call paths and didn't see free_fs_info called on the mount failure path:
> 
> vfs->mount
>   btrfs_mount
>     btrfs_fill_super
>       open_ctree
>         (recover balance fails, frees ctl)
> 
> error is propagated back to vfs, no other fs callback is done (like
> kill_super which does call free_fs_info).
> 
> The only exit path that is not going through free_fs_info is after error
> from btrfs_fill_super, and this can fail from various reasons.
> 
> Either I'm missing something, or we leak a btrfs_fs_info every time a
> mount fails ...

No, we don't, you just missed it.  It's freed from btrfs_kill_super(),
which is called from deactivate_locked_super() after btrfs_fill_super()
errors out.

> 
> 
> Back to your patch, apart from the balance_ctl pointer reset, both are
> ok and given the number of bug reports [useless padding text here]
> 
>   this should go to 3.5-rc.

Thanks,

		Ilya

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

end of thread, other threads:[~2012-06-26 17:35 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-22 18:24 [PATCH 0/2] Restriper restore bugfix Ilya Dryomov
2012-06-22 18:24 ` [PATCH 1/2] Btrfs: restore restriper state on all mounts Ilya Dryomov
2012-06-26 16:17   ` David Sterba
2012-06-26 17:35     ` Ilya Dryomov
2012-06-22 18:24 ` [PATCH 2/2] Btrfs: resume balance on rw (re)mounts properly Ilya Dryomov

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).