diff --git a/include/libzfs_impl.h b/include/libzfs_impl.h index 7daf8348b228..5502455e09a1 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 e945b40a9691..08076bc09b67 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 4a717b7d1768..52557d2104d2 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 640538c2cdaa..04e0996570c9 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 3a83e2d71ccd..0bcfc0423b6b 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)); - - if (ZFS_IS_VOLUME(hdl)) { - (void) zvol_remove_link(hdl->zfs_hdl, hdl->zfs_name); - (void) zvol_create_link(hdl->zfs_hdl, newname); - } + (void) strcat(newname, cn->cn_handle->zfs_name + strlen(src)); - (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 9810b2e2d0e0..90b6572b15c0 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 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive, 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 9f366eea1b6c..12ac9bdf9b3a 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/man/man8/zfs.8 b/man/man8/zfs.8 index 6da58d2bd452..321a297f270a 100644 --- a/man/man8/zfs.8 +++ b/man/man8/zfs.8 @@ -307,7 +307,7 @@ See \fBzpool\fR(8) for more information on creating and administering pools. A snapshot is a read-only copy of a file system or volume. Snapshots can be created extremely quickly, and initially consume no additional space within the pool. As data within the active dataset changes, the snapshot consumes more data than would otherwise be shared with the active dataset. .sp .LP -Snapshots can have arbitrary names. Snapshots of volumes can be cloned or rolled back, but cannot be accessed independently. +Snapshots can have arbitrary names. Snapshots of volumes can be cloned or rolled back. Visibility is determined by the \fBsnapdev\fR property of the parent volume. .sp .LP File system snapshots can be accessed under the \fB\&.zfs/snapshot\fR directory in the root of the file system. Snapshots are automatically mounted on demand and may be unmounted at regular intervals. The visibility of the \fB\&.zfs\fR directory can be controlled by the \fBsnapdir\fR property. diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 9ee9508bf218..52edbd3fa1a5 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 54a7dffb1d67..803a77c25580 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 ae82cb45b1b0..9b084632fead 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 79c56cd78188..e6980271d03b 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -62,8 +62,8 @@ static char *zvol_tag = "zvol_tag"; */ typedef struct zvol_state { char zv_name[MAXNAMELEN]; /* name */ - uint64_t zv_volsize; /* advertised space */ - uint64_t zv_volblocksize;/* volume block size */ + uint64_t zv_volsize; /* advertised space */ + uint64_t zv_volblocksize; /* volume block size */ objset_t *zv_objset; /* objset handle */ uint32_t zv_flags; /* ZVOL_* flags */ uint32_t zv_open_count; /* open counts */ @@ -94,16 +94,16 @@ zvol_find_minor(unsigned *minor) *minor = 0; ASSERT(MUTEX_HELD(&zvol_state_lock)); for (zv = list_head(&zvol_state_list); zv != NULL; - zv = list_next(&zvol_state_list, zv), *minor += ZVOL_MINORS) { + zv = list_next(&zvol_state_list, zv), *minor += ZVOL_MINORS) { if (MINOR(zv->zv_dev) != MINOR(*minor)) break; } /* All minors are in use */ if (*minor >= (1 << MINORBITS)) - return ENXIO; + return (SET_ERROR(ENXIO)); - return 0; + return (0); } /* @@ -116,12 +116,12 @@ zvol_find_by_dev(dev_t dev) ASSERT(MUTEX_HELD(&zvol_state_lock)); for (zv = list_head(&zvol_state_list); zv != NULL; - zv = list_next(&zvol_state_list, zv)) { + zv = list_next(&zvol_state_list, zv)) { if (zv->zv_dev == dev) - return zv; + return (zv); } - return NULL; + return (NULL); } /* @@ -134,12 +134,12 @@ zvol_find_by_name(const char *name) ASSERT(MUTEX_HELD(&zvol_state_lock)); for (zv = list_head(&zvol_state_list); zv != NULL; - zv = list_next(&zvol_state_list, zv)) { - if (!strncmp(zv->zv_name, name, MAXNAMELEN)) - return zv; + zv = list_next(&zvol_state_list, zv)) { + if (strncmp(zv->zv_name, name, MAXNAMELEN) == 0) + return (zv); } - return NULL; + return (NULL); } @@ -160,7 +160,7 @@ zvol_is_zvol(const char *device) bdput(bdev); if (major == zvol_major) - return (B_TRUE); + return (B_TRUE); return (B_FALSE); } @@ -215,10 +215,10 @@ zvol_get_stats(objset_t *os, nvlist_t *nv) error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &val); if (error) - return (error); + return (SET_ERROR(error)); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLSIZE, val); - doi = kmem_alloc(sizeof(dmu_object_info_t), KM_SLEEP); + doi = kmem_alloc(sizeof (dmu_object_info_t), KM_SLEEP); error = dmu_object_info(os, ZVOL_OBJ, doi); if (error == 0) { @@ -226,9 +226,9 @@ zvol_get_stats(objset_t *os, nvlist_t *nv) doi->doi_data_block_size); } - kmem_free(doi, sizeof(dmu_object_info_t)); + kmem_free(doi, sizeof (dmu_object_info_t)); - return (error); + return (SET_ERROR(error)); } /* @@ -267,7 +267,7 @@ zvol_update_volsize(zvol_state_t *zv, uint64_t volsize, objset_t *os) error = dmu_tx_assign(tx, TXG_WAIT); if (error) { dmu_tx_abort(tx); - return (error); + return (SET_ERROR(error)); } error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, @@ -275,12 +275,12 @@ zvol_update_volsize(zvol_state_t *zv, uint64_t volsize, objset_t *os) dmu_tx_commit(tx); if (error) - return (error); + return (SET_ERROR(error)); error = dmu_free_long_range(os, ZVOL_OBJ, volsize, DMU_OBJECT_END); if (error) - return (error); + return (SET_ERROR(error)); bdev = bdget_disk(zv->zv_disk, 0); if (!bdev) @@ -319,7 +319,7 @@ zvol_set_volsize(const char *name, uint64_t volsize) error = dsl_prop_get_integer(name, zfs_prop_to_name(ZFS_PROP_READONLY), &readonly, NULL); if (error != 0) - return (error); + return (SET_ERROR(error)); if (readonly) return (SET_ERROR(EROFS)); @@ -331,14 +331,14 @@ zvol_set_volsize(const char *name, uint64_t volsize) goto out; } - doi = kmem_alloc(sizeof(dmu_object_info_t), KM_SLEEP); + doi = kmem_alloc(sizeof (dmu_object_info_t), KM_SLEEP); error = dmu_objset_hold(name, FTAG, &os); if (error) goto out_doi; - if ((error = dmu_object_info(os, ZVOL_OBJ, doi)) != 0 || - (error = zvol_check_volsize(volsize,doi->doi_data_block_size)) != 0) + if ((error = dmu_object_info(os, ZVOL_OBJ, doi)) || + (error = zvol_check_volsize(volsize, doi->doi_data_block_size))) goto out_doi; VERIFY(dsl_prop_get_integer(name, "readonly", &readonly, NULL) == 0); @@ -347,21 +347,21 @@ 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; } error = zvol_update_volsize(zv, volsize, os); out_doi: - kmem_free(doi, sizeof(dmu_object_info_t)); + kmem_free(doi, sizeof (dmu_object_info_t)); out: if (os) dmu_objset_rele(os, FTAG); mutex_exit(&zvol_state_lock); - return (error); + return (SET_ERROR(error)); } /* @@ -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; } @@ -418,7 +418,7 @@ zvol_set_volblocksize(const char *name, uint64_t volblocksize) out: mutex_exit(&zvol_state_lock); - return (error); + return (SET_ERROR(error)); } /* @@ -448,7 +448,7 @@ zvol_replay_write(zvol_state_t *zv, lr_write_t *lr, boolean_t byteswap) dmu_tx_commit(tx); } - return (error); + return (SET_ERROR(error)); } static int @@ -486,8 +486,8 @@ zil_replay_func_t zvol_replay_vector[TX_MAX_TYPE] = { ssize_t zvol_immediate_write_sz = 32768; static void -zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, - uint64_t offset, uint64_t size, int sync) +zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, uint64_t offset, + uint64_t size, int sync) { uint32_t blocksize = zv->zv_volblocksize; zilog_t *zilog = zv->zv_zilog; @@ -662,7 +662,7 @@ zvol_discard(void *arg) rl = zfs_range_lock(&zv->zv_znode, start, end - start, RL_WRITER); - error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, start, end - start); + error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, start, end-start); /* * TODO: maybe we should add the operation to the log. @@ -750,17 +750,17 @@ zvol_request(struct request_queue *q) if (size != 0 && blk_rq_pos(req) + blk_rq_sectors(req) > get_capacity(zv->zv_disk)) { printk(KERN_INFO - "%s: bad access: block=%llu, count=%lu\n", - req->rq_disk->disk_name, - (long long unsigned)blk_rq_pos(req), - (long unsigned)blk_rq_sectors(req)); + "%s: bad access: block=%llu, count=%lu\n", + req->rq_disk->disk_name, + (long long unsigned)blk_rq_pos(req), + (long unsigned)blk_rq_sectors(req)); __blk_end_request(req, -EIO, size); continue; } if (!blk_fs_request(req)) { printk(KERN_INFO "%s: non-fs cmd\n", - req->rq_disk->disk_name); + req->rq_disk->disk_name); __blk_end_request(req, -EIO, size); continue; } @@ -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; } @@ -787,7 +786,7 @@ zvol_request(struct request_queue *q) break; default: printk(KERN_INFO "%s: unknown cmd: %d\n", - req->rq_disk->disk_name, (int)rq_data_dir(req)); + req->rq_disk->disk_name, (int)rq_data_dir(req)); __blk_end_request(req, -EIO, size); break; } @@ -870,7 +869,7 @@ zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio) zvol_get_done(zgd, error); - return (error); + return (SET_ERROR(error)); } /* @@ -884,7 +883,7 @@ zvol_insert(zvol_state_t *zv_insert) ASSERT(MUTEX_HELD(&zvol_state_lock)); ASSERT3U(MINOR(zv_insert->zv_dev) & ZVOL_MINOR_MASK, ==, 0); for (zv = list_head(&zvol_state_list); zv != NULL; - zv = list_next(&zvol_state_list, zv)) { + zv = list_next(&zvol_state_list, zv)) { if (MINOR(zv->zv_dev) > MINOR(zv_insert->zv_dev)) break; } @@ -970,7 +969,7 @@ zvol_first_open(zvol_state_t *zv) if (locked) mutex_exit(&spa_namespace_lock); - return (-error); + return (SET_ERROR(-error)); } static void @@ -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; } @@ -1037,7 +1035,7 @@ zvol_open(struct block_device *bdev, fmode_t flag) check_disk_change(bdev); - return (error); + return (SET_ERROR(error)); } #ifdef HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID @@ -1071,13 +1069,13 @@ zvol_release(struct gendisk *disk, fmode_t mode) static int zvol_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { zvol_state_t *zv = bdev->bd_disk->private_data; int error = 0; if (zv == NULL) - return (-SET_ERROR(ENXIO)); + return (SET_ERROR(-ENXIO)); switch (cmd) { case BLKFLSBUF: @@ -1093,25 +1091,25 @@ zvol_ioctl(struct block_device *bdev, fmode_t mode, } - return (error); + return (SET_ERROR(error)); } #ifdef CONFIG_COMPAT static int zvol_compat_ioctl(struct block_device *bdev, fmode_t mode, - unsigned cmd, unsigned long arg) + unsigned cmd, unsigned long arg) { - return zvol_ioctl(bdev, mode, cmd, arg); + return (zvol_ioctl(bdev, mode, cmd, arg)); } #else -#define zvol_compat_ioctl NULL +#define zvol_compat_ioctl NULL #endif static int zvol_media_changed(struct gendisk *disk) { zvol_state_t *zv = disk->private_data; - return zv->zv_changed; + return (zv->zv_changed); } static int zvol_revalidate_disk(struct gendisk *disk) @@ -1121,7 +1119,7 @@ static int zvol_revalidate_disk(struct gendisk *disk) zv->zv_changed = 0; set_capacity(zv->zv_disk, zv->zv_volsize >> 9); - return 0; + return (0); } /* @@ -1147,7 +1145,7 @@ zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo) geo->start = 0; geo->cylinders = sectors / (geo->heads * geo->sectors); - return 0; + return (0); } static struct kobject * @@ -1161,19 +1159,19 @@ zvol_probe(dev_t dev, int *part, void *arg) kobj = zv ? get_disk(zv->zv_disk) : NULL; mutex_exit(&zvol_state_lock); - return kobj; + return (kobj); } #ifdef HAVE_BDEV_BLOCK_DEVICE_OPERATIONS static struct block_device_operations zvol_ops = { - .open = zvol_open, - .release = zvol_release, - .ioctl = zvol_ioctl, - .compat_ioctl = zvol_compat_ioctl, - .media_changed = zvol_media_changed, - .revalidate_disk = zvol_revalidate_disk, - .getgeo = zvol_getgeo, - .owner = THIS_MODULE, + .open = zvol_open, + .release = zvol_release, + .ioctl = zvol_ioctl, + .compat_ioctl = zvol_compat_ioctl, + .media_changed = zvol_media_changed, + .revalidate_disk = zvol_revalidate_disk, + .getgeo = zvol_getgeo, + .owner = THIS_MODULE, }; #else /* HAVE_BDEV_BLOCK_DEVICE_OPERATIONS */ @@ -1181,47 +1179,49 @@ static struct block_device_operations zvol_ops = { static int zvol_open_by_inode(struct inode *inode, struct file *file) { - return zvol_open(inode->i_bdev, file->f_mode); + return (zvol_open(inode->i_bdev, file->f_mode)); } static int zvol_release_by_inode(struct inode *inode, struct file *file) { - return zvol_release(inode->i_bdev->bd_disk, file->f_mode); + return (zvol_release(inode->i_bdev->bd_disk, file->f_mode)); } static int zvol_ioctl_by_inode(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { if (file == NULL || inode == NULL) - return -EINVAL; - return zvol_ioctl(inode->i_bdev, file->f_mode, cmd, arg); + return (SET_ERROR(-EINVAL)); + + return (zvol_ioctl(inode->i_bdev, file->f_mode, cmd, arg)); } -# ifdef CONFIG_COMPAT +#ifdef CONFIG_COMPAT static long zvol_compat_ioctl_by_inode(struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { if (file == NULL) - return -EINVAL; - return zvol_compat_ioctl(file->f_dentry->d_inode->i_bdev, - file->f_mode, cmd, arg); + return (SET_ERROR(-EINVAL)); + + return (zvol_compat_ioctl(file->f_dentry->d_inode->i_bdev, + file->f_mode, cmd, arg)); } -# else -# define zvol_compat_ioctl_by_inode NULL -# endif +#else +#define zvol_compat_ioctl_by_inode NULL +#endif static struct block_device_operations zvol_ops = { - .open = zvol_open_by_inode, - .release = zvol_release_by_inode, - .ioctl = zvol_ioctl_by_inode, - .compat_ioctl = zvol_compat_ioctl_by_inode, - .media_changed = zvol_media_changed, - .revalidate_disk = zvol_revalidate_disk, - .getgeo = zvol_getgeo, - .owner = THIS_MODULE, + .open = zvol_open_by_inode, + .release = zvol_release_by_inode, + .ioctl = zvol_ioctl_by_inode, + .compat_ioctl = zvol_compat_ioctl_by_inode, + .media_changed = zvol_media_changed, + .revalidate_disk = zvol_revalidate_disk, + .getgeo = zvol_getgeo, + .owner = THIS_MODULE, }; #endif /* HAVE_BDEV_BLOCK_DEVICE_OPERATIONS */ @@ -1235,7 +1235,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); @@ -1281,14 +1281,14 @@ zvol_alloc(dev_t dev, const char *name) snprintf(zv->zv_disk->disk_name, DISK_NAME_LEN, "%s%d", ZVOL_DEV_NAME, (dev & MINORMASK)); - return zv; + return (zv); out_queue: blk_cleanup_queue(zv->zv_queue); out_kmem: kmem_free(zv, sizeof (zvol_state_t)); - return NULL; + return (NULL); } /* @@ -1310,22 +1310,24 @@ zvol_free(zvol_state_t *zv) static int __zvol_snapdev_hidden(const char *name) { - uint64_t snapdev; - char *parent; - char *atp; - int error = 0; - - parent = kmem_alloc(MAXPATHLEN, KM_SLEEP); - (void) strlcpy(parent, name, MAXPATHLEN); - - if ((atp = strrchr(parent, '@')) != NULL) { - *atp = '\0'; - error = dsl_prop_get_integer(parent, "snapdev", &snapdev, NULL); - if ((error == 0) && (snapdev == ZFS_SNAPDEV_HIDDEN)) - error = SET_ERROR(ENODEV); - } - kmem_free(parent, MAXPATHLEN); - return (error); + uint64_t snapdev; + char *parent; + char *atp; + int error = 0; + + parent = kmem_alloc(MAXPATHLEN, KM_PUSHPAGE); + (void) strlcpy(parent, name, MAXPATHLEN); + + if ((atp = strrchr(parent, '@')) != NULL) { + *atp = '\0'; + error = dsl_prop_get_integer(parent, "snapdev", &snapdev, NULL); + if ((error == 0) && (snapdev == ZFS_SNAPDEV_HIDDEN)) + error = SET_ERROR(ENODEV); + } + + kmem_free(parent, MAXPATHLEN); + + return (SET_ERROR(error)); } static int @@ -1352,7 +1354,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) @@ -1411,7 +1413,7 @@ __zvol_create_minor(const char *name, boolean_t ignore_snapdev) out_dmu_objset_disown: dmu_objset_disown(os, zvol_tag); out_doi: - kmem_free(doi, sizeof(dmu_object_info_t)); + kmem_free(doi, sizeof (dmu_object_info_t)); out: if (error == 0) { @@ -1419,7 +1421,7 @@ __zvol_create_minor(const char *name, boolean_t ignore_snapdev) add_disk(zv->zv_disk); } - return (error); + return (SET_ERROR(error)); } /* @@ -1436,7 +1438,7 @@ zvol_create_minor(const char *name) error = __zvol_create_minor(name, B_FALSE); mutex_exit(&zvol_state_lock); - return (error); + return (SET_ERROR(error)); } static int @@ -1471,80 +1473,121 @@ zvol_remove_minor(const char *name) error = __zvol_remove_minor(name); mutex_exit(&zvol_state_lock); - return (error); + return (SET_ERROR(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) + error = dmu_objset_find((char *)name, zvol_create_minors_cb, + NULL, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); + + return (SET_ERROR(error)); +} + +/* + * Remove minors for specified dataset including children and snapshots. + */ +void +zvol_remove_minors(const char *name) +{ + zvol_state_t *zv, *zv_next; + int namelen = ((name) ? strlen(name) : 0); + if (zvol_inhibit_dev) - return (0); + return; mutex_enter(&zvol_state_lock); - if (pool) { - error = dmu_objset_find(pool, 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; + + for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) { + zv_next = list_next(&zvol_state_list, zv); + + 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(&spa_namespace_lock); } - mutex_exit(&zvol_state_lock); - return error; + mutex_exit(&zvol_state_lock); } /* - * Remove minors for specified pool, if pool is NULL remove all minors. + * Rename minors for specified dataset including children and snapshots. */ void -zvol_remove_minors(const char *pool) +zvol_rename_minors(const char *oldname, const char *newname) { zvol_state_t *zv, *zv_next; - char *str; + int oldnamelen, newnamelen; + char *name; if (zvol_inhibit_dev) return; - str = kmem_zalloc(MAXNAMELEN, KM_SLEEP); - if (pool) { - (void) strncpy(str, pool, strlen(pool)); - (void) strcat(str, "/"); - } + 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 (pool == NULL || !strncmp(str, zv->zv_name, strlen(str))) { - zvol_remove(zv); - zvol_free(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(str, MAXNAMELEN); + + kmem_free(name, MAXNAMELEN); } static int @@ -1552,7 +1595,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 +1607,8 @@ snapdev_snapshot_changed_cb(const char *dsname, void *arg) { (void) zvol_remove_minor(dsname); break; } - return 0; + + return (0); } int @@ -1575,18 +1619,18 @@ zvol_set_snapdev(const char *dsname, uint64_t snapdev) { return (-1); } - int zvol_init(void) { int error; list_create(&zvol_state_list, sizeof (zvol_state_t), - offsetof(zvol_state_t, zv_next)); + offsetof(zvol_state_t, zv_next)); + mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL); zvol_taskq = taskq_create(ZVOL_DRIVER, zvol_threads, maxclsyspri, - zvol_threads, INT_MAX, TASKQ_PREPOPULATE); + zvol_threads, INT_MAX, TASKQ_PREPOPULATE); if (zvol_taskq == NULL) { printk(KERN_INFO "ZFS: taskq_create() failed\n"); error = -ENOMEM; @@ -1600,7 +1644,7 @@ zvol_init(void) } blk_register_region(MKDEV(zvol_major, 0), 1UL << MINORBITS, - THIS_MODULE, zvol_probe, NULL, NULL); + THIS_MODULE, zvol_probe, NULL, NULL); return (0); @@ -1610,7 +1654,7 @@ zvol_init(void) mutex_destroy(&zvol_state_lock); list_destroy(&zvol_state_list); - return (error); + return (SET_ERROR(error)); } void @@ -1634,4 +1678,4 @@ module_param(zvol_threads, uint, 0444); MODULE_PARM_DESC(zvol_threads, "Number of threads for zvol device"); module_param(zvol_max_discard_blocks, ulong, 0444); -MODULE_PARM_DESC(zvol_max_discard_blocks, "Max number of blocks to discard at once"); +MODULE_PARM_DESC(zvol_max_discard_blocks, "Max number of blocks to discard"); diff --git a/scripts/common.sh.in b/scripts/common.sh.in index 29b85d3e10e2..3f63fc053422 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 } diff --git a/scripts/zconfig.sh b/scripts/zconfig.sh index 281166c59ba7..622bb28f17ba 100755 --- a/scripts/zconfig.sh +++ b/scripts/zconfig.sh @@ -403,14 +403,16 @@ test_7() { partition /dev/zvol/${FULL_ZVOL_NAME} primary 1 -1 || fail 4 format /dev/zvol/${FULL_ZVOL_NAME}-part1 ext2 || fail 5 - # Mount the ext2 filesystem and copy some data to it. - mkdir -p /tmp/${ZVOL_NAME}-part1 || fail 6 - mount /dev/zvol/${FULL_ZVOL_NAME}-part1 /tmp/${ZVOL_NAME}-part1 \ - || fail 7 + # Snapshot the pristine ext2 filesystem. + ${ZFS} snapshot ${FULL_SNAP_NAME} || fail 6 + wait_udev /dev/zvol/${FULL_SNAP_NAME}-part1 30 || fail 7 - # Snapshot the pristine ext2 filesystem and mount it read-only. - ${ZFS} snapshot ${FULL_SNAP_NAME} || fail 8 - wait_udev /dev/zvol/${FULL_SNAP_NAME}-part1 30 || fail 8 + # Mount the ext2 filesystem so some data can be copied to it. + mkdir -p /tmp/${ZVOL_NAME}-part1 || fail 7 + mount /dev/zvol/${FULL_ZVOL_NAME}-part1 \ + /tmp/${ZVOL_NAME}-part1 || fail 8 + + # Mount the pristine ext2 snapshot. mkdir -p /tmp/${SNAP_NAME}-part1 || fail 9 mount /dev/zvol/${FULL_SNAP_NAME}-part1 \ /tmp/${SNAP_NAME}-part1 &>/dev/null || fail 10 @@ -496,11 +498,14 @@ test_8() { mount /dev/zvol/${FULL_ZVOL_NAME1}-part1 \ /tmp/${FULL_ZVOL_NAME1}-part1 || fail 7 cp -RL ${SRC_DIR} /tmp/${FULL_ZVOL_NAME1}-part1 || fail 8 - sync || fail 9 - # Snapshot the ext2 filesystem so it may be sent. - ${ZFS} snapshot ${FULL_SNAP_NAME1} || fail 11 - wait_udev /dev/zvol/${FULL_SNAP_NAME1} 30 || fail 11 + # Unmount, snapshot, mount the ext2 filesystem so it may be sent. + # We only unmount to ensure the ext2 filesystem is clean. + umount /tmp/${FULL_ZVOL_NAME1}-part1 || fail 9 + ${ZFS} snapshot ${FULL_SNAP_NAME1} || fail 10 + wait_udev /dev/zvol/${FULL_SNAP_NAME1} 30 || fail 10 + mount /dev/zvol/${FULL_ZVOL_NAME1}-part1 \ + /tmp/${FULL_ZVOL_NAME1}-part1 || 11 # Send/receive the snapshot from POOL_NAME1 to POOL_NAME2 (${ZFS} send ${FULL_SNAP_NAME1} | \