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:
parent
e07de81c28
commit
9246667a22
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue