diff options
author | Eric Taylor <Eric.Taylor@Sun.COM> | 2009-09-21 08:55:28 -0600 |
---|---|---|
committer | Eric Taylor <Eric.Taylor@Sun.COM> | 2009-09-21 08:55:28 -0600 |
commit | 681d9761e8516a7dc5ab6589e2dfe717777e1123 (patch) | |
tree | ea18f070a7e3d7bd82dc2844a3e91008816dcd22 /usr/src/lib/libzfs/common/libzfs_dataset.c | |
parent | 14d3298ea5ac04e3c29e86a4769ff92a49e9f4af (diff) | |
download | illumos-joyent-681d9761e8516a7dc5ab6589e2dfe717777e1123.tar.gz |
6438937 if 'zfs destroy' fails, it can leave a zvol device link missing
6573142 zpool destruction/export should better handle stale zvol links
6718816 ZFS volinit fails when ZFS root pool full
6761786 zpool import with 8500 snapshots took 11hours
6604403 replace volinit/volfini with /dev fs vnode ops
6847760 zfs volinit may happen a little too soon during boot
6488792 Warnings on console whenever a volume is created.
6738837 assertion failure in sdev_open
6878496 dmu_objset_own returns EINVAL instead of EROFS in some situations
Diffstat (limited to 'usr/src/lib/libzfs/common/libzfs_dataset.c')
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_dataset.c | 370 |
1 files changed, 13 insertions, 357 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index d5488d9f0a..56e7ca9737 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -24,10 +24,8 @@ * Use is subject to license terms. */ -#include <assert.h> #include <ctype.h> #include <errno.h> -#include <libdevinfo.h> #include <libintl.h> #include <math.h> #include <stdio.h> @@ -39,7 +37,6 @@ #include <fcntl.h> #include <sys/mntent.h> #include <sys/mount.h> -#include <sys/avl.h> #include <priv.h> #include <pwd.h> #include <grp.h> @@ -58,7 +55,6 @@ #include "libzfs_impl.h" #include "zfs_deleg.h" -static int zvol_create_link_common(libzfs_handle_t *, const char *, int); static int userquota_propname_decode(const char *propname, boolean_t zoned, zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp); @@ -1262,10 +1258,7 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) break; case EBUSY: - if (prop == ZFS_PROP_VOLBLOCKSIZE) - (void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf); - else - (void) zfs_standard_error(hdl, EBUSY, errbuf); + (void) zfs_standard_error(hdl, EBUSY, errbuf); break; case EROFS: @@ -2636,18 +2629,6 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, /* create the dataset */ ret = zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc); - if (ret == 0 && type == ZFS_TYPE_VOLUME) { - ret = zvol_create_link(hdl, path); - if (ret) { - (void) zfs_standard_error(hdl, errno, - dgettext(TEXT_DOMAIN, - "Volume successfully created, but device links " - "were not created")); - zcmd_free_nvlists(&zc); - return (-1); - } - } - zcmd_free_nvlists(&zc); /* check for failure */ @@ -2719,9 +2700,6 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer) return (-1); } - if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) - return (-1); - zc.zc_objset_type = DMU_OST_ZVOL; } else { zc.zc_objset_type = DMU_OST_ZFS; @@ -2746,13 +2724,13 @@ struct destroydata { }; static int -zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) +zfs_check_snap_cb(zfs_handle_t *zhp, void *arg) { struct destroydata *dd = arg; zfs_handle_t *szhp; char name[ZFS_MAXNAMELEN]; boolean_t closezhp = dd->closezhp; - int rv; + int rv = 0; (void) strlcpy(name, zhp->zfs_name, sizeof (name)); (void) strlcat(name, "@", sizeof (name)); @@ -2764,17 +2742,9 @@ zfs_remove_link_cb(zfs_handle_t *zhp, void *arg) zfs_close(szhp); } - if (zhp->zfs_type == ZFS_TYPE_VOLUME) { - (void) zvol_remove_link(zhp->zfs_hdl, name); - /* - * NB: this is simply a best-effort. We don't want to - * return an error, because then we wouldn't visit all - * the volumes. - */ - } - dd->closezhp = B_TRUE; - rv = zfs_iter_filesystems(zhp, zfs_remove_link_cb, arg); + if (!dd->gotone) + rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, arg); if (closezhp) zfs_close(zhp); return (rv); @@ -2791,7 +2761,7 @@ zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) struct destroydata dd = { 0 }; dd.snapname = snapname; - (void) zfs_remove_link_cb(zhp, &dd); + (void) zfs_check_snap_cb(zhp, &dd); if (!dd.gotone) { return (zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, @@ -2909,70 +2879,11 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) return (zfs_standard_error(zhp->zfs_hdl, errno, errbuf)); } - } else if (ZFS_IS_VOLUME(zhp)) { - ret = zvol_create_link(zhp->zfs_hdl, target); } return (ret); } -typedef struct promote_data { - char cb_mountpoint[MAXPATHLEN]; - const char *cb_target; - const char *cb_errbuf; - uint64_t cb_pivot_txg; -} promote_data_t; - -static int -promote_snap_cb(zfs_handle_t *zhp, void *data) -{ - promote_data_t *pd = data; - zfs_handle_t *szhp; - char snapname[MAXPATHLEN]; - int rv = 0; - - /* We don't care about snapshots after the pivot point */ - if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > pd->cb_pivot_txg) { - zfs_close(zhp); - return (0); - } - - /* Remove the device link if it's a zvol. */ - if (ZFS_IS_VOLUME(zhp)) - (void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name); - - /* Check for conflicting names */ - (void) strlcpy(snapname, pd->cb_target, sizeof (snapname)); - (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname)); - szhp = make_dataset_handle(zhp->zfs_hdl, snapname); - if (szhp != NULL) { - zfs_close(szhp); - zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, - "snapshot name '%s' from origin \n" - "conflicts with '%s' from target"), - zhp->zfs_name, snapname); - rv = zfs_error(zhp->zfs_hdl, EZFS_EXISTS, pd->cb_errbuf); - } - zfs_close(zhp); - return (rv); -} - -static int -promote_snap_done_cb(zfs_handle_t *zhp, void *data) -{ - promote_data_t *pd = data; - - /* We don't care about snapshots after the pivot point */ - if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) <= pd->cb_pivot_txg) { - /* Create the device link if it's a zvol. */ - if (ZFS_IS_VOLUME(zhp)) - (void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name); - } - - zfs_close(zhp); - return (0); -} - /* * Promotes the given clone fs to be the clone parent. */ @@ -2982,10 +2893,7 @@ zfs_promote(zfs_handle_t *zhp) libzfs_handle_t *hdl = zhp->zfs_hdl; zfs_cmd_t zc = { 0 }; char parent[MAXPATHLEN]; - char *cp; int ret; - zfs_handle_t *pzhp; - promote_data_t pd; char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, @@ -3003,29 +2911,7 @@ zfs_promote(zfs_handle_t *zhp) "not a cloned filesystem")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); } - cp = strchr(parent, '@'); - *cp = '\0'; - /* Walk the snapshots we will be moving */ - pzhp = zfs_open(hdl, zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT); - if (pzhp == NULL) - return (-1); - pd.cb_pivot_txg = zfs_prop_get_int(pzhp, ZFS_PROP_CREATETXG); - zfs_close(pzhp); - pd.cb_target = zhp->zfs_name; - pd.cb_errbuf = errbuf; - pzhp = zfs_open(hdl, parent, ZFS_TYPE_DATASET); - if (pzhp == NULL) - return (-1); - (void) zfs_prop_get(pzhp, ZFS_PROP_MOUNTPOINT, pd.cb_mountpoint, - sizeof (pd.cb_mountpoint), NULL, NULL, 0, FALSE); - ret = zfs_iter_snapshots(pzhp, promote_snap_cb, &pd); - if (ret != 0) { - zfs_close(pzhp); - return (-1); - } - - /* issue the ioctl */ (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, sizeof (zc.zc_value)); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); @@ -3034,62 +2920,18 @@ zfs_promote(zfs_handle_t *zhp) if (ret != 0) { int save_errno = errno; - (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); - zfs_close(pzhp); - switch (save_errno) { case EEXIST: - /* - * There is a conflicting snapshot name. We - * should have caught this above, but they could - * have renamed something in the mean time. - */ + /* There is a conflicting snapshot name. */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "conflicting snapshot name from parent '%s'"), - parent); + "conflicting snapshot '%s' from parent '%s'"), + zc.zc_string, parent); return (zfs_error(hdl, EZFS_EXISTS, errbuf)); default: return (zfs_standard_error(hdl, save_errno, errbuf)); } - } else { - (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); - } - - zfs_close(pzhp); - return (ret); -} - -struct createdata { - const char *cd_snapname; - int cd_ifexists; -}; - -static int -zfs_create_link_cb(zfs_handle_t *zhp, void *arg) -{ - struct createdata *cd = arg; - int ret; - - if (zhp->zfs_type == ZFS_TYPE_VOLUME) { - char name[MAXPATHLEN]; - - (void) strlcpy(name, zhp->zfs_name, sizeof (name)); - (void) strlcat(name, "@", sizeof (name)); - (void) strlcat(name, cd->cd_snapname, sizeof (name)); - (void) zvol_create_link_common(zhp->zfs_hdl, name, - cd->cd_ifexists); - /* - * NB: this is simply a best-effort. We don't want to - * return an error, because then we wouldn't visit all - * the volumes. - */ } - - ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, cd); - - zfs_close(zhp); - return (ret); } @@ -3153,31 +2995,11 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, * if it was recursive, the one that actually failed will be in * zc.zc_name. */ - if (ret != 0) + if (ret != 0) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); - - if (ret == 0 && recursive) { - struct createdata cd; - - cd.cd_snapname = delim + 1; - cd.cd_ifexists = B_FALSE; - (void) zfs_iter_filesystems(zhp, zfs_create_link_cb, &cd); - } - if (ret == 0 && zhp->zfs_type == ZFS_TYPE_VOLUME) { - ret = zvol_create_link(zhp->zfs_hdl, path); - if (ret != 0) { - (void) zfs_standard_error(hdl, errno, - dgettext(TEXT_DOMAIN, - "Volume successfully snapshotted, but device links " - "were not created")); - zfs_close(zhp); - return (-1); - } - } - - if (ret != 0) (void) zfs_standard_error(hdl, errno, errbuf); + } zfs_close(zhp); @@ -3280,8 +3102,6 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) */ if (zhp->zfs_type == ZFS_TYPE_VOLUME) { - if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0) - return (-1); if (zfs_which_resv_prop(zhp, &resv_prop) < 0) return (-1); old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); @@ -3319,10 +3139,6 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) */ if ((zhp->zfs_type == ZFS_TYPE_VOLUME) && (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { - if (err = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name)) { - zfs_close(zhp); - return (err); - } if (restore_resv) { new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); if (old_volsize != new_volsize) @@ -3475,7 +3291,6 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive) } if (recursive) { - struct destroydata dd; parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); if (parentname == NULL) { @@ -3490,15 +3305,6 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive) goto error; } - dd.snapname = delim + 1; - dd.gotone = B_FALSE; - dd.closezhp = B_TRUE; - - /* We remove any zvol links prior to renaming them */ - ret = zfs_iter_filesystems(zhrp, zfs_remove_link_cb, &dd); - if (ret) { - goto error; - } } else { if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0)) == NULL) return (-1); @@ -3546,27 +3352,10 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive) * On failure, we still want to remount any filesystems that * were previously mounted, so we don't alter the system state. */ - if (recursive) { - struct createdata cd; - - /* only create links for datasets that had existed */ - cd.cd_snapname = delim + 1; - cd.cd_ifexists = B_TRUE; - (void) zfs_iter_filesystems(zhrp, zfs_create_link_cb, - &cd); - } else { + if (!recursive) (void) changelist_postfix(cl); - } } else { - if (recursive) { - struct createdata cd; - - /* only create links for datasets that had existed */ - cd.cd_snapname = strchr(target, '@') + 1; - cd.cd_ifexists = B_TRUE; - ret = zfs_iter_filesystems(zhrp, zfs_create_link_cb, - &cd); - } else { + if (!recursive) { changelist_rename(cl, zfs_get_name(zhp), target); ret = changelist_postfix(cl); } @@ -3585,139 +3374,6 @@ error: return (ret); } -/* - * Given a zvol dataset, issue the ioctl to create the appropriate minor node, - * poke devfsadm to create the /dev link, and then wait for the link to appear. - */ -int -zvol_create_link(libzfs_handle_t *hdl, const char *dataset) -{ - return (zvol_create_link_common(hdl, dataset, B_FALSE)); -} - -static int -zvol_create_link_common(libzfs_handle_t *hdl, const char *dataset, int ifexists) -{ - zfs_cmd_t zc = { 0 }; - di_devlink_handle_t dhdl; - priv_set_t *priv_effective; - int privileged; - - (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); - - /* - * Issue the appropriate ioctl. - */ - if (ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE_MINOR, &zc) != 0) { - switch (errno) { - case EEXIST: - /* - * Silently ignore the case where the link already - * exists. This allows 'zfs volinit' to be run multiple - * times without errors. - */ - return (0); - - case ENOENT: - /* - * Dataset does not exist in the kernel. If we - * don't care (see zfs_rename), then ignore the - * error quietly. - */ - if (ifexists) { - return (0); - } - - /* FALLTHROUGH */ - - default: - return (zfs_standard_error_fmt(hdl, errno, - dgettext(TEXT_DOMAIN, "cannot create device links " - "for '%s'"), dataset)); - } - } - - /* - * If privileged call devfsadm and wait for the links to - * magically appear. - * Otherwise, print out an informational message. - */ - - priv_effective = priv_allocset(); - (void) getppriv(PRIV_EFFECTIVE, priv_effective); - privileged = (priv_isfullset(priv_effective) == B_TRUE); - priv_freeset(priv_effective); - - if (privileged) { - if ((dhdl = di_devlink_init(ZFS_DRIVER, - DI_MAKE_LINK)) == NULL) { - zfs_error_aux(hdl, strerror(errno)); - (void) zfs_error_fmt(hdl, errno, - dgettext(TEXT_DOMAIN, "cannot create device links " - "for '%s'"), dataset); - (void) ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); - return (-1); - } else { - (void) di_devlink_fini(&dhdl); - } - } else { - char pathname[MAXPATHLEN]; - struct stat64 statbuf; - int i; - -#define MAX_WAIT 10 - - /* - * This is the poor mans way of waiting for the link - * to show up. If after 10 seconds we still don't - * have it, then print out a message. - */ - (void) snprintf(pathname, sizeof (pathname), "/dev/zvol/dsk/%s", - dataset); - - for (i = 0; i != MAX_WAIT; i++) { - if (stat64(pathname, &statbuf) == 0) - break; - (void) sleep(1); - } - if (i == MAX_WAIT) - (void) printf(gettext("%s may not be immediately " - "available\n"), pathname); - } - - return (0); -} - -/* - * Remove a minor node for the given zvol and the associated /dev links. - */ -int -zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) -{ - zfs_cmd_t zc = { 0 }; - - (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); - - if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { - switch (errno) { - case ENXIO: - /* - * Silently ignore the case where the link no longer - * exists, so that 'zfs volfini' can be run multiple - * times without errors. - */ - return (0); - - default: - return (zfs_standard_error_fmt(hdl, errno, - dgettext(TEXT_DOMAIN, "cannot remove device " - "links for '%s'"), dataset)); - } - } - - return (0); -} - nvlist_t * zfs_get_user_props(zfs_handle_t *zhp) { |