Add ->invalidate() IO engine ops

Allow IO engines to plug in their own invalidate cache handler.
This fixes an issue on rbd, where we attempt to invalidate the
cache, but fail because it's not a valid file descriptor.

Reported-by: xan.peng@gmail.com
Signed-off-by: Jens Axboe <axboe@fb.com>
diff --git a/engines/rbd.c b/engines/rbd.c
index dc6e7db..d006123 100644
--- a/engines/rbd.c
+++ b/engines/rbd.c
@@ -404,6 +404,11 @@
 	return 0;
 }
 
+static int fio_rbd_invalidate(struct thread_data *td, struct fio_file *f)
+{
+	return 0;
+}
+
 static void fio_rbd_io_u_free(struct thread_data *td, struct io_u *io_u)
 {
 	struct fio_rbd_iou *o = io_u->engine_data;
@@ -426,19 +431,20 @@
 }
 
 static struct ioengine_ops ioengine = {
-	.name               = "rbd",
-	.version            = FIO_IOOPS_VERSION,
-	.setup              = fio_rbd_setup,
-	.init               = fio_rbd_init,
-	.queue              = fio_rbd_queue,
-	.getevents          = fio_rbd_getevents,
-	.event              = fio_rbd_event,
-	.cleanup            = fio_rbd_cleanup,
-	.open_file          = fio_rbd_open,
-	.options            = options,
-	.io_u_init          = fio_rbd_io_u_init,
-	.io_u_free          = fio_rbd_io_u_free,
-	.option_struct_size = sizeof(struct rbd_options),
+	.name			= "rbd",
+	.version		= FIO_IOOPS_VERSION,
+	.setup			= fio_rbd_setup,
+	.init			= fio_rbd_init,
+	.queue			= fio_rbd_queue,
+	.getevents		= fio_rbd_getevents,
+	.event			= fio_rbd_event,
+	.cleanup		= fio_rbd_cleanup,
+	.open_file		= fio_rbd_open,
+	.invalidate		= fio_rbd_invalidate,
+	.options		= options,
+	.io_u_init		= fio_rbd_io_u_init,
+	.io_u_free		= fio_rbd_io_u_free,
+	.option_struct_size	= sizeof(struct rbd_options),
 };
 
 static void fio_init fio_rbd_register(void)
diff --git a/filesetup.c b/filesetup.c
index ad7fb85..84eaed6 100644
--- a/filesetup.c
+++ b/filesetup.c
@@ -401,7 +401,9 @@
 	dprint(FD_IO, "invalidate cache %s: %llu/%llu\n", f->file_name, off,
 								len);
 
-	if (f->mmap_ptr) {
+	if (td->io_ops->invalidate)
+		ret = td->io_ops->invalidate(td, f);
+	else if (f->mmap_ptr) {
 		ret = posix_madvise(f->mmap_ptr, f->mmap_sz, POSIX_MADV_DONTNEED);
 #ifdef FIO_MADV_FREE
 		if (f->filetype == FIO_TYPE_BD)
diff --git a/ioengine.h b/ioengine.h
index 6e3c717..37bf5fc 100644
--- a/ioengine.h
+++ b/ioengine.h
@@ -15,7 +15,7 @@
 #include <guasi.h>
 #endif
 
-#define FIO_IOOPS_VERSION	18
+#define FIO_IOOPS_VERSION	19
 
 enum {
 	IO_U_F_FREE		= 1 << 0,
@@ -143,6 +143,7 @@
 	void (*cleanup)(struct thread_data *);
 	int (*open_file)(struct thread_data *, struct fio_file *);
 	int (*close_file)(struct thread_data *, struct fio_file *);
+	int (*invalidate)(struct thread_data *, struct fio_file *);
 	int (*get_file_size)(struct thread_data *, struct fio_file *);
 	void (*terminate)(struct thread_data *);
 	int (*io_u_init)(struct thread_data *, struct io_u *);