Add file reference counting
We must not close a file, while io is in progress to it. That
will make the queuing engines barf.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/filesetup.c b/filesetup.c
index f6e9974..f3fccdb 100644
--- a/filesetup.c
+++ b/filesetup.c
@@ -445,3 +445,23 @@
td->open_files++;
td->nr_uniq_files = td->open_files;
}
+
+void get_file(struct fio_file *f)
+{
+ f->references++;
+}
+
+void put_file(struct thread_data *td, struct fio_file *f)
+{
+ if (!(f->flags & FIO_FILE_OPEN))
+ return;
+
+ assert(f->references);
+ if (--f->references)
+ return;
+
+ if (td->io_ops->close_file)
+ td->io_ops->close_file(td, f);
+ td->nr_open_files--;
+ f->flags &= ~FIO_FILE_OPEN;
+}
diff --git a/fio.h b/fio.h
index e451f95..5bf8c43 100644
--- a/fio.h
+++ b/fio.h
@@ -219,8 +219,9 @@
};
enum fio_file_flags {
- FIO_FILE_OPEN = 1 << 0,
- FIO_FILE_UNLINK = 1 << 1,
+ FIO_FILE_OPEN = 1 << 0, /* file is open */
+ FIO_FILE_UNLINK = 1 << 1, /* unlink on close */
+ FIO_FILE_CLOSING = 1 << 2, /* file being closed */
};
/*
@@ -252,6 +253,7 @@
unsigned int num_maps;
unsigned int last_free_lookup;
+ int references;
enum fio_file_flags flags;
};
@@ -654,6 +656,8 @@
extern int __must_check generic_open_file(struct thread_data *, struct fio_file *);
extern void generic_close_file(struct thread_data *, struct fio_file *);
extern void add_file(struct thread_data *, const char *);
+extern void get_file(struct fio_file *);
+extern void put_file(struct thread_data *, struct fio_file *);
/*
* ETA/status stuff
diff --git a/init.c b/init.c
index f3c756e..66a50b0 100644
--- a/init.c
+++ b/init.c
@@ -752,7 +752,9 @@
if (td->iodepth_batch > td->iodepth || !td->iodepth_batch)
td->iodepth_batch = td->iodepth;
- if (td->open_files > td->nr_files || !td->open_files)
+ if (!td->nr_files)
+ td->nr_files = td->open_files;
+ else if (td->open_files > td->nr_files || !td->open_files)
td->open_files = td->nr_files;
}
@@ -1103,9 +1105,12 @@
struct thread_data *td = data;
char *fname, *str;
+ td->nr_files = 0;
str = strdup(input);
- while ((fname = strsep(&str, ":")) != NULL)
+ while ((fname = strsep(&str, ":")) != NULL) {
add_file(td, fname);
+ td->nr_files++;
+ }
return 0;
}
diff --git a/io_u.c b/io_u.c
index c16128e..477f387 100644
--- a/io_u.c
+++ b/io_u.c
@@ -340,7 +340,8 @@
fileno = (unsigned int) ((double) (td->open_files * r) / (RAND_MAX + 1.0));
f = &td->files[fileno];
- if (f->flags & FIO_FILE_OPEN)
+ if ((f->flags & FIO_FILE_OPEN) &&
+ !(f->flags & FIO_FILE_CLOSING))
return f;
} while (1);
}
@@ -360,7 +361,8 @@
if (td->next_file >= td->open_files)
td->next_file = 0;
- if (f->flags & FIO_FILE_OPEN)
+ if ((f->flags & FIO_FILE_OPEN) &&
+ !(f->flags & FIO_FILE_CLOSING))
break;
f = NULL;
@@ -537,6 +539,8 @@
assert(io_u->flags & IO_U_F_FLIGHT);
io_u->flags &= ~IO_U_F_FLIGHT;
+ put_file(td, io_u->file);
+
if (io_u->ddir == DDIR_SYNC) {
td->last_was_sync = 1;
return;
diff --git a/ioengines.c b/ioengines.c
index 02455b8..185314f 100644
--- a/ioengines.c
+++ b/ioengines.c
@@ -206,6 +206,9 @@
ret = td->io_ops->queue(td, io_u);
+ if (ret == FIO_Q_QUEUED || ret == FIO_Q_COMPLETED)
+ get_file(io_u->file);
+
if (ret == FIO_Q_QUEUED) {
int r;
@@ -260,20 +263,23 @@
f->last_completed_pos = 0;
f->last_pos = 0;
f->flags |= FIO_FILE_OPEN;
+ f->flags &= ~FIO_FILE_CLOSING;
if (f->file_map)
memset(f->file_map, 0, f->num_maps * sizeof(long));
td->nr_open_files++;
+ get_file(f);
return 0;
}
void td_io_close_file(struct thread_data *td, struct fio_file *f)
{
- if (f->flags & FIO_FILE_OPEN) {
- if (td->io_ops->close_file)
- td->io_ops->close_file(td, f);
- td->nr_open_files--;
- f->flags &= ~FIO_FILE_OPEN;
- }
+ /*
+ * mark as closing, do real close when last io on it has completed
+ */
+ f->flags |= FIO_FILE_CLOSING;
+
+ put_file(td, f);
}
+