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,
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,
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,
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);
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));
}
}
#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);
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();
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;
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);
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);
}
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];
(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;
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);
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.
*/
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,
"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));
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);
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);
}
(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);
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';
*/
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);
*/
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)
}
if (recursive) {
- struct destroydata dd;
parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
if (parentname == NULL) {
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)
* 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);
}
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)
{
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 {
/*
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,
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);
}
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;
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);
}
#include <sys/zio.h>
#include <sys/arc.h>
#include <sys/sunddi.h>
+#include <sys/zvol.h>
#include "zfs_namecheck.h"
static uint64_t dsl_dir_space_towrite(dsl_dir_t *dd);
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);
return (err);
}
-static boolean_t
+boolean_t
dataset_name_hidden(const char *name)
{
/*
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
if (error != 0)
(void) dsl_destroy_head(fsname);
}
+
+#ifdef _KERNEL
+ if (error == 0 && type == DMU_OST_ZVOL)
+ zvol_create_minors(fsname);
+#endif
+
return (error);
}
if (error != 0)
(void) dsl_destroy_head(fsname);
}
+
+#ifdef _KERNEL
+ if (error == 0)
+ zvol_create_minors(fsname);
+#endif
+
return (error);
}
}
error = dsl_dataset_snapshot(snaps, props, outnvl);
+
+#ifdef _KERNEL
+ if (error == 0)
+ zvol_create_minors(poolname);
+#endif
+
return (error);
}
(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));
{
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 ||
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));
}
}
error = 1;
}
#endif
+
+#ifdef _KERNEL
+ if (error == 0)
+ zvol_create_minors(tofs);
+#endif
+
/*
* On error, restore the original props.
*/
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,
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;
}
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;
}
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;
}
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;
}
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);
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) {
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)
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)
+ 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
uint64_t snapdev = *(uint64_t *) arg;
if (strchr(dsname, '@') == NULL)
- return 0;
+ return (0);
switch (snapdev) {
case ZFS_SNAPDEV_VISIBLE:
(void) zvol_remove_minor(dsname);
break;
}
- return 0;
+
+ return (0);
}
int
}
#
-# 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
}