Merge branch 'linux-kernel-disk' into refs/top-bases/linux-zfs-branch

This commit is contained in:
Brian Behlendorf 2010-08-02 12:54:55 -07:00
commit f58729aa42
6 changed files with 163 additions and 169 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

@ -1135,8 +1135,9 @@ zfs_ioc_pool_destroy(struct file *filp, 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);
}
@ -1167,7 +1168,7 @@ zfs_ioc_pool_import(struct file *filp, 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);
@ -1188,10 +1189,9 @@ zfs_ioc_pool_export(struct file *filp, 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);
}
@ -2467,6 +2467,30 @@ zfs_ioc_pool_get_props(struct file *filp, 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
@ -2865,18 +2889,9 @@ zfs_ioc_create(struct file *filp, zfs_cmd_t *zc)
if (error == 0) {
error = zfs_set_prop_nvlist(filp, 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);
}
@ -3001,7 +3016,7 @@ zfs_ioc_destroy(struct file *filp, 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);
}
@ -3105,7 +3120,6 @@ static int
zfs_ioc_rename(struct file *filp, 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 ||
@ -3119,16 +3133,12 @@ zfs_ioc_rename(struct file *filp, 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));
}
@ -4426,6 +4436,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;
}
@ -182,7 +183,7 @@ int
zvol_get_stats(objset_t *os, nvlist_t *nv)
{
int error;
dmu_object_info_t doi;
dmu_object_info_t *doi;
uint64_t val;
error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &val);
@ -190,14 +191,16 @@ zvol_get_stats(objset_t *os, nvlist_t *nv)
return (error);
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLSIZE, val);
error = dmu_object_info(os, ZVOL_OBJ, &doi);
doi = kmem_alloc(sizeof(dmu_object_info_t), KM_SLEEP);
error = dmu_object_info(os, ZVOL_OBJ, doi);
if (error == 0) {
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLBLOCKSIZE,
doi.doi_data_block_size);
doi->doi_data_block_size);
}
kmem_free(doi, sizeof(dmu_object_info_t));
return (error);
}
@ -273,7 +276,7 @@ int
zvol_set_volsize(const char *name, uint64_t volsize)
{
zvol_state_t *zv;
dmu_object_info_t doi;
dmu_object_info_t *doi;
objset_t *os = NULL;
uint64_t readonly;
int error;
@ -286,26 +289,30 @@ zvol_set_volsize(const char *name, uint64_t volsize)
goto out;
}
doi = kmem_alloc(sizeof(dmu_object_info_t), KM_SLEEP);
error = dmu_objset_hold(name, FTAG, &os);
if (error)
goto out;
goto out_doi;
if ((error = dmu_object_info(os, ZVOL_OBJ, &doi)) != 0 ||
(error = zvol_check_volsize(volsize,doi.doi_data_block_size)) != 0)
goto out;
if ((error = dmu_object_info(os, ZVOL_OBJ, doi)) != 0 ||
(error = zvol_check_volsize(volsize,doi->doi_data_block_size)) != 0)
goto out_doi;
VERIFY(dsl_prop_get_integer(name, "readonly", &readonly, NULL) == 0);
if (readonly) {
error = EROFS;
goto out;
goto out_doi;
}
if (get_disk_ro(zv->zv_disk) || (zv->zv_flags & ZVOL_RDONLY)) {
error = EROFS;
goto out;
goto out_doi;
}
error = zvol_update_volsize(zv, volsize);
out_doi:
kmem_free(doi, sizeof(dmu_object_info_t));
out:
if (os)
dmu_objset_rele(os, FTAG);
@ -757,11 +764,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 +788,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 +1036,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 +1049,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;
@ -1071,21 +1077,16 @@ zvol_free(zvol_state_t *zv)
kmem_free(zv, sizeof (zvol_state_t));
}
/*
* 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.
*/
int
zvol_create_minor(const char *name)
static int
__zvol_create_minor(const char *name)
{
zvol_state_t *zv;
objset_t *os;
dmu_object_info_t doi;
dmu_object_info_t *doi;
unsigned minor = 0;
int error = 0;
mutex_enter(&zvol_state_lock);
ASSERT(MUTEX_HELD(&zvol_state_lock));
zv = zvol_find_by_name(name);
if (zv) {
@ -1093,11 +1094,13 @@ zvol_create_minor(const char *name)
goto out;
}
doi = kmem_alloc(sizeof(dmu_object_info_t), KM_SLEEP);
error = dmu_objset_own(name, DMU_OST_ZVOL, B_TRUE, zvol_tag, &os);
if (error)
goto out;
goto out_doi;
error = dmu_object_info(os, ZVOL_OBJ, &doi);
error = dmu_object_info(os, ZVOL_OBJ, doi);
if (error)
goto out_dmu_objset_disown;
@ -1114,7 +1117,7 @@ zvol_create_minor(const char *name)
if (dmu_objset_is_snapshot(os))
zv->zv_flags |= ZVOL_RDONLY;
zv->zv_volblocksize = doi.doi_data_block_size;
zv->zv_volblocksize = doi->doi_data_block_size;
if (zil_replay_disable)
zil_destroy(dmu_objset_zil(os), B_FALSE);
@ -1127,10 +1130,47 @@ zvol_create_minor(const char *name)
out_dmu_objset_disown:
dmu_objset_disown(os, zvol_tag);
out_doi:
kmem_free(doi, sizeof(dmu_object_info_t));
out:
return (error);
}
/*
* 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.
*/
int
zvol_create_minor(const char *name)
{
int error;
mutex_enter(&zvol_state_lock);
error = __zvol_create_minor(name);
mutex_exit(&zvol_state_lock);
return (-error);
return (error);
}
static int
__zvol_remove_minor(const char *name)
{
zvol_state_t *zv;
ASSERT(MUTEX_HELD(&zvol_state_lock));
zv = zvol_find_by_name(name);
if (zv == NULL)
return (ENXIO);
if (zv->zv_open_count > 0)
return (EBUSY);
zvol_remove(zv);
zvol_free(zv);
return (0);
}
/*
@ -1139,25 +1179,10 @@ out:
int
zvol_remove_minor(const char *name)
{
zvol_state_t *zv;
int error = 0;
int error;
mutex_enter(&zvol_state_lock);
zv = zvol_find_by_name(name);
if (zv == NULL) {
error = ENXIO;
goto out;
}
if (zv->zv_open_count > 0) {
error = EBUSY;
goto out;
}
zvol_remove(zv);
zvol_free(zv);
out:
error = __zvol_remove_minor(name);
mutex_exit(&zvol_state_lock);
return (error);
@ -1170,59 +1195,65 @@ zvol_create_minors_cb(spa_t *spa, uint64_t dsobj,
if (strchr(dsname, '/') == NULL)
return 0;
return zvol_create_minor(dsname);
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;
mutex_enter(&zvol_state_lock);
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;
}
mutex_exit(&spa_namespace_lock);
}
mutex_exit(&zvol_state_lock);
return error;
}
/*
* 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 +1293,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);
}

View File

@ -159,52 +159,4 @@ EOF
}
zconfig_test3
# zpool import/export check
zconfig_test4() {
POOL_NAME=test4
ZVOL_NAME1=fish1
ZVOL_NAME2=fish2
FULL_NAME1=${POOL_NAME}/${ZVOL_NAME1}
FULL_NAME2=${POOL_NAME}/${ZVOL_NAME2}
TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
echo -n "test 4 - zpool import/export: "
# Create a pool and volume.
${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 || fail 2
${ZFS} create -V 100M ${FULL_NAME1} || fail 3
${ZFS} create -V 100M ${FULL_NAME2} || fail 4
# Verify the devices were created
stat /dev/${FULL_NAME1} &>/dev/null || fail 5
stat /dev/${FULL_NAME2} &>/dev/null || fail 6
# Export the pool
${ZPOOL} export ${POOL_NAME} || fail 7
# Verify the devices were removed
stat /dev/${FULL_NAME1} &>/dev/null && fail 8
stat /dev/${FULL_NAME2} &>/dev/null && fail 9
# Import the pool
${ZPOOL} import ${POOL_NAME} || fail 10
# Verify the devices were created
stat /dev/${FULL_NAME1} &>/dev/null || fail 11
stat /dev/${FULL_NAME2} &>/dev/null || fail 12
# Destroy the pool and consequently the devices
${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 15
# Verify the devices were removed
stat /dev/${FULL_NAME1} &>/dev/null && fail 16
stat /dev/${FULL_NAME2} &>/dev/null && fail 17
${ZFS_SH} -u || fail 18
pass
}
zconfig_test4
exit 0