| /* |
| * glusterfs engine |
| * |
| * common Glusterfs's gfapi interface |
| * |
| */ |
| |
| #include "gfapi.h" |
| |
| 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 = "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, |
| }, |
| }; |
| |
| 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; |
| |
| g = malloc(sizeof(struct gf_data)); |
| if (!g) { |
| log_err("malloc failed.\n"); |
| return -ENOMEM; |
| } |
| 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, 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. 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; |
| } |
| dprint(FD_FILE, "fio setup %p\n", g->fs); |
| td->io_ops->data = g; |
| cleanup: |
| if (r) { |
| if (g) { |
| if (g->fs) { |
| glfs_fini(g->fs); |
| } |
| free(g); |
| td->io_ops->data = NULL; |
| } |
| } |
| return r; |
| } |
| |
| void fio_gf_cleanup(struct thread_data *td) |
| { |
| struct gf_data *g = td->io_ops->data; |
| |
| 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; |
| } |
| } |
| |
| int fio_gf_get_file_size(struct thread_data *td, struct fio_file *f) |
| { |
| struct stat buf; |
| int ret; |
| struct gf_data *g = td->io_ops->data; |
| |
| dprint(FD_FILE, "get file size %s\n", f->file_name); |
| |
| if (!g || !g->fs) { |
| return 0; |
| } |
| if (fio_file_size_known(f)) |
| return 0; |
| |
| ret = glfs_lstat(g->fs, f->file_name, &buf); |
| if (ret < 0) { |
| log_err("glfs_lstat failed.\n"); |
| return ret; |
| } |
| |
| f->real_file_size = buf.st_size; |
| fio_file_set_size_known(f); |
| |
| return 0; |
| |
| } |
| |
| int fio_gf_open_file(struct thread_data *td, struct fio_file *f) |
| { |
| |
| 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; |
| } else if (td_read(td)) { |
| if (!read_only) |
| flags = O_RDWR; |
| else |
| flags = O_RDONLY; |
| } |
| 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; |
| f->shadow_fd = -1; |
| |
| return ret; |
| } |
| |
| 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) { |
| if (g->fd && glfs_close(g->fd) < 0) |
| ret = errno; |
| |
| if (g->fs) |
| glfs_fini(g->fs); |
| |
| g->fd = NULL; |
| free(g); |
| } |
| td->io_ops->data = NULL; |
| f->engine_data = 0; |
| |
| return ret; |
| } |