From patchwork Tue Aug 23 20:01:57 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Dryomov X-Patchwork-Id: 1089722 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p7NK2ks0007043 for ; Tue, 23 Aug 2011 20:03:06 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756121Ab1HWUCq (ORCPT ); Tue, 23 Aug 2011 16:02:46 -0400 Received: from mail-bw0-f46.google.com ([209.85.214.46]:56659 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755878Ab1HWUCp (ORCPT ); Tue, 23 Aug 2011 16:02:45 -0400 Received: by mail-bw0-f46.google.com with SMTP id 11so372435bke.19 for ; Tue, 23 Aug 2011 13:02:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=rJrmMrOlJU7MJLiJ4UUms2riLzHY3Qsvnp2vlzzCSII=; b=SUlIIxvi0NSoxmuscFujU/LvDW8J7xdAE2rx5Wrut1/W2BnCNV/W9m7dMshCZmOkTV TA33RokMQHnUj6Y0Ob1JgE5Hwar7RfhNWD0wOfH3OgBfzwE6Ktoz3JyouBTKUe+9/apa mYEGON4VaRmQHBO5W/5RPhtFtf/nkvayiVIbw= Received: by 10.204.157.142 with SMTP id b14mr1065437bkx.337.1314129765153; Tue, 23 Aug 2011 13:02:45 -0700 (PDT) Received: from localhost ([31.28.235.172]) by mx.google.com with ESMTPS id 14sm83126bkd.25.2011.08.23.13.02.43 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 23 Aug 2011 13:02:44 -0700 (PDT) From: Ilya Dryomov To: linux-btrfs@vger.kernel.org Cc: Chris Mason , Hugo Mills , idryomov@gmail.com Subject: [PATCH 16/21] Btrfs: allow for cancelling restriper Date: Tue, 23 Aug 2011 23:01:57 +0300 Message-Id: <1314129722-31601-17-git-send-email-idryomov@gmail.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1314129722-31601-1-git-send-email-idryomov@gmail.com> References: <1314129722-31601-1-git-send-email-idryomov@gmail.com> Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Tue, 23 Aug 2011 20:03:06 +0000 (UTC) Implement an ioctl for cancelling restriper. Currently we wait until relocation of the current block group is finished, in future this can be done by triggering a commit. Restripe item is deleted and no memory about the interrupted restripe is kept. Signed-off-by: Ilya Dryomov --- fs/btrfs/ctree.h | 2 + fs/btrfs/disk-io.c | 2 + fs/btrfs/ioctl.c | 20 +++++++++++++++++ fs/btrfs/ioctl.h | 3 ++ fs/btrfs/volumes.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++---- fs/btrfs/volumes.h | 7 ++++++ 6 files changed, 90 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b524034..8e764d9 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1165,6 +1165,8 @@ struct btrfs_fs_info { spinlock_t restripe_lock; struct mutex restripe_mutex; struct restripe_control *restripe_ctl; + unsigned long restripe_state; + wait_queue_head_t restripe_wait; unsigned data_chunk_allocations; unsigned metadata_ratio; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index b3950f2..662a6e6 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1703,6 +1703,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, spin_lock_init(&fs_info->restripe_lock); mutex_init(&fs_info->restripe_mutex); fs_info->restripe_ctl = NULL; + fs_info->restripe_state = 0; + init_waitqueue_head(&fs_info->restripe_wait); sb->s_blocksize = 4096; sb->s_blocksize_bits = blksize_bits(4096); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f371edd..d8bdb67 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2878,6 +2878,10 @@ static long btrfs_ioctl_restripe(struct btrfs_root *root, void __user *arg) return -EROFS; mutex_lock(&fs_info->restripe_mutex); + if (fs_info->restripe_ctl) { + ret = -EINPROGRESS; + goto out; + } rargs = memdup_user(arg, sizeof(*rargs)); if (IS_ERR(rargs)) { @@ -2908,6 +2912,20 @@ out: return ret; } +static long btrfs_ioctl_restripe_ctl(struct btrfs_root *root, + int cmd) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + switch (cmd) { + case BTRFS_RESTRIPE_CTL_CANCEL: + return btrfs_cancel_restripe(root->fs_info); + } + + return -EINVAL; +} + long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2982,6 +3000,8 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_scrub_progress(root, argp); case BTRFS_IOC_RESTRIPE: return btrfs_ioctl_restripe(root, argp); + case BTRFS_IOC_RESTRIPE_CTL: + return btrfs_ioctl_restripe_ctl(root, arg); } return -ENOTTY; diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 798f1d4..4f6ead5 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h @@ -109,6 +109,8 @@ struct btrfs_ioctl_fs_info_args { __u64 reserved[124]; /* pad to 1k */ }; +#define BTRFS_RESTRIPE_CTL_CANCEL 1 + struct btrfs_restripe_args { __u64 profiles; __u64 usage; @@ -285,4 +287,5 @@ struct btrfs_ioctl_space_args { struct btrfs_ioctl_fs_info_args) #define BTRFS_IOC_RESTRIPE _IOW(BTRFS_IOCTL_MAGIC, 32, \ struct btrfs_ioctl_restripe_args) +#define BTRFS_IOC_RESTRIPE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int) #endif diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 4490124..cd43368 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2553,6 +2553,13 @@ static int __btrfs_restripe(struct btrfs_root *dev_root) key.type = BTRFS_CHUNK_ITEM_KEY; while (1) { + struct btrfs_fs_info *fs_info = dev_root->fs_info; + + if (test_bit(RESTRIPE_CANCEL_REQ, &fs_info->restripe_state)) { + ret = -ECANCELED; + goto error; + } + ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); if (ret < 0) goto error; @@ -2715,16 +2722,25 @@ do_restripe: set_restripe_control(rctl, resume); mutex_unlock(&fs_info->volume_mutex); + set_bit(RESTRIPE_RUNNING, &fs_info->restripe_state); + mutex_unlock(&fs_info->restripe_mutex); + err = __btrfs_restripe(fs_info->dev_root); - mutex_lock(&fs_info->volume_mutex); + mutex_lock(&fs_info->restripe_mutex); + clear_bit(RESTRIPE_RUNNING, &fs_info->restripe_state); - unset_restripe_control(fs_info); - ret = del_restripe_item(fs_info->tree_root); - BUG_ON(ret); + if (test_bit(RESTRIPE_CANCEL_REQ, &fs_info->restripe_state)) { + mutex_lock(&fs_info->volume_mutex); - mutex_unlock(&fs_info->volume_mutex); + unset_restripe_control(fs_info); + ret = del_restripe_item(fs_info->tree_root); + BUG_ON(ret); + + mutex_unlock(&fs_info->volume_mutex); + } + wake_up(&fs_info->restripe_wait); return err; out: @@ -2807,6 +2823,41 @@ out: return ret; } +int btrfs_cancel_restripe(struct btrfs_fs_info *fs_info) +{ + int ret = 0; + + mutex_lock(&fs_info->restripe_mutex); + if (!fs_info->restripe_ctl) { + ret = -ENOTCONN; + goto out; + } + + if (test_bit(RESTRIPE_RUNNING, &fs_info->restripe_state)) { + set_bit(RESTRIPE_CANCEL_REQ, &fs_info->restripe_state); + while (test_bit(RESTRIPE_RUNNING, &fs_info->restripe_state)) { + mutex_unlock(&fs_info->restripe_mutex); + wait_event(fs_info->restripe_wait, + !test_bit(RESTRIPE_RUNNING, + &fs_info->restripe_state)); + mutex_lock(&fs_info->restripe_mutex); + } + clear_bit(RESTRIPE_CANCEL_REQ, &fs_info->restripe_state); + } else { + mutex_lock(&fs_info->volume_mutex); + + unset_restripe_control(fs_info); + ret = del_restripe_item(fs_info->tree_root); + BUG_ON(ret); + + mutex_unlock(&fs_info->volume_mutex); + } + +out: + mutex_unlock(&fs_info->restripe_mutex); + return ret; +} + /* * shrinking a device means finding all of the device extents past * the new size, and then following the back refs to the chunks. diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 6fcb4a5..dd1fa7f 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -199,6 +199,12 @@ struct map_lookup { #define BTRFS_RESTRIPE_ARGS_CONVERT (1ULL << 8) #define BTRFS_RESTRIPE_ARGS_SOFT (1ULL << 9) +/* + * Restripe state bits + */ +#define RESTRIPE_RUNNING 0 +#define RESTRIPE_CANCEL_REQ 1 + struct btrfs_restripe_args; struct restripe_control { struct btrfs_fs_info *fs_info; @@ -254,6 +260,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *path); int btrfs_balance(struct btrfs_root *dev_root); int btrfs_restripe(struct restripe_control *rctl, int resume); int btrfs_recover_restripe(struct btrfs_root *tree_root); +int btrfs_cancel_restripe(struct btrfs_fs_info *fs_info); int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); int find_free_dev_extent(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 num_bytes,