Fix changelist mounted-dataset iteration

Commit 0c6d093 caused a regression in the inherit codepath.
The fix is to restrict the changelist iteration on mountpoints and
add proper handling for 'legacy' mountpoints

Reviewed by: Serapheim Dimitropoulos <serapheim.dimitro@delphix.com>
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Alek Pinchuk <apinchuk@datto.com>
Closes #7988 
Closes #7991
This commit is contained in:
Alek P
2018-10-11 00:13:13 -04:00
committed by Brian Behlendorf
parent 5b3bfd86a4
commit 50a343d85c
9 changed files with 201 additions and 28 deletions
+33 -22
View File
@@ -553,39 +553,50 @@ change_one(zfs_handle_t *zhp, void *data)
return (0);
}
/*ARGSUSED*/
static int
compare_mountpoints(const void *a, const void *b, void *unused)
compare_props(const void *a, const void *b, zfs_prop_t prop)
{
const prop_changenode_t *ca = a;
const prop_changenode_t *cb = b;
char mounta[MAXPATHLEN];
char mountb[MAXPATHLEN];
char propa[MAXPATHLEN];
char propb[MAXPATHLEN];
boolean_t hasmounta, hasmountb;
boolean_t haspropa, haspropb;
haspropa = (zfs_prop_get(ca->cn_handle, prop, propa, sizeof (propa),
NULL, NULL, 0, B_FALSE) == 0);
haspropb = (zfs_prop_get(cb->cn_handle, prop, propb, sizeof (propb),
NULL, NULL, 0, B_FALSE) == 0);
if (!haspropa && haspropb)
return (-1);
else if (haspropa && !haspropb)
return (1);
else if (!haspropa && !haspropb)
return (0);
else
return (strcmp(propb, propa));
}
/*ARGSUSED*/
static int
compare_mountpoints(const void *a, const void *b, void *unused)
{
/*
* When unsharing or unmounting filesystems, we need to do it in
* mountpoint order. This allows the user to have a mountpoint
* hierarchy that is different from the dataset hierarchy, and still
* allow it to be changed. However, if either dataset doesn't have a
* mountpoint (because it is a volume or a snapshot), we place it at the
* end of the list, because it doesn't affect our change at all.
* allow it to be changed.
*/
hasmounta = (zfs_prop_get(ca->cn_handle, ZFS_PROP_MOUNTPOINT, mounta,
sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
hasmountb = (zfs_prop_get(cb->cn_handle, ZFS_PROP_MOUNTPOINT, mountb,
sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
return (compare_props(a, b, ZFS_PROP_MOUNTPOINT));
}
if (!hasmounta && hasmountb)
return (-1);
else if (hasmounta && !hasmountb)
return (1);
else if (!hasmounta && !hasmountb)
return (0);
else
return (strcmp(mountb, mounta));
/*ARGSUSED*/
static int
compare_dataset_names(const void *a, const void *b, void *unused)
{
return (compare_props(a, b, ZFS_PROP_NAME));
}
/*
@@ -630,7 +641,7 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
clp->cl_pool = uu_avl_pool_create("changelist_pool",
sizeof (prop_changenode_t),
offsetof(prop_changenode_t, cn_treenode),
compare_mountpoints, 0);
legacy ? compare_dataset_names : compare_mountpoints, 0);
if (clp->cl_pool == NULL) {
assert(uu_error() == UU_ERROR_NO_MEMORY);
(void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
@@ -687,7 +698,7 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
clp->cl_shareprop = ZFS_PROP_SHARENFS;
if (clp->cl_prop == ZFS_PROP_MOUNTPOINT &&
(clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) == 0) {
(clp->cl_gflags & CL_GATHER_ITER_MOUNTED)) {
/*
* Instead of iterating through all of the dataset children we
* gather mounted dataset children from MNTTAB
+3 -1
View File
@@ -30,6 +30,7 @@
* Copyright 2017 Nexenta Systems, Inc.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
* Copyright 2017-2018 RackTop Systems.
* Copyright (c) 2018 Datto Inc.
*/
#include <ctype.h>
@@ -4548,7 +4549,8 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
goto error;
}
} else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) {
if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0,
if ((cl = changelist_gather(zhp, ZFS_PROP_NAME,
CL_GATHER_ITER_MOUNTED,
force_unmount ? MS_FORCE : 0)) == NULL)
return (-1);
+3 -1
View File
@@ -25,6 +25,7 @@
* Copyright (c) 2014, 2015 by Delphix. All rights reserved.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
* Copyright 2017 RackTop Systems.
* Copyright (c) 2018 Datto Inc.
*/
/*
@@ -699,7 +700,8 @@ zfs_unmountall(zfs_handle_t *zhp, int flags)
prop_changelist_t *clp;
int ret;
clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags);
clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
CL_GATHER_ITER_MOUNTED, 0);
if (clp == NULL)
return (-1);