From 1438208f3c4c55f6aa524495d68b6ac0a2dbf424 Mon Sep 17 00:00:00 2001 From: Ameer Hamza Date: Wed, 25 Oct 2023 02:53:27 +0500 Subject: [PATCH] zvol: Implement zvol threading as a Property Currently, zvol threading can be switched through the zvol_request_sync module parameter system-wide. By making it a zvol property, zvol threading can be switched per zvol. Signed-off-by: Ameer Hamza --- include/sys/fs/zfs.h | 1 + include/sys/zvol.h | 1 + include/sys/zvol_impl.h | 1 + lib/libzfs/libzfs.abi | 3 ++- man/man7/zfsprops.7 | 12 ++++++++++++ module/os/linux/zfs/zvol_os.c | 9 ++++++++- module/zcommon/zfs_prop.c | 3 +++ module/zfs/zfs_ioctl.c | 9 +++++++++ module/zfs/zvol.c | 14 ++++++++++++++ 9 files changed, 51 insertions(+), 2 deletions(-) diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index bc940e8a79..d8b6ff3fbd 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -191,6 +191,7 @@ typedef enum { ZFS_PROP_REDACTED, ZFS_PROP_REDACT_SNAPS, ZFS_PROP_SNAPSHOTS_CHANGED, + ZFS_PROP_VOLTHREADING, ZFS_NUM_PROPS } zfs_prop_t; diff --git a/include/sys/zvol.h b/include/sys/zvol.h index 5e92a3367b..c9eefbeb48 100644 --- a/include/sys/zvol.h +++ b/include/sys/zvol.h @@ -50,6 +50,7 @@ extern int zvol_get_stats(objset_t *, nvlist_t *); extern boolean_t zvol_is_zvol(const char *); extern void zvol_create_cb(objset_t *, void *, cred_t *, dmu_tx_t *); extern int zvol_set_volsize(const char *, uint64_t); +extern int zvol_set_volthreading(const char *, boolean_t); extern int zvol_set_common(const char *, zfs_prop_t, zprop_source_t, uint64_t); extern zvol_state_handle_t *zvol_suspend(const char *); extern int zvol_resume(zvol_state_handle_t *); diff --git a/include/sys/zvol_impl.h b/include/sys/zvol_impl.h index 3243917bcd..de4f6dec86 100644 --- a/include/sys/zvol_impl.h +++ b/include/sys/zvol_impl.h @@ -58,6 +58,7 @@ typedef struct zvol_state { atomic_t zv_suspend_ref; /* refcount for suspend */ krwlock_t zv_suspend_lock; /* suspend lock */ struct zvol_state_os *zv_zso; /* private platform state */ + boolean_t zv_threading; /* volthreading property */ } zvol_state_t; diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 2d612a16b2..fdc36487dc 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -1867,7 +1867,8 @@ - + + diff --git a/man/man7/zfsprops.7 b/man/man7/zfsprops.7 index f8554c81c8..069be5e383 100644 --- a/man/man7/zfsprops.7 +++ b/man/man7/zfsprops.7 @@ -1192,6 +1192,18 @@ are equivalent to the and .Sy noexec mount options. +.It Sy volthreading Ns = Ns Sy on Ns | Ns Sy off +Controls internal zvol threading. +The value +.Sy off +disables zvol threading, and zvol relies on application threads. +The default value is +.Sy on , +which enables threading within a zvol. +Please note that this property will be overridden by +.Sy zvol_request_sync +module parameter. +This property is only applicable to Linux. .It Sy filesystem_limit Ns = Ns Ar count Ns | Ns Sy none Limits the number of filesystems and volumes that can exist under this point in the dataset tree. diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c index f94ce69fb9..a7bcda252f 100644 --- a/module/os/linux/zfs/zvol_os.c +++ b/module/os/linux/zfs/zvol_os.c @@ -512,7 +512,7 @@ zvol_request_impl(zvol_state_t *zv, struct bio *bio, struct request *rq, uint64_t size = io_size(bio, rq); int rw = io_data_dir(bio, rq); - if (zvol_request_sync) + if (zvol_request_sync || zv->zv_threading == B_FALSE) force_sync = 1; zv_request_t zvr = { @@ -1304,6 +1304,7 @@ zvol_os_create_minor(const char *name) int error = 0; int idx; uint64_t hash = zvol_name_hash(name); + uint64_t volthreading; bool replayed_zil = B_FALSE; if (zvol_inhibit_dev) @@ -1350,6 +1351,12 @@ zvol_os_create_minor(const char *name) zv->zv_volsize = volsize; zv->zv_objset = os; + /* Default */ + zv->zv_threading = B_TRUE; + if (dsl_prop_get_integer(name, "volthreading", &volthreading, NULL) + == 0) + zv->zv_threading = volthreading; + set_capacity(zv->zv_zso->zvo_disk, zv->zv_volsize >> 9); blk_queue_max_hw_sectors(zv->zv_zso->zvo_queue, diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 00b5393a89..f63c2ad2f6 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -611,6 +611,9 @@ zfs_prop_init(void) ZVOL_DEFAULT_BLOCKSIZE, PROP_ONETIME, ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK", B_FALSE, sfeatures); + zprop_register_index(ZFS_PROP_VOLTHREADING, "volthreading", + 1, PROP_DEFAULT, ZFS_TYPE_VOLUME, "on | off", "zvol threading", + boolean_table, sfeatures); zprop_register_number(ZFS_PROP_USEDSNAP, "usedbysnapshots", 0, PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "", "USEDSNAP", B_FALSE, sfeatures); diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index d780b9f3da..72d5fc8192 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -2523,6 +2523,15 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source, case ZFS_PROP_VOLSIZE: err = zvol_set_volsize(dsname, intval); break; + case ZFS_PROP_VOLTHREADING: + err = zvol_set_volthreading(dsname, intval); + /* + * Set err to -1 to force the zfs_set_prop_nvlist code down the + * default path to set the value in the nvlist. + */ + if (err == 0) + err = -1; + break; case ZFS_PROP_SNAPDEV: case ZFS_PROP_VOLMODE: err = zvol_set_common(dsname, prop, source, intval); diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 023a6386d6..c576e34696 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -369,6 +369,20 @@ out: return (SET_ERROR(error)); } +/* + * Update volthreading. + */ +int +zvol_set_volthreading(const char *name, boolean_t value) +{ + zvol_state_t *zv = zvol_find_by_name(name, RW_NONE); + if (zv == NULL) + return (ENOENT); + zv->zv_threading = value; + mutex_exit(&zv->zv_state_lock); + return (0); +} + /* * Sanity check volume block size. */