mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 14:50:19 +00:00
btrfs: add cancellation to resize
Accept literal string "cancel" as resize operation and interpret that as a request to cancel the running operation. If it's running, wait until it finishes current work and return ECANCELED. Shrinking resize uses relocation to move the chunks away, use the conditional exclusive operation start and cancellation helpers. Reviewed-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
17aaa434ed
commit
bb059a37c9
@ -1659,6 +1659,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
char *devstr = NULL;
|
||||
int ret = 0;
|
||||
int mod = 0;
|
||||
bool cancel;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
@ -1667,20 +1668,23 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!btrfs_exclop_start(fs_info, BTRFS_EXCLOP_RESIZE)) {
|
||||
mnt_drop_write_file(file);
|
||||
return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the arguments before checking exclusivity to be able to
|
||||
* distinguish regular resize and cancel
|
||||
*/
|
||||
vol_args = memdup_user(arg, sizeof(*vol_args));
|
||||
if (IS_ERR(vol_args)) {
|
||||
ret = PTR_ERR(vol_args);
|
||||
goto out;
|
||||
goto out_drop;
|
||||
}
|
||||
|
||||
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
||||
|
||||
sizestr = vol_args->name;
|
||||
cancel = (strcmp("cancel", sizestr) == 0);
|
||||
ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_RESIZE, cancel);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
/* Exclusive operation is now claimed */
|
||||
|
||||
devstr = strchr(sizestr, ':');
|
||||
if (devstr) {
|
||||
sizestr = devstr + 1;
|
||||
@ -1688,10 +1692,10 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
devstr = vol_args->name;
|
||||
ret = kstrtoull(devstr, 10, &devid);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
if (!devid) {
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
}
|
||||
btrfs_info(fs_info, "resizing devid %llu", devid);
|
||||
}
|
||||
@ -1701,7 +1705,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
btrfs_info(fs_info, "resizer unable to find device %llu",
|
||||
devid);
|
||||
ret = -ENODEV;
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
}
|
||||
|
||||
if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
|
||||
@ -1709,7 +1713,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
"resizer unable to apply on readonly device %llu",
|
||||
devid);
|
||||
ret = -EPERM;
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
}
|
||||
|
||||
if (!strcmp(sizestr, "max"))
|
||||
@ -1725,13 +1729,13 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
new_size = memparse(sizestr, &retptr);
|
||||
if (*retptr != '\0' || new_size == 0) {
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) {
|
||||
ret = -EPERM;
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
}
|
||||
|
||||
old_size = btrfs_device_get_total_bytes(device);
|
||||
@ -1739,24 +1743,24 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
if (mod < 0) {
|
||||
if (new_size > old_size) {
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
}
|
||||
new_size = old_size - new_size;
|
||||
} else if (mod > 0) {
|
||||
if (new_size > ULLONG_MAX - old_size) {
|
||||
ret = -ERANGE;
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
}
|
||||
new_size = old_size + new_size;
|
||||
}
|
||||
|
||||
if (new_size < SZ_256M) {
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
}
|
||||
if (new_size > device->bdev->bd_inode->i_size) {
|
||||
ret = -EFBIG;
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
}
|
||||
|
||||
new_size = round_down(new_size, fs_info->sectorsize);
|
||||
@ -1765,7 +1769,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
trans = btrfs_start_transaction(root, 0);
|
||||
if (IS_ERR(trans)) {
|
||||
ret = PTR_ERR(trans);
|
||||
goto out_free;
|
||||
goto out_finish;
|
||||
}
|
||||
ret = btrfs_grow_device(trans, device, new_size);
|
||||
btrfs_commit_transaction(trans);
|
||||
@ -1778,10 +1782,11 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
"resize device %s (devid %llu) from %llu to %llu",
|
||||
rcu_str_deref(device->name), device->devid,
|
||||
old_size, new_size);
|
||||
out_finish:
|
||||
btrfs_exclop_finish(fs_info);
|
||||
out_free:
|
||||
kfree(vol_args);
|
||||
out:
|
||||
btrfs_exclop_finish(fs_info);
|
||||
out_drop:
|
||||
mnt_drop_write_file(file);
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user