Better management of open files

This is a first step to properly supporting dynamic open/close of
new files, differently sized files, etc.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/filesetup.c b/filesetup.c
index cf9fa3c..850dc2f 100644
--- a/filesetup.c
+++ b/filesetup.c
@@ -8,6 +8,30 @@
 #include "fio.h"
 #include "os.h"
 
+int open_file(struct thread_data *td, struct fio_file *f, int flags, int perm)
+{
+	if (flags & O_CREAT)
+		f->fd = open(f->file_name, flags, perm);
+	else
+		f->fd = open(f->file_name, flags);
+
+	if (f->fd != -1) {
+		td->nr_open_files++;
+		return 0;
+	}
+
+	return 1;
+}
+
+void close_file(struct thread_data *td, struct fio_file *f)
+{
+	if (f->fd != -1) {
+		close(f->fd);
+		f->fd = -1;
+		td->nr_open_files--;
+	}
+}
+
 /*
  * Check if the file exists and it's large enough.
  */
@@ -372,14 +396,14 @@
 				flags |= O_CREAT;
 			}
 
-			f->fd = open(f->file_name, flags, 0600);
+			open_file(td, f, flags, 0600);
 		} else {
 			if (td->filetype == FIO_TYPE_CHAR)
 				flags |= O_RDWR;
 			else
 				flags |= O_RDONLY;
 
-			f->fd = open(f->file_name, flags);
+			open_file(td, f, flags, 0);
 		}
 	}
 
@@ -392,8 +416,10 @@
 		return 1;
 	}
 
-	if (get_file_size(td, f))
+	if (get_file_size(td, f)) {
+		close_file(td, f);
 		return 1;
+	}
 
 	return 0;
 }
@@ -412,12 +438,8 @@
 	if (!err)
 		return 0;
 
-	for_each_file(td, f, i) {
-		if (f->fd != -1) {
-			close(f->fd);
-			f->fd = -1;
-		}
-	}
+	for_each_file(td, f, i)
+		close_file(td, f);
 
 	return err;
 }
@@ -465,12 +487,8 @@
 	else
 		err = setup_files_plain(td);
 
-	for_each_file(td, f, i) {
-		if (f->fd != -1) {
-			close(f->fd);
-			f->fd = -1;
-		}
-	}
+	for_each_file(td, f, i)
+		close_file(td, f);
 
 	return err;
 }
@@ -487,10 +505,9 @@
 			free(f->file_name);
 			f->file_name = NULL;
 		}
-		if (f->fd != -1) {
-			close(f->fd);
-			f->fd = -1;
-		}
+
+		close_file(td, f);
+
 		if (f->mmap) {
 			munmap(f->mmap, f->file_size);
 			f->mmap = NULL;
diff --git a/fio.h b/fio.h
index f8f9a5e..efc9e51 100644
--- a/fio.h
+++ b/fio.h
@@ -297,6 +297,7 @@
 	enum fio_filetype filetype;
 	struct fio_file *files;
 	unsigned int nr_files;
+	unsigned int nr_open_files;
 	unsigned int nr_uniq_files;
 	union {
 		unsigned int next_file;
@@ -619,6 +620,8 @@
 extern void close_files(struct thread_data *);
 extern int __must_check setup_files(struct thread_data *);
 extern int __must_check open_files(struct thread_data *);
+extern int open_file(struct thread_data *, struct fio_file *, int, int);
+extern void close_file(struct thread_data *, struct fio_file *);
 extern int __must_check file_invalidate_cache(struct thread_data *, struct fio_file *);
 
 /*
diff --git a/io_u.c b/io_u.c
index 426a5f8..978771e 100644
--- a/io_u.c
+++ b/io_u.c
@@ -365,6 +365,17 @@
 	return f;
 }
 
+static struct fio_file *get_next_file(struct thread_data *td)
+{
+	if (!td->nr_open_files)
+		return NULL;
+
+	if (td->file_service_type == FIO_FSERVICE_RR)
+		return get_next_file_rr(td);
+	else
+		return get_next_file_rand(td);
+}
+
 struct io_u *__get_io_u(struct thread_data *td)
 {
 	struct io_u *io_u = NULL;
@@ -413,23 +424,24 @@
 	if (io_u->file)
 		goto out;
 
-	if (td->file_service_type == FIO_FSERVICE_RR)
-		f = get_next_file_rr(td);
-	else
-		f = get_next_file_rand(td);
+	do {
+		f = get_next_file(td);
+		if (!f) {
+			put_io_u(td, io_u);
+			return NULL;
+		}
 
-	if (!f) {
-		put_io_u(td, io_u);
-		return NULL;
-	}
+		io_u->file = f;
 
-	io_u->file = f;
+		if (!fill_io_u(td, io_u))
+			break;
 
-
-	if (fill_io_u(td, io_u)) {
-		put_io_u(td, io_u);
-		return NULL;
-	}
+		/*
+		 * No more to do for this file, close it
+		 */
+		io_u->file = NULL;
+		close_file(td, f);
+	} while (1);
 
 	if (td->zone_bytes >= td->zone_size) {
 		td->zone_bytes = 0;