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")); "<filesystem|volume>@<snap> ...\n"));
case HELP_UNMOUNT: case HELP_UNMOUNT:
return (gettext("\tunmount [-fu] " return (gettext("\tunmount [-fu] "
"<-a | filesystem|mountpoint>\n")); "<-a [filesystem] | [-A] filesystem|mountpoint>\n"));
case HELP_UNSHARE: case HELP_UNSHARE:
return (gettext("\tunshare " return (gettext("\tunshare "
"<-a [nfs|smb] | filesystem|mountpoint>\n")); "<-a [nfs|smb] | filesystem|mountpoint>\n"));
@ -7488,7 +7488,8 @@ out:
static int static int
unshare_unmount(int op, int argc, char **argv) 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 flags = 0;
int ret = 0; int ret = 0;
int c; int c;
@ -7497,10 +7498,13 @@ unshare_unmount(int op, int argc, char **argv)
char sharesmb[ZFS_MAXPROPLEN]; char sharesmb[ZFS_MAXPROPLEN];
/* check options */ /* 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) { switch (c) {
case 'a': case 'a':
do_all = 1; do_all = B_TRUE;
break;
case 'A':
do_noauto = B_TRUE;
break; break;
case 'f': case 'f':
flags |= MS_FORCE; flags |= MS_FORCE;
@ -7523,7 +7527,7 @@ unshare_unmount(int op, int argc, char **argv)
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (do_all) { if (do_all || do_noauto) {
/* /*
* We could make use of zfs_for_each() to walk all datasets in * We could make use of zfs_for_each() to walk all datasets in
* the system, but this would be very inefficient, especially * the system, but this would be very inefficient, especially
@ -7555,11 +7559,31 @@ unshare_unmount(int op, int argc, char **argv)
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")); (void) fprintf(stderr, gettext("too many arguments\n"));
usage(B_FALSE); 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", if (((pool = uu_avl_pool_create("unmount_pool",
sizeof (unshare_unmount_node_t), sizeof (unshare_unmount_node_t),
offsetof(unshare_unmount_node_t, un_avlnode), 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); NULL, NULL, 0, B_FALSE) == 0);
if (strcmp(nfs_mnt_prop, "legacy") == 0) if (strcmp(nfs_mnt_prop, "legacy") == 0)
continue; 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) == if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
ZFS_CANMOUNT_NOAUTO) ZFS_CANMOUNT_NOAUTO && !do_noauto)
continue; continue;
break; break;
default: default:
break; 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 = safe_malloc(sizeof (unshare_unmount_node_t));
node->un_zhp = zhp; node->un_zhp = zhp;
node->un_mountp = safe_strdup(entry.mnt_mountp); node->un_mountp = safe_strdup(entry.mnt_mountp);