From 29c1349f1840c3f60434c9da602074bc8fde4afe Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sat, 1 Mar 2008 19:25:20 +0100 Subject: [PATCH] Add the file sharing bits When you use the same filename for several jobs now, they will share the same file structure. Enable locking through two new options: - lockfile. If set, a semaphore is associated with the file and it is held from ->prep() to ->queue() has done its work. - lockfile_batch. This controls how many IOs the job gets to do per semaphore acqusition. Signed-off-by: Jens Axboe --- HOWTO | 8 +++++++ filesetup.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++----- fio.h | 10 +++++++++ ioengines.c | 5 +++++ options.c | 16 ++++++++++++++ 5 files changed, 94 insertions(+), 5 deletions(-) diff --git a/HOWTO b/HOWTO index d8c6b941..3e0a31b6 100644 --- a/HOWTO +++ b/HOWTO @@ -219,6 +219,14 @@ filename=str Fio normally makes up a filename based on the job name, opendir=str Tell fio to recursively add any file it can find in this directory and down the file system tree. +lockfile=bool If set, fio will lock a file internally before doing IO to it. + This makes it safe to share file descriptors across fio + jobs that run at the same time. + +lockfile_batch=int Acquiring a semaphore can be quite expensive, so + allow a process to complete this number of IOs before releasing + the semaphore again. Defaults to 1. + readwrite=str rw=str Type of io pattern. Accepted values are: diff --git a/filesetup.c b/filesetup.c index e2c71cd0..4e2a36cd 100644 --- a/filesetup.c +++ b/filesetup.c @@ -228,8 +228,10 @@ int generic_close_file(struct thread_data fio_unused *td, struct fio_file *f) int generic_open_file(struct thread_data *td, struct fio_file *f) { + struct fio_file *__f; int is_std = 0; int flags = 0; + int from_hash = 0; dprint(FD_FILE, "fd open %s\n", f->file_name); @@ -265,8 +267,16 @@ open_again: if (is_std) f->fd = dup(STDOUT_FILENO); - else - f->fd = open(f->file_name, flags, 0600); + else { + __f = lookup_file_hash(f->file_name); + if (__f) { + f->sem = __f->sem; + f->fd = dup(__f->fd); + f->references++; + from_hash = 1; + } else + f->fd = open(f->file_name, flags, 0600); + } } else { if (f->filetype == FIO_TYPE_CHAR && !read_only) flags |= O_RDWR; @@ -275,8 +285,16 @@ open_again: if (is_std) f->fd = dup(STDIN_FILENO); - else - f->fd = open(f->file_name, flags); + else { + __f = lookup_file_hash(f->file_name); + if (__f) { + f->sem = __f->sem; + f->fd = dup(__f->fd); + f->references++; + from_hash = 1; + } else + f->fd = open(f->file_name, flags); + } } if (f->fd == -1) { @@ -296,7 +314,17 @@ open_again: if (get_file_size(td, f)) goto err; - add_file_hash(f); + if (!from_hash && f->fd != -1) { + if (add_file_hash(f)) { + int ret; + + /* + * OK to ignore, we haven't done anything with it + */ + ret = generic_close_file(td, f); + goto open_again; + } + } return 0; err: @@ -613,6 +641,9 @@ int add_file(struct thread_data *td, const char *fname) get_file_type(f); + if (td->o.lockfile) + f->sem = fio_sem_init(1); + td->files_index++; if (f->filetype == FIO_TYPE_FILE) td->nr_normal_files++; @@ -653,10 +684,29 @@ int put_file(struct thread_data *td, struct fio_file *f) void lock_file(struct thread_data *td, struct fio_file *f) { + if (f && f->sem) { + if (f->sem_owner == td && f->sem_batch--) + return; + + fio_sem_down(f->sem); + f->sem_owner = td; + f->sem_batch = td->o.lockfile_batch; + } } void unlock_file(struct fio_file *f) { + if (f && f->sem) { + int sem_val; + + if (f->sem_batch) + return; + + sem_getvalue(&f->sem->sem, &sem_val); + if (!sem_val) + f->sem_owner = NULL; + fio_sem_up(f->sem); + } } static int recurse_dir(struct thread_data *td, const char *dirname) diff --git a/fio.h b/fio.h index fe1a227d..ffd3d7d0 100644 --- a/fio.h +++ b/fio.h @@ -22,6 +22,7 @@ #include "arch/arch.h" #include "os/os.h" #include "mutex.h" +#include "sem.h" #include "log.h" #include "debug.h" @@ -309,6 +310,13 @@ struct fio_file { unsigned long long last_pos; + /* + * if io is protected by a semaphore, this is set + */ + struct fio_sem *sem; + void *sem_owner; + unsigned int sem_batch; + /* * block map for random io */ @@ -407,6 +415,8 @@ struct thread_options { unsigned int nr_files; unsigned int open_files; + unsigned int lockfile; + unsigned int lockfile_batch; unsigned int odirect; unsigned int invalidate_cache; diff --git a/ioengines.c b/ioengines.c index 5a2d6b90..bd2eb4a7 100644 --- a/ioengines.c +++ b/ioengines.c @@ -359,5 +359,10 @@ int td_io_close_file(struct thread_data *td, struct fio_file *f) */ f->flags |= FIO_FILE_CLOSING; + if (f->sem_owner == td && f->sem_batch) { + f->sem_batch = 0; + unlock_file(f); + } + return put_file(td, f); } diff --git a/options.c b/options.c index 1119a980..27b4fb65 100644 --- a/options.c +++ b/options.c @@ -384,6 +384,22 @@ static struct fio_option options[] = { .cb = str_filename_cb, .help = "File(s) to use for the workload", }, + { + .name = "lockfile", + .type = FIO_OPT_BOOL, + .off1 = td_var_offset(lockfile), + .help = "Lock file when doing IO to it", + .parent = "filename", + .def = "0", + }, + { + .name = "lockfile_batch", + .type = FIO_OPT_INT, + .off1 = td_var_offset(lockfile_batch), + .help = "Number of IOs to allow per file lock", + .parent = "lockfile", + .def = "1", + }, { .name = "opendir", .type = FIO_OPT_STR_STORE, -- 2.25.1