Update close file handler to return potential error

Filesystems like NFS do return errors on close(), up until now we
have been ignoring them. Fix that. Adjust io_ops engine version
to 9, since this is an API change.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/engines/mmap.c b/engines/mmap.c
index 604f8b0..3e1e6c8 100644
--- a/engines/mmap.c
+++ b/engines/mmap.c
@@ -107,14 +107,23 @@
 	return 1;
 }
 
-static void fio_mmapio_close(struct thread_data fio_unused *td,
-			     struct fio_file *f)
+static int fio_mmapio_close(struct thread_data fio_unused *td,
+			    struct fio_file *f)
 {
+	int ret = 0, ret2;
+
 	if (f->mmap) {
-		munmap(f->mmap, f->io_size);
+		if (munmap(f->mmap, f->io_size) < 0)
+			ret = errno;
+
 		f->mmap = NULL;
 	}
-	generic_close_file(td, f);
+
+	ret2 = generic_close_file(td, f);
+	if (!ret && ret2)
+		ret = ret2;
+
+	return ret;
 }
 
 static struct ioengine_ops ioengine = {
diff --git a/engines/sg.c b/engines/sg.c
index a9ff93a..c50ad55 100644
--- a/engines/sg.c
+++ b/engines/sg.c
@@ -388,7 +388,7 @@
 		return ret;
 
 	if (sd && !sd->type_checked && fio_sgio_type_check(td, f)) {
-		generic_close_file(td, f);
+		ret = generic_close_file(td, f);
 		return 1;
 	}
 
diff --git a/filesetup.c b/filesetup.c
index 3e11c4c..c0403d2 100644
--- a/filesetup.c
+++ b/filesetup.c
@@ -209,11 +209,16 @@
 	return ret;
 }
 
-void generic_close_file(struct thread_data fio_unused *td, struct fio_file *f)
+int generic_close_file(struct thread_data fio_unused *td, struct fio_file *f)
 {
+	int ret = 0;
+
 	dprint(FD_FILE, "fd close %s\n", f->file_name);
-	close(f->fd);
+	if (close(f->fd) < 0)
+		ret = errno;
+
 	f->fd = -1;
+	return ret;
 }
 
 int generic_open_file(struct thread_data *td, struct fio_file *f)
@@ -614,25 +619,28 @@
 	f->references++;
 }
 
-void put_file(struct thread_data *td, struct fio_file *f)
+int put_file(struct thread_data *td, struct fio_file *f)
 {
+	int ret = 0;
+
 	dprint(FD_FILE, "put file %s, ref=%d\n", f->file_name, f->references);
 
 	if (!(f->flags & FIO_FILE_OPEN))
-		return;
+		return 0;
 
 	assert(f->references);
 	if (--f->references)
-		return;
+		return 0;
 
 	if (should_fsync(td) && td->o.fsync_on_close)
 		fsync(f->fd);
 
 	if (td->io_ops->close_file)
-		td->io_ops->close_file(td, f);
+		ret = td->io_ops->close_file(td, f);
 
 	td->nr_open_files--;
 	f->flags &= ~FIO_FILE_OPEN;
+	return ret;
 }
 
 static int recurse_dir(struct thread_data *td, const char *dirname)
diff --git a/fio.h b/fio.h
index 4fbc704..9281934 100644
--- a/fio.h
+++ b/fio.h
@@ -805,10 +805,10 @@
 extern int __must_check open_files(struct thread_data *);
 extern int __must_check file_invalidate_cache(struct thread_data *, struct fio_file *);
 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 int __must_check generic_close_file(struct thread_data *, struct fio_file *);
 extern int add_file(struct thread_data *, const char *);
 extern void get_file(struct fio_file *);
-extern void put_file(struct thread_data *, struct fio_file *);
+extern int __must_check put_file(struct thread_data *, struct fio_file *);
 extern int add_dir_files(struct thread_data *, const char *);
 extern int init_random_map(struct thread_data *);
 extern void dup_files(struct thread_data *, struct thread_data *);
@@ -894,7 +894,7 @@
 extern int __must_check td_io_getevents(struct thread_data *, unsigned int, unsigned int, struct timespec *);
 extern int __must_check td_io_commit(struct thread_data *);
 extern int __must_check td_io_open_file(struct thread_data *, struct fio_file *);
-extern void td_io_close_file(struct thread_data *, struct fio_file *);
+extern int td_io_close_file(struct thread_data *, struct fio_file *);
 
 /*
  * blktrace support
@@ -919,12 +919,12 @@
 	int (*cancel)(struct thread_data *, struct io_u *);
 	void (*cleanup)(struct thread_data *);
 	int (*open_file)(struct thread_data *, struct fio_file *);
-	void (*close_file)(struct thread_data *, struct fio_file *);
+	int (*close_file)(struct thread_data *, struct fio_file *);
 	void *data;
 	void *dlhandle;
 };
 
-#define FIO_IOOPS_VERSION	8
+#define FIO_IOOPS_VERSION	9
 
 extern struct ioengine_ops *load_ioengine(struct thread_data *, const char *);
 extern void register_ioengine(struct ioengine_ops *);
diff --git a/io_u.c b/io_u.c
index faa1c5e..0ffae29 100644
--- a/io_u.c
+++ b/io_u.c
@@ -328,8 +328,12 @@
 	assert((io_u->flags & IO_U_F_FREE) == 0);
 	io_u->flags |= IO_U_F_FREE;
 
-	if (io_u->file)
-		put_file(td, io_u->file);
+	if (io_u->file) {
+		int ret = put_file(td, io_u->file);
+
+		if (ret)
+			td_verror(td, ret, "file close");
+	}
 
 	io_u->file = NULL;
 	list_del(&io_u->list);
diff --git a/ioengines.c b/ioengines.c
index 979ac28..a81c7b8 100644
--- a/ioengines.c
+++ b/ioengines.c
@@ -344,7 +344,7 @@
 	return 1;
 }
 
-void td_io_close_file(struct thread_data *td, struct fio_file *f)
+int td_io_close_file(struct thread_data *td, struct fio_file *f)
 {
 	if (!(f->flags & FIO_FILE_CLOSING))
 		log_file(td, f, FIO_LOG_CLOSE_FILE);
@@ -354,5 +354,5 @@
 	 */
 	f->flags |= FIO_FILE_CLOSING;
 
-	put_file(td, f);
+	return put_file(td, f);
 }