X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=lib%2Flibzfs%2Flibzfs_dataset.c;h=c51b99d53cd71da96a836632502cf908a8847afc;hb=ea1fdf46e2d37e9eb048f9add0fb06e77e9ee6e2;hp=e8c329ced9cb42773ecf6cb8a3f086647679e04a;hpb=ff998d804ff2fec3adc91fd0e78d25998094aca9;p=zfs.git diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index e8c329c..c51b99d 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -22,7 +22,8 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2010 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2011 by Delphix. All rights reserved. + * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2012 Pawel Jakub Dawidek . */ #include @@ -480,6 +481,23 @@ make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) return (zhp); } +static zfs_handle_t * +make_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc) +{ + zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1); + + if (zhp == NULL) + return (NULL); + + zhp->zfs_hdl = pzhp->zfs_hdl; + (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); + zhp->zfs_head_type = pzhp->zfs_type; + zhp->zfs_type = ZFS_TYPE_SNAPSHOT; + zhp->zpool_hdl = zpool_handle(zhp); + + return (zhp); +} + /* * Opens the given snapshot, filesystem, or volume. The 'types' * argument is a mask of acceptable types. The function will print an @@ -2518,7 +2536,8 @@ zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) * Iterate over all snapshots */ int -zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) +zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func, + void *data) { zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 }; zfs_handle_t *nzhp; @@ -2527,15 +2546,19 @@ zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data) if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) return (0); + zc.zc_simple = simple; + if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) return (-1); while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc)) == 0) { - if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, - &zc)) == NULL) { + if (simple) + nzhp = make_dataset_simple_handle_zc(zhp, &zc); + else + nzhp = make_dataset_handle_zc(zhp->zfs_hdl, &zc); + if (nzhp == NULL) continue; - } if ((ret = func(nzhp, data)) != 0) { zcmd_free_nvlists(&zc); @@ -2557,7 +2580,7 @@ zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) return (ret); - return (zfs_iter_snapshots(zhp, func, data)); + return (zfs_iter_snapshots(zhp, B_FALSE, func, data)); } /* @@ -3287,7 +3310,7 @@ zfs_promote(zfs_handle_t *zhp) 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); + ret = zfs_iter_snapshots(pzhp, B_FALSE, promote_snap_cb, &pd); if (ret != 0) { zfs_close(pzhp); return (-1); @@ -3302,7 +3325,8 @@ zfs_promote(zfs_handle_t *zhp) if (ret != 0) { int save_errno = errno; - (void) zfs_iter_snapshots(pzhp, promote_snap_done_cb, &pd); + (void) zfs_iter_snapshots(pzhp, B_FALSE, promote_snap_done_cb, + &pd); zfs_close(pzhp); switch (save_errno) { @@ -3321,7 +3345,8 @@ zfs_promote(zfs_handle_t *zhp) return (zfs_standard_error(hdl, save_errno, errbuf)); } } else { - (void) zfs_iter_snapshots(zhp, promote_snap_done_cb, &pd); + (void) zfs_iter_snapshots(zhp, B_FALSE, promote_snap_done_cb, + &pd); } zfs_close(pzhp); @@ -3920,10 +3945,29 @@ int zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) { zfs_cmd_t zc = { "\0", "\0", "\0", "\0", 0 }; + int timeout = 3000; /* in milliseconds */ + int error = 0; + int i; (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); - if (ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc) != 0) { + /* + * Due to concurrent updates by udev the device may be reported as + * busy. In this case don't immediately fail. Instead briefly delay + * and retry the ioctl() which is now likely to succeed. If unable + * remove the link after timeout milliseconds return the failure. + */ + for (i = 0; i < timeout; i++) { + error = ioctl(hdl->libzfs_fd, ZFS_IOC_REMOVE_MINOR, &zc); + if (error && errno == EBUSY) { + usleep(1000); + continue; + } else { + break; + } + } + + if (error) { switch (errno) { case ENXIO: /* @@ -3936,7 +3980,7 @@ zvol_remove_link(libzfs_handle_t *hdl, const char *dataset) default: return (zfs_standard_error_fmt(hdl, errno, dgettext(TEXT_DOMAIN, "cannot remove device " - "links for '%s'"), dataset)); + "links for '%s': %s"), dataset, strerror(errno))); } } @@ -4333,7 +4377,7 @@ tryagain: (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); - if (zfs_ioctl(hdl, ZFS_IOC_GET_FSACL, &zc) != 0) { + if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), zc.zc_name);