From 80df942fe7e7b22f2dc62f597be0b8da6fefc43a Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Tue, 25 Aug 2020 10:03:37 -0500 Subject: [PATCH] btrfs-progs: check for exclusive operation before issuing another If the exclusive operation is available in sysfs file, check if there's one already running. The check is done for: - device add, remove, replace - balance - filesystem resize All commands will validate arguments and check before the ioctl or before any potentially irreversible operations (like clearing device before replacing). Signed-off-by: Goldwyn Rodrigues Signed-off-by: David Sterba --- cmds/balance.c | 10 ++++++++++ cmds/device.c | 20 ++++++++++++++++++++ cmds/filesystem.c | 10 ++++++++++ cmds/replace.c | 12 ++++++++++++ 4 files changed, 52 insertions(+) diff --git a/cmds/balance.c b/cmds/balance.c index 43812b24..7cad15b1 100644 --- a/cmds/balance.c +++ b/cmds/balance.c @@ -436,11 +436,21 @@ static int do_balance(const char *path, struct btrfs_ioctl_balance_args *args, int fd; int ret; DIR *dirstream = NULL; + int exclop; fd = btrfs_open_dir(path, &dirstream, 1); if (fd < 0) return 1; + exclop = get_fs_exclop(fd); + if (exclop > 0 ) { + error( + "unable to start balance, another exclusive operation '%s' in progress", + get_fs_exclop_name(exclop)); + close_file_or_dir(fd, dirstream); + return 1; + } + ret = ioctl(fd, BTRFS_IOC_BALANCE_V2, args); if (ret < 0) { /* diff --git a/cmds/device.c b/cmds/device.c index d72881f8..1034bc9e 100644 --- a/cmds/device.c +++ b/cmds/device.c @@ -61,6 +61,7 @@ static int cmd_device_add(const struct cmd_struct *cmd, int discard = 1; int force = 0; int last_dev; + int exclop; optind = 0; while (1) { @@ -96,6 +97,15 @@ static int cmd_device_add(const struct cmd_struct *cmd, if (fdmnt < 0) return 1; + exclop = get_fs_exclop(fdmnt); + if (exclop > 0) { + error( + "unable to start device add, another exclusive operation '%s' in progress", + get_fs_exclop_name(exclop)); + close_file_or_dir(fdmnt, dirstream); + return 1; + } + for (i = optind; i < last_dev; i++){ struct btrfs_ioctl_vol_args ioctl_args; int devfd, res; @@ -155,6 +165,7 @@ static int _cmd_device_remove(const struct cmd_struct *cmd, char *mntpnt; int i, fdmnt, ret = 0; DIR *dirstream = NULL; + int exclop; clean_args_no_options(cmd, argc, argv); @@ -167,6 +178,15 @@ static int _cmd_device_remove(const struct cmd_struct *cmd, if (fdmnt < 0) return 1; + exclop = get_fs_exclop(fdmnt); + if (exclop > 0 ) { + error( + "unable to start device remove, another exclusive operation '%s' in progress", + get_fs_exclop_name(exclop)); + close_file_or_dir(fdmnt, dirstream); + return 1; + } + for(i = optind; i < argc - 1; i++) { struct btrfs_ioctl_vol_args arg; struct btrfs_ioctl_vol_args_v2 argv2 = {0}; diff --git a/cmds/filesystem.c b/cmds/filesystem.c index 5d94b3dc..9a943227 100644 --- a/cmds/filesystem.c +++ b/cmds/filesystem.c @@ -1079,6 +1079,7 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, char *amount, *path; DIR *dirstream = NULL; struct stat st; + int exclop; clean_args_no_options_relaxed(cmd, argc, argv); @@ -1110,6 +1111,15 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, if (fd < 0) return 1; + exclop = get_fs_exclop(fd); + if (exclop > 0) { + error( +"unable to start filesystem resize, nother exclusive operation '%s' in progress", + get_fs_exclop_name(exclop)); + close_file_or_dir(fd, dirstream); + return 1; + } + printf("Resize '%s' of '%s'\n", path, amount); memset(&args, 0, sizeof(args)); strncpy_null(args.name, amount); diff --git a/cmds/replace.c b/cmds/replace.c index 7c4ca81c..ebd3c7c6 100644 --- a/cmds/replace.c +++ b/cmds/replace.c @@ -136,6 +136,7 @@ static int cmd_replace_start(const struct cmd_struct *cmd, DIR *dirstream = NULL; u64 srcdev_size; u64 dstdev_size; + int exclop; optind = 0; while ((c = getopt(argc, argv, "Brf")) != -1) { @@ -257,6 +258,17 @@ static int cmd_replace_start(const struct cmd_struct *cmd, error("unable to open %s: %m", dstdev); goto leave_with_error; } + + /* Check status before any potentially destructive operation */ + exclop = get_fs_exclop(fdmnt); + if (exclop > 0) { + error( + "unable to start device replace, another exclusive operation '%s' in progress", + get_fs_exclop_name(exclop)); + close_file_or_dir(fdmnt, dirstream); + goto leave_with_error; + } + strncpy((char *)start_args.start.tgtdev_name, dstdev, BTRFS_DEVICE_PATH_NAME_MAX); ret = btrfs_prepare_device(fddstdev, dstdev, &dstdev_block_count, 0,