Skip to content

Commit 7d474c6

Browse files
fuporovvStackFedorUporovVstack
authored andcommitted
zvol: Enable zvol threading functionality on FreeBSD
Make zvol I/O requests processing asynchronous on FreeBSD side in some cases. Clone zvol threading logic and required module parameters from Linux side. Make zvol threadpool creation/destruction logic shared for both Linux and FreeBSD. The IO requests are processed asynchronously in next cases: - volmode=geom: if IO request passed thru zvol_geom_worker thread. - volmode=cdev: if IO request passed thru struct cdevsw .d_strategy routine, mean is AIO request. In all other cases the IO requests are processed synchronously. Signed-off-by: Fedor Uporov <[email protected]>
1 parent 3862ebb commit 7d474c6

File tree

7 files changed

+236
-153
lines changed

7 files changed

+236
-153
lines changed

include/sys/zvol_impl.h

+33-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,32 @@ typedef struct zvol_state {
6060
boolean_t zv_threading; /* volthreading property */
6161
} zvol_state_t;
6262

63+
/*
64+
* zvol taskqs
65+
*/
66+
typedef struct zv_taskq {
67+
uint_t tqs_cnt;
68+
taskq_t **tqs_taskq;
69+
} zv_taskq_t;
70+
71+
typedef struct zv_request_stack {
72+
zvol_state_t *zv;
73+
struct bio *bio;
74+
#ifdef __linux__
75+
struct request *rq;
76+
#endif
77+
} zv_request_t;
78+
79+
typedef struct zv_request_task {
80+
zv_request_t zvr;
81+
taskq_ent_t ent;
82+
} zv_request_task_t;
83+
84+
/*
85+
* Switch taskq at multiple of 512 MB offset. This can be set to a lower value
86+
* to utilize more threads for small files but may affect prefetch hits.
87+
*/
88+
#define ZVOL_TASKQ_OFFSET_SHIFT 29
6389

6490
extern krwlock_t zvol_state_lock;
6591
#define ZVOL_HT_SIZE 1024
@@ -69,6 +95,10 @@ extern zil_replay_func_t *const zvol_replay_vector[TX_MAX_TYPE];
6995

7096
extern unsigned int zvol_volmode;
7197
extern unsigned int zvol_inhibit_dev;
98+
extern unsigned int zvol_threads;
99+
extern unsigned int zvol_num_taskqs;
100+
extern unsigned int zvol_request_sync;
101+
extern zv_taskq_t zvol_taskqs;
72102

73103
/*
74104
* platform independent functions exported to platform code
@@ -86,14 +116,16 @@ void zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, uint64_t offset,
86116
uint64_t size, boolean_t commit);
87117
int zvol_get_data(void *arg, uint64_t arg2, lr_write_t *lr, char *buf,
88118
struct lwb *lwb, zio_t *zio);
89-
int zvol_init_impl(void);
119+
int zvol_init_impl(uint32_t ncpus, uint32_t num_taskqs, uint32_t zvol_threads);
90120
void zvol_fini_impl(void);
91121
void zvol_wait_close(zvol_state_t *zv);
92122
int zvol_clone_range(zvol_state_handle_t *, uint64_t,
93123
zvol_state_handle_t *, uint64_t, uint64_t);
94124
void zvol_log_clone_range(zilog_t *zilog, dmu_tx_t *tx, int txtype,
95125
uint64_t off, uint64_t len, uint64_t blksz, const blkptr_t *bps,
96126
size_t nbps);
127+
zv_request_task_t *zv_request_task_create(zv_request_t zvr);
128+
void zv_request_task_free(zv_request_task_t *task);
97129

98130
/*
99131
* platform dependent functions exported to platform independent code

module/os/freebsd/zfs/zvol_os.c

+70-13
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
#include <geom/geom.h>
100100
#include <sys/zvol.h>
101101
#include <sys/zvol_impl.h>
102+
#include <cityhash.h>
102103

103104
#include "zfs_namecheck.h"
104105

@@ -169,7 +170,7 @@ static d_close_t zvol_cdev_close;
169170
static d_ioctl_t zvol_cdev_ioctl;
170171
static d_read_t zvol_cdev_read;
171172
static d_write_t zvol_cdev_write;
172-
static d_strategy_t zvol_geom_bio_strategy;
173+
static d_strategy_t zvol_bio_strategy;
173174
static d_kqfilter_t zvol_cdev_kqfilter;
174175

175176
static struct cdevsw zvol_cdevsw = {
@@ -181,7 +182,7 @@ static struct cdevsw zvol_cdevsw = {
181182
.d_ioctl = zvol_cdev_ioctl,
182183
.d_read = zvol_cdev_read,
183184
.d_write = zvol_cdev_write,
184-
.d_strategy = zvol_geom_bio_strategy,
185+
.d_strategy = zvol_bio_strategy,
185186
.d_kqfilter = zvol_cdev_kqfilter,
186187
};
187188

@@ -211,7 +212,8 @@ static int zvol_geom_access(struct g_provider *pp, int acr, int acw, int ace);
211212
static void zvol_geom_worker(void *arg);
212213
static void zvol_geom_bio_start(struct bio *bp);
213214
static int zvol_geom_bio_getattr(struct bio *bp);
214-
/* static d_strategy_t zvol_geom_bio_strategy; (declared elsewhere) */
215+
/* static d_strategy_t zvol_bio_strategy; (declared elsewhere) */
216+
static void zvol_geom_bio_strategy(struct bio *bp, boolean_t sync);
215217

216218
/*
217219
* GEOM mode implementation
@@ -544,7 +546,7 @@ zvol_geom_worker(void *arg)
544546
continue;
545547
}
546548
mtx_unlock(&zsg->zsg_queue_mtx);
547-
zvol_geom_bio_strategy(bp);
549+
zvol_geom_bio_strategy(bp, B_FALSE);
548550
}
549551
}
550552

@@ -576,7 +578,7 @@ zvol_geom_bio_start(struct bio *bp)
576578
return;
577579
}
578580

579-
zvol_geom_bio_strategy(bp);
581+
zvol_geom_bio_strategy(bp, B_TRUE);
580582
}
581583

582584
static int
@@ -660,9 +662,10 @@ zvol_cdev_kqfilter(struct cdev *dev, struct knote *kn)
660662
}
661663

662664
static void
663-
zvol_geom_bio_strategy(struct bio *bp)
665+
zvol_strategy_impl(zv_request_t *zvr)
664666
{
665667
zvol_state_t *zv;
668+
struct bio *bp;
666669
uint64_t off, volsize;
667670
size_t resid;
668671
char *addr;
@@ -673,11 +676,8 @@ zvol_geom_bio_strategy(struct bio *bp)
673676
boolean_t is_dumpified;
674677
boolean_t commit;
675678

676-
if (bp->bio_to)
677-
zv = bp->bio_to->private;
678-
else
679-
zv = bp->bio_dev->si_drv2;
680-
679+
bp = zvr->bio;
680+
zv = zvr->zv;
681681
if (zv == NULL) {
682682
error = SET_ERROR(ENXIO);
683683
goto out;
@@ -813,6 +813,64 @@ zvol_geom_bio_strategy(struct bio *bp)
813813
biofinish(bp, NULL, error);
814814
}
815815

816+
static void
817+
zvol_strategy_task(void *arg)
818+
{
819+
zv_request_task_t *task = arg;
820+
821+
zvol_strategy_impl(&task->zvr);
822+
zv_request_task_free(task);
823+
}
824+
825+
static void
826+
zvol_geom_bio_strategy(struct bio *bp, boolean_t sync)
827+
{
828+
zv_taskq_t *ztqs = &zvol_taskqs;
829+
zv_request_task_t *task;
830+
zvol_state_t *zv;
831+
uint64_t taskq_hash;
832+
uint32_t tq_idx;
833+
int error;
834+
835+
if (bp->bio_to)
836+
zv = bp->bio_to->private;
837+
else
838+
zv = bp->bio_dev->si_drv2;
839+
840+
if (zv == NULL) {
841+
error = SET_ERROR(ENXIO);
842+
if (bp->bio_to)
843+
g_io_deliver(bp, error);
844+
else
845+
biofinish(bp, NULL, error);
846+
847+
return;
848+
}
849+
850+
zv_request_t zvr = {
851+
.zv = zv,
852+
.bio = bp,
853+
};
854+
855+
if (sync || zvol_request_sync) {
856+
zvol_strategy_impl(&zvr);
857+
return;
858+
}
859+
860+
taskq_hash = cityhash3((uintptr_t)zv, curcpu, bp->bio_offset >>
861+
ZVOL_TASKQ_OFFSET_SHIFT);
862+
tq_idx = taskq_hash % ztqs->tqs_cnt;
863+
task = zv_request_task_create(zvr);
864+
taskq_dispatch_ent(ztqs->tqs_taskq[tq_idx], zvol_strategy_task, task,
865+
0, &task->ent);
866+
}
867+
868+
static void
869+
zvol_bio_strategy(struct bio *bp)
870+
{
871+
zvol_geom_bio_strategy(bp, B_FALSE);
872+
}
873+
816874
/*
817875
* Character device mode implementation
818876
*/
@@ -1606,8 +1664,7 @@ zvol_busy(void)
16061664
int
16071665
zvol_init(void)
16081666
{
1609-
zvol_init_impl();
1610-
return (0);
1667+
return (zvol_init_impl(mp_ncpus, zvol_num_taskqs, zvol_threads));
16111668
}
16121669

16131670
void

0 commit comments

Comments
 (0)