From: Jens Axboe Date: Mon, 19 Mar 2018 16:24:10 +0000 (-0600) Subject: Merge branch 'master' of https://github.com/bvanassche/fio X-Git-Tag: fio-3.6~37 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=d3d378218e9e03411749b65451b32d7a7466ff61;hp=4f37732a580d7983467ea1ba11f963da4e8cf06e Merge branch 'master' of https://github.com/bvanassche/fio * 'master' of https://github.com/bvanassche/fio: Suppress uninteresting data race reports gettime: Rework the clock thread starting mechanism Improve Valgrind instrumentation of memory allocations Rename fio_mutex into fio_sem Split mutex.c and .h each into three files --- diff --git a/HOWTO b/HOWTO index acb9e97f..dbbbfaa1 100644 --- a/HOWTO +++ b/HOWTO @@ -1747,6 +1747,7 @@ I/O engine :manpage:`read(2)` and :manpage:`write(2)` for asynchronous I/O. Requires :option:`filename` option to specify either block or character devices. + The sg engine includes engine specific options. **null** Doesn't transfer any data, just pretends to. This is mainly used to @@ -2068,6 +2069,17 @@ with the caveat that when used on the command line, they must come after the multiple paths exist between the client and the server or in certain loopback configurations. +.. option:: readfua=bool : [sg] + + With readfua option set to 1, read operations include + the force unit access (fua) flag. Default is 0. + +.. option:: writefua=bool : [sg] + + With writefua option set to 1, write operations include + the force unit access (fua) flag. Default is 0. + + I/O depth ~~~~~~~~~ diff --git a/engines/sg.c b/engines/sg.c index 4540b573..f2407555 100644 --- a/engines/sg.c +++ b/engines/sg.c @@ -12,9 +12,43 @@ #include #include "../fio.h" +#include "../optgroup.h" #ifdef FIO_HAVE_SGIO + +struct sg_options { + void *pad; + unsigned int readfua; + unsigned int writefua; +}; + +static struct fio_option options[] = { + { + .name = "readfua", + .lname = "sg engine read fua flag support", + .type = FIO_OPT_BOOL, + .off1 = offsetof(struct sg_options, readfua), + .help = "Set FUA flag (force unit access) for all Read operations", + .def = "0", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_SG, + }, + { + .name = "writefua", + .lname = "sg engine write fua flag support", + .type = FIO_OPT_BOOL, + .off1 = offsetof(struct sg_options, writefua), + .help = "Set FUA flag (force unit access) for all Write operations", + .def = "0", + .category = FIO_OPT_C_ENGINE, + .group = FIO_OPT_G_SG, + }, + { + .name = NULL, + }, +}; + #define MAX_10B_LBA 0xFFFFFFFFULL #define SCSI_TIMEOUT_MS 30000 // 30 second timeout; currently no method to override #define MAX_SB 64 // sense block maximum return size @@ -267,6 +301,7 @@ static int fio_sgio_doio(struct thread_data *td, struct io_u *io_u, int do_sync) static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u) { struct sg_io_hdr *hdr = &io_u->hdr; + struct sg_options *o = td->eo; struct sgio_data *sd = td->io_ops_data; long long nr_blocks, lba; @@ -286,6 +321,10 @@ static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u) hdr->cmdp[0] = 0x28; // read(10) else hdr->cmdp[0] = 0x88; // read(16) + + if (o->readfua) + hdr->cmdp[1] |= 0x08; + } else if (io_u->ddir == DDIR_WRITE) { sgio_hdr_init(sd, hdr, io_u, 1); @@ -294,6 +333,10 @@ static int fio_sgio_prep(struct thread_data *td, struct io_u *io_u) hdr->cmdp[0] = 0x2a; // write(10) else hdr->cmdp[0] = 0x8a; // write(16) + + if (o->writefua) + hdr->cmdp[1] |= 0x08; + } else { sgio_hdr_init(sd, hdr, io_u, 0); hdr->dxfer_direction = SG_DXFER_NONE; @@ -822,6 +865,8 @@ static struct ioengine_ops ioengine = { .close_file = generic_close_file, .get_file_size = fio_sgio_get_file_size, .flags = FIO_SYNCIO | FIO_RAWIO, + .options = options, + .option_struct_size = sizeof(struct sg_options) }; #else /* FIO_HAVE_SGIO */ diff --git a/fio.1 b/fio.1 index f9551676..5ca57ce4 100644 --- a/fio.1 +++ b/fio.1 @@ -1523,7 +1523,7 @@ SCSI generic sg v3 I/O. May either be synchronous using the SG_IO ioctl, or if the target is an sg character device we use \fBread\fR\|(2) and \fBwrite\fR\|(2) for asynchronous I/O. Requires \fBfilename\fR option to specify either block or -character devices. +character devices. The sg engine includes engine specific options. .TP .B null Doesn't transfer any data, just pretends to. This is mainly used to @@ -1820,6 +1820,14 @@ server side this will be passed into the rdma_bind_addr() function and on the client site it will be used in the rdma_resolve_add() function. This can be useful when multiple paths exist between the client and the server or in certain loopback configurations. +.TP +.BI (sg)readfua \fR=\fPbool +With readfua option set to 1, read operations include the force +unit access (fua) flag. Default: 0. +.TP +.BI (sg)writefua \fR=\fPbool +With writefua option set to 1, write operations include the force +unit access (fua) flag. Default: 0. .SS "I/O depth" .TP .BI iodepth \fR=\fPint diff --git a/io_u.c b/io_u.c index 01b36938..f3b59322 100644 --- a/io_u.c +++ b/io_u.c @@ -856,8 +856,8 @@ void put_io_u(struct thread_data *td, struct io_u *io_u) assert(!(td->flags & TD_F_CHILD)); } io_u_qpush(&td->io_u_freelist, io_u); - td_io_u_unlock(td); td_io_u_free_notify(td); + td_io_u_unlock(td); } void clear_io_u(struct thread_data *td, struct io_u *io_u) @@ -889,8 +889,8 @@ void requeue_io_u(struct thread_data *td, struct io_u **io_u) } io_u_rpush(&td->io_u_requeues, __io_u); - td_io_u_unlock(td); td_io_u_free_notify(td); + td_io_u_unlock(td); *io_u = NULL; } @@ -1558,6 +1558,7 @@ bool queue_full(const struct thread_data *td) struct io_u *__get_io_u(struct thread_data *td) { struct io_u *io_u = NULL; + int ret; if (td->stop_io) return NULL; @@ -1594,7 +1595,8 @@ again: * return one */ assert(!(td->flags & TD_F_CHILD)); - assert(!pthread_cond_wait(&td->free_cond, &td->io_u_lock)); + ret = pthread_cond_wait(&td->free_cond, &td->io_u_lock); + assert(ret == 0); goto again; } diff --git a/optgroup.h b/optgroup.h index 815ac167..d5e968d4 100644 --- a/optgroup.h +++ b/optgroup.h @@ -55,10 +55,11 @@ enum opt_category_group { __FIO_OPT_G_LIBAIO, __FIO_OPT_G_ACT, __FIO_OPT_G_LATPROF, - __FIO_OPT_G_RBD, - __FIO_OPT_G_GFAPI, - __FIO_OPT_G_MTD, + __FIO_OPT_G_RBD, + __FIO_OPT_G_GFAPI, + __FIO_OPT_G_MTD, __FIO_OPT_G_HDFS, + __FIO_OPT_G_SG, __FIO_OPT_G_NR, FIO_OPT_G_RATE = (1ULL << __FIO_OPT_G_RATE), @@ -93,6 +94,7 @@ enum opt_category_group { FIO_OPT_G_GFAPI = (1ULL << __FIO_OPT_G_GFAPI), FIO_OPT_G_MTD = (1ULL << __FIO_OPT_G_MTD), FIO_OPT_G_HDFS = (1ULL << __FIO_OPT_G_HDFS), + FIO_OPT_G_SG = (1ULL << __FIO_OPT_G_SG), FIO_OPT_G_INVALID = (1ULL << __FIO_OPT_G_NR), }; diff --git a/verify.c b/verify.c index 17af3bb9..d10670bb 100644 --- a/verify.c +++ b/verify.c @@ -1454,9 +1454,9 @@ static void *verify_async_thread(void *data) done: pthread_mutex_lock(&td->io_u_lock); td->nr_verify_threads--; + pthread_cond_signal(&td->free_cond); pthread_mutex_unlock(&td->io_u_lock); - pthread_cond_signal(&td->free_cond); return NULL; } @@ -1492,9 +1492,12 @@ int verify_async_init(struct thread_data *td) if (i != td->o.verify_async) { log_err("fio: only %d verify threads started, exiting\n", i); + + pthread_mutex_lock(&td->io_u_lock); td->verify_thread_exit = 1; - write_barrier(); pthread_cond_broadcast(&td->verify_cond); + pthread_mutex_unlock(&td->io_u_lock); + return 1; } @@ -1503,12 +1506,10 @@ int verify_async_init(struct thread_data *td) void verify_async_exit(struct thread_data *td) { + pthread_mutex_lock(&td->io_u_lock); td->verify_thread_exit = 1; - write_barrier(); pthread_cond_broadcast(&td->verify_cond); - pthread_mutex_lock(&td->io_u_lock); - while (td->nr_verify_threads) pthread_cond_wait(&td->free_cond, &td->io_u_lock);