summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@suse.de>2005-12-07 21:23:26 +0100
committerJens Axboe <axboe@suse.de>2005-12-07 21:23:26 +0100
commit410de646b75dc74cb480aae3d151bd4503e67780 (patch)
treee7b2e53b1462ca69ea069dd60569f489ca5731b0
parent409a8614a46da061e373963ae52d3a60a5b63a81 (diff)
[PATCH] fio: add SG_IO ioengine
-rw-r--r--README.fio5
-rw-r--r--fio-ini.c4
-rw-r--r--fio-io.c117
-rw-r--r--fio.c8
-rw-r--r--fio.h12
-rw-r--r--os-freebsd.h1
-rw-r--r--os-linux.h1
-rw-r--r--os.h6
8 files changed, 147 insertions, 7 deletions
diff --git a/README.fio b/README.fio
index f3aad7d..afef8ec 100644
--- a/README.fio
+++ b/README.fio
@@ -28,7 +28,10 @@ The <jobs> format is as follows:
size=x Set file size to x bytes (x string can include k/m/g)
ioengine=x 'x' may be: aio/libaio/linuxaio for Linux aio,
posixaio for POSIX aio, sync for regular read/write io,
- or mmap for mmap'ed io.
+ mmap for mmap'ed io, or sgio for direct SG_IO io. The
+ latter only works on Linux on SCSI (or SCSI-like
+ devices, such as usb-storage or sata/libata driven)
+ devices.
iodepth=x For async io, allow 'x' ios in flight
overwrite=x If 'x', layout a write file first.
prio=x Run io at prio X, 0-7 is the kernel allowed range
diff --git a/fio-ini.c b/fio-ini.c
index 093b9b3..c6ff200 100644
--- a/fio-ini.c
+++ b/fio-ini.c
@@ -552,6 +552,10 @@ static int str_ioengine_cb(struct thread_data *td, char *str)
strcpy(td->io_engine_name, "mmap");
td->io_engine = FIO_MMAPIO;
return 0;
+ } else if (!strncmp(str, "sgio", 4)) {
+ strcpy(td->io_engine_name, "sgio");
+ td->io_engine = FIO_SGIO;
+ return 0;
}
fprintf(stderr, "bad ioengine type: %s\n", str);
diff --git a/fio-io.c b/fio-io.c
index fc8dc83..3c86639 100644
--- a/fio-io.c
+++ b/fio-io.c
@@ -458,3 +458,120 @@ int fio_mmapio_init(struct thread_data *td)
td->io_data = sd;
return 0;
}
+
+#ifdef FIO_HAVE_SGIO
+
+struct sgio_data {
+ struct io_u *last_io_u;
+ unsigned char cdb[10];
+ unsigned int bs;
+};
+
+static int fio_sgio_sync(struct thread_data *td)
+{
+ /*
+ * need to issue flush cache
+ */
+ return 0;
+}
+
+static int fio_sgio_queue(struct thread_data *td, struct io_u *io_u)
+{
+ struct sg_io_hdr *hdr = &io_u->hdr;
+ struct sgio_data *sd = td->io_data;
+ int nr_blocks, lba, ret;
+
+ if (io_u->buflen & (sd->bs - 1)) {
+ fprintf(stderr, "read/write not sector aligned\n");
+ return EINVAL;
+ }
+
+ memset(hdr, 0, sizeof(*hdr));
+ memset(sd->cdb, 0, sizeof(sd->cdb));
+
+ hdr->interface_id = 'S';
+ hdr->cmdp = sd->cdb;
+ hdr->cmd_len = sizeof(sd->cdb);
+ hdr->dxferp = io_u->buf;
+ hdr->dxfer_len = io_u->buflen;
+
+ if (io_u->ddir == DDIR_READ) {
+ hdr->dxfer_direction = SG_DXFER_FROM_DEV;
+ hdr->cmdp[0] = 0x28;
+ } else {
+ hdr->dxfer_direction = SG_DXFER_TO_DEV;
+ hdr->cmdp[0] = 0x2a;
+ }
+
+ nr_blocks = io_u->buflen / sd->bs;
+ lba = io_u->offset / sd->bs;
+ hdr->cmdp[2] = (lba >> 24) & 0xff;
+ hdr->cmdp[3] = (lba >> 16) & 0xff;
+ hdr->cmdp[4] = (lba >> 8) & 0xff;
+ hdr->cmdp[5] = lba & 0xff;
+ hdr->cmdp[7] = (nr_blocks >> 8) & 0xff;
+ hdr->cmdp[8] = nr_blocks & 0xff;
+
+ ret = ioctl(td->fd, SG_IO, hdr);
+ if (ret < 0)
+ io_u->error = errno;
+ else if (hdr->status) {
+ io_u->resid = hdr->resid;
+ io_u->error = EIO;
+ }
+
+ if (!io_u->error)
+ sd->last_io_u = io_u;
+
+ return io_u->error;
+
+}
+
+static struct io_u *fio_sgio_event(struct thread_data *td, int event)
+{
+ struct sgio_data *sd = td->io_data;
+
+ assert(event == 0);
+
+ return sd->last_io_u;
+}
+
+int fio_sgio_init(struct thread_data *td)
+{
+ struct sgio_data *sd;
+ int bs;
+
+ if (td->filetype != FIO_TYPE_BD) {
+ fprintf(stderr, "ioengine sgio only works on block devices\n");
+ return 1;
+ }
+
+ if (ioctl(td->fd, BLKSSZGET, &bs) < 0) {
+ td_verror(td, errno);
+ return 1;
+ }
+
+ sd = malloc(sizeof(*sd));
+ sd->bs = bs;
+
+ td->io_prep = NULL;
+ td->io_queue = fio_sgio_queue;
+ td->io_getevents = fio_syncio_getevents;
+ td->io_event = fio_sgio_event;
+ td->io_cancel = NULL;
+ td->io_cleanup = fio_syncio_cleanup;
+ td->io_sync = fio_sgio_sync;
+
+ sd->last_io_u = NULL;
+ td->io_data = sd;
+ return 0;
+}
+
+#else /* FIO_HAVE_SGIO */
+
+int fio_sgio_init(struct thread_data *td)
+{
+ return EINVAL;
+}
+
+#endif /* FIO_HAVE_SGIO */
diff --git a/fio.c b/fio.c
index 89f8e92..30b84ac 100644
--- a/fio.c
+++ b/fio.c
@@ -725,6 +725,8 @@ static int io_u_getevents(struct thread_data *td, int min, int max,
static int io_u_queue(struct thread_data *td, struct io_u *io_u)
{
+ gettimeofday(&io_u->issue_time, NULL);
+
return td->io_queue(td, io_u);
}
@@ -937,8 +939,8 @@ static void do_io(struct thread_data *td)
break;
}
- gettimeofday(&io_u->issue_time, NULL);
add_slat_sample(td, io_u->ddir, mtime_since(&io_u->start_time, &io_u->issue_time));
+
if (td->cur_depth < td->iodepth) {
timeout = &ts;
min_evts = 0;
@@ -1010,6 +1012,8 @@ static int init_io(struct thread_data *td)
return fio_libaio_init(td);
else if (td->io_engine == FIO_POSIXAIO)
return fio_posixaio_init(td);
+ else if (td->io_engine == FIO_SGIO)
+ return fio_sgio_init(td);
else {
fprintf(stderr, "bad io_engine %d\n", td->io_engine);
return 1;
@@ -1812,7 +1816,7 @@ static void show_thread_status(struct thread_data *td,
sys_cpu = 0;
}
- printf(" cpu : usr=%3.2f%%, sys=%3.2f%%, ctx=%lu\n", usr_cpu, sys_cpu, td->ctx);
+ printf(" cpu : usr=%3.2f%%, sys=%3.2f%%, ctx=%lu\n", usr_cpu, sys_cpu, td->ctx);
}
static void check_str_update(struct thread_data *td)
diff --git a/fio.h b/fio.h
index 600c3be..4021b74 100644
--- a/fio.h
+++ b/fio.h
@@ -50,6 +50,9 @@ struct io_u {
#ifdef FIO_HAVE_POSIXAIO
struct aiocb aiocb;
#endif
+#ifdef FIO_HAVE_SGIO
+ struct sg_io_hdr hdr;
+#endif
};
struct timeval start_time;
struct timeval issue_time;
@@ -254,10 +257,11 @@ enum {
};
enum {
- FIO_SYNCIO = 1 << 0,
- FIO_MMAPIO = 1 << 1 | FIO_SYNCIO,
- FIO_LIBAIO = 1 << 2,
- FIO_POSIXAIO = 1 << 3,
+ FIO_SYNCIO = 1 << 0,
+ FIO_MMAPIO = 1 << 1 | FIO_SYNCIO,
+ FIO_LIBAIO = 1 << 2,
+ FIO_POSIXAIO = 1 << 3,
+ FIO_SGIO = 1 << 4,
};
#define td_read(td) ((td)->ddir == DDIR_READ)
diff --git a/os-freebsd.h b/os-freebsd.h
index a79483b..26dba90 100644
--- a/os-freebsd.h
+++ b/os-freebsd.h
@@ -6,6 +6,7 @@
#undef FIO_HAVE_FADVISE
#undef FIO_HAVE_CPU_AFFINITY
#undef FIO_HAVE_DISK_UTIL
+#undef FIO_HAVE_SGIO
#define OS_MAP_ANON (MAP_ANON)
diff --git a/os-linux.h b/os-linux.h
index e414364..0b1fc00 100644
--- a/os-linux.h
+++ b/os-linux.h
@@ -8,6 +8,7 @@
#define FIO_HAVE_FADVISE
#define FIO_HAVE_CPU_AFFINITY
#define FIO_HAVE_DISK_UTIL
+#define FIO_HAVE_SGIO
#define OS_MAP_ANON (MAP_ANONYMOUS)
diff --git a/os.h b/os.h
index 1ba0b24..3ee1368 100644
--- a/os.h
+++ b/os.h
@@ -17,6 +17,11 @@
#include <aio.h>
#endif
+#ifdef FIO_HAVE_SGIO
+#include <linux/fs.h>
+#include <scsi/sg.h>
+#endif
+
#ifndef FIO_HAVE_FADVISE
#define fadvise(fd, off, len, advice) (0)
@@ -39,5 +44,6 @@ extern int fio_libaio_init(struct thread_data *);
extern int fio_posixaio_init(struct thread_data *);
extern int fio_syncio_init(struct thread_data *);
extern int fio_mmapio_init(struct thread_data *);
+extern int fio_sgio_init(struct thread_data *);
#endif