summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Fiddaman <[email protected]>2018-10-20 14:48:39 -0700
committerBrian Behlendorf <[email protected]>2018-12-07 11:02:23 -0800
commite63ac16d25fbe991a356489c86d4077567dfea21 (patch)
tree0a42687af7455964395ac1315380a2f4286a9004
parent4b611761bd09718c267d5e3dcb3ded62e3a545df (diff)
OpenZFS 9880 - Race in ZFS parallel mount
Porting Notes: * Not required for Linux since the zone is always global. But we'll want this change if we start using the zones code. Authored by: Andy Fiddaman <[email protected]> Reviewed by: Jason King <[email protected]> Reviewed by: Sebastien Roy <[email protected]> Reviewed by: Tom Caputi <[email protected]> Approved by: Joshua M. Clulow <[email protected]> Ported-by: Brian Behlendorf <[email protected]> OpenZFS-issue: https://www.illumos.org/issues/9880 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/bc4c0ff134 Closes #8189
-rw-r--r--lib/libzfs/libzfs_mount.c34
1 files changed, 31 insertions, 3 deletions
diff --git a/lib/libzfs/libzfs_mount.c b/lib/libzfs/libzfs_mount.c
index ef18bafab..649c232aa 100644
--- a/lib/libzfs/libzfs_mount.c
+++ b/lib/libzfs/libzfs_mount.c
@@ -26,6 +26,7 @@
* Copyright 2016 Igor Kozhukhov <[email protected]>
* Copyright 2017 RackTop Systems.
* Copyright (c) 2018 Datto Inc.
+ * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
*/
/*
@@ -1217,19 +1218,28 @@ zfs_iter_cb(zfs_handle_t *zhp, void *data)
/*
* Sort comparator that compares two mountpoint paths. We sort these paths so
* that subdirectories immediately follow their parents. This means that we
- * effectively treat the '/' character as the lowest value non-nul char. An
- * example sorted list using this comparator would look like:
+ * effectively treat the '/' character as the lowest value non-nul char.
+ * Since filesystems from non-global zones can have the same mountpoint
+ * as other filesystems, the comparator sorts global zone filesystems to
+ * the top of the list. This means that the global zone will traverse the
+ * filesystem list in the correct order and can stop when it sees the
+ * first zoned filesystem. In a non-global zone, only the delegated
+ * filesystems are seen.
+ *
+ * An example sorted list using this comparator would look like:
*
* /foo
* /foo/bar
* /foo/bar/baz
* /foo/baz
* /foo.bar
+ * /foo (NGZ1)
+ * /foo (NGZ2)
*
* The mounting code depends on this ordering to deterministically iterate
* over filesystems in order to spawn parallel mount tasks.
*/
-int
+static int
mountpoint_cmp(const void *arga, const void *argb)
{
zfs_handle_t *const *zap = arga;
@@ -1241,6 +1251,14 @@ mountpoint_cmp(const void *arga, const void *argb)
const char *a = mounta;
const char *b = mountb;
boolean_t gota, gotb;
+ uint64_t zoneda, zonedb;
+
+ zoneda = zfs_prop_get_int(za, ZFS_PROP_ZONED);
+ zonedb = zfs_prop_get_int(zb, ZFS_PROP_ZONED);
+ if (zoneda && !zonedb)
+ return (1);
+ if (!zoneda && zonedb)
+ return (-1);
gota = (zfs_get_type(za) == ZFS_TYPE_FILESYSTEM);
if (gota) {
@@ -1461,6 +1479,8 @@ void
zfs_foreach_mountpoint(libzfs_handle_t *hdl, zfs_handle_t **handles,
size_t num_handles, zfs_iter_f func, void *data, boolean_t parallel)
{
+ zoneid_t zoneid = getzoneid();
+
/*
* The ZFS_SERIAL_MOUNT environment variable is an undocumented
* variable that can be used as a convenience to do a/b comparison
@@ -1495,6 +1515,14 @@ zfs_foreach_mountpoint(libzfs_handle_t *hdl, zfs_handle_t **handles,
*/
for (int i = 0; i < num_handles;
i = non_descendant_idx(handles, num_handles, i)) {
+ /*
+ * Since the mountpoints have been sorted so that the zoned
+ * filesystems are at the end, a zoned filesystem seen from
+ * the global zone means that we're done.
+ */
+ if (zoneid == GLOBAL_ZONEID &&
+ zfs_prop_get_int(handles[i], ZFS_PROP_ZONED))
+ break;
zfs_dispatch_mount(hdl, handles, num_handles, i, func, data,
tp);
}