Add support for fdatasync()
authorJens Axboe <jens.axboe@oracle.com>
Tue, 16 Jun 2009 20:40:26 +0000 (22:40 +0200)
committerJens Axboe <jens.axboe@oracle.com>
Tue, 16 Jun 2009 20:40:26 +0000 (22:40 +0200)
Adds a new option, fdatasync=. It's identical to the fsync= option,
but uses fdatasync() instead.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
15 files changed:
HOWTO
engines/guasi.c
engines/libaio.c
engines/mmap.c
engines/sg.c
engines/solarisaio.c
engines/sync.c
engines/syslet-rw.c
fio.1
fio.h
io_ddir.h
io_u.c
ioengines.c
log.c
options.c

diff --git a/HOWTO b/HOWTO
index 0eab6e113a9d5c99fae86f1f30bb2a4196b97f14..f323c204d3c67be97e98926ae8efd0ae1d82314d 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -530,6 +530,9 @@ fsync=int   If writing to a file, issue a sync of the dirty data
                not sync the file. The exception is the sg io engine, which
                synchronizes the disk cache anyway.
 
+fsyncdata=int  Like fsync= but uses fdatasync() to only sync data and not
+               metadata blocks.
+
 overwrite=bool If true, writes to a file will always overwrite existing
                data. If the file doesn't already exist, it will be
                created before the write phase begins. If the file exists
index 3802f2c21e4ea4ff9a6db588a41df60e4ee36087..15d4801ad2ae1f37d9710d02254acb61d67a7bda 100644 (file)
@@ -174,7 +174,7 @@ static int fio_guasi_commit(struct thread_data *td)
                        io_u->greq = guasi__pwrite(ld->hctx, ld, io_u, 0,
                                                   f->fd, io_u->xfer_buf, io_u->xfer_buflen,
                                                   io_u->offset);
-               else if (io_u->ddir == DDIR_SYNC)
+               else if (ddir_sync(io_u->ddir))
                        io_u->greq = guasi__fsync(ld->hctx, ld, io_u, 0, f->fd);
                else {
                        log_err("fio_guasi_commit() FAILED: unknow request %d\n",
index e452f1ca7c55f630c18c49186ece3f091713d0db..bd8ebb8b65553fe1c8067815811b8a9393b788dc 100644 (file)
@@ -32,7 +32,7 @@ static int fio_libaio_prep(struct thread_data fio_unused *td, struct io_u *io_u)
                io_prep_pread(&io_u->iocb, f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
        else if (io_u->ddir == DDIR_WRITE)
                io_prep_pwrite(&io_u->iocb, f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
-       else if (io_u->ddir == DDIR_SYNC)
+       else if (ddir_sync(io_u->ddir))
                io_prep_fsync(&io_u->iocb, f->fd);
        else
                return 1;
@@ -103,6 +103,13 @@ static int fio_libaio_queue(struct thread_data *td, struct io_u *io_u)
                if (fsync(io_u->file->fd) < 0)
                        io_u->error = errno;
 
+               return FIO_Q_COMPLETED;
+       } else if (io_u->ddir == DDIR_DATASYNC) {
+               if (ld->iocbs_nr)
+                       return FIO_Q_BUSY;
+               if (fdatasync(io_u->file->fd) < 0)
+                       io_u->error = errno;
+
                return FIO_Q_COMPLETED;
        }
 
index fde68f1d9b0b5b6a7e3e6f404a003a02f1b4bf45..6671fc0e66d8e78e9f7c0fbeac8dd98a8b4d0946 100644 (file)
@@ -113,7 +113,7 @@ static int fio_mmapio_queue(struct thread_data *td, struct io_u *io_u)
                memcpy(io_u->xfer_buf, io_u->mmap_data, io_u->xfer_buflen);
        else if (io_u->ddir == DDIR_WRITE)
                memcpy(io_u->mmap_data, io_u->xfer_buf, io_u->xfer_buflen);
-       else if (io_u->ddir == DDIR_SYNC) {
+       else if (ddir_sync(io_u->ddir)) {
                if (msync(f->mmap_ptr, f->mmap_sz, MS_SYNC)) {
                        io_u->error = errno;
                        td_verror(td, io_u->error, "msync");
@@ -123,7 +123,7 @@ static int fio_mmapio_queue(struct thread_data *td, struct io_u *io_u)
        /*
         * not really direct, but should drop the pages from the cache
         */
-       if (td->o.odirect && io_u->ddir != DDIR_SYNC) {
+       if (td->o.odirect && !ddir_sync(io_u->ddir)) {
                if (msync(io_u->mmap_data, io_u->xfer_buflen, MS_SYNC) < 0) {
                        io_u->error = errno;
                        td_verror(td, io_u->error, "msync");
index 39f99d8d0922050eb1a3aa3d60305cd865a09113..0ed39b3d9527e5569bc84015e376c5296caff5be 100644 (file)
@@ -244,7 +244,7 @@ static int fio_sgio_queue(struct thread_data *td, struct io_u *io_u)
 
        fio_ro_check(td, io_u);
 
-       ret = fio_sgio_doio(td, io_u, io_u->ddir == DDIR_SYNC);
+       ret = fio_sgio_doio(td, io_u, ddir_sync(io_u->ddir));
 
        if (ret < 0)
                io_u->error = errno;
index a48ec41825b67ceae574682ba73cc545bcd9156e..17b7e22c87bcc9b850def35739e4a973d7a129f6 100644 (file)
@@ -126,6 +126,15 @@ static int fio_solarisaio_queue(struct thread_data fio_unused *td,
                return FIO_Q_COMPLETED;
        }
 
+       if (io_u->ddir == DDIR_DATASYNC) {
+               if (sd->nr)
+                       return FIO_Q_BUSY;
+               if (fdatasync(f->fd) < 0)
+                       io_u->error = errno;
+
+               return FIO_Q_COMPLETED;
+       }
+
        if (sd->nr == sd->max_depth)
                return FIO_Q_BUSY;
 
index 842c6c0b29a4f0bf33351bdbbc5ea18581361f5b..7c1cca63c700c4f318d1dd2003cc0fca5d52653f 100644 (file)
@@ -30,7 +30,7 @@ static int fio_syncio_prep(struct thread_data *td, struct io_u *io_u)
 {
        struct fio_file *f = io_u->file;
 
-       if (io_u->ddir == DDIR_SYNC)
+       if (ddir_sync(io_u->ddir))
                return 0;
 
        if (lseek(f->fd, io_u->offset, SEEK_SET) == -1) {
@@ -120,7 +120,7 @@ static int fio_vsyncio_append(struct thread_data *td, struct io_u *io_u)
 {
        struct syncio_data *sd = td->io_ops->data;
 
-       if (io_u->ddir == DDIR_SYNC)
+       if (ddir_sync(io_u->ddir))
                return 0;
 
        if (io_u->offset == sd->last_offset && io_u->file == sd->last_file &&
@@ -161,8 +161,12 @@ static int fio_vsyncio_queue(struct thread_data *td, struct io_u *io_u)
                        int ret = fsync(io_u->file->fd);
 
                        return fio_io_end(td, io_u, ret);
-               }
+               } else if (io_u->ddir == DDIR_DATASYNC) {
+                       int ret = fdatasync(io_u->file->fd);
 
+                       return fio_io_end(td, io_u, ret);
+               }
+       
                sd->queued = 0;
                sd->queued_bytes = 0;
                fio_vsyncio_set_iov(sd, io_u, 0);
index ad9cb35972c59042baa90093901f79fa9fcd0239..c11e4f21fc39990fc6ece7bfd2dc03bee4c682a2 100644 (file)
@@ -131,6 +131,12 @@ static void fio_syslet_prep_sync(struct fio_file *f,
        FILL_IN(*regs, __NR_fsync, (long) f->fd);
 }
 
+static void fio_syslet_prep_datasync(struct fio_file *f,
+                                    struct indirect_registers *regs)
+{
+       FILL_IN(*regs, __NR_fdatasync, (long) f->fd);
+}
+
 static void fio_syslet_prep_rw(struct io_u *io_u, struct fio_file *f,
                               struct indirect_registers *regs)
 {
@@ -154,6 +160,8 @@ static void fio_syslet_prep(struct io_u *io_u, struct indirect_registers *regs)
 
        if (io_u->ddir == DDIR_SYNC)
                fio_syslet_prep_sync(f, regs);
+       else if (io_u->ddir == DDIR_DATASYNC)
+               fio_syslet_prep_datasync(f, regs);
        else
                fio_syslet_prep_rw(io_u, f, regs);
 }
diff --git a/fio.1 b/fio.1
index 637304e5ffe7c8368a2b611cb8897566a31e4830..fc055e4d8cb2dbd1e4b763ffd316aedcba4d667b 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -365,6 +365,10 @@ Offset in the file to start I/O. Data before the offset will not be touched.
 How many I/Os to perform before issuing an \fBfsync\fR\|(2) of dirty data.  If
 0, don't sync.  Default: 0.
 .TP
+.BI fdatasync \fR=\fPint
+Like \fBfsync\fR, but uses \fBfdatasync\fR\|(2) instead to only sync the
+data parts of the file. Default: 0.
+.TP
 .BI overwrite \fR=\fPbool
 If writing, setup the file first and do overwrites.  Default: false.
 .TP
diff --git a/fio.h b/fio.h
index 7c059d10ff65c34b2371f3f4fd0e5f634e8d2b75..71ae71db2c876749e1445996a8a980d8aafe0253 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -192,6 +192,7 @@ struct thread_options {
        unsigned int thinktime_spin;
        unsigned int thinktime_blocks;
        unsigned int fsync_blocks;
+       unsigned int fdatasync_blocks;
        unsigned int start_delay;
        unsigned long long timeout;
        unsigned long long ramp_time;
index d2ee40ceefa5db7aaf93f10bacd6c0c29e6dc7ad..620a9ee32d51ec8f18d94c565da7b962f015adfe 100644 (file)
--- a/io_ddir.h
+++ b/io_ddir.h
@@ -5,6 +5,7 @@ enum fio_ddir {
        DDIR_READ = 0,
        DDIR_WRITE,
        DDIR_SYNC,
+       DDIR_DATASYNC,
        DDIR_INVAL = -1,
 };
 
@@ -24,4 +25,9 @@ enum td_ddir {
 #define td_random(td)          ((td)->o.td_ddir & TD_DDIR_RAND)
 #define file_randommap(td, f)  (!(td)->o.norandommap && (f)->file_map)
 
+static inline int ddir_sync(enum fio_ddir ddir)
+{
+       return ddir == DDIR_SYNC || ddir == DDIR_DATASYNC;
+}
+
 #endif
diff --git a/io_u.c b/io_u.c
index 276f3b0cd2ddf41c3a007e7a4e3aa74255a2a42a..41b5cdbb04894192cb06e2d86a49bdf28d48be9d 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -363,6 +363,22 @@ static enum fio_ddir get_rw_ddir(struct thread_data *td)
 {
        enum fio_ddir ddir;
 
+       /*
+        * see if it's time to fsync
+        */
+       if (td->o.fsync_blocks &&
+          !(td->io_issues[DDIR_WRITE] % td->o.fsync_blocks) &&
+            td->io_issues[DDIR_WRITE] && should_fsync(td))
+               return DDIR_SYNC;
+
+       /*
+        * see if it's time to fdatasync
+        */
+       if (td->o.fdatasync_blocks &&
+          !(td->io_issues[DDIR_WRITE] % td->o.fdatasync_blocks) &&
+            td->io_issues[DDIR_WRITE] && should_fsync(td))
+               return DDIR_DATASYNC;
+
        if (td_rw(td)) {
                /*
                 * Check if it's time to seed a new data direction.
@@ -425,7 +441,7 @@ void requeue_io_u(struct thread_data *td, struct io_u **io_u)
        dprint(FD_IO, "requeue %p\n", __io_u);
 
        __io_u->flags |= IO_U_F_FREE;
-       if ((__io_u->flags & IO_U_F_FLIGHT) && (__io_u->ddir != DDIR_SYNC))
+       if ((__io_u->flags & IO_U_F_FLIGHT) && !ddir_sync(__io_u->ddir))
                td->io_issues[__io_u->ddir]--;
 
        __io_u->flags &= ~IO_U_F_FLIGHT;
@@ -441,17 +457,13 @@ static int fill_io_u(struct thread_data *td, struct io_u *io_u)
        if (td->io_ops->flags & FIO_NOIO)
                goto out;
 
+       io_u->ddir = get_rw_ddir(td);
+
        /*
-        * see if it's time to sync
+        * fsync() or fdatasync(), we are done
         */
-       if (td->o.fsync_blocks &&
-          !(td->io_issues[DDIR_WRITE] % td->o.fsync_blocks) &&
-            td->io_issues[DDIR_WRITE] && should_fsync(td)) {
-               io_u->ddir = DDIR_SYNC;
+       if (ddir_sync(io_u->ddir))
                goto out;
-       }
-
-       io_u->ddir = get_rw_ddir(td);
 
        /*
         * See if it's time to switch to a new zone
@@ -878,7 +890,7 @@ struct io_u *get_io_u(struct thread_data *td)
        f = io_u->file;
        assert(fio_file_open(f));
 
-       if (io_u->ddir != DDIR_SYNC) {
+       if (!ddir_sync(io_u->ddir)) {
                if (!io_u->buflen && !(td->io_ops->flags & FIO_NOIO)) {
                        dprint(FD_IO, "get_io_u: zero buflen on %p\n", io_u);
                        goto err_put;
@@ -942,7 +954,7 @@ static void io_completed(struct thread_data *td, struct io_u *io_u,
        assert(io_u->flags & IO_U_F_FLIGHT);
        io_u->flags &= ~IO_U_F_FLIGHT;
 
-       if (io_u->ddir == DDIR_SYNC) {
+       if (ddir_sync(io_u->ddir)) {
                td->last_was_sync = 1;
                return;
        }
index c143b3387d8213de770ca6a8bd609089cbf1a700..4c97d038630e05c8767907fbd09db1ac862f21f4 100644 (file)
@@ -238,7 +238,7 @@ int td_io_queue(struct thread_data *td, struct io_u *io_u)
                                        sizeof(struct timeval));
        }
 
-       if (io_u->ddir != DDIR_SYNC)
+       if (!ddir_sync(io_u->ddir))
                td->io_issues[io_u->ddir]++;
 
        ret = td->io_ops->queue(td, io_u);
@@ -251,14 +251,14 @@ int td_io_queue(struct thread_data *td, struct io_u *io_u)
        }
 
        if (ret == FIO_Q_COMPLETED) {
-               if (io_u->ddir != DDIR_SYNC) {
+               if (!ddir_sync(io_u->ddir)) {
                        io_u_mark_depth(td, 1);
                        td->ts.total_io_u[io_u->ddir]++;
                }
        } else if (ret == FIO_Q_QUEUED) {
                int r;
 
-               if (io_u->ddir != DDIR_SYNC) {
+               if (!ddir_sync(io_u->ddir)) {
                        td->io_u_queued++;
                        td->ts.total_io_u[io_u->ddir]++;
                }
diff --git a/log.c b/log.c
index 5014b484e252c6d7f1055f3a7cad462db735c9c4..c44d8221ee936c4c0d235c87efa0f7607eca8dc7 100644 (file)
--- a/log.c
+++ b/log.c
@@ -20,7 +20,7 @@ void queue_io_piece(struct thread_data *td, struct io_piece *ipo)
 
 void log_io_u(struct thread_data *td, struct io_u *io_u)
 {
-       const char *act[] = { "read", "write", "sync" };
+       const char *act[] = { "read", "write", "sync", "datasync" };
 
        assert(io_u->ddir < 3);
 
@@ -273,6 +273,8 @@ static int read_iolog2(struct thread_data *td, FILE *f)
                                rw = DDIR_WRITE;
                        else if (!strcmp(act, "sync"))
                                rw = DDIR_SYNC;
+                       else if (!strcmp(act, "datasync"))
+                               rw = DDIR_DATASYNC;
                        else {
                                log_err("fio: bad iolog file action: %s\n",
                                                                        act);
@@ -310,7 +312,7 @@ static int read_iolog2(struct thread_data *td, FILE *f)
                        if (read_only)
                                continue;
                        writes++;
-               } else if (rw != DDIR_SYNC && rw != DDIR_INVAL) {
+               } else if (!ddir_sync(rw)) {
                        log_err("bad ddir: %d\n", rw);
                        continue;
                }
index 9606ab20e5a3fcb06e548347b3922502718b6f91..394472a4dadf61512e6c49f8495f97f248b357f5 100644 (file)
--- a/options.c
+++ b/options.c
@@ -931,6 +931,13 @@ static struct fio_option options[] = {
                .help   = "Issue fsync for writes every given number of blocks",
                .def    = "0",
        },
+       {
+               .name   = "fdatasync",
+               .type   = FIO_OPT_INT,
+               .off1   = td_var_offset(fdatasync_blocks),
+               .help   = "Issue fdatasync for writes every given number of blocks",
+               .def    = "0",
+       },
        {
                .name   = "direct",
                .type   = FIO_OPT_BOOL,