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.
 
                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
 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);
                        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",
                        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);
                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;
                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;
 
                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;
        }
 
                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);
                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");
                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
         */
        /*
         * 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");
                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);
 
 
        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;
 
        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;
        }
 
                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;
 
        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;
 
 {
        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) {
                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;
 
 {
        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 &&
                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);
                        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);
                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);
 }
 
        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)
 {
 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);
 
        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);
 }
        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
 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
 .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 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;
        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_READ = 0,
        DDIR_WRITE,
        DDIR_SYNC,
+       DDIR_DATASYNC,
        DDIR_INVAL = -1,
 };
 
        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)
 
 #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
 #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;
 
 {
        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.
        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;
        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;
                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;
 
        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;
                goto out;
-       }
-
-       io_u->ddir = get_rw_ddir(td);
 
        /*
         * See if it's time to switch to a new zone
 
        /*
         * 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));
 
        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;
                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;
 
        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;
        }
                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));
        }
 
                                        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);
                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 (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;
 
                        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]++;
                }
                        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)
 {
 
 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);
 
 
        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;
                                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);
                        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++;
                        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;
                }
                        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",
        },
                .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,
        {
                .name   = "direct",
                .type   = FIO_OPT_BOOL,