Initial suppor for sync_file_range()
authorJens Axboe <jens.axboe@oracle.com>
Tue, 9 Mar 2010 19:09:44 +0000 (20:09 +0100)
committerJens Axboe <jens.axboe@oracle.com>
Tue, 9 Mar 2010 19:09:44 +0000 (20:09 +0100)
This revs the ioengine to 11, as we now have another data direction.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
engines/sync.c
file.h
fio.h
io_ddir.h
io_u.c
ioengine.h
ioengines.c
log.c
options.c
os/os-linux.h

index 12b85f6a65917c8e2fc197bd35c844bd61684b28..a673ae9e77cf1a4b94228917d5cc94ba33478826 100644 (file)
@@ -64,6 +64,29 @@ static int fio_io_end(struct thread_data *td, struct io_u *io_u, int ret)
        return FIO_Q_COMPLETED;
 }
 
        return FIO_Q_COMPLETED;
 }
 
+static int fio_syncio_sync(struct thread_data *td, struct io_u *io_u)
+{
+       int ret;
+
+       if (io_u->ddir == DDIR_SYNC) {
+               ret = fsync(io_u->file->fd);
+       } else if (io_u->ddir == DDIR_DATASYNC) {
+#ifdef FIO_HAVE_FDATASYNC
+               ret = fdatasync(io_u->file->fd);
+#else
+               ret = io_u->xfer_buflen;
+               io_u->error = EINVAL;
+#endif
+       } else if (io_u->ddir == DDIR_SYNC_FILE_RANGE)
+               ret = do_sync_file_range(td, io_u->file);
+       else {
+               ret = io_u->xfer_buflen;
+               io_u->error = EINVAL;
+       }
+
+       return fio_io_end(td, io_u, ret);
+}
+
 static int fio_psyncio_queue(struct thread_data *td, struct io_u *io_u)
 {
        struct fio_file *f = io_u->file;
 static int fio_psyncio_queue(struct thread_data *td, struct io_u *io_u)
 {
        struct fio_file *f = io_u->file;
@@ -76,7 +99,7 @@ static int fio_psyncio_queue(struct thread_data *td, struct io_u *io_u)
        else if (io_u->ddir == DDIR_WRITE)
                ret = pwrite(f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
        else
        else if (io_u->ddir == DDIR_WRITE)
                ret = pwrite(f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
        else
-               ret = fsync(f->fd);
+               return fio_syncio_sync(td, io_u);
 
        return fio_io_end(td, io_u, ret);
 }
 
        return fio_io_end(td, io_u, ret);
 }
@@ -93,7 +116,7 @@ static int fio_syncio_queue(struct thread_data *td, struct io_u *io_u)
        else if (io_u->ddir == DDIR_WRITE)
                ret = write(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
        else
        else if (io_u->ddir == DDIR_WRITE)
                ret = write(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
        else
-               ret = fsync(f->fd);
+               return fio_syncio_sync(td, io_u);
 
        return fio_io_end(td, io_u, ret);
 }
 
        return fio_io_end(td, io_u, ret);
 }
@@ -163,22 +186,9 @@ static int fio_vsyncio_queue(struct thread_data *td, struct io_u *io_u)
                 */
                if (sd->queued)
                        return FIO_Q_BUSY;
                 */
                if (sd->queued)
                        return FIO_Q_BUSY;
-               if (io_u->ddir == DDIR_SYNC) {
-                       int ret = fsync(io_u->file->fd);
+               if (ddir_sync(io_u->ddir))
+                       return fio_syncio_sync(td, io_u);
 
 
-                       return fio_io_end(td, io_u, ret);
-               } else if (io_u->ddir == DDIR_DATASYNC) {
-                       int ret;
-#ifdef FIO_HAVE_FDATASYNC
-                       ret = fdatasync(io_u->file->fd);
-#else
-                       ret = io_u->xfer_buflen;
-                       io_u->error = EINVAL;
-#endif
-                       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);
diff --git a/file.h b/file.h
index 2abe3ba4db9c3a3b04312aa6c9f6d4514547e4c0..30293fc9ddc34e4515a56cc8f5ab0091eb254030 100644 (file)
--- a/file.h
+++ b/file.h
@@ -74,6 +74,9 @@ struct fio_file {
 
        unsigned long long last_pos;
 
 
        unsigned long long last_pos;
 
+       unsigned long long first_write;
+       unsigned long long last_write;
+
        /*
         * For use by the io engine
         */
        /*
         * For use by the io engine
         */
diff --git a/fio.h b/fio.h
index f00f64a9dc4297217e870eae87b27b5980151719..05911c00d1934f6368b5d7e28942a9deaae278a4 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -282,6 +282,8 @@ struct thread_options {
 
        unsigned int uid;
        unsigned int gid;
 
        unsigned int uid;
        unsigned int gid;
+
+       unsigned int sync_file_range;
 };
 
 #define FIO_VERROR_SIZE        128
 };
 
 #define FIO_VERROR_SIZE        128
@@ -417,6 +419,8 @@ struct thread_data {
        unsigned int file_service_left;
        struct fio_file *file_service_file;
 
        unsigned int file_service_left;
        struct fio_file *file_service_file;
 
+       unsigned int sync_file_range_nr;
+
        /*
         * For generating file sizes
         */
        /*
         * For generating file sizes
         */
index 03eefdb87c0db8931a82b8e7cd628fec4f957742..87cded4642b5ea367d0146c8f19d2e70aa29c0c6 100644 (file)
--- a/io_ddir.h
+++ b/io_ddir.h
@@ -6,6 +6,7 @@ enum fio_ddir {
        DDIR_WRITE,
        DDIR_SYNC,
        DDIR_DATASYNC,
        DDIR_WRITE,
        DDIR_SYNC,
        DDIR_DATASYNC,
+       DDIR_SYNC_FILE_RANGE,
        DDIR_WAIT,
        DDIR_INVAL = -1,
 };
        DDIR_WAIT,
        DDIR_INVAL = -1,
 };
@@ -28,7 +29,8 @@ enum td_ddir {
 
 static inline int ddir_sync(enum fio_ddir ddir)
 {
 
 static inline int ddir_sync(enum fio_ddir ddir)
 {
-       return ddir == DDIR_SYNC || ddir == DDIR_DATASYNC;
+       return ddir == DDIR_SYNC || ddir == DDIR_DATASYNC ||
+              ddir == DDIR_SYNC_FILE_RANGE;
 }
 
 #endif
 }
 
 #endif
diff --git a/io_u.c b/io_u.c
index 9b9570eaee1fa925e3f9494c5615210a42b92b7e..a4bf0c08581861076ccd31a8f720dcd861fbfe01 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -394,6 +394,14 @@ static enum fio_ddir get_rw_ddir(struct thread_data *td)
             td->io_issues[DDIR_WRITE] && should_fsync(td))
                return DDIR_DATASYNC;
 
             td->io_issues[DDIR_WRITE] && should_fsync(td))
                return DDIR_DATASYNC;
 
+       /*
+        * see if it's time to sync_file_range
+        */
+       if (td->sync_file_range_nr &&
+          !(td->io_issues[DDIR_WRITE] % td->sync_file_range_nr) &&
+            td->io_issues[DDIR_WRITE] && should_fsync(td))
+               return DDIR_SYNC_FILE_RANGE;
+
        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.
@@ -996,6 +1004,7 @@ static void io_completed(struct thread_data *td, struct io_u *io_u,
         * initialized, silence that warning.
         */
        unsigned long uninitialized_var(usec);
         * initialized, silence that warning.
         */
        unsigned long uninitialized_var(usec);
+       struct fio_file *f;
 
        dprint_io_u(io_u, "io complete");
 
 
        dprint_io_u(io_u, "io complete");
 
@@ -1006,6 +1015,11 @@ static void io_completed(struct thread_data *td, struct io_u *io_u,
 
        if (ddir_sync(io_u->ddir)) {
                td->last_was_sync = 1;
 
        if (ddir_sync(io_u->ddir)) {
                td->last_was_sync = 1;
+               f = io_u->file;
+               if (f) {
+                       f->first_write = -1ULL;
+                       f->last_write = -1ULL;
+               }
                return;
        }
 
                return;
        }
 
@@ -1021,6 +1035,18 @@ static void io_completed(struct thread_data *td, struct io_u *io_u,
                td->io_bytes[idx] += bytes;
                td->this_io_bytes[idx] += bytes;
 
                td->io_bytes[idx] += bytes;
                td->this_io_bytes[idx] += bytes;
 
+               if (idx == DDIR_WRITE) {
+                       f = io_u->file;
+                       if (f) {
+                               if (f->first_write == -1ULL ||
+                                   io_u->offset < f->first_write)
+                                       f->first_write = io_u->offset;
+                               if (f->last_write == -1ULL ||
+                                   ((io_u->offset + bytes) > f->last_write))
+                                       f->last_write = io_u->offset + bytes;
+                       }
+               }
+
                if (ramp_time_over(td)) {
                        unsigned long uninitialized_var(lusec);
 
                if (ramp_time_over(td)) {
                        unsigned long uninitialized_var(lusec);
 
index eb6655d165cad381e747a332cfee5b93736e7fd8..5acfbd205d18198f4301cdf35af8cf453fa7f042 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef FIO_IOENGINE_H
 #define FIO_IOENGINE_H
 
 #ifndef FIO_IOENGINE_H
 #define FIO_IOENGINE_H
 
-#define FIO_IOOPS_VERSION      10
+#define FIO_IOOPS_VERSION      11
 
 enum {
        IO_U_F_FREE             = 1 << 0,
 
 enum {
        IO_U_F_FREE             = 1 << 0,
@@ -153,6 +153,8 @@ extern void io_u_fill_buffer(struct thread_data *td, struct io_u *, unsigned int
 void io_u_mark_complete(struct thread_data *, unsigned int);
 void io_u_mark_submit(struct thread_data *, unsigned int);
 
 void io_u_mark_complete(struct thread_data *, unsigned int);
 void io_u_mark_submit(struct thread_data *, unsigned int);
 
+int do_sync_file_range(struct thread_data *, struct fio_file *);
+
 #ifdef FIO_INC_DEBUG
 static inline void dprint_io_u(struct io_u *io_u, const char *p)
 {
 #ifdef FIO_INC_DEBUG
 static inline void dprint_io_u(struct io_u *io_u, const char *p)
 {
index 7f0a5c4520bab954d1e8eaa4df04ee115f8290e1..0e8953404f7e4339572f44aad104f58b2c1a052e 100644 (file)
@@ -431,3 +431,16 @@ int td_io_get_file_size(struct thread_data *td, struct fio_file *f)
 
        return td->io_ops->get_file_size(td, f);
 }
 
        return td->io_ops->get_file_size(td, f);
 }
+
+int do_sync_file_range(struct thread_data *td, struct fio_file *f)
+{
+       off64_t offset, nbytes;
+
+       offset = f->first_write;
+       nbytes = f->last_write - f->first_write;
+
+       if (nbytes)
+               return sync_file_range(f->fd, offset, nbytes, 0);
+
+       return 0;
+}
diff --git a/log.c b/log.c
index ba52f0768744df5ea19cec1c2758a399e0cc8db9..99f20b53083b29ae4399827ff677b89e1d16781f 100644 (file)
--- a/log.c
+++ b/log.c
@@ -20,9 +20,10 @@ 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", "datasync" };
+       const char *act[] = { "read", "write", "sync", "datasync",
+                               "sync_file_range" };
 
 
-       assert(io_u->ddir < 3);
+       assert(io_u->ddir <= 4);
 
        if (!td->o.write_iolog_file)
                return;
 
        if (!td->o.write_iolog_file)
                return;
index e2daf37df09c26be2663a36a0b2f3aa031477ba8..bee15cf9586af5bf9eeb9171a2606c765356bec4 100644 (file)
--- a/options.c
+++ b/options.c
@@ -429,6 +429,20 @@ static int str_fst_cb(void *data, const char *str)
        return 0;
 }
 
        return 0;
 }
 
+static int str_sfr_cb(void *data, const char *str)
+{
+       struct thread_data *td = data;
+       char *nr = get_opt_postfix(str);
+
+       td->sync_file_range_nr = 1;
+       if (nr) {
+               td->sync_file_range_nr = atoi(nr);
+               free(nr);
+       }
+
+       return 0;
+}
+
 static int check_dir(struct thread_data *td, char *fname)
 {
        char file[PATH_MAX], *dir;
 static int check_dir(struct thread_data *td, char *fname)
 {
        char file[PATH_MAX], *dir;
@@ -1110,6 +1124,30 @@ static struct fio_option options[FIO_MAX_OPTS] = {
                .help   = "Issue fdatasync for writes every given number of blocks",
                .def    = "0",
        },
                .help   = "Issue fdatasync for writes every given number of blocks",
                .def    = "0",
        },
+#ifdef FIO_HAVE_SYNC_FILE_RANGE
+       {
+               .name   = "sync_file_range",
+               .posval = {
+                         { .ival = "wait_before",
+                           .oval = SYNC_FILE_RANGE_WAIT_BEFORE,
+                           .help = "SYNC_FILE_RANGE_WAIT_BEFORE",
+                         },
+                         { .ival = "write",
+                           .oval = SYNC_FILE_RANGE_WRITE,
+                           .help = "SYNC_FILE_RANGE_WRITE",
+                         },
+                         {
+                           .ival = "wait_after",
+                           .oval = SYNC_FILE_RANGE_WAIT_AFTER,
+                           .help = "SYNC_FILE_RANGE_WAIT_AFTER",
+                         },
+               },
+               .type   = FIO_OPT_STR,
+               .cb     = str_sfr_cb,
+               .off1   = td_var_offset(sync_file_range),
+               .help   = "Use sync_file_range()",
+       },
+#endif
        {
                .name   = "direct",
                .type   = FIO_OPT_BOOL,
        {
                .name   = "direct",
                .type   = FIO_OPT_BOOL,
index 01140e0d1ba0009942ec1913125324576c329de6..8c61cc05fda6a73f2e79ca1b830abf3aad00c42f 100644 (file)
@@ -34,6 +34,7 @@
 #define FIO_HAVE_CL_SIZE
 #define FIO_HAVE_CGROUPS
 #define FIO_HAVE_FDATASYNC
 #define FIO_HAVE_CL_SIZE
 #define FIO_HAVE_CGROUPS
 #define FIO_HAVE_FDATASYNC
+#define FIO_HAVE_SYNC_FILE_RANGE
 
 #define OS_MAP_ANON            MAP_ANONYMOUS
 
 
 #define OS_MAP_ANON            MAP_ANONYMOUS