From 8a981c3356b194b3b5c0ae9276a9cc31cd2f93a3 Mon Sep 17 00:00:00 2001 From: Daniel Hoffman Date: Thu, 13 Apr 2017 14:26:51 -0700 Subject: [PATCH] 7955 libshare needs to initialize only those datasets being modified by the consumer Reviewed by: Steve Gonczi Reviewed by: Sebastien Roy Reviewed by: Matthew Ahrens Reviewed by: George Wilson Reviewed by: Pavel Zakharov Reviewed by: Yuri Pankov Approved by: Gordon Ross --- usr/src/cmd/zfs/zfs_main.c | 10 + usr/src/lib/libshare/Makefile.com | 2 + usr/src/lib/libshare/common/libshare.c | 96 ++++- usr/src/lib/libshare/common/libshare.h | 25 ++ usr/src/lib/libshare/common/libshare_impl.h | 5 + usr/src/lib/libshare/common/libshare_zfs.c | 387 +++++++++++++-------- usr/src/lib/libshare/common/libsharecore.c | 292 ++++++++++------ usr/src/lib/libshare/common/mapfile-vers | 2 + usr/src/lib/libzfs/common/libzfs.h | 11 + usr/src/lib/libzfs/common/libzfs_changelist.c | 32 +- usr/src/lib/libzfs/common/libzfs_impl.h | 1 - usr/src/lib/libzfs/common/libzfs_mount.c | 54 ++- usr/src/lib/libzfs/common/mapfile-vers | 2 + .../functional/inheritance/inherit_001_pos.ksh | 2 +- 14 files changed, 639 insertions(+), 282 deletions(-) diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c index 78dfeea98b..e34a40a474 100644 --- a/usr/src/cmd/zfs/zfs_main.c +++ b/usr/src/cmd/zfs/zfs_main.c @@ -68,6 +68,7 @@ #include #include #include +#include #include "zfs_iter.h" #include "zfs_util.h" @@ -6138,6 +6139,15 @@ share_mount(int op, int argc, char **argv) return (0); qsort(dslist, count, sizeof (void *), libzfs_dataset_cmp); + sa_init_selective_arg_t sharearg; + sharearg.zhandle_arr = dslist; + sharearg.zhandle_len = count; + if ((ret = zfs_init_libshare_arg(zfs_get_handle(dslist[0]), + SA_INIT_SHARE_API_SELECTIVE, &sharearg)) != SA_OK) { + (void) fprintf(stderr, + gettext("Could not initialize libshare, %d"), ret); + return (ret); + } for (i = 0; i < count; i++) { if (verbose) diff --git a/usr/src/lib/libshare/Makefile.com b/usr/src/lib/libshare/Makefile.com index 328ffb353a..2f8aad345f 100644 --- a/usr/src/lib/libshare/Makefile.com +++ b/usr/src/lib/libshare/Makefile.com @@ -19,6 +19,7 @@ # CDDL HEADER END # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016 by Delphix. All rights reserved. # LIBRARY = libshare.a VERS = .1 @@ -42,6 +43,7 @@ $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) #add nfs/lib directory as part of the include path CFLAGS += $(CCVERBOSE) +C99MODE += $(C99_ENABLE) CERRWARN += -_gcc=-Wno-parentheses CERRWARN += -_gcc=-Wno-uninitialized CERRWARN += -_gcc=-Wno-switch diff --git a/usr/src/lib/libshare/common/libshare.c b/usr/src/lib/libshare/common/libshare.c index 6950031978..5a58e0268e 100644 --- a/usr/src/lib/libshare/common/libshare.c +++ b/usr/src/lib/libshare/common/libshare.c @@ -22,6 +22,7 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2016 by Delphix. All rights reserved. */ /* @@ -68,6 +69,7 @@ extern struct sa_proto_plugin *sap_proto_list; /* current SMF/SVC repository handle */ extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); extern int gettransients(sa_handle_impl_t, xmlNodePtr *); +extern int get_one_transient(sa_handle_impl_t, xmlNodePtr *, char **, size_t); extern char *sa_fstype(char *); extern int sa_is_share(void *); extern int sa_is_resource(void *); @@ -814,21 +816,23 @@ verifydefgroupopts(sa_handle_t handle) } /* - * sa_init(init_service) + * sa_init_impl(init_service, arg) * Initialize the API * find all the shared objects * init the tables with all objects * read in the current configuration + * + * arg is a parameter passed in whose meaning is based on the init_service. + * See libshare.h under API initialization. */ - #define GETPROP(prop) scf_simple_prop_next_astring(prop) #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ tval != TSTAMP(st.st_ctim) - -sa_handle_t -sa_init(int init_service) +static sa_handle_t +sa_init_impl(int init_service, void *arg) { struct stat st; + /* legacy is used for debugging only as far as I can tell */ int legacy = 0; uint64_t tval = 0; int lockfd; @@ -841,6 +845,7 @@ sa_init(int init_service) handle = calloc(sizeof (struct sa_handle_impl), 1); if (handle != NULL) { + handle->sa_service = init_service; /* * Get protocol specific structures, but only if this * is the only handle. @@ -849,7 +854,9 @@ sa_init(int init_service) if (sa_global_handles == NULL) (void) proto_plugin_init(); (void) mutex_unlock(&sa_global_lock); - if (init_service & SA_INIT_SHARE_API) { + if (init_service & (SA_INIT_SHARE_API | + SA_INIT_SHARE_API_SELECTIVE | SA_INIT_ONE_SHARE_FROM_NAME | + SA_INIT_ONE_SHARE_FROM_HANDLE)) { /* * initialize access into libzfs. We use this * when collecting info about ZFS datasets and @@ -1025,8 +1032,60 @@ sa_init(int init_service) handle->tstrans = 0; scf_simple_prop_free(prop); } - legacy |= sa_get_zfs_shares(handle, "zfs"); - legacy |= gettransients(handle, &handle->tree); + /* + * In this conditional the library reads from + * zfs and /etc/dfs/sharetab to find datasets + * that must be shared. The result is a tree of + * groups that are stored in the handle for + * libshare to utilize later when asked to share + * or unshare datasets. + */ + if (init_service & + SA_INIT_SHARE_API_SELECTIVE) { + char **paths; + size_t paths_len, i; + + legacy |= sa_get_one_zfs_share(handle, + "zfs", + (sa_init_selective_arg_t *)arg, + &paths, &paths_len); + legacy |= get_one_transient(handle, + &handle->tree, paths, paths_len); + for (i = 0; i < paths_len; ++i) { + free(paths[i]); + } + free(paths); + } else if (init_service & + SA_INIT_ONE_SHARE_FROM_NAME) { + char path[ZFS_MAXPROPLEN]; + char *ptr = path; + char **ptr_to_path = &ptr; + + legacy |= + sa_get_zfs_share_for_name(handle, + "zfs", (char *)arg, path); + legacy |= get_one_transient(handle, + &handle->tree, ptr_to_path, 1); + } else if (init_service & + SA_INIT_ONE_SHARE_FROM_HANDLE) { + char path[ZFS_MAXPROPLEN]; + char *ptr = path; + char **ptr_to_path = &ptr; + + legacy |= + sa_get_zfs_share_for_name(handle, + "zfs", + zfs_get_name( + (zfs_handle_t *)arg), + path); + legacy |= get_one_transient(handle, + &handle->tree, ptr_to_path, 1); + } else { + legacy |= sa_get_zfs_shares(handle, + "zfs"); + legacy |= gettransients(handle, + &handle->tree); + } } } } @@ -1034,6 +1093,25 @@ sa_init(int init_service) } /* + * sa_init exists as a legacy interface, new consumers should use sa_init_arg. + */ +sa_handle_t +sa_init(int init_service) +{ + return (sa_init_impl(init_service, NULL)); +} + +/* + * See libshare.h "API Initialization" section for valid values of init_service + * as well as the appropriate argument type for a given init_service. + */ +sa_handle_t +sa_init_arg(int init_service, void *arg) +{ + return (sa_init_impl(init_service, arg)); +} + +/* * sa_fini(handle) * Uninitialize the API structures including the configuration * data structures and ZFS related data. @@ -3066,7 +3144,7 @@ add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, static int sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, - sa_property_t prop, int type) + sa_property_t prop, int type) { char *name; char *valstr; diff --git a/usr/src/lib/libshare/common/libshare.h b/usr/src/lib/libshare/common/libshare.h index 9348e76341..7ad9fefdcd 100644 --- a/usr/src/lib/libshare/common/libshare.h +++ b/usr/src/lib/libshare/common/libshare.h @@ -22,6 +22,7 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2016 by Delphix. All rights reserved. */ /* @@ -37,6 +38,7 @@ extern "C" { #include #include +#include /* * Basic datatypes for most functions @@ -91,9 +93,31 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */ #define SA_SHARE_EXISTS 33 /* path or file is already shared */ /* API Initialization */ +/* Both of these do not care about the value of arg in sa_init_arg */ #define SA_INIT_SHARE_API 0x0001 /* init share specific interface */ #define SA_INIT_CONTROL_API 0x0002 /* init control specific interface */ +/* expects an sa_init_selective_arg_t as an argument */ +#define SA_INIT_SHARE_API_SELECTIVE 0x0004 /* only some shares */ +struct sa_init_selective_arg { + zfs_handle_t **zhandle_arr; + size_t zhandle_len; +}; +typedef struct sa_init_selective_arg sa_init_selective_arg_t; + + +/* + * The SA_INIT_ONE_SHARE* initialization options to sa_init* will cause + * sa_needs_refrsh() to return true even if nothing else in the system has + * changed. If writing code that could possibly need to share/unshare multiple + * shares, it is recommended to use SA_INIT_SHARE_API_SELECTIVE. + */ +/* Expects a single char * as input, the name of the share. */ +#define SA_INIT_ONE_SHARE_FROM_NAME 0x0008 + +/* Expects a single zfs_handle_t as input, the handle of the share. */ +#define SA_INIT_ONE_SHARE_FROM_HANDLE 0x0010 + /* not part of API returns */ #define SA_LEGACY_ERR 32 /* share/unshare error return */ @@ -145,6 +169,7 @@ typedef void *sa_handle_t; /* opaque handle to access core functions */ /* initialization */ extern sa_handle_t sa_init(int); +extern sa_handle_t sa_init_arg(int, void *); extern void sa_fini(sa_handle_t); extern int sa_update_config(sa_handle_t); extern boolean_t sa_needs_refresh(sa_handle_t); diff --git a/usr/src/lib/libshare/common/libshare_impl.h b/usr/src/lib/libshare/common/libshare_impl.h index 1fcffa95d9..1b326e73eb 100644 --- a/usr/src/lib/libshare/common/libshare_impl.h +++ b/usr/src/lib/libshare/common/libshare_impl.h @@ -22,6 +22,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright (c) 2016 by Delphix. All rights reserved. */ /* @@ -110,6 +111,7 @@ typedef struct sa_handle_impl { xmlDocPtr doc; uint64_t tssharetab; uint64_t tstrans; + int sa_service; } *sa_handle_impl_t; extern int sa_proto_share(char *, sa_share_t); @@ -142,7 +144,10 @@ extern void sa_fillshare(sa_share_t share, char *proto, struct share *sh); extern void sa_emptyshare(struct share *sh); /* ZFS functions */ +extern int sa_get_one_zfs_share(sa_handle_t, char *, sa_init_selective_arg_t *, + char ***, size_t *); extern int sa_get_zfs_shares(sa_handle_t, char *); +extern int sa_get_zfs_share_for_name(sa_handle_t, char *, const char *, char *); extern int sa_zfs_update(sa_share_t); extern int sa_share_zfs(sa_share_t, sa_resource_t, char *, share_t *, void *, zfs_share_op_t); diff --git a/usr/src/lib/libshare/common/libshare_zfs.c b/usr/src/lib/libshare/common/libshare_zfs.c index 08b5a00e9d..488841fcff 100644 --- a/usr/src/lib/libshare/common/libshare_zfs.c +++ b/usr/src/lib/libshare/common/libshare_zfs.c @@ -264,6 +264,10 @@ get_legacy_mountpoint(const char *path, char *dataset, size_t dlen, } +/* + * Verifies that a specific zfs filesystem handle meets the criteria necessary + * to be used by libshare operations. See get_zfs_dataset. + */ static char * verify_zfs_handle(zfs_handle_t *hdl, const char *path, boolean_t search_mnttab) { @@ -338,19 +342,16 @@ get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, assert(impl_handle->zfs_libhandle != NULL); libzfs_print_on_error(impl_handle->zfs_libhandle, B_FALSE); - if ((handle_from_path = zfs_open(impl_handle->zfs_libhandle, cutpath, - ZFS_TYPE_FILESYSTEM)) != NULL) { - if ((ret = verify_zfs_handle(handle_from_path, path, - search_mnttab)) != NULL) { - zfs_close(handle_from_path); - libzfs_print_on_error(impl_handle->zfs_libhandle, - B_TRUE); + handle_from_path = zfs_open(impl_handle->zfs_libhandle, cutpath, + ZFS_TYPE_FILESYSTEM); + libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); + if (handle_from_path != NULL) { + ret = verify_zfs_handle(handle_from_path, path, search_mnttab); + zfs_close(handle_from_path); + if (ret != NULL) { return (ret); } - zfs_close(handle_from_path); } - libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); - /* * Couldn't find a filesystem optimistically, check all the handles we * can. @@ -764,8 +765,6 @@ sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, } /* - * sa_get_zfs_shares(handle, groupname) - * * Walk the mnttab for all zfs mounts and determine which are * shared. Find or create the appropriate group/sub-group to contain * the shares. @@ -778,170 +777,197 @@ sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, * a sub-group must be formed at the lower level for both * protocols. That is the nature of the problem in CR 6667349. */ - -int -sa_get_zfs_shares(sa_handle_t handle, char *groupname) +static int +sa_get_zfs_share_common(sa_handle_t handle, zfs_handle_t *fs_handle, char *path, + sa_group_t zfsgroup) { - sa_group_t zfsgroup; - boolean_t nfs; - boolean_t nfs_inherited; - boolean_t smb; - boolean_t smb_inherited; - zfs_handle_t **zlist; + boolean_t smb, nfs; + boolean_t smb_inherited, nfs_inherited; char nfsshareopts[ZFS_MAXPROPLEN]; char smbshareopts[ZFS_MAXPROPLEN]; - sa_share_t share; - zprop_source_t source; char nfssourcestr[ZFS_MAXPROPLEN]; char smbsourcestr[ZFS_MAXPROPLEN]; char mountpoint[ZFS_MAXPROPLEN]; - size_t count = 0, i; - libzfs_handle_t *zfs_libhandle; int err = SA_OK; + zprop_source_t source; + sa_share_t share; + char *dataset; + + source = ZPROP_SRC_ALL; + /* If no mountpoint, skip. */ + if (zfs_prop_get(fs_handle, ZFS_PROP_MOUNTPOINT, + mountpoint, sizeof (mountpoint), NULL, NULL, 0, + B_FALSE) != 0) + return (SA_SYSTEM_ERR); + if (path != NULL) + (void) strncpy(path, mountpoint, sizeof (mountpoint)); /* - * If we can't access libzfs, don't bother doing anything. + * zfs_get_name value must not be freed. It is just a + * pointer to a value in the handle. */ - zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; - if (zfs_libhandle == NULL) + if ((dataset = (char *)zfs_get_name(fs_handle)) == NULL) return (SA_SYSTEM_ERR); - zfsgroup = find_or_create_group(handle, groupname, NULL, &err); - /* Not an error, this could be a legacy condition */ - if (zfsgroup == NULL) - return (SA_OK); - /* - * need to walk the mounted ZFS pools and datasets to - * find shares that are possible. + * only deal with "mounted" file systems since + * unmounted file systems can't actually be shared. */ - get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); - qsort(zlist, count, sizeof (void *), mountpoint_compare); - - for (i = 0; i < count; i++) { - char *dataset; - source = ZPROP_SRC_ALL; - /* If no mountpoint, skip. */ - if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, - mountpoint, sizeof (mountpoint), NULL, NULL, 0, - B_FALSE) != 0) - continue; - - /* - * zfs_get_name value must not be freed. It is just a - * pointer to a value in the handle. - */ - if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) - continue; + if (!zfs_is_mounted(fs_handle, NULL)) + return (SA_SYSTEM_ERR); - /* - * only deal with "mounted" file systems since - * unmounted file systems can't actually be shared. - */ + nfs = nfs_inherited = B_FALSE; - if (!zfs_is_mounted(zlist[i], NULL)) - continue; - - nfs = nfs_inherited = B_FALSE; + if (zfs_prop_get(fs_handle, ZFS_PROP_SHARENFS, nfsshareopts, + sizeof (nfsshareopts), &source, nfssourcestr, + ZFS_MAXPROPLEN, B_FALSE) == 0 && + strcmp(nfsshareopts, "off") != 0) { + if (source & ZPROP_SRC_INHERITED) + nfs_inherited = B_TRUE; + else + nfs = B_TRUE; + } - if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, nfsshareopts, - sizeof (nfsshareopts), &source, nfssourcestr, - ZFS_MAXPROPLEN, B_FALSE) == 0 && - strcmp(nfsshareopts, "off") != 0) { - if (source & ZPROP_SRC_INHERITED) - nfs_inherited = B_TRUE; - else - nfs = B_TRUE; - } + smb = smb_inherited = B_FALSE; + if (zfs_prop_get(fs_handle, ZFS_PROP_SHARESMB, smbshareopts, + sizeof (smbshareopts), &source, smbsourcestr, + ZFS_MAXPROPLEN, B_FALSE) == 0 && + strcmp(smbshareopts, "off") != 0) { + if (source & ZPROP_SRC_INHERITED) + smb_inherited = B_TRUE; + else + smb = B_TRUE; + } - smb = smb_inherited = B_FALSE; - if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, smbshareopts, - sizeof (smbshareopts), &source, smbsourcestr, - ZFS_MAXPROPLEN, B_FALSE) == 0 && - strcmp(smbshareopts, "off") != 0) { - if (source & ZPROP_SRC_INHERITED) - smb_inherited = B_TRUE; - else - smb = B_TRUE; - } + /* + * If the mountpoint is already shared, it must be a + * non-ZFS share. We want to remove the share from its + * parent group and reshare it under ZFS. + */ + share = sa_find_share(handle, mountpoint); + if (share != NULL && + (nfs || smb || nfs_inherited || smb_inherited)) { + err = sa_remove_share(share); + share = NULL; + } + /* + * At this point, we have the information needed to + * determine what to do with the share. + * + * If smb or nfs is set, we have a new sub-group. + * If smb_inherit and/or nfs_inherit is set, then + * place on an existing sub-group. If both are set, + * the existing sub-group is the closest up the tree. + */ + if (nfs || smb) { /* - * If the mountpoint is already shared, it must be a - * non-ZFS share. We want to remove the share from its - * parent group and reshare it under ZFS. + * Non-inherited is the straightforward + * case. sa_zfs_process_share handles it + * directly. Make sure that if the "other" + * protocol is inherited, that we treat it as + * non-inherited as well. */ - share = sa_find_share(handle, mountpoint); - if (share != NULL && - (nfs || smb || nfs_inherited || smb_inherited)) { - err = sa_remove_share(share); - share = NULL; + if (nfs || nfs_inherited) { + err = sa_zfs_process_share(handle, zfsgroup, + share, mountpoint, "nfs", + 0, nfsshareopts, + nfssourcestr, dataset); + share = sa_find_share(handle, mountpoint); } - + if (smb || smb_inherited) { + err = sa_zfs_process_share(handle, zfsgroup, + share, mountpoint, "smb", + 0, smbshareopts, + smbsourcestr, dataset); + } + } else if (nfs_inherited || smb_inherited) { + char *grpdataset; /* - * At this point, we have the information needed to - * determine what to do with the share. - * - * If smb or nfs is set, we have a new sub-group. - * If smb_inherit and/or nfs_inherit is set, then - * place on an existing sub-group. If both are set, - * the existing sub-group is the closest up the tree. + * If we only have inherited groups, it is + * important to find the closer of the two if + * the protocols are set at different + * levels. The closest sub-group is the one we + * want to work with. */ - if (nfs || smb) { - /* - * Non-inherited is the straightforward - * case. sa_zfs_process_share handles it - * directly. Make sure that if the "other" - * protocol is inherited, that we treat it as - * non-inherited as well. - */ - if (nfs || nfs_inherited) { - err = sa_zfs_process_share(handle, zfsgroup, - share, mountpoint, "nfs", - 0, nfsshareopts, - nfssourcestr, dataset); - share = sa_find_share(handle, mountpoint); - } - if (smb || smb_inherited) { - err = sa_zfs_process_share(handle, zfsgroup, - share, mountpoint, "smb", - 0, smbshareopts, - smbsourcestr, dataset); - } - } else if (nfs_inherited || smb_inherited) { - char *grpdataset; - /* - * If we only have inherited groups, it is - * important to find the closer of the two if - * the protocols are set at different - * levels. The closest sub-group is the one we - * want to work with. - */ - if (nfs_inherited && smb_inherited) { - if (strcmp(nfssourcestr, smbsourcestr) <= 0) - grpdataset = nfssourcestr; - else - grpdataset = smbsourcestr; - } else if (nfs_inherited) { + if (nfs_inherited && smb_inherited) { + if (strcmp(nfssourcestr, smbsourcestr) <= 0) grpdataset = nfssourcestr; - } else if (smb_inherited) { + else grpdataset = smbsourcestr; - } - if (nfs_inherited) { - err = sa_zfs_process_share(handle, zfsgroup, - share, mountpoint, "nfs", - ZPROP_SRC_INHERITED, nfsshareopts, - grpdataset, dataset); - share = sa_find_share(handle, mountpoint); - } - if (smb_inherited) { - err = sa_zfs_process_share(handle, zfsgroup, - share, mountpoint, "smb", - ZPROP_SRC_INHERITED, smbshareopts, - grpdataset, dataset); - } + } else if (nfs_inherited) { + grpdataset = nfssourcestr; + } else if (smb_inherited) { + grpdataset = smbsourcestr; + } + if (nfs_inherited) { + err = sa_zfs_process_share(handle, zfsgroup, + share, mountpoint, "nfs", + ZPROP_SRC_INHERITED, nfsshareopts, + grpdataset, dataset); + share = sa_find_share(handle, mountpoint); + } + if (smb_inherited) { + err = sa_zfs_process_share(handle, zfsgroup, + share, mountpoint, "smb", + ZPROP_SRC_INHERITED, smbshareopts, + grpdataset, dataset); } } + return (err); +} + +/* + * Handles preparing generic objects such as the libzfs handle and group for + * sa_get_one_zfs_share, sa_get_zfs_share_for_name, and sa_get_zfs_shares. + */ +static int +prep_zfs_handle_and_group(sa_handle_t handle, char *groupname, + libzfs_handle_t **zfs_libhandle, sa_group_t *zfsgroup, int *err) +{ + /* + * If we can't access libzfs, don't bother doing anything. + */ + *zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; + if (*zfs_libhandle == NULL) + return (SA_SYSTEM_ERR); + + *zfsgroup = find_or_create_group(handle, groupname, NULL, err); + return (SA_OK); +} + +/* + * The O.G. zfs share preparation function. This initializes all zfs shares for + * use with libshare. + */ +int +sa_get_zfs_shares(sa_handle_t handle, char *groupname) +{ + sa_group_t zfsgroup; + zfs_handle_t **zlist; + size_t count = 0; + libzfs_handle_t *zfs_libhandle; + int err; + + if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle, + &zfsgroup, &err)) != SA_OK) { + return (err); + } + /* Not an error, this could be a legacy condition */ + if (zfsgroup == NULL) + return (SA_OK); + + /* + * need to walk the mounted ZFS pools and datasets to + * find shares that are possible. + */ + get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); + qsort(zlist, count, sizeof (void *), mountpoint_compare); + + for (int i = 0; i < count; i++) { + err = sa_get_zfs_share_common(handle, zlist[i], NULL, zfsgroup); + } /* * Don't need to free the "zlist" variable since it is only a * pointer to a cached value that will be freed when @@ -950,6 +976,73 @@ sa_get_zfs_shares(sa_handle_t handle, char *groupname) return (err); } +/* + * Initializes only the handles specified in the sharearg for use with libshare. + * This is used as a performance optimization relative to sa_get_zfs_shares. + */ +int +sa_get_one_zfs_share(sa_handle_t handle, char *groupname, + sa_init_selective_arg_t *sharearg, char ***paths, size_t *paths_len) +{ + sa_group_t zfsgroup; + libzfs_handle_t *zfs_libhandle; + int err; + + if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle, + &zfsgroup, &err)) != SA_OK) { + return (err); + } + /* Not an error, this could be a legacy condition */ + if (zfsgroup == NULL) + return (SA_OK); + + *paths_len = sharearg->zhandle_len; + *paths = malloc(sizeof (char *) * (*paths_len)); + for (int i = 0; i < sharearg->zhandle_len; ++i) { + zfs_handle_t *fs_handle = + ((zfs_handle_t **)(sharearg->zhandle_arr))[i]; + if (fs_handle == NULL) { + return (SA_SYSTEM_ERR); + } + (*paths)[i] = malloc(sizeof (char) * ZFS_MAXPROPLEN); + err |= sa_get_zfs_share_common(handle, fs_handle, (*paths)[i], + zfsgroup); + } + return (err); +} + +/* + * Initializes only the share with the specified sharename for use with + * libshare. + */ +int +sa_get_zfs_share_for_name(sa_handle_t handle, char *groupname, + const char *sharename, char *outpath) +{ + sa_group_t zfsgroup; + libzfs_handle_t *zfs_libhandle; + int err; + + if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle, + &zfsgroup, &err)) != SA_OK) { + return (err); + } + /* Not an error, this could be a legacy condition */ + if (zfsgroup == NULL) + return (SA_OK); + + zfs_handle_t *fs_handle = zfs_open(zfs_libhandle, + sharename + strspn(sharename, "/"), ZFS_TYPE_DATASET); + if (fs_handle == NULL) + return (SA_SYSTEM_ERR); + + err = sa_get_zfs_share_common(handle, fs_handle, outpath, zfsgroup); + zfs_close(fs_handle); + return (err); +} + + + #define COMMAND "/usr/sbin/zfs" /* diff --git a/usr/src/lib/libshare/common/libsharecore.c b/usr/src/lib/libshare/common/libsharecore.c index 87657a13bf..b8bd1156b1 100644 --- a/usr/src/lib/libshare/common/libsharecore.c +++ b/usr/src/lib/libshare/common/libsharecore.c @@ -1433,146 +1433,221 @@ err: } /* - * parse_sharetab(handle) + * parse_sharetab_impl(handle, tmplist, lgroup) * * Read the /etc/dfs/sharetab file and see which entries don't exist * in the repository. These shares are marked transient. We also need * to see if they are ZFS shares since ZFS bypasses the SMF * repository. + * + * The return value is used to contribute to values indicating if it is a legacy + * share. Right now this is 0 or 1, but as multiple systems become legacy that + * could change. */ -int -parse_sharetab(sa_handle_t handle) +static int +parse_sharetab_impl(sa_handle_t handle, xfs_sharelist_t *tmplist, + sa_group_t lgroup) { - xfs_sharelist_t *list, *tmplist; int err = 0; sa_share_t share; sa_group_t group; - sa_group_t lgroup; char *groupname; int legacy = 0; char shareopts[MAXNAMLEN]; - list = get_share_list(&err); - if (list == NULL) - return (legacy); - - lgroup = sa_get_group(handle, "default"); + group = NULL; + share = sa_find_share(handle, tmplist->path); + if (share != NULL) { + /* + * If this is a legacy share, mark as shared so we only update + * sharetab appropriately. We also keep the sharetab options in + * order to display for legacy share with no arguments. + */ + set_node_attr(share, "shared", "true"); + (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", + tmplist->fstype); + set_node_attr(share, shareopts, tmplist->options); + return (1); + } - for (tmplist = list; tmplist != NULL; tmplist = tmplist->next) { - group = NULL; - share = sa_find_share(handle, tmplist->path); - if (share != NULL) { + /* + * This share is transient so needs to be added. Initially, this will be + * under default(legacy) unless it is a ZFS share. If zfs, we need a zfs + * group. + */ + if (tmplist->resource != NULL && + (groupname = strchr(tmplist->resource, '@')) != NULL) { + /* There is a defined group */ + *groupname++ = '\0'; + group = sa_get_group(handle, groupname); + if (group != NULL) { + share = _sa_add_share(group, tmplist->path, + SA_SHARE_TRANSIENT, &err, + (uint64_t)SA_FEATURE_NONE); + } else { /* - * If this is a legacy share, mark as shared so we - * only update sharetab appropriately. We also keep - * the sharetab options in order to display for legacy - * share with no arguments. + * While this case shouldn't occur very often, it does + * occur out of a "zfs set sharenfs=off" when the + * dataset is also set to canmount=off. A warning will + * then cause the zfs command to abort. Since we add it + * to the default list, everything works properly anyway + * and the library doesn't need to give a warning. */ - set_node_attr(share, "shared", "true"); - (void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s", - tmplist->fstype); - set_node_attr(share, shareopts, tmplist->options); - continue; + share = _sa_add_share(lgroup, + tmplist->path, SA_SHARE_TRANSIENT, + &err, (uint64_t)SA_FEATURE_NONE); } - - /* - * This share is transient so needs to be - * added. Initially, this will be under - * default(legacy) unless it is a ZFS - * share. If zfs, we need a zfs group. - */ - if (tmplist->resource != NULL && - (groupname = strchr(tmplist->resource, '@')) != NULL) { - /* There is a defined group */ - *groupname++ = '\0'; - group = sa_get_group(handle, groupname); + } else { + if (sa_zfs_is_shared(handle, tmplist->path)) { + group = sa_get_group(handle, "zfs"); + if (group == NULL) { + group = sa_create_group(handle, + "zfs", &err); + if (group == NULL && + err == SA_NO_PERMISSION) { + group = _sa_create_group( + (sa_handle_impl_t) + handle, + "zfs"); + } + if (group != NULL) { + (void) sa_create_optionset( + group, tmplist->fstype); + (void) sa_set_group_attr(group, + "zfs", "true"); + } + } if (group != NULL) { - share = _sa_add_share(group, tmplist->path, - SA_SHARE_TRANSIENT, &err, - (uint64_t)SA_FEATURE_NONE); - } else { - /* - * While this case shouldn't - * occur very often, it does - * occur out of a "zfs set - * sharenfs=off" when the - * dataset is also set to - * canmount=off. A warning - * will then cause the zfs - * command to abort. Since we - * add it to the default list, - * everything works properly - * anyway and the library - * doesn't need to give a - * warning. - */ - share = _sa_add_share(lgroup, + share = _sa_add_share(group, tmplist->path, SA_SHARE_TRANSIENT, &err, (uint64_t)SA_FEATURE_NONE); } } else { - if (sa_zfs_is_shared(handle, tmplist->path)) { - group = sa_get_group(handle, "zfs"); - if (group == NULL) { - group = sa_create_group(handle, - "zfs", &err); - if (group == NULL && - err == SA_NO_PERMISSION) { - group = _sa_create_group( - (sa_handle_impl_t) - handle, - "zfs"); - } - if (group != NULL) { - (void) sa_create_optionset( - group, tmplist->fstype); - (void) sa_set_group_attr(group, - "zfs", "true"); - } - } - if (group != NULL) { - share = _sa_add_share(group, - tmplist->path, SA_SHARE_TRANSIENT, - &err, (uint64_t)SA_FEATURE_NONE); - } - } else { - share = _sa_add_share(lgroup, tmplist->path, - SA_SHARE_TRANSIENT, &err, - (uint64_t)SA_FEATURE_NONE); - } + share = _sa_add_share(lgroup, tmplist->path, + SA_SHARE_TRANSIENT, &err, + (uint64_t)SA_FEATURE_NONE); } - if (share == NULL) - (void) printf(dgettext(TEXT_DOMAIN, - "Problem with transient: %s\n"), sa_errorstr(err)); - if (share != NULL) - set_node_attr(share, "shared", "true"); - if (err == SA_OK) { - if (tmplist->options != NULL && - strlen(tmplist->options) > 0) { - (void) sa_parse_legacy_options(share, - tmplist->options, tmplist->fstype); - } - if (tmplist->resource != NULL && - strcmp(tmplist->resource, "-") != 0) - set_node_attr(share, "resource", - tmplist->resource); - if (tmplist->description != NULL) { - xmlNodePtr node; - node = xmlNewChild((xmlNodePtr)share, NULL, - (xmlChar *)"description", NULL); - xmlNodeSetContent(node, - (xmlChar *)tmplist->description); + } + if (share == NULL) + (void) printf(dgettext(TEXT_DOMAIN, + "Problem with transient: %s\n"), sa_errorstr(err)); + if (share != NULL) + set_node_attr(share, "shared", "true"); + if (err == SA_OK) { + if (tmplist->options != NULL && + strlen(tmplist->options) > 0) { + (void) sa_parse_legacy_options(share, + tmplist->options, tmplist->fstype); + } + if (tmplist->resource != NULL && + strcmp(tmplist->resource, "-") != 0) + set_node_attr(share, "resource", + tmplist->resource); + if (tmplist->description != NULL) { + xmlNodePtr node; + node = xmlNewChild((xmlNodePtr)share, NULL, + (xmlChar *)"description", NULL); + xmlNodeSetContent(node, + (xmlChar *)tmplist->description); + } + legacy = 1; + } + return (legacy); +} + +/* + * Given an array of paths, parses the sharetab in /etc/dfs/sharetab looking for + * matches to each path that could be transients from that file. + * + * parse_sharetab_impl has more information on what exactly it is looking for. + */ +int +parse_sharetab_for_paths(sa_handle_t handle, char **paths, size_t paths_len) +{ + int err = 0; + int legacy = 0; + sa_group_t lgroup; + xfs_sharelist_t *list = get_share_list(&err); + + if (list == NULL) + return (legacy); + + lgroup = sa_get_group(handle, "default"); + for (int i = 0; i < paths_len; ++i) { + xfs_sharelist_t *tmplist; + + for (tmplist = list; tmplist != NULL; tmplist = tmplist->next) { + if (strcmp(tmplist->path, paths[i]) == 0) { + break; } - legacy = 1; } + if (tmplist == NULL) { + continue; + } + + legacy = parse_sharetab_impl(handle, tmplist, lgroup); + + } + dfs_free_list(list); + return (legacy); +} + +/* + * Runs parse_sharetab_impl on all the different share lists on the system. + */ +int +parse_sharetab(sa_handle_t handle) +{ + int err = 0; + int legacy = 0; + sa_group_t lgroup; + xfs_sharelist_t *list = get_share_list(&err); + + list = get_share_list(&err); + if (list == NULL) + return (legacy); + + lgroup = sa_get_group(handle, "default"); + + for (xfs_sharelist_t *tmplist = list; tmplist != NULL; + tmplist = tmplist->next) { + legacy |= parse_sharetab_impl(handle, tmplist, lgroup); } dfs_free_list(list); return (legacy); } /* - * Get the transient shares from the sharetab (or other) file. since + * This is the same as gettransients except when parsing sharetab the entries + * are only processed if the path matches an element of paths. + */ +int +get_one_transient(sa_handle_impl_t ihandle, xmlNodePtr *root, char **paths, + size_t paths_len) +{ + int legacy = 0; + char **protocols = NULL; + + if (root != NULL) { + if (*root == NULL) + *root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); + if (*root != NULL) { + legacy = parse_sharetab_for_paths(ihandle, paths, + paths_len); + int numproto = sa_get_protocols(&protocols); + for (int i = 0; i < numproto; i++) + legacy |= sa_proto_get_transients( + (sa_handle_t)ihandle, protocols[i]); + if (protocols != NULL) + free(protocols); + } + } + return (legacy); +} + +/* + * Get the transient shares from the sharetab (or other) file. Since * these are transient, they only appear in the working file and not * in a repository. */ @@ -2183,7 +2258,8 @@ sa_needs_refresh(sa_handle_t handle) uint64_t tstamp; scf_simple_prop_t *prop; - if (handle == NULL) + if (handle == NULL || implhandle->sa_service & + (SA_INIT_ONE_SHARE_FROM_NAME | SA_INIT_ONE_SHARE_FROM_HANDLE)) return (B_TRUE); /* diff --git a/usr/src/lib/libshare/common/mapfile-vers b/usr/src/lib/libshare/common/mapfile-vers index 7314caf827..de74d62038 100644 --- a/usr/src/lib/libshare/common/mapfile-vers +++ b/usr/src/lib/libshare/common/mapfile-vers @@ -20,6 +20,7 @@ # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016 by Delphix. All rights reserved. # # @@ -112,6 +113,7 @@ SYMBOL_VERSION SUNWprivate { sa_get_next_security; sa_get_protocol_status; sa_init; + sa_init_arg; sa_find_share; sa_set_protocol_property; sa_fini; diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index 237c4ca1a2..657ab3f2a2 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -783,6 +783,17 @@ extern int zpool_fru_set(zpool_handle_t *, uint64_t, const char *); extern int zfs_get_hole_count(const char *, uint64_t *, uint64_t *); +/* Allow consumers to initialize libshare externally for optimal performance */ +extern int zfs_init_libshare_arg(libzfs_handle_t *, int, void *); +/* + * For most consumers, zfs_init_libshare_arg is sufficient on its own, and + * zfs_uninit_libshare is unnecessary. zfs_uninit_libshare should only be called + * if the caller has already initialized libshare for one set of zfs handles, + * and wishes to share or unshare filesystems outside of that set. In that case, + * the caller should uninitialize libshare, and then re-initialize it with the + * new handles being shared or unshared. + */ +extern void zfs_uninit_libshare(libzfs_handle_t *); #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libzfs/common/libzfs_changelist.c b/usr/src/lib/libzfs/common/libzfs_changelist.c index 04666cce99..af5cb35f9d 100644 --- a/usr/src/lib/libzfs/common/libzfs_changelist.c +++ b/usr/src/lib/libzfs/common/libzfs_changelist.c @@ -24,7 +24,7 @@ * Use is subject to license terms. * * Portions Copyright 2007 Ramprakash Jelari - * Copyright (c) 2014, 2015 by Delphix. All rights reserved. + * Copyright (c) 2014, 2016 by Delphix. All rights reserved. * Copyright 2016 Igor Kozhukhov */ @@ -162,6 +162,9 @@ changelist_postfix(prop_changelist_t *clp) char shareopts[ZFS_MAXPROPLEN]; int errors = 0; libzfs_handle_t *hdl; + size_t num_datasets = 0, i; + zfs_handle_t **zhandle_arr; + sa_init_selective_arg_t sharearg; /* * If we're changing the mountpoint, attempt to destroy the underlying @@ -186,8 +189,31 @@ changelist_postfix(prop_changelist_t *clp) hdl = cn->cn_handle->zfs_hdl; assert(hdl != NULL); zfs_uninit_libshare(hdl); - } + /* + * For efficiencies sake, we initialize libshare for only a few + * shares (the ones affected here). Future initializations in + * this process should just use the cached initialization. + */ + for (cn = uu_list_last(clp->cl_list); cn != NULL; + cn = uu_list_prev(clp->cl_list, cn)) { + num_datasets++; + } + + zhandle_arr = zfs_alloc(hdl, + num_datasets * sizeof (zfs_handle_t *)); + for (i = 0, cn = uu_list_last(clp->cl_list); cn != NULL; + cn = uu_list_prev(clp->cl_list, cn)) { + zhandle_arr[i++] = cn->cn_handle; + zfs_refresh_properties(cn->cn_handle); + } + assert(i == num_datasets); + sharearg.zhandle_arr = zhandle_arr; + sharearg.zhandle_len = num_datasets; + errors = zfs_init_libshare_arg(hdl, SA_INIT_SHARE_API_SELECTIVE, + &sharearg); + free(zhandle_arr); + } /* * We walk the datasets in reverse, because we want to mount any parent * datasets before mounting the children. We walk all datasets even if @@ -212,8 +238,6 @@ changelist_postfix(prop_changelist_t *clp) continue; cn->cn_needpost = B_FALSE; - zfs_refresh_properties(cn->cn_handle); - if (ZFS_IS_VOLUME(cn->cn_handle)) continue; diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h index d21f167bf3..37d9cf7a79 100644 --- a/usr/src/lib/libzfs/common/libzfs_impl.h +++ b/usr/src/lib/libzfs/common/libzfs_impl.h @@ -203,7 +203,6 @@ void namespace_clear(libzfs_handle_t *); */ extern int zfs_init_libshare(libzfs_handle_t *, int); -extern void zfs_uninit_libshare(libzfs_handle_t *); extern int zfs_parse_options(char *, zfs_share_proto_t); extern int zfs_unshare_proto(zfs_handle_t *, diff --git a/usr/src/lib/libzfs/common/libzfs_mount.c b/usr/src/lib/libzfs/common/libzfs_mount.c index d1419fb3a8..ae6df7fa16 100644 --- a/usr/src/lib/libzfs/common/libzfs_mount.c +++ b/usr/src/lib/libzfs/common/libzfs_mount.c @@ -567,6 +567,7 @@ zfs_is_shared_smb(zfs_handle_t *zhp, char **where) */ static sa_handle_t (*_sa_init)(int); +static sa_handle_t (*_sa_init_arg)(int, void *); static void (*_sa_fini)(sa_handle_t); static sa_share_t (*_sa_find_share)(sa_handle_t, char *); static int (*_sa_enable_share)(sa_share_t, char *); @@ -606,6 +607,8 @@ _zfs_init_libshare(void) if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) { _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init"); + _sa_init_arg = (sa_handle_t (*)(int, void *))dlsym(libshare, + "sa_init_arg"); _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini"); _sa_find_share = (sa_share_t (*)(sa_handle_t, char *)) dlsym(libshare, "sa_find_share"); @@ -625,14 +628,15 @@ _zfs_init_libshare(void) char *, char *))dlsym(libshare, "sa_zfs_process_share"); _sa_update_sharetab_ts = (void (*)(sa_handle_t)) dlsym(libshare, "sa_update_sharetab_ts"); - if (_sa_init == NULL || _sa_fini == NULL || - _sa_find_share == NULL || _sa_enable_share == NULL || - _sa_disable_share == NULL || _sa_errorstr == NULL || - _sa_parse_legacy_options == NULL || + if (_sa_init == NULL || _sa_init_arg == NULL || + _sa_fini == NULL || _sa_find_share == NULL || + _sa_enable_share == NULL || _sa_disable_share == NULL || + _sa_errorstr == NULL || _sa_parse_legacy_options == NULL || _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL || _sa_zfs_process_share == NULL || _sa_update_sharetab_ts == NULL) { _sa_init = NULL; + _sa_init_arg = NULL; _sa_fini = NULL; _sa_disable_share = NULL; _sa_enable_share = NULL; @@ -655,8 +659,8 @@ _zfs_init_libshare(void) * service value is which part(s) of the API to initialize and is a * direct map to the libshare sa_init(service) interface. */ -int -zfs_init_libshare(libzfs_handle_t *zhandle, int service) +static int +zfs_init_libshare_impl(libzfs_handle_t *zhandle, int service, void *arg) { if (_sa_init == NULL) return (SA_CONFIG_ERR); @@ -672,17 +676,29 @@ zfs_init_libshare(libzfs_handle_t *zhandle, int service) if (_sa_needs_refresh != NULL && _sa_needs_refresh(zhandle->libzfs_sharehdl)) { zfs_uninit_libshare(zhandle); - zhandle->libzfs_sharehdl = _sa_init(service); + zhandle->libzfs_sharehdl = _sa_init_arg(service, arg); } if (zhandle && zhandle->libzfs_sharehdl == NULL) - zhandle->libzfs_sharehdl = _sa_init(service); + zhandle->libzfs_sharehdl = _sa_init_arg(service, arg); if (zhandle->libzfs_sharehdl == NULL) return (SA_NO_MEMORY); return (SA_OK); } +int +zfs_init_libshare(libzfs_handle_t *zhandle, int service) +{ + return (zfs_init_libshare_impl(zhandle, service, NULL)); +} + +int +zfs_init_libshare_arg(libzfs_handle_t *zhandle, int service, void *arg) +{ + return (zfs_init_libshare_impl(zhandle, service, arg)); +} + /* * zfs_uninit_libshare(zhandle) @@ -787,8 +803,8 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) ZFS_MAXPROPLEN, B_FALSE) != 0 || strcmp(shareopts, "off") == 0) continue; - - ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API); + ret = zfs_init_libshare_arg(hdl, SA_INIT_ONE_SHARE_FROM_HANDLE, + zhp); if (ret != SA_OK) { (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), @@ -882,6 +898,7 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, sa_share_t share; int err; char *mntpt; + /* * Mountpoint could get trashed if libshare calls getmntany * which it does during API initialization, so strdup the @@ -889,8 +906,14 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, */ mntpt = zfs_strdup(hdl, mountpoint); - /* make sure libshare initialized */ - if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { + /* + * make sure libshare initialized, initialize everything because we + * don't know what other unsharing may happen later. Functions up the + * stack are allowed to initialize instead a subset of shares at the + * time the set is known. + */ + if ((err = zfs_init_libshare_arg(hdl, SA_INIT_ONE_SHARE_FROM_NAME, + (void *)name)) != SA_OK) { free(mntpt); /* don't need the copy anymore */ return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), @@ -1222,6 +1245,7 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) int i; int ret = -1; int flags = (force ? MS_FORCE : 0); + sa_init_selective_arg_t sharearg; namelen = strlen(zhp->zpool_name); @@ -1296,6 +1320,12 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) * At this point, we have the entire list of filesystems, so sort it by * mountpoint. */ + sharearg.zhandle_arr = datasets; + sharearg.zhandle_len = used; + ret = zfs_init_libshare_arg(hdl, SA_INIT_SHARE_API_SELECTIVE, + &sharearg); + if (ret != 0) + goto out; qsort(mountpoints, used, sizeof (char *), mountpoint_compare); /* diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers index bc616be0c2..7fa722a532 100644 --- a/usr/src/lib/libzfs/common/mapfile-vers +++ b/usr/src/lib/libzfs/common/mapfile-vers @@ -88,6 +88,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { zfs_handle_dup; zfs_history_event_names; zfs_hold; + zfs_init_libshare_arg; zfs_is_mounted; zfs_is_shared; zfs_is_shared_nfs; @@ -161,6 +162,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { zfs_spa_version_map; zfs_standard_error; zfs_type_to_name; + zfs_uninit_libshare; zfs_unmount; zfs_unmountall; zfs_unshare; diff --git a/usr/src/test/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh b/usr/src/test/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh index 84e82f9eb8..497529f94f 100644 --- a/usr/src/test/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh +++ b/usr/src/test/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh @@ -331,7 +331,7 @@ function scan_state { #state-file if [[ $op == "-" ]]; then log_note "No operation specified" else - export __ZFS_POOL_RESTRICT="$TESTPOOL" + export __ZFS_POOL_RESTRICT="TESTPOOL" log_must zfs unmount -a unset __ZFS_POOL_RESTRICT -- 2.11.4.GIT