btrfs-progs: subvolume delete: add new option for recursive deletion

Add new option --recursive 'btrfs subvol delete', causing it to pass the
BTRFS_UTIL_DELETE_SUBVOLUME_RECURSIVE flag through to libbtrfsutil.

This can work in two modes, depending on the user:

- regular user - this will skip subvolumes that are not accessible
- root (CAP_SYS_ADMIN) - no limitations

Pull-request: #861
Signed-off-by: Mark Harmstone <maharmstone@meta.com>
Co-authored-by: Omar Sandoval <osandov@osandov.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
[ Add details to man page, fix indent in the doc. ]
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Omar Sandoval 2024-06-27 16:21:38 +01:00 committed by David Sterba
parent 8859114eae
commit afd02e4dcb
2 changed files with 23 additions and 2 deletions

View File

@ -112,6 +112,15 @@ delete [options] [<subvolume> [<subvolume>...]], delete -i|--subvolid <subvolid>
-i|--subvolid <subvolid>
subvolume id to be removed instead of the <path> that should point to the
filesystem with the subvolume
-R|--recursive
delete subvolumes beneath each subvolume recursively
This requires either `CAP_SYS_ADMIN` or the filesystem must be
mounted with `user_subvol_rm_allowed` mount option.
In the unprivileged case, subvolumes which cannot be accessed
are skipped. The deletion is not atomic.
-v|--verbose
(deprecated) alias for global *-v* option

View File

@ -347,6 +347,8 @@ static const char * const cmd_subvolume_delete_usage[] = {
OPTLINE("-c|--commit-after", "wait for transaction commit at the end of the operation"),
OPTLINE("-C|--commit-each", "wait for transaction commit after deleting each subvolume"),
OPTLINE("-i|--subvolid", "subvolume id of the to be removed subvolume"),
OPTLINE("-R|--recursive", "delete accessible subvolumes beneath each subvolume recursively, "
"this is not atomic, may need root to delete subvolumes not accessible by the user"),
OPTLINE("-v|--verbose", "deprecated, alias for global -v option"),
HELPINFO_INSERT_GLOBALS,
HELPINFO_INSERT_VERBOSE,
@ -367,6 +369,7 @@ static int cmd_subvolume_delete(const struct cmd_struct *cmd, int argc, char **a
char *path = NULL;
int commit_mode = 0;
bool subvol_path_not_found = false;
int flags = 0;
u8 fsid[BTRFS_FSID_SIZE];
u64 subvolid = 0;
char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
@ -383,11 +386,12 @@ static int cmd_subvolume_delete(const struct cmd_struct *cmd, int argc, char **a
{"commit-after", no_argument, NULL, 'c'},
{"commit-each", no_argument, NULL, 'C'},
{"subvolid", required_argument, NULL, 'i'},
{"recursive", no_argument, NULL, 'R'},
{"verbose", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0}
};
c = getopt_long(argc, argv, "cCi:v", long_options, NULL);
c = getopt_long(argc, argv, "cCi:Rv", long_options, NULL);
if (c < 0)
break;
@ -401,6 +405,9 @@ static int cmd_subvolume_delete(const struct cmd_struct *cmd, int argc, char **a
case 'i':
subvolid = arg_strtou64(optarg);
break;
case 'R':
flags |= BTRFS_UTIL_DELETE_SUBVOLUME_RECURSIVE;
break;
case 'v':
bconf_be_verbose();
break;
@ -416,6 +423,11 @@ static int cmd_subvolume_delete(const struct cmd_struct *cmd, int argc, char **a
if (subvolid > 0 && check_argc_exact(argc - optind, 1))
return 1;
if (subvolid > 0 && flags & BTRFS_UTIL_DELETE_SUBVOLUME_RECURSIVE) {
error("option --recursive is not supported with --subvolid");
return 1;
}
pr_verbose(LOG_INFO, "Transaction commit: %s\n",
!commit_mode ? "none (default)" :
commit_mode == COMMIT_AFTER ? "at the end" : "after each");
@ -528,7 +540,7 @@ again:
/* Start deleting. */
if (subvolid == 0)
err = btrfs_util_delete_subvolume_fd(fd, vname, 0);
err = btrfs_util_delete_subvolume_fd(fd, vname, flags);
else
err = btrfs_util_delete_subvolume_by_id_fd(fd, subvolid);
if (err) {