Full readonly check
Both in core and in engines. To the extent possible, this should catch
even fio errors.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/engines/guasi.c b/engines/guasi.c
index 7db09c3..69b2cd2 100644
--- a/engines/guasi.c
+++ b/engines/guasi.c
@@ -124,6 +124,8 @@
{
struct guasi_data *ld = td->io_ops->data;
+ fio_ro_check(td, io_u);
+
GDBG_PRINT(("fio_guasi_queue(%p)\n", io_u));
if (ld->queued_nr == (int) td->o.iodepth)
return FIO_Q_BUSY;
diff --git a/engines/libaio.c b/engines/libaio.c
index f8990c1..8f67711 100644
--- a/engines/libaio.c
+++ b/engines/libaio.c
@@ -86,6 +86,8 @@
{
struct libaio_data *ld = td->io_ops->data;
+ fio_ro_check(td, io_u);
+
if (ld->iocbs_nr == (int) td->o.iodepth)
return FIO_Q_BUSY;
diff --git a/engines/mmap.c b/engines/mmap.c
index f3d55c1..604f8b0 100644
--- a/engines/mmap.c
+++ b/engines/mmap.c
@@ -19,6 +19,8 @@
struct fio_file *f = io_u->file;
unsigned long long real_off = io_u->offset - f->file_offset;
+ fio_ro_check(td, io_u);
+
if (io_u->ddir == DDIR_READ)
memcpy(io_u->xfer_buf, f->mmap + real_off, io_u->xfer_buflen);
else if (io_u->ddir == DDIR_WRITE)
diff --git a/engines/net.c b/engines/net.c
index 0adc006..552ad0b 100644
--- a/engines/net.c
+++ b/engines/net.c
@@ -198,6 +198,8 @@
struct netio_data *nd = td->io_ops->data;
int ret;
+ fio_ro_check(td, io_u);
+
if (io_u->ddir == DDIR_WRITE) {
if (nd->use_splice)
ret = fio_netio_splice_out(td, io_u);
diff --git a/engines/null.c b/engines/null.c
index 823d40d..bbb4e8a 100644
--- a/engines/null.c
+++ b/engines/null.c
@@ -56,6 +56,8 @@
{
struct null_data *nd = td->io_ops->data;
+ fio_ro_check(td, io_u);
+
if (td->io_ops->flags & FIO_SYNCIO)
return FIO_Q_COMPLETED;
if (nd->events)
diff --git a/engines/posixaio.c b/engines/posixaio.c
index 88ed402..9ff05c4 100644
--- a/engines/posixaio.c
+++ b/engines/posixaio.c
@@ -148,6 +148,8 @@
struct aiocb *aiocb = &io_u->aiocb;
int ret;
+ fio_ro_check(td, io_u);
+
if (io_u->ddir == DDIR_READ)
ret = aio_read(aiocb);
else if (io_u->ddir == DDIR_WRITE)
diff --git a/engines/sg.c b/engines/sg.c
index cc50d6b..790019e 100644
--- a/engines/sg.c
+++ b/engines/sg.c
@@ -242,6 +242,8 @@
struct sg_io_hdr *hdr = &io_u->hdr;
int ret;
+ fio_ro_check(td, io_u);
+
ret = fio_sgio_doio(td, io_u, io_u->ddir == DDIR_SYNC);
if (ret < 0)
diff --git a/engines/skeleton_external.c b/engines/skeleton_external.c
index 9000acc..26dbedf 100644
--- a/engines/skeleton_external.c
+++ b/engines/skeleton_external.c
@@ -65,6 +65,11 @@
static int fio_skeleton_queue(struct thread_data *td, struct io_u *io_u)
{
/*
+ * Double sanity check to catch errant write on a readonly setup
+ */
+ fio_ro_check(td, io_u);
+
+ /*
* Could return FIO_Q_QUEUED for a queued request,
* FIO_Q_COMPLETED for a completed request, and FIO_Q_BUSY
* if we could queue no more at this point (you'd have to
diff --git a/engines/splice.c b/engines/splice.c
index 440196b..2344fdd 100644
--- a/engines/splice.c
+++ b/engines/splice.c
@@ -185,6 +185,8 @@
struct spliceio_data *sd = td->io_ops->data;
int ret;
+ fio_ro_check(td, io_u);
+
if (io_u->ddir == DDIR_READ) {
if (sd->vmsplice_to_user) {
ret = fio_splice_read(td, io_u);
diff --git a/engines/sync.c b/engines/sync.c
index ee8e3c3..597ee01 100644
--- a/engines/sync.c
+++ b/engines/sync.c
@@ -35,6 +35,8 @@
struct fio_file *f = io_u->file;
int ret;
+ fio_ro_check(td, io_u);
+
if (io_u->ddir == DDIR_READ)
ret = read(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
else if (io_u->ddir == DDIR_WRITE)
diff --git a/engines/syslet-rw.c b/engines/syslet-rw.c
index 7e407d7..e0dddd8 100644
--- a/engines/syslet-rw.c
+++ b/engines/syslet-rw.c
@@ -253,6 +253,8 @@
{
struct syslet_data *sd = td->io_ops->data;
+ fio_ro_check(td, io_u);
+
if (sd->tail) {
sd->tail->next = &io_u->req.atom;
sd->tail = &io_u->req.atom;
diff --git a/fio.h b/fio.h
index 20d1408..1b392a0 100644
--- a/fio.h
+++ b/fio.h
@@ -13,6 +13,7 @@
#include <string.h>
#include <getopt.h>
#include <inttypes.h>
+#include <assert.h>
#include "compiler/compiler.h"
#include "list.h"
@@ -670,6 +671,11 @@
#define td_rw(td) (((td)->o.td_ddir & TD_DDIR_RW) == TD_DDIR_RW)
#define td_random(td) ((td)->o.td_ddir & TD_DDIR_RAND)
+static inline void fio_ro_check(struct thread_data *td, struct io_u *io_u)
+{
+ assert(!(io_u->ddir == DDIR_WRITE && !td_write(td)));
+}
+
#define BLOCKS_PER_MAP (8 * sizeof(long))
#define TO_MAP_BLOCK(td, f, b) ((b) - ((f)->file_offset / (td)->o.rw_min_bs))
#define RAND_MAP_IDX(td, f, b) (TO_MAP_BLOCK(td, f, b) / BLOCKS_PER_MAP)
diff --git a/ioengines.c b/ioengines.c
index 8e6fae2..cf8c2f1 100644
--- a/ioengines.c
+++ b/ioengines.c
@@ -157,6 +157,8 @@
int td_io_prep(struct thread_data *td, struct io_u *io_u)
{
+ fio_ro_check(td, io_u);
+
if (td->io_ops->prep)
return td->io_ops->prep(td, io_u);
@@ -182,13 +184,13 @@
{
int ret;
+ fio_ro_check(td, io_u);
+
assert((io_u->flags & IO_U_F_FLIGHT) == 0);
io_u->flags |= IO_U_F_FLIGHT;
assert(io_u->file->flags & FIO_FILE_OPEN);
- assert(!(io_u->ddir == DDIR_WRITE && !td_write(td)));
-
io_u->error = 0;
io_u->resid = 0;