Add ability to invoke fallocate() FALLOC_FL_KEEP_SIZE.

Linux offers fallocate() and the FALLOC_FL_KEEP_SIZE option as
an alternative to posix_fallocate(). When FALLOC_FL_KEEP_SIZE is
specified for an falloc request going beyond the end of the file,
the requested blocks get preallocated without changing the apparent
size of the file. This is is a commonly recommended use of fallocate()
for workloads performing append writes.

This patch modifies the fallocate option from a boolean option
to a string option accepting none/posix/keep/0/1. 'keep' is only
made available on systems where FALLOC_FL_KEEP_SIZE is available
(i.e., Linux at this time). If specified, fallocate() is used
with FALLOC_FL_KEEP_SIZE set. 'none' disables pre-allocation while
'posix' uses posix_fallocate(). The default behavior remains unchaned,
i.e., invoking posix_fallocate. The settings '0'/'1' are there to
provide backward compatibility for users who had explicitly set the
boolean option.

Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
diff --git a/filesetup.c b/filesetup.c
index 799202f..6d8aa7a 100644
--- a/filesetup.c
+++ b/filesetup.c
@@ -13,6 +13,10 @@
 #include "filehash.h"
 #include "os/os.h"
 
+#ifdef FIO_HAVE_LINUX_FALLOCATE
+#include <linux/falloc.h>
+#endif
+
 static int root_warn;
 
 static inline void clear_error(struct thread_data *td)
@@ -67,17 +71,41 @@
 	}
 
 #ifdef FIO_HAVE_FALLOCATE
-	if (td->o.fallocate && !td->o.fill_device) {
-		dprint(FD_FILE, "fallocate file %s size %llu\n", f->file_name,
-							f->real_file_size);
+	if (!td->o.fill_device) {
+		switch (td->o.fallocate_mode) {
+		case FIO_FALLOCATE_NONE:
+			break;
+		case FIO_FALLOCATE_POSIX:
+			dprint(FD_FILE, "posix_fallocate file %s size %llu\n",
+				 f->file_name, f->real_file_size);
 
-		r = posix_fallocate(f->fd, 0, f->real_file_size);
-		if (r > 0) {
-			log_err("fio: posix_fallocate fails: %s\n",
-					strerror(r));
+			r = posix_fallocate(f->fd, 0, f->real_file_size);
+			if (r > 0) {
+				log_err("fio: posix_fallocate fails: %s\n",
+						strerror(r));
+			}
+			break;
+#ifdef FIO_HAVE_LINUX_FALLOCATE
+		case FIO_FALLOCATE_KEEP_SIZE:
+			dprint(FD_FILE,
+				"fallocate(FALLOC_FL_KEEP_SIZE) "
+				"file %s size %llu\n",
+				f->file_name, f->real_file_size);
+
+			r = fallocate(f->fd, FALLOC_FL_KEEP_SIZE, 0,
+					f->real_file_size);
+			if (r != 0) {
+				td_verror(td, errno, "fallocate");
+			}
+			break;
+#endif /* FIO_HAVE_LINUX_FALLOCATE */
+		default:
+			log_err("fio: unknown fallocate mode: %d\n",
+				td->o.fallocate_mode);
+			assert(0);
 		}
 	}
-#endif
+#endif /* FIO_HAVE_FALLOCATE */
 
 	if (!new_layout)
 		goto done;