Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zvol_create_minors(): check snapdev before traversing snapshots #2479

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion include/sys/zvol.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ extern int zvol_check_volblocksize(const char *name, 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 *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);
Expand Down
5 changes: 0 additions & 5 deletions module/zfs/zfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3305,11 +3305,6 @@ 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);
}

Expand Down
117 changes: 76 additions & 41 deletions module/zfs/zvol.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
#include <sys/zvol.h>
#include <linux/blkdev_compat.h>

static int
zvol_create_minors_cb(const char *dsname, void *arg);

unsigned int zvol_inhibit_dev = 0;
unsigned int zvol_major = ZVOL_MAJOR;
unsigned int zvol_prefetch_bytes = (128 * 1024);
Expand Down Expand Up @@ -1269,30 +1272,7 @@ 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 (SET_ERROR(error));
}

static int
__zvol_create_minor(const char *name, boolean_t ignore_snapdev)
__zvol_create_minor(const char *name)
{
zvol_state_t *zv;
objset_t *os;
Expand All @@ -1310,13 +1290,7 @@ __zvol_create_minor(const char *name, boolean_t ignore_snapdev)
goto out;
}

if (ignore_snapdev == B_FALSE) {
error = __zvol_snapdev_hidden(name);
if (error)
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)
Expand Down Expand Up @@ -1403,15 +1377,35 @@ __zvol_create_minor(const char *name, boolean_t ignore_snapdev)
* Create a block device minor node and setup the linkage between it
* and the specified volume. Once this function returns the block
* device is live and ready for use.
* Check the snapdev option before traversing snapshots of the 'name'.
*/
int
zvol_create_minor(const char *name)
static int
zvol_create_minor(const char *name, uint64_t snapdev)
{
int error;

mutex_enter(&zvol_state_lock);
error = __zvol_create_minor(name, B_FALSE);
mutex_exit(&zvol_state_lock);
if (strchr(name, '@') == 0) {
/* create minor for the 'name' explicitly */
mutex_enter(&zvol_state_lock);
error = __zvol_create_minor(name);
mutex_exit(&zvol_state_lock);
if (error == 0 && snapdev == ZFS_SNAPDEV_VISIBLE) {
/*
* traverse snapshots only, do not traverse children,
* and skip the 'name'
*/
error = dmu_objset_find((char *)name,
zvol_create_minors_cb, (void *)name,
DS_FIND_SNAPSHOTS);
}
} else {
if (snapdev == ZFS_SNAPDEV_VISIBLE) {
/* create minor for the snapshot */
mutex_enter(&zvol_state_lock);
error = __zvol_create_minor(name);
mutex_exit(&zvol_state_lock);
}
}

return (SET_ERROR(error));
}
Expand Down Expand Up @@ -1475,25 +1469,66 @@ __zvol_rename_minor(zvol_state_t *zv, const char *newname)
set_disk_ro(zv->zv_disk, readonly);
}

/* Mask errors to continue dmu_objset_find() traversal */
static int
zvol_create_minors_cb(const char *dsname, void *arg)
{
(void) zvol_create_minor(dsname);
const char *name = (const char *)arg;
uint64_t snapdev;
int error;

/* skip the designated dataset */
if (name && strcmp(dsname, name) == 0)
return 0;

error = dsl_prop_get_integer(dsname, "snapdev", &snapdev, NULL);
if (error)
return (0);

(void) zvol_create_minor(dsname, snapdev);

return (0);
}

/*
* Create minors for specified dataset including children and snapshots.
* Pay attention to the 'snapdev' property and traverse the snapshots
* only if the property is set.
*/
int
zvol_create_minors(const char *name)
{
int error = 0;

if (!zvol_inhibit_dev)
error = dmu_objset_find((char *)name, zvol_create_minors_cb,
NULL, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
/*
* dmu_objset_find() does not expect snapshot name (with '@') in its
* first argument. So, check for the '@' in the name.
*/
if (!zvol_inhibit_dev) {
char *atp, *parent;

parent = kmem_alloc(MAXPATHLEN, KM_PUSHPAGE);
(void) strlcpy(parent, name, MAXPATHLEN);

if ((atp = strrchr(parent, '@')) != NULL) {
uint64_t snapdev;

*atp = '\0';
error = dsl_prop_get_integer(parent, "snapdev",
&snapdev, NULL);

if (error == 0 && snapdev == ZFS_SNAPDEV_VISIBLE) {
mutex_enter(&zvol_state_lock);
error = __zvol_create_minor(name);
mutex_exit(&zvol_state_lock);
}
} else {
error = dmu_objset_find(parent, zvol_create_minors_cb,
NULL, DS_FIND_CHILDREN);
}

kmem_free(parent, MAXPATHLEN);
}

return (SET_ERROR(error));
}
Expand Down Expand Up @@ -1575,7 +1610,7 @@ snapdev_snapshot_changed_cb(const char *dsname, void *arg) {
switch (snapdev) {
case ZFS_SNAPDEV_VISIBLE:
mutex_enter(&zvol_state_lock);
(void) __zvol_create_minor(dsname, B_TRUE);
(void) __zvol_create_minor(dsname);
mutex_exit(&zvol_state_lock);
break;
case ZFS_SNAPDEV_HIDDEN:
Expand Down