Added limited/recursive operation to `zfs unmount`

This commit introduces limited/recursive filesystem unmounting by
leveraging the existing `zfs unmount -a` codebase with minor additions
and modifications.

Now, when running `zfs unmount <-a|-A> zpool/dataset`, the command will
unmount all datasets that are the specified dataset itself or it's
children, provided they are available. In addition, `-A` flag  will also
mount datasets with `canmount=noauto` property.

Changes in `zfs_main.c`:
- `HELP_UNMOUNT`
  - Updated `usage()` message to reflect the changes.
- `unshare_unmount()`
  - Changed `do_all` from `int` to `boolean_t`
  - Added `boolean_t do_noauto` property; used for mounting datasets
    with `canmount=noauto` as `canmount=on`.
  - Added the `-A` flag; when used sets `do_noauto` to `B_TRUE`.
  - Updated argument check; displaies the correct error messages.
  - Limited the usage of `<-a|-A> filesystem` to `zfs unmount` only
  - Added a check; to validate that the specified filesystem is indeed a
    valid ZFS filesystem.
  - Modified the 'noauto' check; when unmounting datasets,
    if `do_noauto` is true, treat the unmount as if `canmount=on`.
  - Added a check; if `filesystem` is set, skips any datasets that are
    not `filesystem` itself or it's children.

Signed-off-by: QORTEC <lowell.bv@gmail.com>
This commit is contained in:
QORTEC 2023-10-10 18:06:08 -04:00
parent e07de81c28
commit 9246667a22
1 changed files with 42 additions and 8 deletions

View File

@ -347,7 +347,7 @@ get_usage(zfs_help_t idx)
"<filesystem|volume>@<snap> ...\n"));
case HELP_UNMOUNT:
return (gettext("\tunmount [-fu] "
"<-a | filesystem|mountpoint>\n"));
"<-a [filesystem] | [-A] filesystem|mountpoint>\n"));
case HELP_UNSHARE:
return (gettext("\tunshare "
"<-a [nfs|smb] | filesystem|mountpoint>\n"));
@ -7488,7 +7488,8 @@ out:
static int
unshare_unmount(int op, int argc, char **argv)
{
int do_all = 0;
boolean_t do_all = B_FALSE;
boolean_t do_noauto = B_FALSE;
int flags = 0;
int ret = 0;
int c;
@ -7497,10 +7498,13 @@ unshare_unmount(int op, int argc, char **argv)
char sharesmb[ZFS_MAXPROPLEN];
/* check options */
while ((c = getopt(argc, argv, op == OP_SHARE ? ":a" : "afu")) != -1) {
while ((c = getopt(argc, argv, op == OP_SHARE ? ":a" : "aAfu")) != -1) {
switch (c) {
case 'a':
do_all = 1;
do_all = B_TRUE;
break;
case 'A':
do_noauto = B_TRUE;
break;
case 'f':
flags |= MS_FORCE;
@ -7523,7 +7527,7 @@ unshare_unmount(int op, int argc, char **argv)
argc -= optind;
argv += optind;
if (do_all) {
if (do_all || do_noauto) {
/*
* We could make use of zfs_for_each() to walk all datasets in
* the system, but this would be very inefficient, especially
@ -7555,11 +7559,31 @@ unshare_unmount(int op, int argc, char **argv)
argv++;
}
if (argc != 0) {
/* check number of arguments */
if (do_noauto && argc < 1) {
(void) fprintf(stderr, gettext("missing "
"dataset argument\n"));
usage(B_FALSE);
}
if ((op == OP_SHARE && argc != 0) || argc > 1) {
(void) fprintf(stderr, gettext("too many arguments\n"));
usage(B_FALSE);
}
/*
* Limit `-a filesystem` to unmount only
*/
const char *filesystem = NULL;
if (op == OP_MOUNT)
filesystem = argv[0];
/*
* Validate filesystem is actually a valid zfs filesystem
*/
if (filesystem != NULL && (zhp = zfs_open(g_zfs,
filesystem, ZFS_TYPE_FILESYSTEM)) == NULL)
return (1);
if (((pool = uu_avl_pool_create("unmount_pool",
sizeof (unshare_unmount_node_t),
offsetof(unshare_unmount_node_t, un_avlnode),
@ -7621,15 +7645,25 @@ unshare_unmount(int op, int argc, char **argv)
NULL, NULL, 0, B_FALSE) == 0);
if (strcmp(nfs_mnt_prop, "legacy") == 0)
continue;
/* Ignore canmount=noauto mounts */
/*
* Ignore canmount=noauto mounts if
* 'do_noauto' is set to false (default: false)
*/
if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
ZFS_CANMOUNT_NOAUTO)
ZFS_CANMOUNT_NOAUTO && !do_noauto)
continue;
break;
default:
break;
}
/*
* Skip any dataset that's not related to filesystem.
*/
if (filesystem != NULL &&
!zfs_dataset_related(zhp, filesystem))
continue;
node = safe_malloc(sizeof (unshare_unmount_node_t));
node->un_zhp = zhp;
node->un_mountp = safe_strdup(entry.mnt_mountp);