Message ID | 1658577730-11447-1-git-send-email-zhanglikernel@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | btrfs-progs: fix btrfs resize failed. | expand |
On 2022/7/23 20:02, Li Zhang wrote: > related issuse: > https://github.com/kdave/btrfs-progs/issues/470 > > V1 link: > https://www.spinics.net/lists/linux-btrfs/msg126661.html > > [BUG] > If there is no devid=1, when the user uses the btrfs file system tool, > the following error will be reported, > > $ sudo btrfs filesystem show /mnt/1 > Label: none uuid: 64dc0f68-9afa-4465-9ea1-2bbebfdb6cec > Total devices 2 FS bytes used 704.00KiB > devid 2 size 15.00GiB used 1.16GiB path /dev/loop2 > devid 3 size 15.00GiB used 1.16GiB path /dev/loop3 > $ sudo btrfs filesystem resize -1G /mnt/1 > ERROR: cannot find devid: 1 > ERROR: unable to resize '/mnt/1': No such device > > [CAUSE] > If the user does not specify the devid id explicitly, > btrfs will use the default devid 1, so it will report an error when dev 1 is missing. > > [FIX] > If the file system contains multiple devices, output an error message to the user. > > If the filesystem has only one device, resize should automatically add the unique devid. > > [RESULT] > > $ sudo btrfs filesystem show /mnt/1/ > Label: none uuid: 2025e6ae-0b6d-40b4-8685-3e7e9fc9b2c2 > Total devices 2 FS bytes used 144.00KiB > devid 2 size 15.00GiB used 1.16GiB path /dev/loop2 > devid 3 size 15.00GiB used 1.16GiB path /dev/loop3 > > $ sudo btrfs filesystem resize -1G /mnt/1 > ERROR: The file system has multiple devices, please specify devid exactly. > ERROR: The device information list is as follows. > devid 2 size 15.00GiB used 1.16GiB path /dev/loop2 > devid 3 size 15.00GiB used 1.16GiB path /dev/loop3 > > $ sudo btrfs device delete 2 /mnt/1/ > > $ sudo btrfs filesystem show /mnt/1/ > Label: none uuid: 2025e6ae-0b6d-40b4-8685-3e7e9fc9b2c2 > Total devices 1 FS bytes used 144.00KiB > devid 3 size 15.00GiB used 1.28GiB path /dev/loop3 > > $ sudo btrfs filesystem resize -1G /mnt/1 > Resize device id 3 (/dev/loop3) from 15.00GiB to 14.00GiB The new output and logic looks pretty good to me, but still some small nitpicks. > > Signed-off-by: Li Zhang <zhanglikernel@gmail.com> > --- > cmds/filesystem.c | 63 ++++++++++++++++++++++++++++++++++++++++++++----------- Shouldn't we also update the man page of "btrfs-filesystem"? Mostly to make it explicit when we can skip the devid/device path argument. > 1 file changed, 51 insertions(+), 12 deletions(-) > > diff --git a/cmds/filesystem.c b/cmds/filesystem.c > index 7cd08fc..c26ba2b 100644 > --- a/cmds/filesystem.c > +++ b/cmds/filesystem.c > @@ -1087,7 +1087,8 @@ static const char * const cmd_filesystem_resize_usage[] = { > NULL > }; > > -static int check_resize_args(const char *amount, const char *path) { > +static int check_resize_args(char * const amount, const char *path) > +{ > struct btrfs_ioctl_fs_info_args fi_args; > struct btrfs_ioctl_dev_info_args *di_args = NULL; > int ret, i, dev_idx = -1; > @@ -1102,7 +1103,8 @@ static int check_resize_args(const char *amount, const char *path) { > > if (ret) { > error("unable to retrieve fs info"); > - return 1; > + ret = 1; > + goto out; > } > > if (!fi_args.num_devices) { > @@ -1112,11 +1114,14 @@ static int check_resize_args(const char *amount, const char *path) { > } > > ret = snprintf(amount_dup, BTRFS_VOL_NAME_MAX, "%s", amount); > +check: > if (strlen(amount) != ret) { > error("newsize argument is too long"); > ret = 1; > goto out; > } > + if (strcmp(amount, amount_dup) != 0) > + strcpy(amount, amount_dup); > > sizestr = amount_dup; > devstr = strchr(sizestr, ':'); > @@ -1133,6 +1138,24 @@ static int check_resize_args(const char *amount, const char *path) { > ret = 1; > goto out; > } > + } else if (fi_args.num_devices != 1) { > + error("The file system has multiple devices, please specify devid exactly."); > + error("The device information list is as follows."); > + for (i = 0; i < fi_args.num_devices; i++) { > + fprintf(stderr, "\tdevid %4llu size %s used %s path %s\n", > + di_args[i].devid, > + pretty_size_mode(di_args[i].total_bytes, UNITS_DEFAULT), > + pretty_size_mode(di_args[i].bytes_used, UNITS_DEFAULT), > + di_args[i].path); > + } > + ret = 1; > + goto out; > + } else { > + memset(amount_dup, 0, BTRFS_VOL_NAME_MAX); > + ret = snprintf(amount_dup, BTRFS_VOL_NAME_MAX, "%llu:", di_args[0].devid); > + ret = snprintf(amount_dup + strlen(amount_dup), > + BTRFS_VOL_NAME_MAX - strlen(amount_dup), "%s", amount); > + goto check; > } > > dev_idx = -1; > @@ -1200,10 +1223,11 @@ static int check_resize_args(const char *amount, const char *path) { > di_args[dev_idx].path, > pretty_size_mode(di_args[dev_idx].total_bytes, UNITS_DEFAULT), > res_str); > + ret = 1; Previously if we reach this path, we should have everything prepared and return 0. But now it always return 1, is that expected? Especially the only caller will just error out if the return value is not 0. > > out: > free(di_args); > - return 0; > + return ret; In fact, this turns out to be an existing bug, there are quite a lot of existing paths setting ret to 1, and goto out to return error. Those error paths are not properly handled previously. Thus changing the out: label to return @ret is in fact a bug fix. Not sure if we need to split the patch into two, one to fix the return value first, then introduce the new behavior. > } > > static int cmd_filesystem_resize(const struct cmd_struct *cmd, > @@ -1235,8 +1259,10 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > } > } > > - if (check_argc_exact(argc - optind, 2)) > - return 1; > + if (check_argc_exact(argc - optind, 2)) { > + ret = 1; > + goto out; > + } > > amount = argv[optind]; > path = argv[optind + 1]; > @@ -1244,7 +1270,8 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > len = strlen(amount); > if (len == 0 || len >= BTRFS_VOL_NAME_MAX) { > error("resize value too long (%s)", amount); > - return 1; > + ret = 1; > + goto out; This change doesn't look necessary, the new out label is just returning the @ret value, not really worthy a new label. > } > > cancel = (strcmp("cancel", amount) == 0); > @@ -1258,7 +1285,8 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > "directories as argument. Passing file containing a btrfs image\n" > "would resize the underlying filesystem instead of the image.\n"); > } > - return 1; > + ret = 1; > + goto out; The same here. > } > > /* > @@ -1273,14 +1301,22 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > error( > "unable to check status of exclusive operation: %m"); > close_file_or_dir(fd, dirstream); > - return 1; > + goto out; And here. > } > } > > + amount = (char *)malloc(BTRFS_VOL_NAME_MAX); No need to do the type cast, (void *) can be assigned to any pointer type without the need to type cast. > + if (!amount) { > + ret = -ENOMEM; > + goto out; The same here too. Thanks, Qu > + } > + strcpy(amount, argv[optind]); > + > ret = check_resize_args(amount, path); > if (ret != 0) { > close_file_or_dir(fd, dirstream); > - return 1; > + ret = 1; > + goto free_amount; > } > > memset(&args, 0, sizeof(args)); > @@ -1298,7 +1334,7 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > error("unable to resize '%s': %m", path); > break; > } > - return 1; > + ret = 1; > } else if (res > 0) { > const char *err_str = btrfs_err_str(res); > > @@ -1308,9 +1344,12 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > error("resizing of '%s' failed: unknown error %d", > path, res); > } > - return 1; > + ret = 1; > } > - return 0; > +free_amount: > + free(amount); > +out: > + return ret; > } > static DEFINE_SIMPLE_COMMAND(filesystem_resize, "resize"); >
sorry, my fault, this code @@ -1200,10 +1223,11 @@ static int check_resize_args(const char *amount, const char *path) { di_args[dev_idx].path, pretty_size_mode(di_args[dev_idx].total_bytes, UNITS_DEFAULT), res_str); + ret = 1; should be ret = 0 And for new label out, I think you are right, it doesn't need a label that does nothing, I will correct my patch. thanks, Li Qu Wenruo <wqu@suse.com> 于2022年7月24日周日 07:21写道: > > > > On 2022/7/23 20:02, Li Zhang wrote: > > related issuse: > > https://github.com/kdave/btrfs-progs/issues/470 > > > > V1 link: > > https://www.spinics.net/lists/linux-btrfs/msg126661.html > > > > [BUG] > > If there is no devid=1, when the user uses the btrfs file system tool, > > the following error will be reported, > > > > $ sudo btrfs filesystem show /mnt/1 > > Label: none uuid: 64dc0f68-9afa-4465-9ea1-2bbebfdb6cec > > Total devices 2 FS bytes used 704.00KiB > > devid 2 size 15.00GiB used 1.16GiB path /dev/loop2 > > devid 3 size 15.00GiB used 1.16GiB path /dev/loop3 > > $ sudo btrfs filesystem resize -1G /mnt/1 > > ERROR: cannot find devid: 1 > > ERROR: unable to resize '/mnt/1': No such device > > > > [CAUSE] > > If the user does not specify the devid id explicitly, > > btrfs will use the default devid 1, so it will report an error when dev 1 is missing. > > > > [FIX] > > If the file system contains multiple devices, output an error message to the user. > > > > If the filesystem has only one device, resize should automatically add the unique devid. > > > > [RESULT] > > > > $ sudo btrfs filesystem show /mnt/1/ > > Label: none uuid: 2025e6ae-0b6d-40b4-8685-3e7e9fc9b2c2 > > Total devices 2 FS bytes used 144.00KiB > > devid 2 size 15.00GiB used 1.16GiB path /dev/loop2 > > devid 3 size 15.00GiB used 1.16GiB path /dev/loop3 > > > > $ sudo btrfs filesystem resize -1G /mnt/1 > > ERROR: The file system has multiple devices, please specify devid exactly. > > ERROR: The device information list is as follows. > > devid 2 size 15.00GiB used 1.16GiB path /dev/loop2 > > devid 3 size 15.00GiB used 1.16GiB path /dev/loop3 > > > > $ sudo btrfs device delete 2 /mnt/1/ > > > > $ sudo btrfs filesystem show /mnt/1/ > > Label: none uuid: 2025e6ae-0b6d-40b4-8685-3e7e9fc9b2c2 > > Total devices 1 FS bytes used 144.00KiB > > devid 3 size 15.00GiB used 1.28GiB path /dev/loop3 > > > > $ sudo btrfs filesystem resize -1G /mnt/1 > > Resize device id 3 (/dev/loop3) from 15.00GiB to 14.00GiB > > The new output and logic looks pretty good to me, but still some small > nitpicks. > > > > > Signed-off-by: Li Zhang <zhanglikernel@gmail.com> > > --- > > cmds/filesystem.c | 63 ++++++++++++++++++++++++++++++++++++++++++++----------- > > Shouldn't we also update the man page of "btrfs-filesystem"? > Mostly to make it explicit when we can skip the devid/device path argument. > > > 1 file changed, 51 insertions(+), 12 deletions(-) > > > > diff --git a/cmds/filesystem.c b/cmds/filesystem.c > > index 7cd08fc..c26ba2b 100644 > > --- a/cmds/filesystem.c > > +++ b/cmds/filesystem.c > > @@ -1087,7 +1087,8 @@ static const char * const cmd_filesystem_resize_usage[] = { > > NULL > > }; > > > > -static int check_resize_args(const char *amount, const char *path) { > > +static int check_resize_args(char * const amount, const char *path) > > +{ > > struct btrfs_ioctl_fs_info_args fi_args; > > struct btrfs_ioctl_dev_info_args *di_args = NULL; > > int ret, i, dev_idx = -1; > > @@ -1102,7 +1103,8 @@ static int check_resize_args(const char *amount, const char *path) { > > > > if (ret) { > > error("unable to retrieve fs info"); > > - return 1; > > + ret = 1; > > + goto out; > > } > > > > if (!fi_args.num_devices) { > > @@ -1112,11 +1114,14 @@ static int check_resize_args(const char *amount, const char *path) { > > } > > > > ret = snprintf(amount_dup, BTRFS_VOL_NAME_MAX, "%s", amount); > > +check: > > if (strlen(amount) != ret) { > > error("newsize argument is too long"); > > ret = 1; > > goto out; > > } > > + if (strcmp(amount, amount_dup) != 0) > > + strcpy(amount, amount_dup); > > > > sizestr = amount_dup; > > devstr = strchr(sizestr, ':'); > > @@ -1133,6 +1138,24 @@ static int check_resize_args(const char *amount, const char *path) { > > ret = 1; > > goto out; > > } > > + } else if (fi_args.num_devices != 1) { > > + error("The file system has multiple devices, please specify devid exactly."); > > + error("The device information list is as follows."); > > + for (i = 0; i < fi_args.num_devices; i++) { > > + fprintf(stderr, "\tdevid %4llu size %s used %s path %s\n", > > + di_args[i].devid, > > + pretty_size_mode(di_args[i].total_bytes, UNITS_DEFAULT), > > + pretty_size_mode(di_args[i].bytes_used, UNITS_DEFAULT), > > + di_args[i].path); > > + } > > + ret = 1; > > + goto out; > > + } else { > > + memset(amount_dup, 0, BTRFS_VOL_NAME_MAX); > > + ret = snprintf(amount_dup, BTRFS_VOL_NAME_MAX, "%llu:", di_args[0].devid); > > + ret = snprintf(amount_dup + strlen(amount_dup), > > + BTRFS_VOL_NAME_MAX - strlen(amount_dup), "%s", amount); > > + goto check; > > } > > > > dev_idx = -1; > > @@ -1200,10 +1223,11 @@ static int check_resize_args(const char *amount, const char *path) { > > di_args[dev_idx].path, > > pretty_size_mode(di_args[dev_idx].total_bytes, UNITS_DEFAULT), > > res_str); > > + ret = 1; > > Previously if we reach this path, we should have everything prepared and > return 0. > > But now it always return 1, is that expected? Especially the only caller > will just error out if the return value is not 0. > > > > > out: > > free(di_args); > > - return 0; > > + return ret; > > In fact, this turns out to be an existing bug, there are quite a lot of > existing paths setting ret to 1, and goto out to return error. > > Those error paths are not properly handled previously. > > Thus changing the out: label to return @ret is in fact a bug fix. > > Not sure if we need to split the patch into two, one to fix the return > value first, then introduce the new behavior. > > > } > > > > static int cmd_filesystem_resize(const struct cmd_struct *cmd, > > @@ -1235,8 +1259,10 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > > } > > } > > > > - if (check_argc_exact(argc - optind, 2)) > > - return 1; > > + if (check_argc_exact(argc - optind, 2)) { > > + ret = 1; > > + goto out; > > + } > > > > amount = argv[optind]; > > path = argv[optind + 1]; > > @@ -1244,7 +1270,8 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > > len = strlen(amount); > > if (len == 0 || len >= BTRFS_VOL_NAME_MAX) { > > error("resize value too long (%s)", amount); > > - return 1; > > + ret = 1; > > + goto out; > > This change doesn't look necessary, the new out label is just returning > the @ret value, not really worthy a new label. > > > } > > > > cancel = (strcmp("cancel", amount) == 0); > > @@ -1258,7 +1285,8 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > > "directories as argument. Passing file containing a btrfs image\n" > > "would resize the underlying filesystem instead of the image.\n"); > > } > > - return 1; > > + ret = 1; > > + goto out; > > The same here. > > > } > > > > /* > > @@ -1273,14 +1301,22 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > > error( > > "unable to check status of exclusive operation: %m"); > > close_file_or_dir(fd, dirstream); > > - return 1; > > + goto out; > > And here. > > > } > > } > > > > + amount = (char *)malloc(BTRFS_VOL_NAME_MAX); > > No need to do the type cast, (void *) can be assigned to any pointer > type without the need to type cast. > > > + if (!amount) { > > + ret = -ENOMEM; > > + goto out; > > The same here too. > > Thanks, > Qu > > > + } > > + strcpy(amount, argv[optind]); > > + > > ret = check_resize_args(amount, path); > > if (ret != 0) { > > close_file_or_dir(fd, dirstream); > > - return 1; > > + ret = 1; > > + goto free_amount; > > } > > > > memset(&args, 0, sizeof(args)); > > @@ -1298,7 +1334,7 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > > error("unable to resize '%s': %m", path); > > break; > > } > > - return 1; > > + ret = 1; > > } else if (res > 0) { > > const char *err_str = btrfs_err_str(res); > > > > @@ -1308,9 +1344,12 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, > > error("resizing of '%s' failed: unknown error %d", > > path, res); > > } > > - return 1; > > + ret = 1; > > } > > - return 0; > > +free_amount: > > + free(amount); > > +out: > > + return ret; > > } > > static DEFINE_SIMPLE_COMMAND(filesystem_resize, "resize"); > >
diff --git a/cmds/filesystem.c b/cmds/filesystem.c index 7cd08fc..c26ba2b 100644 --- a/cmds/filesystem.c +++ b/cmds/filesystem.c @@ -1087,7 +1087,8 @@ static const char * const cmd_filesystem_resize_usage[] = { NULL }; -static int check_resize_args(const char *amount, const char *path) { +static int check_resize_args(char * const amount, const char *path) +{ struct btrfs_ioctl_fs_info_args fi_args; struct btrfs_ioctl_dev_info_args *di_args = NULL; int ret, i, dev_idx = -1; @@ -1102,7 +1103,8 @@ static int check_resize_args(const char *amount, const char *path) { if (ret) { error("unable to retrieve fs info"); - return 1; + ret = 1; + goto out; } if (!fi_args.num_devices) { @@ -1112,11 +1114,14 @@ static int check_resize_args(const char *amount, const char *path) { } ret = snprintf(amount_dup, BTRFS_VOL_NAME_MAX, "%s", amount); +check: if (strlen(amount) != ret) { error("newsize argument is too long"); ret = 1; goto out; } + if (strcmp(amount, amount_dup) != 0) + strcpy(amount, amount_dup); sizestr = amount_dup; devstr = strchr(sizestr, ':'); @@ -1133,6 +1138,24 @@ static int check_resize_args(const char *amount, const char *path) { ret = 1; goto out; } + } else if (fi_args.num_devices != 1) { + error("The file system has multiple devices, please specify devid exactly."); + error("The device information list is as follows."); + for (i = 0; i < fi_args.num_devices; i++) { + fprintf(stderr, "\tdevid %4llu size %s used %s path %s\n", + di_args[i].devid, + pretty_size_mode(di_args[i].total_bytes, UNITS_DEFAULT), + pretty_size_mode(di_args[i].bytes_used, UNITS_DEFAULT), + di_args[i].path); + } + ret = 1; + goto out; + } else { + memset(amount_dup, 0, BTRFS_VOL_NAME_MAX); + ret = snprintf(amount_dup, BTRFS_VOL_NAME_MAX, "%llu:", di_args[0].devid); + ret = snprintf(amount_dup + strlen(amount_dup), + BTRFS_VOL_NAME_MAX - strlen(amount_dup), "%s", amount); + goto check; } dev_idx = -1; @@ -1200,10 +1223,11 @@ static int check_resize_args(const char *amount, const char *path) { di_args[dev_idx].path, pretty_size_mode(di_args[dev_idx].total_bytes, UNITS_DEFAULT), res_str); + ret = 1; out: free(di_args); - return 0; + return ret; } static int cmd_filesystem_resize(const struct cmd_struct *cmd, @@ -1235,8 +1259,10 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, } } - if (check_argc_exact(argc - optind, 2)) - return 1; + if (check_argc_exact(argc - optind, 2)) { + ret = 1; + goto out; + } amount = argv[optind]; path = argv[optind + 1]; @@ -1244,7 +1270,8 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, len = strlen(amount); if (len == 0 || len >= BTRFS_VOL_NAME_MAX) { error("resize value too long (%s)", amount); - return 1; + ret = 1; + goto out; } cancel = (strcmp("cancel", amount) == 0); @@ -1258,7 +1285,8 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, "directories as argument. Passing file containing a btrfs image\n" "would resize the underlying filesystem instead of the image.\n"); } - return 1; + ret = 1; + goto out; } /* @@ -1273,14 +1301,22 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, error( "unable to check status of exclusive operation: %m"); close_file_or_dir(fd, dirstream); - return 1; + goto out; } } + amount = (char *)malloc(BTRFS_VOL_NAME_MAX); + if (!amount) { + ret = -ENOMEM; + goto out; + } + strcpy(amount, argv[optind]); + ret = check_resize_args(amount, path); if (ret != 0) { close_file_or_dir(fd, dirstream); - return 1; + ret = 1; + goto free_amount; } memset(&args, 0, sizeof(args)); @@ -1298,7 +1334,7 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, error("unable to resize '%s': %m", path); break; } - return 1; + ret = 1; } else if (res > 0) { const char *err_str = btrfs_err_str(res); @@ -1308,9 +1344,12 @@ static int cmd_filesystem_resize(const struct cmd_struct *cmd, error("resizing of '%s' failed: unknown error %d", path, res); } - return 1; + ret = 1; } - return 0; +free_amount: + free(amount); +out: + return ret; } static DEFINE_SIMPLE_COMMAND(filesystem_resize, "resize");
related issuse: https://github.com/kdave/btrfs-progs/issues/470 V1 link: https://www.spinics.net/lists/linux-btrfs/msg126661.html [BUG] If there is no devid=1, when the user uses the btrfs file system tool, the following error will be reported, $ sudo btrfs filesystem show /mnt/1 Label: none uuid: 64dc0f68-9afa-4465-9ea1-2bbebfdb6cec Total devices 2 FS bytes used 704.00KiB devid 2 size 15.00GiB used 1.16GiB path /dev/loop2 devid 3 size 15.00GiB used 1.16GiB path /dev/loop3 $ sudo btrfs filesystem resize -1G /mnt/1 ERROR: cannot find devid: 1 ERROR: unable to resize '/mnt/1': No such device [CAUSE] If the user does not specify the devid id explicitly, btrfs will use the default devid 1, so it will report an error when dev 1 is missing. [FIX] If the file system contains multiple devices, output an error message to the user. If the filesystem has only one device, resize should automatically add the unique devid. [RESULT] $ sudo btrfs filesystem show /mnt/1/ Label: none uuid: 2025e6ae-0b6d-40b4-8685-3e7e9fc9b2c2 Total devices 2 FS bytes used 144.00KiB devid 2 size 15.00GiB used 1.16GiB path /dev/loop2 devid 3 size 15.00GiB used 1.16GiB path /dev/loop3 $ sudo btrfs filesystem resize -1G /mnt/1 ERROR: The file system has multiple devices, please specify devid exactly. ERROR: The device information list is as follows. devid 2 size 15.00GiB used 1.16GiB path /dev/loop2 devid 3 size 15.00GiB used 1.16GiB path /dev/loop3 $ sudo btrfs device delete 2 /mnt/1/ $ sudo btrfs filesystem show /mnt/1/ Label: none uuid: 2025e6ae-0b6d-40b4-8685-3e7e9fc9b2c2 Total devices 1 FS bytes used 144.00KiB devid 3 size 15.00GiB used 1.28GiB path /dev/loop3 $ sudo btrfs filesystem resize -1G /mnt/1 Resize device id 3 (/dev/loop3) from 15.00GiB to 14.00GiB Signed-off-by: Li Zhang <zhanglikernel@gmail.com> --- cmds/filesystem.c | 63 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 12 deletions(-)