summaryrefslogtreecommitdiff
path: root/usr/src/lib/libzfs/common/libzfs_dataset.c
diff options
context:
space:
mode:
authorEric Taylor <Eric.Taylor@Sun.COM>2009-09-21 08:55:28 -0600
committerEric Taylor <Eric.Taylor@Sun.COM>2009-09-21 08:55:28 -0600
commit681d9761e8516a7dc5ab6589e2dfe717777e1123 (patch)
treeea18f070a7e3d7bd82dc2844a3e91008816dcd22 /usr/src/lib/libzfs/common/libzfs_dataset.c
parent14d3298ea5ac04e3c29e86a4769ff92a49e9f4af (diff)
downloadillumos-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.c370
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)
{