diff --git a/include/libzfs_impl.h b/include/libzfs_impl.h index 7daf8348b..5502455e0 100644 --- a/include/libzfs_impl.h +++ b/include/libzfs_impl.h @@ -193,8 +193,6 @@ zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *); int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **); -int zvol_create_link(libzfs_handle_t *, const char *); -int zvol_remove_link(libzfs_handle_t *, const char *); boolean_t zpool_name_valid(libzfs_handle_t *, boolean_t, const char *); int zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index e945b40a9..08076bc09 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -793,8 +793,6 @@ typedef enum zfs_ioc { ZFS_IOC_DATASET_LIST_NEXT, ZFS_IOC_SNAPSHOT_LIST_NEXT, ZFS_IOC_SET_PROP, - ZFS_IOC_CREATE_MINOR, - ZFS_IOC_REMOVE_MINOR, ZFS_IOC_CREATE, ZFS_IOC_DESTROY, ZFS_IOC_ROLLBACK, diff --git a/include/sys/zfs_ioctl.h b/include/sys/zfs_ioctl.h index 4a717b7d1..52557d210 100644 --- a/include/sys/zfs_ioctl.h +++ b/include/sys/zfs_ioctl.h @@ -359,6 +359,8 @@ extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr); extern int zfs_unmount_snap(const char *); extern void zfs_destroy_unmount_origin(const char *); +extern boolean_t dataset_name_hidden(const char *name); + enum zfsdev_state_type { ZST_ONEXIT, ZST_ZEVENT, diff --git a/include/sys/zvol.h b/include/sys/zvol.h index 640538c2c..04e099657 100644 --- a/include/sys/zvol.h +++ b/include/sys/zvol.h @@ -38,10 +38,11 @@ extern int zvol_check_volblocksize(uint64_t volblocksize); extern int zvol_get_stats(objset_t *os, nvlist_t *nv); extern boolean_t zvol_is_zvol(const char *); extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); -extern int zvol_create_minor(const char *); -extern int zvol_create_minors(char *); -extern int zvol_remove_minor(const char *); -extern void zvol_remove_minors(const char *); +extern int zvol_create_minor(const char *name); +extern int zvol_create_minors(const char *name); +extern int zvol_remove_minor(const char *name); +extern void zvol_remove_minors(const char *name); +extern void zvol_rename_minors(const char *oldname, const char *newname); extern int zvol_set_volsize(const char *, uint64_t); extern int zvol_set_volblocksize(const char *, uint64_t); extern int zvol_set_snapdev(const char *, uint64_t); diff --git a/lib/libzfs/libzfs_changelist.c b/lib/libzfs/libzfs_changelist.c index 3a83e2d71..0bcfc0423 100644 --- a/lib/libzfs/libzfs_changelist.c +++ b/lib/libzfs/libzfs_changelist.c @@ -291,30 +291,22 @@ changelist_rename(prop_changelist_t *clp, const char *src, const char *dst) for (cn = uu_list_first(clp->cl_list); cn != NULL; cn = uu_list_next(clp->cl_list, cn)) { - zfs_handle_t *hdl; - - hdl = cn->cn_handle; - /* * Do not rename a clone that's not in the source hierarchy. */ - if (!isa_child_of(hdl->zfs_name, src)) + if (!isa_child_of(cn->cn_handle->zfs_name, src)) continue; /* * Destroy the previous mountpoint if needed. */ - remove_mountpoint(hdl); + remove_mountpoint(cn->cn_handle); (void) strlcpy(newname, dst, sizeof (newname)); - (void) strcat(newname, hdl->zfs_name + strlen(src)); + (void) strcat(newname, cn->cn_handle->zfs_name + strlen(src)); - if (ZFS_IS_VOLUME(hdl)) { - (void) zvol_remove_link(hdl->zfs_hdl, hdl->zfs_name); - (void) zvol_create_link(hdl->zfs_hdl, newname); - } - - (void) strlcpy(hdl->zfs_name, newname, sizeof (hdl->zfs_name)); + (void) strlcpy(cn->cn_handle->zfs_name, newname, + sizeof (cn->cn_handle->zfs_name)); } } diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 9810b2e2d..90b6572b1 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -63,7 +63,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); @@ -418,8 +417,7 @@ make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS) zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM; else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER) - return (-1); /* zpios' and other testing datasets are - of this type, ignore if encountered */ + return (-1); else abort(); @@ -2121,7 +2119,8 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, localtime_r(&time, &t) == NULL || strftime(propbuf, proplen, "%a %b %e %k:%M %Y", &t) == 0) - (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t) val); + (void) snprintf(propbuf, proplen, "%llu", + (u_longlong_t) val); } break; @@ -2628,7 +2627,7 @@ zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, if (literal) { (void) snprintf(propbuf, proplen, "%llu", - (u_longlong_t)propvalue); + (u_longlong_t)propvalue); } else if (propvalue == 0 && (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA)) { (void) strlcpy(propbuf, "none", proplen); @@ -2685,7 +2684,8 @@ zfs_prop_get_written(zfs_handle_t *zhp, const char *propname, return (err); if (literal) { - (void) snprintf(propbuf, proplen, "%llu", (long long unsigned int)propvalue); + (void) snprintf(propbuf, proplen, "%llu", + (u_longlong_t)propvalue); } else { zfs_nicenum(propvalue, propbuf, proplen); } @@ -3056,17 +3056,6 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, ret = lzc_create(path, ost, props); nvlist_free(props); - 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")); - return (-1); - } - } - /* check for failure */ if (ret != 0) { char parent[ZFS_MAXNAMELEN]; @@ -3128,9 +3117,6 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer) (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (ZFS_IS_VOLUME(zhp)) { - 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; @@ -3167,15 +3153,6 @@ zfs_check_snap_cb(zfs_handle_t *zhp, void *arg) if (lzc_exists(name)) verify(nvlist_add_boolean(dd->nvl, name) == 0); - 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. - */ - } - rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd); zfs_close(zhp); return (rv); @@ -3320,70 +3297,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. */ @@ -3393,10 +3311,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, @@ -3414,29 +3329,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, B_FALSE, 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)); @@ -3445,17 +3338,9 @@ zfs_promote(zfs_handle_t *zhp) if (ret != 0) { int save_errno = errno; - (void) zfs_iter_snapshots(pzhp, B_FALSE, 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 '%s' from parent '%s'"), zc.zc_string, parent); @@ -3464,45 +3349,7 @@ zfs_promote(zfs_handle_t *zhp) default: return (zfs_standard_error(hdl, save_errno, errbuf)); } - } else { - (void) zfs_iter_snapshots(zhp, B_FALSE, 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); } @@ -3593,31 +3440,6 @@ zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props) (void) zfs_standard_error(hdl, ret, errbuf); } } - } else { - zfs_handle_t *zhp; - int linktries = 0, linkok = 0, linkfail = 0; - nvpair_t *snap; - - for (snap = nvlist_next_nvpair(snaps, NULL); snap != NULL; - snap = nvlist_next_nvpair(snaps, snap)) { - char *cp, *snapname; - - snapname = nvpair_name(snap); - cp = strchr(snapname, '@'); - *cp = '\0'; - - if ((zhp = zfs_open(hdl, snapname, ZFS_TYPE_FILESYSTEM | - ZFS_TYPE_VOLUME)) != NULL) { - if (zhp->zfs_type == ZFS_TYPE_VOLUME) { - ++linktries; - *cp = '@'; - if (zvol_create_link(zhp->zfs_hdl, nvpair_name(snap))) - ++linkfail; - else - ++linkok; - } - } - } } nvlist_free(props); @@ -3641,7 +3463,7 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); - + (void) strlcpy(fsname, path, sizeof (fsname)); cp = strchr(fsname, '@'); *cp = '\0'; @@ -3756,8 +3578,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); @@ -3788,10 +3608,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) @@ -3905,7 +3721,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) { @@ -3920,15 +3735,6 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive, goto error; } - dd.snapname = delim + 1; - - /* We remove any zvol links prior to renaming them */ - verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0); - ret = zfs_iter_filesystems(zhrp, zfs_check_snap_cb, &dd); - nvlist_free(dd.nvl); - if (ret) { - goto error; - } } else { if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, force_unmount ? MS_FORCE : 0)) == NULL) @@ -3978,27 +3784,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); } @@ -4017,126 +3806,6 @@ error: return (ret); } -/* - * Given a zvol dataset, issue the ioctl to create the appropriate minor node, - * and wait briefly for udev to create the /dev link. - */ -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"}; - char path[MAXPATHLEN]; - int error; - - (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 ENODEV: - /* - * snapdev set to hidden : - * device creation was not permitted (see zvol.c) - * ignore error quietly - */ - 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)); - } - } - - /* - * Wait for udev to create the device. - */ - (void) snprintf(path, sizeof (path), "%s/%s", ZVOL_DIR, dataset); - error = zpool_label_disk_wait(path, DISK_LABEL_WAIT); - if (error) - (void) printf(gettext("%s may not be immediately " - "available\n"), path); - - 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"}; - int timeout = 3000; /* in milliseconds */ - int error = 0; - int i; - - (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); - - /* - * 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: - /* - * 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': %s"), dataset, strerror(errno))); - } - } - - return (0); -} - nvlist_t * zfs_get_user_props(zfs_handle_t *zhp) { diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 9f366eea1..12ac9bdf9 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -2790,12 +2790,6 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, return (-1); } } - if (!flags->dryrun && zhp->zfs_type == ZFS_TYPE_VOLUME && - zvol_remove_link(hdl, zhp->zfs_name) != 0) { - zfs_close(zhp); - zcmd_free_nvlists(&zc); - return (-1); - } zfs_close(zhp); } else { /* @@ -3001,10 +2995,6 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, if (h != NULL) { if (h->zfs_type == ZFS_TYPE_VOLUME) { *cp = '@'; - err = zvol_create_link(hdl, h->zfs_name); - if (err == 0 && ioctl_err == 0) - err = zvol_create_link(hdl, - zc.zc_value); } else if (newfs || stream_avl) { /* * Track the first/top of hierarchy fs, diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 9ee9508bf..52edbd3fa 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -1229,6 +1229,16 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors) fnvlist_free(suspended); } +#ifdef _KERNEL + if (error == 0) { + for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; + pair = nvlist_next_nvpair(snaps, pair)) { + char *snapname = nvpair_name(pair); + zvol_create_minors(snapname); + } + } +#endif + return (error); } @@ -1601,6 +1611,9 @@ static int dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg) { +#ifdef _KERNEL + char *oldname, *newname; +#endif dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; dsl_dataset_t *ds; uint64_t val; @@ -1627,6 +1640,18 @@ dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp, VERIFY0(zap_add(dp->dp_meta_objset, hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 8, 1, &ds->ds_object, tx)); +#ifdef _KERNEL + oldname = kmem_alloc(MAXPATHLEN, KM_PUSHPAGE); + newname = kmem_alloc(MAXPATHLEN, KM_PUSHPAGE); + snprintf(oldname, MAXPATHLEN, "%s@%s", ddrsa->ddrsa_fsname, + ddrsa->ddrsa_oldsnapname); + snprintf(newname, MAXPATHLEN, "%s@%s", ddrsa->ddrsa_fsname, + ddrsa->ddrsa_newsnapname); + zvol_rename_minors(oldname, newname); + kmem_free(newname, MAXPATHLEN); + kmem_free(oldname, MAXPATHLEN); +#endif + dsl_dataset_rele(ds, FTAG); return (0); } diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index 54a7dffb1..803a77c25 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "zfs_namecheck.h" static uint64_t dsl_dir_space_towrite(dsl_dir_t *dd); @@ -1302,6 +1303,10 @@ dsl_dir_rename_sync(void *arg, dmu_tx_t *tx) VERIFY0(zap_add(mos, newparent->dd_phys->dd_child_dir_zapobj, dd->dd_myname, 8, 1, &dd->dd_object, tx)); +#ifdef _KERNEL + zvol_rename_minors(ddra->ddra_oldname, ddra->ddra_newname); +#endif + dsl_prop_notify_all(dd); dsl_dir_rele(newparent, FTAG); diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index ae82cb45b..9b084632f 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -2089,7 +2089,7 @@ zfs_ioc_objset_zplprops(zfs_cmd_t *zc) return (err); } -static boolean_t +boolean_t dataset_name_hidden(const char *name) { /* @@ -2808,30 +2808,6 @@ zfs_ioc_pool_get_props(zfs_cmd_t *zc) return (error); } -/* - * inputs: - * zc_name name of volume - * - * outputs: none - */ -static int -zfs_ioc_create_minor(zfs_cmd_t *zc) -{ - return (zvol_create_minor(zc->zc_name)); -} - -/* - * inputs: - * zc_name name of volume - * - * outputs: none - */ -static int -zfs_ioc_remove_minor(zfs_cmd_t *zc) -{ - return (zvol_remove_minor(zc->zc_name)); -} - /* * inputs: * zc_name name of filesystem @@ -3174,6 +3150,12 @@ zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) if (error != 0) (void) dsl_destroy_head(fsname); } + +#ifdef _KERNEL + if (error == 0 && type == DMU_OST_ZVOL) + zvol_create_minors(fsname); +#endif + return (error); } @@ -3216,6 +3198,12 @@ zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) if (error != 0) (void) dsl_destroy_head(fsname); } + +#ifdef _KERNEL + if (error == 0) + zvol_create_minors(fsname); +#endif + return (error); } @@ -3276,6 +3264,12 @@ zfs_ioc_snapshot(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) } error = dsl_dataset_snapshot(snaps, props, outnvl); + +#ifdef _KERNEL + if (error == 0) + zvol_create_minors(poolname); +#endif + return (error); } @@ -3427,10 +3421,10 @@ zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) (name[poollen] != '/' && name[poollen] != '@')) return (SET_ERROR(EXDEV)); - (void) zvol_remove_minor(name); error = zfs_unmount_snap(name); if (error != 0) return (error); + (void) zvol_remove_minor(name); } return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl)); @@ -3520,7 +3514,6 @@ zfs_ioc_rename(zfs_cmd_t *zc) { boolean_t recursive = zc->zc_cookie & 1; char *at; - int err; zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || @@ -3550,12 +3543,7 @@ zfs_ioc_rename(zfs_cmd_t *zc) return (error); } else { - err = dsl_dir_rename(zc->zc_name, zc->zc_value); - if (!err && zc->zc_objset_type == DMU_OST_ZVOL) { - (void) zvol_remove_minor(zc->zc_name); - (void) zvol_create_minor(zc->zc_value); - } - return (err); + return (dsl_dir_rename(zc->zc_name, zc->zc_value)); } } @@ -4045,6 +4033,12 @@ zfs_ioc_recv(zfs_cmd_t *zc) error = 1; } #endif + +#ifdef _KERNEL + if (error == 0) + zvol_create_minors(tofs); +#endif + /* * On error, restore the original props. */ @@ -5391,12 +5385,8 @@ zfs_ioctl_init(void) POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY); /* - * ZoL functions + * ZoL functions */ - zfs_ioctl_register_legacy(ZFS_IOC_CREATE_MINOR, zfs_ioc_create_minor, - zfs_secpolicy_config, DATASET_NAME, B_FALSE, POOL_CHECK_NONE); - zfs_ioctl_register_legacy(ZFS_IOC_REMOVE_MINOR, zfs_ioc_remove_minor, - zfs_secpolicy_config, DATASET_NAME, B_FALSE, POOL_CHECK_NONE); zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_NEXT, zfs_ioc_events_next, zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE); zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_CLEAR, zfs_ioc_events_clear, diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 79c56cd78..cb3d18108 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -347,7 +347,7 @@ zvol_set_volsize(const char *name, uint64_t volsize) goto out_doi; } - if (get_disk_ro(zv->zv_disk) || (zv->zv_flags & ZVOL_RDONLY)) { + if (zv->zv_flags & ZVOL_RDONLY) { error = SET_ERROR(EROFS); goto out_doi; } @@ -396,7 +396,7 @@ zvol_set_volblocksize(const char *name, uint64_t volblocksize) goto out; } - if (get_disk_ro(zv->zv_disk) || (zv->zv_flags & ZVOL_RDONLY)) { + if (zv->zv_flags & ZVOL_RDONLY) { error = SET_ERROR(EROFS); goto out; } @@ -770,8 +770,7 @@ zvol_request(struct request_queue *q) zvol_dispatch(zvol_read, req); break; case WRITE: - if (unlikely(get_disk_ro(zv->zv_disk)) || - unlikely(zv->zv_flags & ZVOL_RDONLY)) { + if (unlikely(zv->zv_flags & ZVOL_RDONLY)) { __blk_end_request(req, -EROFS, size); break; } @@ -1019,8 +1018,7 @@ zvol_open(struct block_device *bdev, fmode_t flag) goto out_mutex; } - if ((flag & FMODE_WRITE) && - (get_disk_ro(zv->zv_disk) || (zv->zv_flags & ZVOL_RDONLY))) { + if ((flag & FMODE_WRITE) && (zv->zv_flags & ZVOL_RDONLY)) { error = -EROFS; goto out_open_count; } @@ -1235,7 +1233,7 @@ zvol_alloc(dev_t dev, const char *name) zvol_state_t *zv; int error = 0; - zv = kmem_zalloc(sizeof (zvol_state_t), KM_SLEEP); + zv = kmem_zalloc(sizeof (zvol_state_t), KM_PUSHPAGE); spin_lock_init(&zv->zv_lock); list_link_init(&zv->zv_next); @@ -1315,7 +1313,7 @@ __zvol_snapdev_hidden(const char *name) char *atp; int error = 0; - parent = kmem_alloc(MAXPATHLEN, KM_SLEEP); + parent = kmem_alloc(MAXPATHLEN, KM_PUSHPAGE); (void) strlcpy(parent, name, MAXPATHLEN); if ((atp = strrchr(parent, '@')) != NULL) { @@ -1352,7 +1350,7 @@ __zvol_create_minor(const char *name, boolean_t ignore_snapdev) goto out; } - doi = kmem_alloc(sizeof(dmu_object_info_t), KM_SLEEP); + doi = kmem_alloc(sizeof(dmu_object_info_t), KM_PUSHPAGE); error = dmu_objset_own(name, DMU_OST_ZVOL, B_TRUE, zvol_tag, &os); if (error) @@ -1474,77 +1472,118 @@ zvol_remove_minor(const char *name) return (error); } +/* + * Rename a block device minor mode for the specified volume. + */ +static void +__zvol_rename_minor(zvol_state_t *zv, const char *newname) +{ + int readonly = get_disk_ro(zv->zv_disk); + + ASSERT(MUTEX_HELD(&zvol_state_lock)); + + strlcpy(zv->zv_name, newname, sizeof (zv->zv_name)); + + /* + * The block device's read-only state is briefly changed causing + * a KOBJ_CHANGE uevent to be issued. This ensures udev detects + * the name change and fixes the symlinks. This does not change + * ZVOL_RDONLY in zv->zv_flags so the actual read-only state never + * changes. This would normally be done using kobject_uevent() but + * that is a GPL-only symbol which is why we need this workaround. + */ + set_disk_ro(zv->zv_disk, !readonly); + set_disk_ro(zv->zv_disk, readonly); +} + static int zvol_create_minors_cb(const char *dsname, void *arg) { - if (strchr(dsname, '/') == NULL) - return 0; + (void) zvol_create_minor(dsname); - (void) __zvol_create_minor(dsname, B_FALSE); return (0); } /* - * Create minors for specified pool, if pool is NULL create minors - * for all available pools. + * Create minors for specified dataset including children and snapshots. */ int -zvol_create_minors(char *pool) +zvol_create_minors(const char *name) { - spa_t *spa = NULL; int error = 0; - if (zvol_inhibit_dev) - return (0); - - mutex_enter(&zvol_state_lock); - if (pool) { - error = dmu_objset_find(pool, zvol_create_minors_cb, + if (!zvol_inhibit_dev) + error = dmu_objset_find((char *)name, zvol_create_minors_cb, NULL, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); - } else { - mutex_enter(&spa_namespace_lock); - while ((spa = spa_next(spa)) != NULL) { - error = dmu_objset_find(spa_name(spa), zvol_create_minors_cb, NULL, - DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); - if (error) - break; - } - mutex_exit(&spa_namespace_lock); - } - mutex_exit(&zvol_state_lock); - return error; + return (SET_ERROR(error)); } /* - * Remove minors for specified pool, if pool is NULL remove all minors. + * Remove minors for specified dataset including children and snapshots. */ void -zvol_remove_minors(const char *pool) +zvol_remove_minors(const char *name) { zvol_state_t *zv, *zv_next; - char *str; + int namelen = ((name) ? strlen(name) : 0); if (zvol_inhibit_dev) return; - str = kmem_zalloc(MAXNAMELEN, KM_SLEEP); - if (pool) { - (void) strncpy(str, pool, strlen(pool)); - (void) strcat(str, "/"); - } - mutex_enter(&zvol_state_lock); + for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) { zv_next = list_next(&zvol_state_list, zv); - if (pool == NULL || !strncmp(str, zv->zv_name, strlen(str))) { + if (name == NULL || strcmp(zv->zv_name, name) == 0 || + (strncmp(zv->zv_name, name, namelen) == 0 && + zv->zv_name[namelen] == '/')) { zvol_remove(zv); zvol_free(zv); } } + mutex_exit(&zvol_state_lock); - kmem_free(str, MAXNAMELEN); +} + +/* + * Rename minors for specified dataset including children and snapshots. + */ +void +zvol_rename_minors(const char *oldname, const char *newname) +{ + zvol_state_t *zv, *zv_next; + int oldnamelen, newnamelen; + char *name; + + if (zvol_inhibit_dev) + return; + + oldnamelen = strlen(oldname); + newnamelen = strlen(newname); + name = kmem_alloc(MAXNAMELEN, KM_PUSHPAGE); + + mutex_enter(&zvol_state_lock); + + for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) { + zv_next = list_next(&zvol_state_list, zv); + + if (strcmp(zv->zv_name, oldname) == 0) { + __zvol_rename_minor(zv, newname); + } else if (strncmp(zv->zv_name, oldname, oldnamelen) == 0 && + (zv->zv_name[oldnamelen] == '/' || + zv->zv_name[oldnamelen] == '@')) { + snprintf(name, MAXNAMELEN, "%s%c%s", newname, + zv->zv_name[oldnamelen], + zv->zv_name + oldnamelen + 1); + __zvol_rename_minor(zv, name); + } + } + + mutex_exit(&zvol_state_lock); + + kmem_free(name, MAXNAMELEN); } static int @@ -1552,7 +1591,7 @@ snapdev_snapshot_changed_cb(const char *dsname, void *arg) { uint64_t snapdev = *(uint64_t *) arg; if (strchr(dsname, '@') == NULL) - return 0; + return (0); switch (snapdev) { case ZFS_SNAPDEV_VISIBLE: @@ -1564,7 +1603,8 @@ snapdev_snapshot_changed_cb(const char *dsname, void *arg) { (void) zvol_remove_minor(dsname); break; } - return 0; + + return (0); } int diff --git a/scripts/common.sh.in b/scripts/common.sh.in index 29b85d3e1..3f63fc053 100644 --- a/scripts/common.sh.in +++ b/scripts/common.sh.in @@ -333,13 +333,14 @@ destroy_loop_devices() { } # -# Create a device label. +# Create a device label taking care to briefly wait if udev needs to settle. # label() { local DEVICE=$1 local LABEL=$2 - ${PARTED} ${DEVICE} --script -- mklabel ${LABEL} || return 1 + wait_udev ${DEVICE} 30 || return 1 + ${PARTED} ${DEVICE} --script -- mklabel ${LABEL} || return 2 return 0 }