X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=lib%2Flibzfs%2Flibzfs_mount.c;h=0fe83e550c144efd0468df9a86aa7511a2f65b7f;hb=e18be9a637088911d2b618788cd45982986e63cb;hp=7c5c7f3ecaeed850c032b254610c643d60adbd6f;hpb=172bb4bd5e4afef721dd4d2972d8680d983f144b;p=zfs.git diff --git a/lib/libzfs/libzfs_mount.c b/lib/libzfs/libzfs_mount.c index 7c5c7f3..0fe83e5 100644 --- a/lib/libzfs/libzfs_mount.c +++ b/lib/libzfs/libzfs_mount.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -44,17 +43,14 @@ * * zfs_is_shared_nfs() * zfs_is_shared_smb() - * zfs_is_shared_iscsi() * zfs_share_proto() * zfs_shareall(); - * zfs_share_iscsi() * zfs_unshare_nfs() * zfs_unshare_smb() * zfs_unshareall_nfs() * zfs_unshareall_smb() * zfs_unshareall() * zfs_unshareall_bypath() - * zfs_unshare_iscsi() * * The following functions are available for pool consumers, and will * mount/unmount and share/unshare all datasets within pool: @@ -74,7 +70,6 @@ #include #include #include -#include #include #include @@ -90,11 +85,6 @@ static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *); zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **, zfs_share_proto_t); -static int (*iscsitgt_zfs_share)(const char *); -static int (*iscsitgt_zfs_unshare)(const char *); -static int (*iscsitgt_zfs_is_shared)(const char *); -static int (*iscsitgt_svc_online)(); - /* * The share protocols table must be in the same order as the zfs_share_prot_t * enum in libzfs_impl.h @@ -126,29 +116,6 @@ zfs_share_proto_t share_all_proto[] = { PROTO_END }; -#pragma init(zfs_iscsi_init) -static void -zfs_iscsi_init(void) -{ - void *libiscsitgt; - - if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1", - RTLD_LAZY | RTLD_GLOBAL)) == NULL || - (iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt, - "iscsitgt_zfs_share")) == NULL || - (iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt, - "iscsitgt_zfs_unshare")) == NULL || - (iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt, - "iscsitgt_zfs_is_shared")) == NULL || - (iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt, - "iscsitgt_svc_online")) == NULL) { - iscsitgt_zfs_share = NULL; - iscsitgt_zfs_unshare = NULL; - iscsitgt_zfs_is_shared = NULL; - iscsitgt_svc_online = NULL; - } -} - /* * Search the sharetab for the given mountpoint and protocol, returning * a zfs_share_type_t value. @@ -236,18 +203,9 @@ dir_is_empty(const char *dirname) boolean_t is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where) { - struct mnttab search = { 0 }, entry; - - /* - * Search for the entry in /etc/mnttab. We don't bother getting the - * mountpoint, as we can just search for the special device. This will - * also let us find mounts when the mountpoint is 'legacy'. - */ - search.mnt_special = (char *)special; - search.mnt_fstype = MNTTYPE_ZFS; + struct mnttab entry; - rewind(zfs_hdl->libzfs_mnttab); - if (getmntany(zfs_hdl->libzfs_mnttab, &entry, &search) != 0) + if (libzfs_mnttab_find(zfs_hdl, special, &entry) != 0) return (B_FALSE); if (where != NULL) @@ -297,6 +255,128 @@ zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, } /* + * The filesystem is mounted by invoking the system mount utility rather + * than by the system call mount(2). This ensures that the /etc/mtab + * file is correctly locked for the update. Performing our own locking + * and /etc/mtab update requires making an unsafe assumption about how + * the mount utility performs its locking. Unfortunately, this also means + * in the case of a mount failure we do not have the exact errno. We must + * make due with return value from the mount process. + * + * In the long term a shared library called libmount is under development + * which provides a common API to address the locking and errno issues. + * Once the standard mount utility has been updated to use this library + * we can add an autoconf check to conditionally use it. + * + * http://www.kernel.org/pub/linux/utils/util-linux/libmount-docs/index.html + */ + +static int +do_mount(const char *src, const char *mntpt, char *opts) +{ + char *argv[8] = { + "/bin/mount", + "-t", MNTTYPE_ZFS, + "-o", opts, + (char *)src, + (char *)mntpt, + (char *)NULL }; + int rc; + + /* Return only the most critical mount error */ + rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE); + if (rc) { + if (rc & MOUNT_FILEIO) + return EIO; + if (rc & MOUNT_USER) + return EINTR; + if (rc & MOUNT_SOFTWARE) + return EPIPE; + if (rc & MOUNT_SYSERR) + return EAGAIN; + if (rc & MOUNT_USAGE) + return EINVAL; + + return ENXIO; /* Generic error */ + } + + return 0; +} + +static int +do_unmount(const char *mntpt, int flags) +{ + char force_opt[] = "-f"; + char lazy_opt[] = "-l"; + char *argv[7] = { + "/bin/umount", + "-t", MNTTYPE_ZFS, + NULL, NULL, NULL, NULL }; + int rc, count = 3; + + if (flags & MS_FORCE) { + argv[count] = force_opt; + count++; + } + + if (flags & MS_DETACH) { + argv[count] = lazy_opt; + count++; + } + + argv[count] = (char *)mntpt; + rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE); + + return (rc ? EINVAL : 0); +} + +static int +zfs_add_option(zfs_handle_t *zhp, char *options, int len, + zfs_prop_t prop, char *on, char *off) +{ + char *source; + uint64_t value; + + /* Skip adding duplicate default options */ + if ((strstr(options, on) != NULL) || (strstr(options, off) != NULL)) + return (0); + + /* + * zfs_prop_get_int() to not used to ensure our mount options + * are not influenced by the current /etc/mtab contents. + */ + value = getprop_uint64(zhp, prop, &source); + + (void) strlcat(options, ",", len); + (void) strlcat(options, value ? on : off, len); + + return (0); +} + +static int +zfs_add_options(zfs_handle_t *zhp, char *options, int len) +{ + int error = 0; + + error = zfs_add_option(zhp, options, len, + ZFS_PROP_ATIME, MNTOPT_ATIME, MNTOPT_NOATIME); + error = error ? error : zfs_add_option(zhp, options, len, + ZFS_PROP_DEVICES, MNTOPT_DEVICES, MNTOPT_NODEVICES); + error = error ? error : zfs_add_option(zhp, options, len, + ZFS_PROP_EXEC, MNTOPT_EXEC, MNTOPT_NOEXEC); + error = error ? error : zfs_add_option(zhp, options, len, + ZFS_PROP_READONLY, MNTOPT_RO, MNTOPT_RW); + error = error ? error : zfs_add_option(zhp, options, len, + ZFS_PROP_SETUID, MNTOPT_SETUID, MNTOPT_NOSETUID); + error = error ? error : zfs_add_option(zhp, options, len, + ZFS_PROP_XATTR, MNTOPT_XATTR, MNTOPT_NOXATTR); + error = error ? error : zfs_add_option(zhp, options, len, + ZFS_PROP_NBMAND, MNTOPT_NBMAND, MNTOPT_NONBMAND); + + return (error); +} + +/* * Mount the given filesystem. */ int @@ -306,11 +386,43 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags) char mountpoint[ZFS_MAXPROPLEN]; char mntopts[MNT_LINE_MAX]; libzfs_handle_t *hdl = zhp->zfs_hdl; + int remount = 0, rc; - if (options == NULL) - mntopts[0] = '\0'; - else + if (options == NULL) { + (void) strlcpy(mntopts, MNTOPT_DEFAULTS, sizeof (mntopts)); + } else { (void) strlcpy(mntopts, options, sizeof (mntopts)); + } + + if (strstr(mntopts, MNTOPT_REMOUNT) != NULL) + remount = 1; + + /* + * If the pool is imported read-only then all mounts must be read-only + */ + if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL)) + (void) strlcat(mntopts, "," MNTOPT_RO, sizeof (mntopts)); + + /* + * Append default mount options which apply to the mount point. + * This is done because under Linux (unlike Solaris) multiple mount + * points may reference a single super block. This means that just + * given a super block there is no back reference to update the per + * mount point options. + */ + rc = zfs_add_options(zhp, mntopts, sizeof (mntopts)); + if (rc) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "default options unavailable")); + return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, + dgettext(TEXT_DOMAIN, "cannot mount '%s'"), + mountpoint)); + } + + /* + * Append zfsutil option so the mount helper allow the mount + */ + strlcat(mntopts, "," MNTOPT_ZFSUTIL, sizeof (mntopts)); if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) return (0); @@ -328,12 +440,10 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags) /* * Determine if the mountpoint is empty. If so, refuse to perform the - * mount. We don't perform this check if MS_OVERLAY is specified, which - * would defeat the point. We also avoid this check if 'remount' is - * specified. + * mount. We don't perform this check if 'remount' is + * specified or if overlay option(-O) is given */ - if ((flags & MS_OVERLAY) == 0 && - strstr(mntopts, MNTOPT_REMOUNT) == NULL && + if ((flags & MS_OVERLAY) == 0 && !remount && !dir_is_empty(mountpoint)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "directory is not empty")); @@ -342,28 +452,45 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags) } /* perform the mount */ - if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, - MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { + rc = do_mount(zfs_get_name(zhp), mountpoint, mntopts); + if (rc) { /* * Generic errors are nasty, but there are just way too many * from mount(), and they're well-understood. We pick a few * common ones to improve upon. */ - if (errno == EBUSY) { + if (rc == EBUSY) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "mountpoint or dataset is busy")); - } else if (errno == EPERM) { + } else if (rc == EPERM) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Insufficient privileges")); + } else if (rc == ENOTSUP) { + char buf[256]; + int spa_version; + + VERIFY(zfs_spa_version(zhp, &spa_version) == 0); + (void) snprintf(buf, sizeof (buf), + dgettext(TEXT_DOMAIN, "Can't mount a version %lld " + "file system on a version %d pool. Pool must be" + " upgraded to mount this file system."), + (u_longlong_t)zfs_prop_get_int(zhp, + ZFS_PROP_VERSION), spa_version); + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf)); } else { - zfs_error_aux(hdl, strerror(errno)); + zfs_error_aux(hdl, strerror(rc)); } - return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, dgettext(TEXT_DOMAIN, "cannot mount '%s'"), zhp->zfs_name)); } + /* remove the mounted entry before re-adding on remount */ + if (remount) + libzfs_mnttab_remove(hdl, zhp->zfs_name); + + /* add the mounted entry into our cache */ + libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint, mntopts); return (0); } @@ -373,8 +500,10 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags) static int unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags) { - if (umount2(mountpoint, flags) != 0) { - zfs_error_aux(hdl, strerror(errno)); + int error; + + error = do_unmount(mountpoint, flags); + if (error != 0) { return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED, dgettext(TEXT_DOMAIN, "cannot unmount '%s'"), mountpoint)); @@ -389,26 +518,23 @@ unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags) int zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) { - struct mnttab search = { 0 }, entry; + libzfs_handle_t *hdl = zhp->zfs_hdl; + struct mnttab entry; char *mntpt = NULL; - /* check to see if need to unmount the filesystem */ - search.mnt_special = zhp->zfs_name; - search.mnt_fstype = MNTTYPE_ZFS; - rewind(zhp->zfs_hdl->libzfs_mnttab); + /* check to see if we need to unmount the filesystem */ if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && - getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { - + libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) { /* * mountpoint may have come from a call to * getmnt/getmntany if it isn't NULL. If it is NULL, - * we know it comes from getmntany which can then get - * overwritten later. We strdup it to play it safe. + * we know it comes from libzfs_mnttab_find which can + * then get freed later. We strdup it to play it safe. */ if (mountpoint == NULL) - mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); + mntpt = zfs_strdup(hdl, entry.mnt_mountp); else - mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint); + mntpt = zfs_strdup(hdl, mountpoint); /* * Unshare and unmount the filesystem @@ -416,11 +542,12 @@ zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) return (-1); - if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) { + if (unmount_one(hdl, mntpt, flags) != 0) { free(mntpt); (void) zfs_shareall(zhp); return (-1); } + libzfs_mnttab_remove(hdl, zhp->zfs_name); free(mntpt); } @@ -455,7 +582,7 @@ zfs_is_shared(zfs_handle_t *zhp) zfs_share_proto_t *curr_proto; if (ZFS_IS_VOLUME(zhp)) - return (zfs_is_shared_iscsi(zhp)); + return (B_FALSE); for (curr_proto = share_all_proto; *curr_proto != PROTO_END; curr_proto++) @@ -467,18 +594,14 @@ zfs_is_shared(zfs_handle_t *zhp) int zfs_share(zfs_handle_t *zhp) { - if (ZFS_IS_VOLUME(zhp)) - return (zfs_share_iscsi(zhp)); - + assert(!ZFS_IS_VOLUME(zhp)); return (zfs_share_proto(zhp, share_all_proto)); } int zfs_unshare(zfs_handle_t *zhp) { - if (ZFS_IS_VOLUME(zhp)) - return (zfs_unshare_iscsi(zhp)); - + assert(!ZFS_IS_VOLUME(zhp)); return (zfs_unshareall(zhp)); } @@ -494,7 +617,7 @@ zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto) if (!zfs_is_mounted(zhp, &mountpoint)) return (SHARED_NOT_SHARED); - if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) { + if ((rc = is_shared(zhp->zfs_hdl, mountpoint, proto))) { if (where != NULL) *where = mountpoint; else @@ -521,93 +644,6 @@ zfs_is_shared_smb(zfs_handle_t *zhp, char **where) } /* - * Make sure things will work if libshare isn't installed by using - * wrapper functions that check to see that the pointers to functions - * initialized in _zfs_init_libshare() are actually present. - */ - -static sa_handle_t (*_sa_init)(int); -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 *); -static int (*_sa_disable_share)(sa_share_t, char *); -static char *(*_sa_errorstr)(int); -static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *); -static boolean_t (*_sa_needs_refresh)(sa_handle_t *); -static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t); -static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t, - char *, char *, zprop_source_t, char *, char *, char *); -static void (*_sa_update_sharetab_ts)(sa_handle_t); - -/* - * _zfs_init_libshare() - * - * Find the libshare.so.1 entry points that we use here and save the - * values to be used later. This is triggered by the runtime loader. - * Make sure the correct ISA version is loaded. - */ - -#pragma init(_zfs_init_libshare) -static void -_zfs_init_libshare(void) -{ - void *libshare; - char path[MAXPATHLEN]; - char isa[MAXISALEN]; - -#if defined(_LP64) - if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1) - isa[0] = '\0'; -#else - isa[0] = '\0'; -#endif - (void) snprintf(path, MAXPATHLEN, - "/usr/lib/%s/libshare.so.1", isa); - - if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) { - _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init"); - _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"); - _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare, - "sa_enable_share"); - _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare, - "sa_disable_share"); - _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr"); - _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *)) - dlsym(libshare, "sa_parse_legacy_options"); - _sa_needs_refresh = (boolean_t (*)(sa_handle_t *)) - dlsym(libshare, "sa_needs_refresh"); - _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t)) - dlsym(libshare, "sa_get_zfs_handle"); - _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t, - sa_share_t, char *, char *, zprop_source_t, char *, - 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 || - _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL || - _sa_zfs_process_share == NULL || - _sa_update_sharetab_ts == NULL) { - _sa_init = NULL; - _sa_fini = NULL; - _sa_disable_share = NULL; - _sa_enable_share = NULL; - _sa_errorstr = NULL; - _sa_parse_legacy_options = NULL; - (void) dlclose(libshare); - _sa_needs_refresh = NULL; - _sa_get_zfs_handle = NULL; - _sa_zfs_process_share = NULL; - _sa_update_sharetab_ts = NULL; - } - } -} - -/* * zfs_init_libshare(zhandle, service) * * Initialize the libshare API if it hasn't already been initialized. @@ -620,9 +656,6 @@ zfs_init_libshare(libzfs_handle_t *zhandle, int service) { int ret = SA_OK; - if (_sa_init == NULL) - ret = SA_CONFIG_ERR; - if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) { /* * We had a cache miss. Most likely it is a new ZFS @@ -633,15 +666,14 @@ zfs_init_libshare(libzfs_handle_t *zhandle, int service) * internal cache. */ zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS; - if (_sa_needs_refresh != NULL && - _sa_needs_refresh(zhandle->libzfs_sharehdl)) { + if (sa_needs_refresh(zhandle->libzfs_sharehdl)) { zfs_uninit_libshare(zhandle); - zhandle->libzfs_sharehdl = _sa_init(service); + zhandle->libzfs_sharehdl = sa_init(service); } } if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL) - zhandle->libzfs_sharehdl = _sa_init(service); + zhandle->libzfs_sharehdl = sa_init(service); if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL) ret = SA_NO_MEMORY; @@ -659,8 +691,7 @@ void zfs_uninit_libshare(libzfs_handle_t *zhandle) { if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) { - if (_sa_fini != NULL) - _sa_fini(zhandle->libzfs_sharehdl); + sa_fini(zhandle->libzfs_sharehdl); zhandle->libzfs_sharehdl = NULL; } } @@ -674,53 +705,8 @@ zfs_uninit_libshare(libzfs_handle_t *zhandle) int zfs_parse_options(char *options, zfs_share_proto_t proto) { - if (_sa_parse_legacy_options != NULL) { - return (_sa_parse_legacy_options(NULL, options, - proto_table[proto].p_name)); - } - return (SA_CONFIG_ERR); -} - -/* - * zfs_sa_find_share(handle, path) - * - * wrapper around sa_find_share to find a share path in the - * configuration. - */ -static sa_share_t -zfs_sa_find_share(sa_handle_t handle, char *path) -{ - if (_sa_find_share != NULL) - return (_sa_find_share(handle, path)); - return (NULL); -} - -/* - * zfs_sa_enable_share(share, proto) - * - * Wrapper for sa_enable_share which enables a share for a specified - * protocol. - */ -static int -zfs_sa_enable_share(sa_share_t share, char *proto) -{ - if (_sa_enable_share != NULL) - return (_sa_enable_share(share, proto)); - return (SA_CONFIG_ERR); -} - -/* - * zfs_sa_disable_share(share, proto) - * - * Wrapper for sa_enable_share which disables a share for a specified - * protocol. - */ -static int -zfs_sa_disable_share(sa_share_t share, char *proto) -{ - if (_sa_disable_share != NULL) - return (_sa_disable_share(share, proto)); - return (SA_CONFIG_ERR); + return (sa_parse_legacy_options(NULL, options, + proto_table[proto].p_name)); } /* @@ -746,8 +732,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), - zfs_get_name(zhp), _sa_errorstr != NULL ? - _sa_errorstr(ret) : ""); + zfs_get_name(zhp), sa_errorstr(ret)); return (-1); } @@ -770,7 +755,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) continue; - share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint); + share = sa_find_share(hdl->libzfs_sharehdl, mountpoint); if (share == NULL) { /* * This may be a new file system that was just @@ -781,7 +766,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) * safe to add this to the internal * configuration. */ - if (_sa_zfs_process_share(hdl->libzfs_sharehdl, + if (sa_zfs_process_share(hdl->libzfs_sharehdl, NULL, NULL, mountpoint, proto_table[*curr_proto].p_name, sourcetype, shareopts, sourcestr, zhp->zfs_name) != SA_OK) { @@ -792,12 +777,12 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) return (-1); } hdl->libzfs_shareflags |= ZFSSHARE_MISS; - share = zfs_sa_find_share(hdl->libzfs_sharehdl, + share = sa_find_share(hdl->libzfs_sharehdl, mountpoint); } if (share != NULL) { int err; - err = zfs_sa_enable_share(share, + err = sa_enable_share(share, proto_table[*curr_proto].p_name); if (err != SA_OK) { (void) zfs_error_fmt(hdl, @@ -849,7 +834,7 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, char *mntpt; /* * Mountpoint could get trashed if libshare calls getmntany - * which id does during API initialization, so strdup the + * which it does during API initialization, so strdup the * value. */ mntpt = zfs_strdup(hdl, mountpoint); @@ -859,18 +844,18 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, free(mntpt); /* don't need the copy anymore */ return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), - name, _sa_errorstr(err))); + name, sa_errorstr(err))); } - share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt); + share = sa_find_share(hdl->libzfs_sharehdl, mntpt); free(mntpt); /* don't need the copy anymore */ if (share != NULL) { - err = zfs_sa_disable_share(share, proto_table[proto].p_name); + err = sa_disable_share(share, proto_table[proto].p_name); if (err != SA_OK) { return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), - name, _sa_errorstr(err))); + name, sa_errorstr(err))); } } else { return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, @@ -887,18 +872,17 @@ int zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, zfs_share_proto_t *proto) { - struct mnttab search = { 0 }, entry; + libzfs_handle_t *hdl = zhp->zfs_hdl; + struct mnttab entry; char *mntpt = NULL; /* check to see if need to unmount the filesystem */ - search.mnt_special = (char *)zfs_get_name(zhp); - search.mnt_fstype = MNTTYPE_ZFS; rewind(zhp->zfs_hdl->libzfs_mnttab); if (mountpoint != NULL) - mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint); + mountpoint = mntpt = zfs_strdup(hdl, mountpoint); if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && - getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { + libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) { zfs_share_proto_t *curr_proto; if (mountpoint == NULL) @@ -907,8 +891,8 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { - if (is_shared(zhp->zfs_hdl, mntpt, *curr_proto) && - unshare_one(zhp->zfs_hdl, zhp->zfs_name, + if (is_shared(hdl, mntpt, *curr_proto) && + unshare_one(hdl, zhp->zfs_name, mntpt, *curr_proto) != 0) { if (mntpt != NULL) free(mntpt); @@ -1010,93 +994,29 @@ remove_mountpoint(zfs_handle_t *zhp) } } -boolean_t -zfs_is_shared_iscsi(zfs_handle_t *zhp) -{ - - /* - * If iscsi deamon isn't running then we aren't shared - */ - if (iscsitgt_svc_online && iscsitgt_svc_online() == 1) - return (B_FALSE); - else - return (iscsitgt_zfs_is_shared != NULL && - iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); -} - -int -zfs_share_iscsi(zfs_handle_t *zhp) -{ - char shareopts[ZFS_MAXPROPLEN]; - const char *dataset = zhp->zfs_name; - libzfs_handle_t *hdl = zhp->zfs_hdl; - - /* - * Return success if there are no share options. - */ - if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, - sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || - strcmp(shareopts, "off") == 0) - return (0); - - if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) { - int error = EZFS_SHAREISCSIFAILED; - - /* - * If service isn't availabele and EPERM was - * returned then use special error. - */ - if (iscsitgt_svc_online && errno == EPERM && - (iscsitgt_svc_online() != 0)) - error = EZFS_ISCSISVCUNAVAIL; - - return (zfs_error_fmt(hdl, error, - dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); - } - - return (0); -} - -int -zfs_unshare_iscsi(zfs_handle_t *zhp) +void +libzfs_add_handle(get_all_cb_t *cbp, zfs_handle_t *zhp) { - const char *dataset = zfs_get_name(zhp); - libzfs_handle_t *hdl = zhp->zfs_hdl; - - /* - * Return if the volume is not shared - */ - if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI) - return (0); + if (cbp->cb_alloc == cbp->cb_used) { + size_t newsz; + void *ptr; - /* - * If this fails with ENODEV it indicates that zvol wasn't shared so - * we should return success in that case. - */ - if (iscsitgt_zfs_unshare == NULL || - (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) { - if (errno == EPERM) - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "Insufficient privileges to unshare iscsi")); - return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED, - dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); + newsz = cbp->cb_alloc ? cbp->cb_alloc * 2 : 64; + ptr = zfs_realloc(zhp->zfs_hdl, + cbp->cb_handles, cbp->cb_alloc * sizeof (void *), + newsz * sizeof (void *)); + cbp->cb_handles = ptr; + cbp->cb_alloc = newsz; } - - return (0); + cbp->cb_handles[cbp->cb_used++] = zhp; } -typedef struct mount_cbdata { - zfs_handle_t **cb_datasets; - int cb_used; - int cb_alloc; -} mount_cbdata_t; - static int mount_cb(zfs_handle_t *zhp, void *data) { - mount_cbdata_t *cbp = data; + get_all_cb_t *cbp = data; - if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) { + if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) { zfs_close(zhp); return (0); } @@ -1106,25 +1026,16 @@ mount_cb(zfs_handle_t *zhp, void *data) return (0); } - if (cbp->cb_alloc == cbp->cb_used) { - void *ptr; - - if ((ptr = zfs_realloc(zhp->zfs_hdl, - cbp->cb_datasets, cbp->cb_alloc * sizeof (void *), - cbp->cb_alloc * 2 * sizeof (void *))) == NULL) - return (-1); - cbp->cb_datasets = ptr; - - cbp->cb_alloc *= 2; + libzfs_add_handle(cbp, zhp); + if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) { + zfs_close(zhp); + return (-1); } - - cbp->cb_datasets[cbp->cb_used++] = zhp; - - return (zfs_iter_filesystems(zhp, mount_cb, cbp)); + return (0); } -static int -dataset_cmp(const void *a, const void *b) +int +libzfs_dataset_cmp(const void *a, const void *b) { zfs_handle_t **za = (zfs_handle_t **)a; zfs_handle_t **zb = (zfs_handle_t **)b; @@ -1162,7 +1073,7 @@ dataset_cmp(const void *a, const void *b) int zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) { - mount_cbdata_t cb = { 0 }; + get_all_cb_t cb = { 0 }; libzfs_handle_t *hdl = zhp->zpool_hdl; zfs_handle_t *zfsp; int i, ret = -1; @@ -1171,33 +1082,29 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) /* * Gather all non-snap datasets within the pool. */ - if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) - return (-1); - cb.cb_alloc = 4; - if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL) goto out; - cb.cb_datasets[0] = zfsp; - cb.cb_used = 1; - + libzfs_add_handle(&cb, zfsp); if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0) goto out; - /* * Sort the datasets by mountpoint. */ - qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp); + qsort(cb.cb_handles, cb.cb_used, sizeof (void *), + libzfs_dataset_cmp); /* * And mount all the datasets, keeping track of which ones - * succeeded or failed. By using zfs_alloc(), the good pointer - * will always be non-NULL. + * succeeded or failed. */ - good = zfs_alloc(zhp->zpool_hdl, cb.cb_used * sizeof (int)); + if ((good = zfs_alloc(zhp->zpool_hdl, + cb.cb_used * sizeof (int))) == NULL) + goto out; + ret = 0; for (i = 0; i < cb.cb_used; i++) { - if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0) + if (zfs_mount(cb.cb_handles[i], mntopts, flags) != 0) ret = -1; else good[i] = 1; @@ -1210,7 +1117,7 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) * zfs_alloc is supposed to exit if memory isn't available. */ for (i = 0; i < cb.cb_used; i++) { - if (good[i] && zfs_share(cb.cb_datasets[i]) != 0) + if (good[i] && zfs_share(cb.cb_handles[i]) != 0) ret = -1; } @@ -1218,34 +1125,12 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) out: for (i = 0; i < cb.cb_used; i++) - zfs_close(cb.cb_datasets[i]); - free(cb.cb_datasets); + zfs_close(cb.cb_handles[i]); + free(cb.cb_handles); return (ret); } - -static int -zvol_cb(const char *dataset, void *data) -{ - libzfs_handle_t *hdl = data; - zfs_handle_t *zhp; - - /* - * Ignore snapshots and ignore failures from non-existant datasets. - */ - if (strchr(dataset, '@') != NULL || - (zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL) - return (0); - - if (zfs_unshare_iscsi(zhp) != 0) - return (-1); - - zfs_close(zhp); - - return (0); -} - static int mountpoint_compare(const void *a, const void *b) { @@ -1255,14 +1140,15 @@ mountpoint_compare(const void *a, const void *b) return (strcmp(mountb, mounta)); } +/* alias for 2002/240 */ +#pragma weak zpool_unmount_datasets = zpool_disable_datasets /* * Unshare and unmount all datasets within the given pool. We don't want to * rely on traversing the DSL to discover the filesystems within the pool, * because this may be expensive (if not all of them are mounted), and can fail - * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and + * arbitrarily (on I/O error, for example). Instead, we walk /etc/mtab and * gather all the filesystems that are currently mounted. */ -#pragma weak zpool_unmount_datasets = zpool_disable_datasets int zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) { @@ -1276,12 +1162,6 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) int ret = -1; int flags = (force ? MS_FORCE : 0); - /* - * First unshare all zvols. - */ - if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0) - return (-1); - namelen = strlen(zhp->zpool_name); rewind(hdl->libzfs_mnttab);