/* * zfs_init_libshare(zhandle, service) * * Initialize the libshare API if it hasn't already been initialized. * In all cases it returns 0 if it succeeded and an error if not. The * 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) { int ret = SA_OK; if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) { /* * We had a cache miss. Most likely it is a new ZFS * dataset that was just created. We want to make sure * so check timestamps to see if a different process * has updated any of the configuration. If there was * some non-ZFS change, we need to re-initialize the * internal cache. */ zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS; if (sa_needs_refresh(zhandle->libzfs_sharehdl)) { zfs_uninit_libshare(zhandle); zhandle->libzfs_sharehdl = sa_init(service); } } if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL) zhandle->libzfs_sharehdl = sa_init(service); if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL) ret = SA_NO_MEMORY; return (ret); }
/* * zfs_init_libshare(zhandle, service) * * Initialize the libshare API if it hasn't already been initialized. * In all cases it returns 0 if it succeeded and an error if not. The * 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) { if (_sa_init == NULL) return (SA_CONFIG_ERR); /* * Attempt to refresh libshare. This is necessary if there was a cache * miss for a new ZFS dataset that was just created, or if state of the * sharetab file has changed since libshare was last initialized. We * want to make sure so check timestamps to see if a different process * has updated any of the configuration. If there was some non-ZFS * change, we need to re-initialize the internal cache. */ if (_sa_needs_refresh != NULL && _sa_needs_refresh(zhandle->libzfs_sharehdl)) { zfs_uninit_libshare(zhandle); zhandle->libzfs_sharehdl = _sa_init(service); } if (zhandle && zhandle->libzfs_sharehdl == NULL) zhandle->libzfs_sharehdl = _sa_init(service); if (zhandle->libzfs_sharehdl == NULL) return (SA_NO_MEMORY); return (SA_OK); }
void libzfs_fini(libzfs_handle_t *hdl) { (void) close(hdl->libzfs_fd); if (hdl->libzfs_mnttab) (void) fclose(hdl->libzfs_mnttab); if (hdl->libzfs_sharetab) (void) fclose(hdl->libzfs_sharetab); #ifndef __APPLE__ zfs_uninit_libshare(hdl); #endif if (hdl->libzfs_log_str) (void) free(hdl->libzfs_log_str); namespace_clear(hdl); free(hdl); }
/* * zfs_init_libshare(zhandle, service) * * Initialize the libshare API if it hasn't already been initialized. * In all cases it returns 0 if it succeeded and an error if not. The * service value is which part(s) of the API to initialize and is a * direct map to the libshare sa_init(service) interface. */ static int zfs_init_libshare_impl(libzfs_handle_t *zhandle, int service, void *arg) { #ifdef illumos /* * libshare is either not installed or we're in a branded zone. The * rest of the wrapper functions around the libshare calls already * handle NULL function pointers, but we don't want the callers of * zfs_init_libshare() to fail prematurely if libshare is not available. */ if (_sa_init == NULL) return (SA_OK); /* * Attempt to refresh libshare. This is necessary if there was a cache * miss for a new ZFS dataset that was just created, or if state of the * sharetab file has changed since libshare was last initialized. We * want to make sure so check timestamps to see if a different process * has updated any of the configuration. If there was some non-ZFS * change, we need to re-initialize the internal cache. */ if (_sa_needs_refresh != NULL && _sa_needs_refresh(zhandle->libzfs_sharehdl)) { zfs_uninit_libshare(zhandle); zhandle->libzfs_sharehdl = _sa_init_arg(service, arg); } if (zhandle && zhandle->libzfs_sharehdl == NULL) zhandle->libzfs_sharehdl = _sa_init_arg(service, arg); if (zhandle->libzfs_sharehdl == NULL) return (SA_NO_MEMORY); #endif return (SA_OK); }
/* * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or * reshare the filesystems as necessary. In changelist_gather() we recorded * whether the filesystem was previously shared or mounted. The action we take * depends on the previous state, and whether the value was previously 'legacy'. * For non-legacy properties, we only remount/reshare the filesystem if it was * previously mounted/shared. Otherwise, we always remount/reshare the * filesystem. */ int changelist_postfix(prop_changelist_t *clp) { prop_changenode_t *cn; char shareopts[ZFS_MAXPROPLEN]; int errors = 0; libzfs_handle_t *hdl; /* * If we're changing the mountpoint, attempt to destroy the underlying * mountpoint. All other datasets will have inherited from this dataset * (in which case their mountpoints exist in the filesystem in the new * location), or have explicit mountpoints set (in which case they won't * be in the changelist). */ if ((cn = uu_list_last(clp->cl_list)) == NULL) return (0); if (clp->cl_prop == ZFS_PROP_MOUNTPOINT && !(clp->cl_gflags & CL_GATHER_DONT_UNMOUNT)) { 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. 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; boolean_t mounted; /* * If we are in the global zone, but this dataset is exported * to a local zone, do nothing. */ 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)) continue; /* * 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)); mounted = (clp->cl_gflags & CL_GATHER_DONT_UNMOUNT) || zfs_is_mounted(cn->cn_handle, NULL); if (!mounted && (cn->cn_mounted || ((sharenfs || sharesmb || clp->cl_waslegacy) && (zfs_prop_get_int(cn->cn_handle, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON)))) { if (zfs_mount(cn->cn_handle, NULL, 0) != 0) errors++; else mounted = TRUE; } /* * If the file system is mounted we always re-share even * if the filesystem is currently shared, so that we can * adopt any new options. */ if (sharenfs && mounted) 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 && mounted) errors += zfs_share_smb(cn->cn_handle); else if (cn->cn_shared || clp->cl_waslegacy) errors += zfs_unshare_smb(cn->cn_handle, NULL); } return (errors ? -1 : 0); }
/* * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or * reshare the filesystems as necessary. In changelist_gather() we recorded * whether the filesystem was previously shared or mounted. The action we take * depends on the previous state, and whether the value was previously 'legacy'. * For non-legacy properties, we only remount/reshare the filesystem if it was * previously mounted/shared. Otherwise, we always remount/reshare the * filesystem. */ int changelist_postfix(prop_changelist_t *clp) { prop_changenode_t *cn; char shareopts[ZFS_MAXPROPLEN]; int ret = 0; libzfs_handle_t *hdl; /* * If we're changing the mountpoint, attempt to destroy the underlying * mountpoint. All other datasets will have inherited from this dataset * (in which case their mountpoints exist in the filesystem in the new * location), or have explicit mountpoints set (in which case they won't * be in the changelist). */ if ((cn = uu_list_last(clp->cl_list)) == NULL) return (0); if (clp->cl_prop == ZFS_PROP_MOUNTPOINT) 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); #ifndef __APPLE__ zfs_uninit_libshare(hdl); #endif } /* * We walk the datasets in reverse, because we want to mount any parent * datasets before mounting the children. */ for (cn = uu_list_last(clp->cl_list); cn != NULL; cn = uu_list_prev(clp->cl_list, cn)) { boolean_t sharenfs; #ifndef __APPLE__ /* * If we are in the global zone, but this dataset is exported * to a local zone, do nothing. */ if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned) continue; #endif /*!__APPLE__*/ zfs_refresh_properties(cn->cn_handle); if (ZFS_IS_VOLUME(cn->cn_handle)) { /* * If we're doing a rename, recreate the /dev/zvol * links. */ if (clp->cl_realprop == ZFS_PROP_NAME && zvol_create_link(cn->cn_handle->zfs_hdl, cn->cn_handle->zfs_name) != 0) { ret = -1; } else if (cn->cn_shared || clp->cl_prop == ZFS_PROP_SHAREISCSI) { if (zfs_prop_get(cn->cn_handle, ZFS_PROP_SHAREISCSI, shareopts, sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 && strcmp(shareopts, "off") == 0) { ret = zfs_unshare_iscsi(cn->cn_handle); } else { ret = zfs_share_iscsi(cn->cn_handle); } } continue; } /* * Remount if previously mounted or mountpoint was legacy, * or sharenfs 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)); if ((cn->cn_mounted || clp->cl_waslegacy || sharenfs) && !zfs_is_mounted(cn->cn_handle, NULL) && zfs_mount(cn->cn_handle, NULL, 0) != 0) ret = -1; /* * 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_waslegacy || sharenfs) { if (sharenfs) ret = zfs_share_nfs(cn->cn_handle); else ret = zfs_unshare_nfs(cn->cn_handle, NULL); } } return (ret); }