Merge branch 'master' of git://github.com/cvubrugier/fio
[fio.git] / engines / glusterfs.c
index 6aed265a36ddc344f5172f40263fe3b6abde314f..230274af430001cba57aa0dda0d8f35130b9d3fe 100644 (file)
@@ -1,53 +1,44 @@
 /*
  * glusterfs engine
  *
- * IO engine using Glusterfs's gfapi interface
+ * common Glusterfs's gfapi interface
  *
  */
 
-#include <glusterfs/api/glfs.h>
+#include "gfapi.h"
 
-#include "../fio.h"
-
-struct gf_options {
-    struct thread_data *td;
-    char *gf_vol;
-    char *gf_brick;
-};
-
-struct gf_data {
-    glfs_t *fs;
-    glfs_fd_t *fd;
-};
-static struct fio_option options[] = {
+struct fio_option gfapi_options[] = {
     {
-       .name     = "volume",
-       .lname    = "Glusterfs volume",
-       .type     = FIO_OPT_STR_STORE,
-       .help     = "Name of the Glusterfs volume",
-       .off1     = offsetof(struct gf_options, gf_vol),
-       .category = FIO_OPT_C_ENGINE,
-       .group    = FIO_OPT_G_GFAPI,
+        .name     = "volume",
+        .lname    = "Glusterfs volume",
+        .type     = FIO_OPT_STR_STORE,
+        .help     = "Name of the Glusterfs volume",
+        .off1     = offsetof(struct gf_options, gf_vol),
+        .category = FIO_OPT_C_ENGINE,
+        .group    = FIO_OPT_G_GFAPI,
     },
     {
-       .name     = "brick",
-       .lname    = "Glusterfs brick name",
-       .type     = FIO_OPT_STR_STORE,
-       .help     = "Name of the Glusterfs brick to connect",
-       .off1     = offsetof(struct gf_options, gf_brick),
-       .category = FIO_OPT_C_ENGINE,
-       .group    = FIO_OPT_G_GFAPI,
+        .name     = "brick",
+        .lname    = "Glusterfs brick name",
+        .type     = FIO_OPT_STR_STORE,
+        .help     = "Name of the Glusterfs brick to connect",
+        .off1     = offsetof(struct gf_options, gf_brick),
+        .category = FIO_OPT_C_ENGINE,
+        .group    = FIO_OPT_G_GFAPI,
     },
     {
-       .name = NULL,
+        .name = NULL,
     },
 };
 
-static int fio_gf_setup(struct thread_data *td)
+int fio_gf_setup(struct thread_data *td)
 {
        int r = 0;
        struct gf_data *g = NULL;
        struct gf_options *opt = td->eo;
+    struct stat sb = {0, };
+
+       dprint(FD_IO, "fio setup\n");
 
        if (td->io_ops->data)
            return 0;
@@ -57,51 +48,63 @@ static int fio_gf_setup(struct thread_data *td)
            log_err("malloc failed.\n");
            return -ENOMEM;
        }
-       g->fs = NULL; g->fd = NULL;
+       g->fs = NULL; g->fd = NULL; g->aio_events = NULL;
 
        g->fs = glfs_new (opt->gf_vol);
        if (!g->fs){
            log_err("glfs_new failed.\n");
            goto cleanup;
        }
-
+       glfs_set_logging (g->fs, "/tmp/fio_gfapi.log", 7);
        /* default to tcp */
-       r = glfs_set_volfile_server(g->fs, "tcp", opt->gf_brick, 24007);
+       r = glfs_set_volfile_server(g->fs, "tcp", opt->gf_brick, 0);
        if (r){
            log_err("glfs_set_volfile_server failed.\n");
            goto cleanup;
        }
        r = glfs_init(g->fs);
        if (r){
-           log_err("glfs_init failed.\n");
+           log_err("glfs_init failed. Is glusterd running on brick?\n");
+           goto cleanup;
+       }
+       sleep(2);
+       r = glfs_lstat (g->fs, ".", &sb);
+       if (r){
+           log_err("glfs_lstat failed.\n");
            goto cleanup;
        }
-       glfs_set_logging (g->fs, "/dev/stderr", 7);
-       
+       dprint(FD_FILE, "fio setup %p\n", g->fs);
        td->io_ops->data = g;
 cleanup:
-       if (g){
-           if (g->fs){
-               glfs_fini(g->fs);
+       if (r){
+           if (g){
+            if (g->fs){
+                glfs_fini(g->fs);
+            }
+            free(g);
+            td->io_ops->data = NULL;
            }
-           free(g);
        }
        return r;
 }
 
-static void fio_gf_cleanup(struct thread_data *td)
+void fio_gf_cleanup(struct thread_data *td)
 {
        struct gf_data *g = td->io_ops->data;
 
-       if (g){
-           if (g->fs){
-               glfs_fini(g->fs);
-           }
-           free(g);
+       if (g) {
+        if (g->aio_events)
+            free(g->aio_events);
+        if (g->fd)
+            glfs_close(g->fd);
+        if (g->fs)
+            glfs_fini(g->fs);
+        free(g);
+        td->io_ops->data = NULL;
        }
 }
 
-static int fio_gf_get_file_size(struct thread_data *td, struct fio_file *f)
+int fio_gf_get_file_size(struct thread_data *td, struct fio_file *f)
 {
     struct stat buf;
     int ret;
@@ -111,15 +114,16 @@ static int fio_gf_get_file_size(struct thread_data *td, struct fio_file *f)
 
     if (!g || !g->fs)
     {
-       return 0;
+        return 0;
     }
-
     if (fio_file_size_known(f))
-       return 0;
+        return 0;
 
     ret = glfs_lstat (g->fs, f->file_name, &buf);
-    if (ret < 0)
-       return ret;
+    if (ret < 0){
+        log_err("glfs_lstat failed.\n");
+        return ret;
+    }
 
     f->real_file_size = buf.st_size;
     fio_file_set_size_known(f);
@@ -128,121 +132,137 @@ static int fio_gf_get_file_size(struct thread_data *td, struct fio_file *f)
 
 }
 
-static int fio_gf_open_file(struct thread_data *td, struct fio_file *f)
+int fio_gf_open_file(struct thread_data *td, struct fio_file *f)
 {
-    struct gf_data *g = td->io_ops->data;
-    int flags = 0;
 
-    dprint(FD_FILE, "fd open %s\n", f->file_name);
+    int flags = 0;
+    int ret = 0;
+    struct gf_data *g = td->io_ops->data;
+    struct stat sb = {0, };
 
     if (td_write(td)) {
-       if (!read_only)
-           flags = O_RDWR;
+        if (!read_only)
+            flags = O_RDWR;
     } else if (td_read(td)) {
-       if (!read_only)
-           flags = O_RDWR;
-       else
-           flags = O_RDONLY;
+        if (!read_only)
+            flags = O_RDWR;
+        else
+            flags = O_RDONLY;
     }
-    if (td->o.create_on_open)
-       flags |= O_CREAT;
-
-    g->fd = glfs_open(g->fs, f->file_name, flags);
+    dprint(FD_FILE, "fio file %s open mode %s td rw %s\n", f->file_name,
+           flags == O_RDONLY? "ro":"rw", td_read(td)? "read":"write");
+    g->fd = glfs_creat(g->fs, f->file_name, flags, 0644);    
+    if (!g->fd){
+        log_err("glfs_creat failed.\n");
+        ret = errno;
+    }
+    /* file for read doesn't exist or shorter than required, create/extend it */
+    if (td_read(td)){
+        if (glfs_lstat (g->fs, f->file_name, &sb) || sb.st_size < f->real_file_size){
+            dprint(FD_FILE, "fio extend file %s from %ld to %ld\n", f->file_name, sb.st_size, f->real_file_size);
+            ret = glfs_ftruncate (g->fd, f->real_file_size);
+            if (ret){
+                log_err("failed fio extend file %s to %ld\n", f->file_name, f->real_file_size);
+            }else{
+                unsigned long long left;
+                unsigned int bs;
+                char *b;
+                int r;
+
+                /* fill the file, copied from extend_file */
+                b = malloc(td->o.max_bs[DDIR_WRITE]);
+
+                left = f->real_file_size;
+                while (left && !td->terminate) {
+                    bs = td->o.max_bs[DDIR_WRITE];
+                    if (bs > left)
+                        bs = left;
+
+                    fill_io_buffer(td, b, bs, bs);
+
+                    r = glfs_write(g->fd, b, bs, 0);
+                    dprint(FD_IO, "fio write %d of %ld file %s\n", r, f->real_file_size, f->file_name);
+
+                    if (r > 0) {
+                        left -= r;
+                        continue;
+                    } else {
+                        if (r < 0) {
+                            int __e = errno;
+
+                            if (__e == ENOSPC) {
+                                if (td->o.fill_device)
+                                    break;
+                                log_info("fio: ENOSPC on laying out "
+                                         "file, stopping\n");
+                                break;
+                            }
+                            td_verror(td, errno, "write");
+                        } else
+                            td_verror(td, EIO, "write");
+
+                        break;
+                    }
+                }
+
+                if (b) free(b);
+                glfs_lseek(g->fd, 0, SEEK_SET);
+
+                if (td->terminate) {
+                    dprint(FD_FILE, "terminate unlink %s\n", f->file_name);
+                    unlink(f->file_name);
+                } else if (td->o.create_fsync) {
+                    if (glfs_fsync(g->fd) < 0) {
+                        dprint(FD_FILE, "failed to sync, close %s\n", f->file_name);
+                        td_verror(td, errno, "fsync");
+                        glfs_close(g->fd);
+                        g->fd = NULL;
+                        return 1;
+                    }
+                }
+            }
+        }
+    }
+#if defined(GFAPI_USE_FADVISE)
+    {
+        int r = 0; 
+        if (td_random(td)){
+            r = glfs_fadvise(g->fd, 0, f->real_file_size, POSIX_FADV_RANDOM);
+        }else{
+            r = glfs_fadvise(g->fd, 0, f->real_file_size, POSIX_FADV_SEQUENTIAL);
+        }
+        if (r){
+            dprint(FD_FILE, "fio %p fadvise %s status %d\n", g->fs, f->file_name, r);
+        }
+    }
+#endif
+    dprint(FD_FILE, "fio %p created %s\n", g->fs, f->file_name);
     f->fd = -1;
-    return 0;
+    f->shadow_fd = -1;    
+
+    return ret;
 }
 
-static int fio_gf_close_file(struct thread_data *td, struct fio_file *f)
+int fio_gf_close_file(struct thread_data *td, struct fio_file *f)
 {
        int ret = 0;
        struct gf_data *g = td->io_ops->data;
 
        dprint(FD_FILE, "fd close %s\n", f->file_name);
 
-       if (!g->fd && glfs_close(g->fd) < 0)
-               ret = errno;
-
-       g->fd = NULL;
-       f->engine_data = 0;
-
-       return ret;
-}
-
-#define LAST_POS(f)    ((f)->engine_data)
-static int fio_gf_prep(struct thread_data *td, struct io_u *io_u)
-{
-       struct fio_file *f = io_u->file;
-       struct gf_data *g = td->io_ops->data;
-
-       if (!ddir_rw(io_u->ddir))
-               return 0;
-
-       if (LAST_POS(f) != -1ULL && LAST_POS(f) == io_u->offset)
-               return 0;
-
-       if (glfs_lseek(g->fd, io_u->offset, SEEK_SET) < 0) {
-               td_verror(td, errno, "lseek");
-               return 1;
-       }
-
-       return 0;
-}
-
-static int fio_gf_queue(struct thread_data *td, struct io_u *io_u)
-{
-    struct gf_data *g = td->io_ops->data;
-    int ret = 0;
+    if (g){
+        if (g->fd && glfs_close(g->fd) < 0)
+            ret = errno;
 
-    fio_ro_check(td, io_u);
+        if (g->fs)
+            glfs_fini(g->fs);
 
-    if (io_u->ddir == DDIR_READ)
-       ret = glfs_read(g->fd, io_u->xfer_buf, io_u->xfer_buflen, 0);
-    else if (io_u->ddir == DDIR_WRITE)
-       ret = glfs_write(g->fd, io_u->xfer_buf, io_u->xfer_buflen, 0);
-    else {         
-       log_err("unsupported operation.\n");
-       return -EINVAL;
+        g->fd = NULL;
+        free(g);
     }
-    if (io_u->file && ret >= 0 && ddir_rw(io_u->ddir))
-       LAST_POS(io_u->file) = io_u->offset + ret;
-
-    if (ret != (int) io_u->xfer_buflen) {
-       if (ret >= 0) {
-           io_u->resid = io_u->xfer_buflen - ret;
-           io_u->error = 0;
-           return FIO_Q_COMPLETED;
-       } else
-           io_u->error = errno;
-    }
-
-    if (io_u->error)
-       td_verror(td, io_u->error, "xfer");
-
-    return FIO_Q_COMPLETED;
-
-}
-
-static struct ioengine_ops ioengine = {
-       .name               = "gfapi",
-       .version            = FIO_IOOPS_VERSION,
-       .setup              = fio_gf_setup,
-       .cleanup            = fio_gf_cleanup,
-       .prep               = fio_gf_prep,
-       .queue              = fio_gf_queue,
-       .open_file          = fio_gf_open_file,
-       .close_file         = fio_gf_close_file,
-       .get_file_size      = fio_gf_get_file_size,
-       .options            = options,
-       .option_struct_size = sizeof(struct gf_options),
-       .flags              = FIO_SYNCIO,
-};
+       td->io_ops->data = NULL;
+       f->engine_data = 0;
 
-static void fio_init fio_gf_register(void)
-{
-    register_ioengine(&ioengine);
+       return ret;
 }
 
-static void fio_exit fio_gf_unregister(void)
-{
-    unregister_ioengine(&ioengine);
-}