mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-27 03:19:35 +03:00
Remove ZFC_IOC_*_MINOR ioctl()s
Early versions of ZFS coordinated the creation and destruction of device minors from userspace. This was inherently racy and in late 2009 these ioctl()s were removed leaving everything up to the kernel. This significantly simplified the code. However, we never picked up these changes in ZoL since we'd already significantly adjusted this code for Linux. This patch aims to rectify that by finally removing ZFC_IOC_*_MINOR ioctl()s and moving all the functionality down in to the kernel. Since this cleanup will change the kernel/user ABI it's being done in the same tag as the previous libzfs_core ABI changes. This will minimize, but not eliminate, the disruption to end users. Once merged ZoL, Illumos, and FreeBSD will basically be back in sync in regards to handling ZVOLs in the common code. While each platform must have its own custom zvol.c implemenation the interfaces provided are consistent. NOTES: 1) This patch introduces one subtle change in behavior which could not be easily avoided. Prior to this change callers of 'zfs create -V ...' were guaranteed that upon exit the /dev/zvol/ block device link would be created or an error returned. That's no longer the case. The utilities will no longer block waiting for the symlink to be created. Callers are now responsible for blocking, this is why a 'udev_wait' call was added to the 'label' function in scripts/common.sh. 2) The read-only behavior of a ZVOL now solely depends on if the ZVOL_RDONLY bit is set in zv->zv_flags. The redundant policy setting in the gendisk structure was removed. This both simplifies the code and allows us to safely leverage set_disk_ro() to issue a KOBJ_CHANGE uevent. See the comment in the code for futher details on this. 3) Because __zvol_create_minor() and zvol_alloc() may now be called in a sync task they must use KM_PUSHPAGE. References: illumos/illumos-gate@681d9761e8 Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Ned Bass <bass6@llnl.gov> Signed-off-by: Tim Chase <tim@chase2k.com> Closes #1969
This commit is contained in:
parent
dda12da9f1
commit
ba6a24026c
@ -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 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 *);
|
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,
|
int zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
|
||||||
|
@ -793,8 +793,6 @@ typedef enum zfs_ioc {
|
|||||||
ZFS_IOC_DATASET_LIST_NEXT,
|
ZFS_IOC_DATASET_LIST_NEXT,
|
||||||
ZFS_IOC_SNAPSHOT_LIST_NEXT,
|
ZFS_IOC_SNAPSHOT_LIST_NEXT,
|
||||||
ZFS_IOC_SET_PROP,
|
ZFS_IOC_SET_PROP,
|
||||||
ZFS_IOC_CREATE_MINOR,
|
|
||||||
ZFS_IOC_REMOVE_MINOR,
|
|
||||||
ZFS_IOC_CREATE,
|
ZFS_IOC_CREATE,
|
||||||
ZFS_IOC_DESTROY,
|
ZFS_IOC_DESTROY,
|
||||||
ZFS_IOC_ROLLBACK,
|
ZFS_IOC_ROLLBACK,
|
||||||
|
@ -359,6 +359,8 @@ extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr);
|
|||||||
extern int zfs_unmount_snap(const char *);
|
extern int zfs_unmount_snap(const char *);
|
||||||
extern void zfs_destroy_unmount_origin(const char *);
|
extern void zfs_destroy_unmount_origin(const char *);
|
||||||
|
|
||||||
|
extern boolean_t dataset_name_hidden(const char *name);
|
||||||
|
|
||||||
enum zfsdev_state_type {
|
enum zfsdev_state_type {
|
||||||
ZST_ONEXIT,
|
ZST_ONEXIT,
|
||||||
ZST_ZEVENT,
|
ZST_ZEVENT,
|
||||||
|
@ -38,10 +38,11 @@ extern int zvol_check_volblocksize(uint64_t volblocksize);
|
|||||||
extern int zvol_get_stats(objset_t *os, nvlist_t *nv);
|
extern int zvol_get_stats(objset_t *os, nvlist_t *nv);
|
||||||
extern boolean_t zvol_is_zvol(const char *);
|
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 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_minor(const char *name);
|
||||||
extern int zvol_create_minors(char *);
|
extern int zvol_create_minors(const char *name);
|
||||||
extern int zvol_remove_minor(const char *);
|
extern int zvol_remove_minor(const char *name);
|
||||||
extern void zvol_remove_minors(const char *);
|
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_volsize(const char *, uint64_t);
|
||||||
extern int zvol_set_volblocksize(const char *, uint64_t);
|
extern int zvol_set_volblocksize(const char *, uint64_t);
|
||||||
extern int zvol_set_snapdev(const char *, uint64_t);
|
extern int zvol_set_snapdev(const char *, uint64_t);
|
||||||
|
@ -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;
|
for (cn = uu_list_first(clp->cl_list); cn != NULL;
|
||||||
cn = uu_list_next(clp->cl_list, cn)) {
|
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.
|
* 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;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destroy the previous mountpoint if needed.
|
* Destroy the previous mountpoint if needed.
|
||||||
*/
|
*/
|
||||||
remove_mountpoint(hdl);
|
remove_mountpoint(cn->cn_handle);
|
||||||
|
|
||||||
(void) strlcpy(newname, dst, sizeof (newname));
|
(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) strlcpy(cn->cn_handle->zfs_name, newname,
|
||||||
(void) zvol_remove_link(hdl->zfs_hdl, hdl->zfs_name);
|
sizeof (cn->cn_handle->zfs_name));
|
||||||
(void) zvol_create_link(hdl->zfs_hdl, newname);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) strlcpy(hdl->zfs_name, newname, sizeof (hdl->zfs_name));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,6 @@
|
|||||||
#include "libzfs_impl.h"
|
#include "libzfs_impl.h"
|
||||||
#include "zfs_deleg.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,
|
static int userquota_propname_decode(const char *propname, boolean_t zoned,
|
||||||
zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
|
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)
|
else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
|
||||||
zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
|
zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
|
||||||
else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER)
|
else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER)
|
||||||
return (-1); /* zpios' and other testing datasets are
|
return (-1);
|
||||||
of this type, ignore if encountered */
|
|
||||||
else
|
else
|
||||||
abort();
|
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 ||
|
localtime_r(&time, &t) == NULL ||
|
||||||
strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
|
strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
|
||||||
&t) == 0)
|
&t) == 0)
|
||||||
(void) snprintf(propbuf, proplen, "%llu", (u_longlong_t) val);
|
(void) snprintf(propbuf, proplen, "%llu",
|
||||||
|
(u_longlong_t) val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2685,7 +2684,8 @@ zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
|
|||||||
return (err);
|
return (err);
|
||||||
|
|
||||||
if (literal) {
|
if (literal) {
|
||||||
(void) snprintf(propbuf, proplen, "%llu", (long long unsigned int)propvalue);
|
(void) snprintf(propbuf, proplen, "%llu",
|
||||||
|
(u_longlong_t)propvalue);
|
||||||
} else {
|
} else {
|
||||||
zfs_nicenum(propvalue, propbuf, proplen);
|
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);
|
ret = lzc_create(path, ost, props);
|
||||||
nvlist_free(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 */
|
/* check for failure */
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
char parent[ZFS_MAXNAMELEN];
|
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));
|
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||||
|
|
||||||
if (ZFS_IS_VOLUME(zhp)) {
|
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;
|
zc.zc_objset_type = DMU_OST_ZVOL;
|
||||||
} else {
|
} else {
|
||||||
zc.zc_objset_type = DMU_OST_ZFS;
|
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))
|
if (lzc_exists(name))
|
||||||
verify(nvlist_add_boolean(dd->nvl, name) == 0);
|
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);
|
rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
|
||||||
zfs_close(zhp);
|
zfs_close(zhp);
|
||||||
return (rv);
|
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,
|
return (zfs_standard_error(zhp->zfs_hdl, errno,
|
||||||
errbuf));
|
errbuf));
|
||||||
}
|
}
|
||||||
} else if (ZFS_IS_VOLUME(zhp)) {
|
|
||||||
ret = zvol_create_link(zhp->zfs_hdl, target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ret);
|
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.
|
* 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;
|
libzfs_handle_t *hdl = zhp->zfs_hdl;
|
||||||
zfs_cmd_t zc = {"\0"};
|
zfs_cmd_t zc = {"\0"};
|
||||||
char parent[MAXPATHLEN];
|
char parent[MAXPATHLEN];
|
||||||
char *cp;
|
|
||||||
int ret;
|
int ret;
|
||||||
zfs_handle_t *pzhp;
|
|
||||||
promote_data_t pd;
|
|
||||||
char errbuf[1024];
|
char errbuf[1024];
|
||||||
|
|
||||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||||
@ -3414,29 +3329,7 @@ zfs_promote(zfs_handle_t *zhp)
|
|||||||
"not a cloned filesystem"));
|
"not a cloned filesystem"));
|
||||||
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
|
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,
|
(void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin,
|
||||||
sizeof (zc.zc_value));
|
sizeof (zc.zc_value));
|
||||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
(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) {
|
if (ret != 0) {
|
||||||
int save_errno = errno;
|
int save_errno = errno;
|
||||||
|
|
||||||
(void) zfs_iter_snapshots(pzhp, B_FALSE, promote_snap_done_cb,
|
|
||||||
&pd);
|
|
||||||
zfs_close(pzhp);
|
|
||||||
|
|
||||||
switch (save_errno) {
|
switch (save_errno) {
|
||||||
case EEXIST:
|
case EEXIST:
|
||||||
/*
|
/* There is a conflicting snapshot name. */
|
||||||
* There is a conflicting snapshot name. We
|
|
||||||
* should have caught this above, but they could
|
|
||||||
* have renamed something in the mean time.
|
|
||||||
*/
|
|
||||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
|
||||||
"conflicting snapshot '%s' from parent '%s'"),
|
"conflicting snapshot '%s' from parent '%s'"),
|
||||||
zc.zc_string, parent);
|
zc.zc_string, parent);
|
||||||
@ -3464,45 +3349,7 @@ zfs_promote(zfs_handle_t *zhp)
|
|||||||
default:
|
default:
|
||||||
return (zfs_standard_error(hdl, save_errno, errbuf));
|
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);
|
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);
|
(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);
|
nvlist_free(props);
|
||||||
@ -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 (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)
|
if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
|
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) &&
|
if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
|
||||||
(zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
|
(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) {
|
if (restore_resv) {
|
||||||
new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
|
new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
|
||||||
if (old_volsize != new_volsize)
|
if (old_volsize != new_volsize)
|
||||||
@ -3905,7 +3721,6 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
struct destroydata dd;
|
|
||||||
|
|
||||||
parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
|
parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
|
||||||
if (parentname == NULL) {
|
if (parentname == NULL) {
|
||||||
@ -3920,15 +3735,6 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
|
|||||||
goto error;
|
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 {
|
} else {
|
||||||
if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0,
|
if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0,
|
||||||
force_unmount ? MS_FORCE : 0)) == NULL)
|
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
|
* On failure, we still want to remount any filesystems that
|
||||||
* were previously mounted, so we don't alter the system state.
|
* were previously mounted, so we don't alter the system state.
|
||||||
*/
|
*/
|
||||||
if (recursive) {
|
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 {
|
|
||||||
(void) changelist_postfix(cl);
|
(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 {
|
} else {
|
||||||
|
if (!recursive) {
|
||||||
changelist_rename(cl, zfs_get_name(zhp), target);
|
changelist_rename(cl, zfs_get_name(zhp), target);
|
||||||
ret = changelist_postfix(cl);
|
ret = changelist_postfix(cl);
|
||||||
}
|
}
|
||||||
@ -4017,126 +3806,6 @@ error:
|
|||||||
return (ret);
|
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 *
|
nvlist_t *
|
||||||
zfs_get_user_props(zfs_handle_t *zhp)
|
zfs_get_user_props(zfs_handle_t *zhp)
|
||||||
{
|
{
|
||||||
|
@ -2790,12 +2790,6 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
|||||||
return (-1);
|
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);
|
zfs_close(zhp);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@ -3001,10 +2995,6 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
|||||||
if (h != NULL) {
|
if (h != NULL) {
|
||||||
if (h->zfs_type == ZFS_TYPE_VOLUME) {
|
if (h->zfs_type == ZFS_TYPE_VOLUME) {
|
||||||
*cp = '@';
|
*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) {
|
} else if (newfs || stream_avl) {
|
||||||
/*
|
/*
|
||||||
* Track the first/top of hierarchy fs,
|
* Track the first/top of hierarchy fs,
|
||||||
|
@ -1229,6 +1229,16 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
|
|||||||
fnvlist_free(suspended);
|
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);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1601,6 +1611,9 @@ static int
|
|||||||
dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
|
dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
|
||||||
dsl_dataset_t *hds, void *arg)
|
dsl_dataset_t *hds, void *arg)
|
||||||
{
|
{
|
||||||
|
#ifdef _KERNEL
|
||||||
|
char *oldname, *newname;
|
||||||
|
#endif
|
||||||
dsl_dataset_rename_snapshot_arg_t *ddrsa = arg;
|
dsl_dataset_rename_snapshot_arg_t *ddrsa = arg;
|
||||||
dsl_dataset_t *ds;
|
dsl_dataset_t *ds;
|
||||||
uint64_t val;
|
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,
|
VERIFY0(zap_add(dp->dp_meta_objset, hds->ds_phys->ds_snapnames_zapobj,
|
||||||
ds->ds_snapname, 8, 1, &ds->ds_object, tx));
|
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);
|
dsl_dataset_rele(ds, FTAG);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include <sys/zio.h>
|
#include <sys/zio.h>
|
||||||
#include <sys/arc.h>
|
#include <sys/arc.h>
|
||||||
#include <sys/sunddi.h>
|
#include <sys/sunddi.h>
|
||||||
|
#include <sys/zvol.h>
|
||||||
#include "zfs_namecheck.h"
|
#include "zfs_namecheck.h"
|
||||||
|
|
||||||
static uint64_t dsl_dir_space_towrite(dsl_dir_t *dd);
|
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,
|
VERIFY0(zap_add(mos, newparent->dd_phys->dd_child_dir_zapobj,
|
||||||
dd->dd_myname, 8, 1, &dd->dd_object, tx));
|
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_prop_notify_all(dd);
|
||||||
|
|
||||||
dsl_dir_rele(newparent, FTAG);
|
dsl_dir_rele(newparent, FTAG);
|
||||||
|
@ -2089,7 +2089,7 @@ zfs_ioc_objset_zplprops(zfs_cmd_t *zc)
|
|||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean_t
|
boolean_t
|
||||||
dataset_name_hidden(const char *name)
|
dataset_name_hidden(const char *name)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -2808,30 +2808,6 @@ zfs_ioc_pool_get_props(zfs_cmd_t *zc)
|
|||||||
return (error);
|
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:
|
* inputs:
|
||||||
* zc_name name of filesystem
|
* zc_name name of filesystem
|
||||||
@ -3174,6 +3150,12 @@ zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
|
|||||||
if (error != 0)
|
if (error != 0)
|
||||||
(void) dsl_destroy_head(fsname);
|
(void) dsl_destroy_head(fsname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
if (error == 0 && type == DMU_OST_ZVOL)
|
||||||
|
zvol_create_minors(fsname);
|
||||||
|
#endif
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3216,6 +3198,12 @@ zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
|
|||||||
if (error != 0)
|
if (error != 0)
|
||||||
(void) dsl_destroy_head(fsname);
|
(void) dsl_destroy_head(fsname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
if (error == 0)
|
||||||
|
zvol_create_minors(fsname);
|
||||||
|
#endif
|
||||||
|
|
||||||
return (error);
|
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);
|
error = dsl_dataset_snapshot(snaps, props, outnvl);
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
if (error == 0)
|
||||||
|
zvol_create_minors(poolname);
|
||||||
|
#endif
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3427,10 +3421,10 @@ zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
|||||||
(name[poollen] != '/' && name[poollen] != '@'))
|
(name[poollen] != '/' && name[poollen] != '@'))
|
||||||
return (SET_ERROR(EXDEV));
|
return (SET_ERROR(EXDEV));
|
||||||
|
|
||||||
(void) zvol_remove_minor(name);
|
|
||||||
error = zfs_unmount_snap(name);
|
error = zfs_unmount_snap(name);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
(void) zvol_remove_minor(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
|
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;
|
boolean_t recursive = zc->zc_cookie & 1;
|
||||||
char *at;
|
char *at;
|
||||||
int err;
|
|
||||||
|
|
||||||
zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
|
zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
|
||||||
if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
|
if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
|
||||||
@ -3550,12 +3543,7 @@ zfs_ioc_rename(zfs_cmd_t *zc)
|
|||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
} else {
|
} else {
|
||||||
err = dsl_dir_rename(zc->zc_name, zc->zc_value);
|
return (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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4045,6 +4033,12 @@ zfs_ioc_recv(zfs_cmd_t *zc)
|
|||||||
error = 1;
|
error = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
if (error == 0)
|
||||||
|
zvol_create_minors(tofs);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On error, restore the original props.
|
* On error, restore the original props.
|
||||||
*/
|
*/
|
||||||
@ -5393,10 +5387,6 @@ zfs_ioctl_init(void)
|
|||||||
/*
|
/*
|
||||||
* 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_ioctl_register_legacy(ZFS_IOC_EVENTS_NEXT, zfs_ioc_events_next,
|
||||||
zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
|
zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
|
||||||
zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_CLEAR, zfs_ioc_events_clear,
|
zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_CLEAR, zfs_ioc_events_clear,
|
||||||
|
@ -347,7 +347,7 @@ zvol_set_volsize(const char *name, uint64_t volsize)
|
|||||||
goto out_doi;
|
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);
|
error = SET_ERROR(EROFS);
|
||||||
goto out_doi;
|
goto out_doi;
|
||||||
}
|
}
|
||||||
@ -396,7 +396,7 @@ zvol_set_volblocksize(const char *name, uint64_t volblocksize)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_disk_ro(zv->zv_disk) || (zv->zv_flags & ZVOL_RDONLY)) {
|
if (zv->zv_flags & ZVOL_RDONLY) {
|
||||||
error = SET_ERROR(EROFS);
|
error = SET_ERROR(EROFS);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -770,8 +770,7 @@ zvol_request(struct request_queue *q)
|
|||||||
zvol_dispatch(zvol_read, req);
|
zvol_dispatch(zvol_read, req);
|
||||||
break;
|
break;
|
||||||
case WRITE:
|
case WRITE:
|
||||||
if (unlikely(get_disk_ro(zv->zv_disk)) ||
|
if (unlikely(zv->zv_flags & ZVOL_RDONLY)) {
|
||||||
unlikely(zv->zv_flags & ZVOL_RDONLY)) {
|
|
||||||
__blk_end_request(req, -EROFS, size);
|
__blk_end_request(req, -EROFS, size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1019,8 +1018,7 @@ zvol_open(struct block_device *bdev, fmode_t flag)
|
|||||||
goto out_mutex;
|
goto out_mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flag & FMODE_WRITE) &&
|
if ((flag & FMODE_WRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
|
||||||
(get_disk_ro(zv->zv_disk) || (zv->zv_flags & ZVOL_RDONLY))) {
|
|
||||||
error = -EROFS;
|
error = -EROFS;
|
||||||
goto out_open_count;
|
goto out_open_count;
|
||||||
}
|
}
|
||||||
@ -1235,7 +1233,7 @@ zvol_alloc(dev_t dev, const char *name)
|
|||||||
zvol_state_t *zv;
|
zvol_state_t *zv;
|
||||||
int error = 0;
|
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);
|
spin_lock_init(&zv->zv_lock);
|
||||||
list_link_init(&zv->zv_next);
|
list_link_init(&zv->zv_next);
|
||||||
@ -1315,7 +1313,7 @@ __zvol_snapdev_hidden(const char *name)
|
|||||||
char *atp;
|
char *atp;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
parent = kmem_alloc(MAXPATHLEN, KM_SLEEP);
|
parent = kmem_alloc(MAXPATHLEN, KM_PUSHPAGE);
|
||||||
(void) strlcpy(parent, name, MAXPATHLEN);
|
(void) strlcpy(parent, name, MAXPATHLEN);
|
||||||
|
|
||||||
if ((atp = strrchr(parent, '@')) != NULL) {
|
if ((atp = strrchr(parent, '@')) != NULL) {
|
||||||
@ -1352,7 +1350,7 @@ __zvol_create_minor(const char *name, boolean_t ignore_snapdev)
|
|||||||
goto out;
|
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);
|
error = dmu_objset_own(name, DMU_OST_ZVOL, B_TRUE, zvol_tag, &os);
|
||||||
if (error)
|
if (error)
|
||||||
@ -1474,77 +1472,118 @@ zvol_remove_minor(const char *name)
|
|||||||
return (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
|
static int
|
||||||
zvol_create_minors_cb(const char *dsname, void *arg)
|
zvol_create_minors_cb(const char *dsname, void *arg)
|
||||||
{
|
{
|
||||||
if (strchr(dsname, '/') == NULL)
|
(void) zvol_create_minor(dsname);
|
||||||
return 0;
|
|
||||||
|
|
||||||
(void) __zvol_create_minor(dsname, B_FALSE);
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create minors for specified pool, if pool is NULL create minors
|
* Create minors for specified dataset including children and snapshots.
|
||||||
* for all available pools.
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
zvol_create_minors(char *pool)
|
zvol_create_minors(const char *name)
|
||||||
{
|
{
|
||||||
spa_t *spa = NULL;
|
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
if (zvol_inhibit_dev)
|
if (!zvol_inhibit_dev)
|
||||||
return (0);
|
error = dmu_objset_find((char *)name, zvol_create_minors_cb,
|
||||||
|
|
||||||
mutex_enter(&zvol_state_lock);
|
|
||||||
if (pool) {
|
|
||||||
error = dmu_objset_find(pool, zvol_create_minors_cb,
|
|
||||||
NULL, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
|
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
|
void
|
||||||
zvol_remove_minors(const char *pool)
|
zvol_remove_minors(const char *name)
|
||||||
{
|
{
|
||||||
zvol_state_t *zv, *zv_next;
|
zvol_state_t *zv, *zv_next;
|
||||||
char *str;
|
int namelen = ((name) ? strlen(name) : 0);
|
||||||
|
|
||||||
if (zvol_inhibit_dev)
|
if (zvol_inhibit_dev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
str = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
|
|
||||||
if (pool) {
|
|
||||||
(void) strncpy(str, pool, strlen(pool));
|
|
||||||
(void) strcat(str, "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_enter(&zvol_state_lock);
|
mutex_enter(&zvol_state_lock);
|
||||||
|
|
||||||
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
|
||||||
zv_next = list_next(&zvol_state_list, zv);
|
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_remove(zv);
|
||||||
zvol_free(zv);
|
zvol_free(zv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_exit(&zvol_state_lock);
|
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
|
static int
|
||||||
@ -1552,7 +1591,7 @@ snapdev_snapshot_changed_cb(const char *dsname, void *arg) {
|
|||||||
uint64_t snapdev = *(uint64_t *) arg;
|
uint64_t snapdev = *(uint64_t *) arg;
|
||||||
|
|
||||||
if (strchr(dsname, '@') == NULL)
|
if (strchr(dsname, '@') == NULL)
|
||||||
return 0;
|
return (0);
|
||||||
|
|
||||||
switch (snapdev) {
|
switch (snapdev) {
|
||||||
case ZFS_SNAPDEV_VISIBLE:
|
case ZFS_SNAPDEV_VISIBLE:
|
||||||
@ -1564,7 +1603,8 @@ snapdev_snapshot_changed_cb(const char *dsname, void *arg) {
|
|||||||
(void) zvol_remove_minor(dsname);
|
(void) zvol_remove_minor(dsname);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -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() {
|
label() {
|
||||||
local DEVICE=$1
|
local DEVICE=$1
|
||||||
local LABEL=$2
|
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
|
return 0
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user