Minor device creation/removal (Kernel)

With the update to onnv_141 how minor devices were created and
removed for ZVOL was substantially changed.  The updated system
is much more tightly integrated with Solaris's /dev/ filesystem.
This is great for Solaris but bad for Linux.

On the kernel side the ZFS_IOC_{CREATE,REMOVE}_MINOR ioctl
entry points have been re-added.  They now call directly in
to the ZVOL to create the needed minor node and add the sysfs
entried for udev.

Also as part of this change I've decided it would really be
best if all the zvols were in a /dev/zvol directory like on
Solaris.  Organizationally this makes sense and on the code
side it allows us to know a block device is a zvol simply by
where it is located in /dev/.  Unless Solaris there still is
to ./dsk or ./rdsk as part of the path.
This commit is contained in:
Brian Behlendorf 2010-07-30 13:53:44 -07:00
parent 96ae916dbe
commit f162433deb
5 changed files with 94 additions and 79 deletions

View File

@ -686,13 +686,17 @@ typedef struct ddt_histogram {
ddt_stat_t ddh_stat[64]; /* power-of-two histogram buckets */
} ddt_histogram_t;
#define ZVOL_DRIVER "zvol"
#define ZFS_DRIVER "zfs"
#define ZFS_DEV "/dev/zfs"
#define ZVOL_MAJOR 230
#define ZVOL_MINOR_BITS 4
#define ZVOL_MINOR_MASK ((1U << ZVOL_MINOR_BITS) - 1)
#define ZVOL_MINORS (1 << 4)
#define ZVOL_DRIVER "zvol"
#define ZFS_DRIVER "zfs"
#define ZFS_DEV "/dev/zfs"
/* general zvol path */
#define ZVOL_DIR "/dev/zvol"
#define ZVOL_MAJOR 230
#define ZVOL_MINOR_BITS 4
#define ZVOL_MINOR_MASK ((1U << ZVOL_MINOR_BITS) - 1)
#define ZVOL_MINORS (1 << 4)
#define ZVOL_PROP_NAME "name"
#define ZVOL_DEFAULT_BLOCKSIZE 8192
@ -726,6 +730,8 @@ 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,

View File

@ -42,7 +42,7 @@ 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(const char *);
extern int zvol_remove_minor(const char *);
extern int zvol_remove_minors(const char *);
extern void zvol_remove_minors(const char *);
extern int zvol_set_volsize(const char *, uint64_t);
extern int zvol_set_volblocksize(const char *, uint64_t);

View File

@ -1072,12 +1072,6 @@ vdev_open_child(void *arg)
boolean_t
vdev_uses_zvols(vdev_t *vd)
{
/*
* NOTE: Disabled because under Linux I've choosen not to put all the zvols
* in their own directory. This could be changed or this code can be updated
* to perhap run an ioctl() on the vdev path to determine if it is a zvol.
*/
#if 0
int c;
if (vd->vdev_path && strncmp(vd->vdev_path, ZVOL_DIR,
@ -1086,7 +1080,6 @@ vdev_uses_zvols(vdev_t *vd)
for (c = 0; c < vd->vdev_children; c++)
if (vdev_uses_zvols(vd->vdev_child[c]))
return (B_TRUE);
#endif
return (B_FALSE);
}

View File

@ -1112,8 +1112,9 @@ zfs_ioc_pool_destroy(zfs_cmd_t *zc)
{
int error;
zfs_log_history(zc);
(void) zvol_remove_minors(zc->zc_name);
error = spa_destroy(zc->zc_name);
if (error == 0)
zvol_remove_minors(zc->zc_name);
return (error);
}
@ -1144,7 +1145,7 @@ zfs_ioc_pool_import(zfs_cmd_t *zc)
error = spa_import(zc->zc_name, config, props);
if (error == 0)
error = zvol_create_minors(zc->zc_name);
zvol_create_minors(zc->zc_name);
if (zc->zc_nvlist_dst != 0)
(void) put_nvlist(zc, config);
@ -1165,10 +1166,9 @@ zfs_ioc_pool_export(zfs_cmd_t *zc)
boolean_t hardforce = (boolean_t)zc->zc_guid;
zfs_log_history(zc);
error = zvol_remove_minors(zc->zc_name);
error = spa_export(zc->zc_name, NULL, force, hardforce);
if (error == 0)
error = spa_export(zc->zc_name, NULL, force, hardforce);
zvol_remove_minors(zc->zc_name);
return (error);
}
@ -2438,6 +2438,30 @@ 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(struct file *filp, 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(struct file *filp, zfs_cmd_t *zc)
{
return (zvol_remove_minor(zc->zc_name));
}
/*
* inputs:
* zc_name name of filesystem
@ -2834,18 +2858,9 @@ zfs_ioc_create(zfs_cmd_t *zc)
if (error == 0) {
error = zfs_set_prop_nvlist(zc->zc_name, ZPROP_SRC_LOCAL,
nvprops, NULL);
if (error != 0) {
if (error != 0)
(void) dmu_objset_destroy(zc->zc_name, B_FALSE);
goto out;
}
if (type == DMU_OST_ZVOL) {
error = zvol_create_minor(zc->zc_name);
if (error != 0)
(void) dmu_objset_destroy(zc->zc_name, B_FALSE);
}
}
out:
nvlist_free(nvprops);
return (error);
}
@ -2968,7 +2983,7 @@ zfs_ioc_destroy(zfs_cmd_t *zc)
err = dmu_objset_destroy(zc->zc_name, zc->zc_defer_destroy);
if (zc->zc_objset_type == DMU_OST_ZVOL && err == 0)
err = zvol_remove_minor(zc->zc_name);
(void) zvol_remove_minor(zc->zc_name);
return (err);
}
@ -3068,7 +3083,6 @@ static int
zfs_ioc_rename(zfs_cmd_t *zc)
{
boolean_t recursive = zc->zc_cookie & 1;
int err;
zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
@ -3082,16 +3096,12 @@ zfs_ioc_rename(zfs_cmd_t *zc)
*/
if (!recursive && strchr(zc->zc_name, '@') != NULL &&
zc->zc_objset_type == DMU_OST_ZFS) {
err = zfs_unmount_snap(zc->zc_name, NULL);
int err = zfs_unmount_snap(zc->zc_name, NULL);
if (err)
return (err);
}
if (zc->zc_objset_type == DMU_OST_ZVOL) {
err = zvol_remove_minor(zc->zc_name);
if (err)
return (err);
}
if (zc->zc_objset_type == DMU_OST_ZVOL)
(void) zvol_remove_minor(zc->zc_name);
return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive));
}
@ -4315,6 +4325,10 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = {
{ zfs_ioc_snapshot_list_next, zfs_secpolicy_read, DATASET_NAME, B_FALSE,
B_TRUE },
{ zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE, B_TRUE },
{ zfs_ioc_create_minor, zfs_secpolicy_config, DATASET_NAME, B_FALSE,
B_FALSE },
{ zfs_ioc_remove_minor, zfs_secpolicy_config, DATASET_NAME, B_FALSE,
B_FALSE },
{ zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE, B_TRUE },
{ zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE,
B_TRUE},

View File

@ -57,6 +57,7 @@ static char *zvol_tag = "zvol_tag";
* The in-core state of each volume.
*/
typedef struct zvol_state {
char zv_name[DISK_NAME_LEN]; /* name */
uint64_t zv_volsize; /* advertised space */
uint64_t zv_volblocksize;/* volume block size */
objset_t *zv_objset; /* objset handle */
@ -130,7 +131,7 @@ 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_disk->disk_name, name, DISK_NAME_LEN))
if (!strncmp(zv->zv_name, name, DISK_NAME_LEN))
return zv;
}
@ -757,11 +758,10 @@ zvol_first_open(zvol_state_t *zv)
objset_t *os;
uint64_t volsize;
int error;
uint64_t readonly;
uint64_t ro;
/* lie and say we're read-only */
error = dmu_objset_own(zv->zv_disk->disk_name,
DMU_OST_ZVOL, B_TRUE, zvol_tag, &os);
error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, 1, zvol_tag, &os);
if (error)
return (-error);
@ -782,9 +782,8 @@ zvol_first_open(zvol_state_t *zv)
zv->zv_volsize = volsize;
zv->zv_zilog = zil_open(os, zvol_get_data);
VERIFY(dsl_prop_get_integer(zv->zv_disk->disk_name,
"readonly", &readonly, NULL) == 0);
if (readonly || dmu_objset_is_snapshot(os)) {
VERIFY(dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL) == 0);
if (ro || dmu_objset_is_snapshot(os)) {
set_disk_ro(zv->zv_disk, 1);
zv->zv_flags |= ZVOL_RDONLY;
} else {
@ -1031,6 +1030,7 @@ zvol_alloc(dev_t dev, const char *name)
zv->zv_queue->queuedata = zv;
zv->zv_dev = dev;
zv->zv_open_count = 0;
strlcpy(zv->zv_name, name, DISK_NAME_LEN);
mutex_init(&zv->zv_znode.z_range_lock, NULL, MUTEX_DEFAULT, NULL);
avl_create(&zv->zv_znode.z_range_avl, zfs_range_compare,
@ -1043,7 +1043,7 @@ zvol_alloc(dev_t dev, const char *name)
zv->zv_disk->fops = &zvol_ops;
zv->zv_disk->private_data = zv;
zv->zv_disk->queue = zv->zv_queue;
strlcpy(zv->zv_disk->disk_name, name, DISK_NAME_LEN);
snprintf(zv->zv_disk->disk_name, DISK_NAME_LEN, "zvol/%s", name);
return zv;
@ -1173,31 +1173,25 @@ zvol_create_minors_cb(spa_t *spa, uint64_t dsobj,
return zvol_create_minor(dsname);
}
static int
zvol_remove_minors_cb(spa_t *spa, uint64_t dsobj,
const char *dsname, void *arg)
{
if (strchr(dsname, '/') == NULL)
return 0;
return zvol_remove_minor(dsname);
}
static int
zvol_cr_minors_common(const char *pool,
int func(spa_t *, uint64_t, const char *, void *), void *arg)
/*
* Create minors for specified pool, if pool is NULL create minors
* for all available pools.
*/
int
zvol_create_minors(const char *pool)
{
spa_t *spa = NULL;
int error = 0;
if (pool) {
error = dmu_objset_find_spa(NULL, pool, func, arg,
DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
error = dmu_objset_find_spa(NULL, 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(NULL, spa_name(spa),
func, arg, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
error = dmu_objset_find_spa(NULL,
spa_name(spa), zvol_create_minors_cb, NULL,
DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
if (error)
break;
}
@ -1208,21 +1202,31 @@ zvol_cr_minors_common(const char *pool,
}
/*
* Create minors for specified pool, or if NULL create all minors.
* Remove minors for specified pool, if pool is NULL remove all minors.
*/
int
zvol_create_minors(const char *pool)
{
return zvol_cr_minors_common(pool, zvol_create_minors_cb, NULL);
}
/*
* Remove minors for specified pool, or if NULL remove all minors.
*/
int
void
zvol_remove_minors(const char *pool)
{
return zvol_cr_minors_common(pool, zvol_remove_minors_cb, NULL);
zvol_state_t *zv, *zv_next;
char *str;
str = kmem_zalloc(DISK_NAME_LEN, KM_SLEEP);
if (pool) {
(void) strncpy(str, pool, strlen(pool));
(void) strcat(str, "/");
}
mutex_enter(&zvol_state_lock);
for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
zv_next = list_next(&zvol_state_list, zv);
if (pool == NULL || !strncmp(str, zv->zv_name, strlen(str))) {
zvol_remove(zv);
zvol_free(zv);
}
}
mutex_exit(&zvol_state_lock);
kmem_free(str, DISK_NAME_LEN);
}
int
@ -1262,12 +1266,10 @@ zvol_init(void)
void
zvol_fini(void)
{
(void) zvol_remove_minors(NULL);
zvol_remove_minors(NULL);
blk_unregister_region(MKDEV(zvol_major, 0), 1UL << MINORBITS);
unregister_blkdev(zvol_major, ZVOL_DRIVER);
taskq_destroy(zvol_taskq);
mutex_destroy(&zvol_state_lock);
list_destroy(&zvol_state_list);
}