diff options
Diffstat (limited to 'cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c')
-rw-r--r-- | cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c | 214 |
1 files changed, 164 insertions, 50 deletions
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c index 5e6de6d..b905bc6 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c @@ -20,12 +20,12 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Portions Copyright 2007 Ramprakash Jelari */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <libintl.h> #include <libuutil.h> #include <stddef.h> @@ -65,18 +65,21 @@ typedef struct prop_changenode { int cn_shared; int cn_mounted; int cn_zoned; + boolean_t cn_needpost; /* is postfix() needed? */ uu_list_node_t cn_listnode; } prop_changenode_t; struct prop_changelist { zfs_prop_t cl_prop; zfs_prop_t cl_realprop; + zfs_prop_t cl_shareprop; /* used with sharenfs/sharesmb */ uu_list_pool_t *cl_pool; uu_list_t *cl_list; boolean_t cl_waslegacy; boolean_t cl_allchildren; boolean_t cl_alldependents; - int cl_flags; + int cl_mflags; /* Mount flags */ + int cl_gflags; /* Gather request flags */ boolean_t cl_haszonedchild; boolean_t cl_sorted; }; @@ -84,7 +87,8 @@ struct prop_changelist { /* * If the property is 'mountpoint', go through and unmount filesystems as * necessary. We don't do the same for 'sharenfs', because we can just re-share - * with different options without interrupting service. + * with different options without interrupting service. We do handle 'sharesmb' + * since there may be old resource names that need to be removed. */ int changelist_prefix(prop_changelist_t *clp) @@ -92,11 +96,19 @@ changelist_prefix(prop_changelist_t *clp) prop_changenode_t *cn; int ret = 0; - if (clp->cl_prop != ZFS_PROP_MOUNTPOINT) + if (clp->cl_prop != ZFS_PROP_MOUNTPOINT && + clp->cl_prop != ZFS_PROP_SHARESMB) return (0); for (cn = uu_list_first(clp->cl_list); cn != NULL; cn = uu_list_next(clp->cl_list, cn)) { + + /* if a previous loop failed, set the remaining to false */ + if (ret == -1) { + cn->cn_needpost = B_FALSE; + continue; + } + /* * If we are in the global zone, but this dataset is exported * to a local zone, do nothing. @@ -114,8 +126,11 @@ changelist_prefix(prop_changelist_t *clp) (void) zfs_unshare_iscsi(cn->cn_handle); if (zvol_remove_link(cn->cn_handle->zfs_hdl, - cn->cn_handle->zfs_name) != 0) + cn->cn_handle->zfs_name) != 0) { ret = -1; + cn->cn_needpost = B_FALSE; + (void) zfs_share_iscsi(cn->cn_handle); + } break; case ZFS_PROP_VOLSIZE: @@ -126,10 +141,28 @@ changelist_prefix(prop_changelist_t *clp) (void) zfs_unshare_iscsi(cn->cn_handle); break; } - } else if (zfs_unmount(cn->cn_handle, NULL, clp->cl_flags) != 0) - ret = -1; + } else { + /* + * Do the property specific processing. + */ + switch (clp->cl_prop) { + case ZFS_PROP_MOUNTPOINT: + if (zfs_unmount(cn->cn_handle, NULL, + clp->cl_mflags) != 0) { + ret = -1; + cn->cn_needpost = B_FALSE; + } + break; + case ZFS_PROP_SHARESMB: + (void) zfs_unshare_smb(cn->cn_handle, NULL); + break; + } + } } + if (ret == -1) + (void) changelist_postfix(clp); + return (ret); } @@ -147,7 +180,8 @@ changelist_postfix(prop_changelist_t *clp) { prop_changenode_t *cn; char shareopts[ZFS_MAXPROPLEN]; - int ret = 0; + int errors = 0; + libzfs_handle_t *hdl; /* * If we're changing the mountpoint, attempt to destroy the underlying @@ -163,11 +197,28 @@ changelist_postfix(prop_changelist_t *clp) remove_mountpoint(cn->cn_handle); /* + * It is possible that the changelist_prefix() used libshare + * to unshare some entries. Since libshare caches data, an + * attempt to reshare during postfix can fail unless libshare + * is uninitialized here so that it will reinitialize later. + */ + if (cn->cn_handle != NULL) { + hdl = cn->cn_handle->zfs_hdl; + assert(hdl != NULL); + zfs_uninit_libshare(hdl); + } + + /* * We walk the datasets in reverse, because we want to mount any parent - * datasets before mounting the children. + * datasets before mounting the children. We walk all datasets even if + * there are errors. */ for (cn = uu_list_last(clp->cl_list); cn != NULL; cn = uu_list_prev(clp->cl_list, cn)) { + + boolean_t sharenfs; + boolean_t sharesmb; + /* * If we are in the global zone, but this dataset is exported * to a local zone, do nothing. @@ -175,6 +226,11 @@ changelist_postfix(prop_changelist_t *clp) if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned) continue; + /* Only do post-processing if it's required */ + if (!cn->cn_needpost) + continue; + cn->cn_needpost = B_FALSE; + zfs_refresh_properties(cn->cn_handle); if (ZFS_IS_VOLUME(cn->cn_handle)) { @@ -185,7 +241,7 @@ changelist_postfix(prop_changelist_t *clp) if (clp->cl_realprop == ZFS_PROP_NAME && zvol_create_link(cn->cn_handle->zfs_hdl, cn->cn_handle->zfs_name) != 0) { - ret = -1; + errors++; } else if (cn->cn_shared || clp->cl_prop == ZFS_PROP_SHAREISCSI) { if (zfs_prop_get(cn->cn_handle, @@ -193,43 +249,55 @@ changelist_postfix(prop_changelist_t *clp) sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 && strcmp(shareopts, "off") == 0) { - ret = zfs_unshare_iscsi(cn->cn_handle); + errors += + zfs_unshare_iscsi(cn->cn_handle); } else { - ret = zfs_share_iscsi(cn->cn_handle); + errors += + zfs_share_iscsi(cn->cn_handle); } } continue; } - if ((clp->cl_waslegacy || cn->cn_mounted) && - !zfs_is_mounted(cn->cn_handle, NULL) && + /* + * Remount if previously mounted or mountpoint was legacy, + * or sharenfs or sharesmb property is set. + */ + sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS, + shareopts, sizeof (shareopts), NULL, NULL, 0, + B_FALSE) == 0) && (strcmp(shareopts, "off") != 0)); + + sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB, + shareopts, sizeof (shareopts), NULL, NULL, 0, + B_FALSE) == 0) && (strcmp(shareopts, "off") != 0)); + + if ((cn->cn_mounted || clp->cl_waslegacy || sharenfs || + sharesmb) && !zfs_is_mounted(cn->cn_handle, NULL) && zfs_mount(cn->cn_handle, NULL, 0) != 0) - ret = -1; + errors++; /* * We always re-share even if the filesystem is currently * shared, so that we can adopt any new options. */ - if (cn->cn_shared || - (clp->cl_prop == ZFS_PROP_SHARENFS && clp->cl_waslegacy)) { - if (zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS, - shareopts, sizeof (shareopts), NULL, NULL, 0, - B_FALSE) == 0 && strcmp(shareopts, "off") == 0) { - ret = zfs_unshare_nfs(cn->cn_handle, NULL); - } else { - ret = zfs_share_nfs(cn->cn_handle); - } - } + if (sharenfs) + errors += zfs_share_nfs(cn->cn_handle); + else if (cn->cn_shared || clp->cl_waslegacy) + errors += zfs_unshare_nfs(cn->cn_handle, NULL); + if (sharesmb) + errors += zfs_share_smb(cn->cn_handle); + else if (cn->cn_shared || clp->cl_waslegacy) + errors += zfs_unshare_smb(cn->cn_handle, NULL); } - return (ret); + return (errors ? -1 : 0); } /* * Is this "dataset" a child of "parent"? */ -static boolean_t +boolean_t isa_child_of(const char *dataset, const char *parent) { int len; @@ -280,21 +348,22 @@ changelist_rename(prop_changelist_t *clp, const char *src, const char *dst) } /* - * Given a gathered changelist for the 'sharenfs' property, unshare all the - * datasets in the list. + * Given a gathered changelist for the 'sharenfs' or 'sharesmb' property, + * unshare all the datasets in the list. */ int -changelist_unshare(prop_changelist_t *clp) +changelist_unshare(prop_changelist_t *clp, zfs_share_proto_t *proto) { prop_changenode_t *cn; int ret = 0; - if (clp->cl_prop != ZFS_PROP_SHARENFS) + if (clp->cl_prop != ZFS_PROP_SHARENFS && + clp->cl_prop != ZFS_PROP_SHARESMB) return (0); for (cn = uu_list_first(clp->cl_list); cn != NULL; cn = uu_list_next(clp->cl_list, cn)) { - if (zfs_unshare_nfs(cn->cn_handle, NULL) != 0) + if (zfs_unshare_proto(cn->cn_handle, NULL, proto) != 0) ret = -1; } @@ -316,14 +385,14 @@ changelist_haszonedchild(prop_changelist_t *clp) * Remove a node from a gathered list. */ void -changelist_remove(zfs_handle_t *zhp, prop_changelist_t *clp) +changelist_remove(prop_changelist_t *clp, const char *name) { prop_changenode_t *cn; for (cn = uu_list_first(clp->cl_list); cn != NULL; cn = uu_list_next(clp->cl_list, cn)) { - if (strcmp(cn->cn_handle->zfs_name, zhp->zfs_name) == 0) { + if (strcmp(cn->cn_handle->zfs_name, name) == 0) { uu_list_remove(clp->cl_list, cn); zfs_close(cn->cn_handle); free(cn); @@ -363,7 +432,8 @@ change_one(zfs_handle_t *zhp, void *data) char property[ZFS_MAXPROPLEN]; char where[64]; prop_changenode_t *cn; - zfs_source_t sourcetype; + zprop_source_t sourcetype; + zprop_source_t share_sourcetype; /* * We only want to unmount/unshare those filesystems that may inherit @@ -383,8 +453,25 @@ change_one(zfs_handle_t *zhp, void *data) return (0); } + /* + * If we are "watching" sharenfs or sharesmb + * then check out the companion property which is tracked + * in cl_shareprop + */ + if (clp->cl_shareprop != ZPROP_INVAL && + zfs_prop_get(zhp, clp->cl_shareprop, property, + sizeof (property), &share_sourcetype, where, sizeof (where), + B_FALSE) != 0) { + zfs_close(zhp); + return (0); + } + if (clp->cl_alldependents || clp->cl_allchildren || - sourcetype == ZFS_SRC_DEFAULT || sourcetype == ZFS_SRC_INHERITED) { + sourcetype == ZPROP_SRC_DEFAULT || + sourcetype == ZPROP_SRC_INHERITED || + (clp->cl_shareprop != ZPROP_INVAL && + (share_sourcetype == ZPROP_SRC_DEFAULT || + share_sourcetype == ZPROP_SRC_INHERITED))) { if ((cn = zfs_alloc(zfs_get_handle(zhp), sizeof (prop_changenode_t))) == NULL) { zfs_close(zhp); @@ -392,9 +479,11 @@ change_one(zfs_handle_t *zhp, void *data) } cn->cn_handle = zhp; - cn->cn_mounted = zfs_is_mounted(zhp, NULL); + cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) || + zfs_is_mounted(zhp, NULL); cn->cn_shared = zfs_is_shared(zhp); cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); + cn->cn_needpost = B_TRUE; /* Indicate if any child is exported to a local zone. */ if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned) @@ -467,7 +556,8 @@ compare_mountpoints(const void *a, const void *b, void *unused) * mark whether it was shared beforehand. */ prop_changelist_t * -changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) +changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags, + int mnt_flags) { prop_changelist_t *clp; prop_changenode_t *cn; @@ -484,7 +574,8 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) * order, regardless of their position in the hierarchy. */ if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED || - prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) { + prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS || + prop == ZFS_PROP_SHARESMB) { compare = compare_mountpoints; clp->cl_sorted = B_TRUE; } @@ -502,7 +593,8 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) clp->cl_list = uu_list_create(clp->cl_pool, NULL, clp->cl_sorted ? UU_LIST_SORTED : 0); - clp->cl_flags = flags; + clp->cl_gflags = gather_flags; + clp->cl_mflags = mnt_flags; if (clp->cl_list == NULL) { assert(uu_error() == UU_ERROR_NO_MEMORY); @@ -529,6 +621,8 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) clp->cl_prop = ZFS_PROP_MOUNTPOINT; } else if (prop == ZFS_PROP_VOLSIZE) { clp->cl_prop = ZFS_PROP_MOUNTPOINT; + } else if (prop == ZFS_PROP_VERSION) { + clp->cl_prop = ZFS_PROP_MOUNTPOINT; } else { clp->cl_prop = prop; } @@ -536,9 +630,19 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) if (clp->cl_prop != ZFS_PROP_MOUNTPOINT && clp->cl_prop != ZFS_PROP_SHARENFS && + clp->cl_prop != ZFS_PROP_SHARESMB && clp->cl_prop != ZFS_PROP_SHAREISCSI) return (clp); + /* + * If watching SHARENFS or SHARESMB then + * also watch its companion property. + */ + if (clp->cl_prop == ZFS_PROP_SHARENFS) + clp->cl_shareprop = ZFS_PROP_SHARESMB; + else if (clp->cl_prop == ZFS_PROP_SHARESMB) + clp->cl_shareprop = ZFS_PROP_SHARENFS; + if (clp->cl_alldependents) { if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) { changelist_free(clp); @@ -554,7 +658,7 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) * and can't tell the difference. */ if ((temp = zfs_open(zhp->zfs_hdl, zfs_get_name(zhp), - ZFS_TYPE_ANY)) == NULL) { + ZFS_TYPE_DATASET)) == NULL) { changelist_free(clp); return (NULL); } @@ -571,9 +675,11 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) } cn->cn_handle = temp; - cn->cn_mounted = zfs_is_mounted(temp, NULL); + cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) || + zfs_is_mounted(temp, NULL); cn->cn_shared = zfs_is_shared(temp); cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); + cn->cn_needpost = B_TRUE; uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool); if (clp->cl_sorted) { @@ -586,14 +692,22 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) } /* - * If the property was previously 'legacy' or 'none', record this fact, - * as the behavior of changelist_postfix() will be different. + * If the mountpoint property was previously 'legacy', or 'none', + * record it as the behavior of changelist_postfix() will be different. */ - if (zfs_prop_get(zhp, prop, property, sizeof (property), + if ((clp->cl_prop == ZFS_PROP_MOUNTPOINT) && + (zfs_prop_get(zhp, prop, property, sizeof (property), NULL, NULL, 0, B_FALSE) == 0 && - (strcmp(property, "legacy") == 0 || strcmp(property, "none") == 0 || - strcmp(property, "off") == 0)) - clp->cl_waslegacy = B_TRUE; + (strcmp(property, "legacy") == 0 || + strcmp(property, "none") == 0))) { + /* + * do not automatically mount ex-legacy datasets if + * we specifically set canmount to noauto + */ + if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) != + ZFS_CANMOUNT_NOAUTO) + clp->cl_waslegacy = B_TRUE; + } return (clp); } |