Add option for specifically setting buffer contents

Fio can use zeroes, slightly scrambled data, full random data,
or specifically compressible data. With this option, the user
can now fully control the pattern written, similarly to how
verify_pattern works for verify=meta.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/options.c b/options.c
index 16b6636..b1b6c8e 100644
--- a/options.c
+++ b/options.c
@@ -834,11 +834,12 @@
 	return add_dir_files(td, td->o.opendir);
 }
 
-static int str_verify_pattern_cb(void *data, const char *input)
+static int pattern_cb(char *pattern, unsigned int max_size,
+		      const char *input, unsigned int *pattern_bytes)
 {
-	struct thread_data *td = data;
 	long off;
-	int i = 0, j = 0, len, k, base = 10, pattern_length;
+	int i = 0, j = 0, len, k, base = 10;
+	uint32_t pattern_length;
 	char *loc1, *loc2;
 
 	loc1 = strstr(input, "0x");
@@ -848,7 +849,7 @@
 	off = strtol(input, NULL, base);
 	if (off != LONG_MAX || errno != ERANGE) {
 		while (off) {
-			td->o.verify_pattern[i] = off & 0xff;
+			pattern[i] = off & 0xff;
 			off >>= 8;
 			i++;
 		}
@@ -862,13 +863,13 @@
 				j = loc2 - input + 2;
 		} else
 			return 1;
-		if (len - j < MAX_PATTERN_SIZE * 2) {
+		if (len - j < max_size * 2) {
 			while (k >= j) {
 				off = converthexchartoint(input[k--]);
 				if (k >= j)
 					off += (converthexchartoint(input[k--])
 						* 16);
-				td->o.verify_pattern[i++] = (char) off;
+				pattern[i++] = (char) off;
 			}
 		}
 	}
@@ -878,19 +879,19 @@
 	 * the number of memcpy's we have to do when verifying the IO.
 	 */
 	pattern_length = i;
-	while (i > 1 && i * 2 <= MAX_PATTERN_SIZE) {
-		memcpy(&td->o.verify_pattern[i], &td->o.verify_pattern[0], i);
+	while (i > 1 && i * 2 <= max_size) {
+		memcpy(&pattern[i], &pattern[0], i);
 		i *= 2;
 	}
 
 	/*
 	 * Fill remainder, if the pattern multiple ends up not being
-	 * MAX_PATTERN_SIZE.
+	 * max_size.
 	 */
-	while (i > 1 && i < MAX_PATTERN_SIZE) {
-		unsigned int b = min(pattern_length, MAX_PATTERN_SIZE - i);
+	while (i > 1 && i < max_size) {
+		unsigned int b = min(pattern_length, max_size - i);
 
-		memcpy(&td->o.verify_pattern[i], &td->o.verify_pattern[0], b);
+		memcpy(&pattern[i], &pattern[0], b);
 		i += b;
 	}
 
@@ -899,19 +900,45 @@
 		 * The code in verify_io_u_pattern assumes a single byte pattern
 		 * fills the whole verify pattern buffer.
 		 */
-		memset(td->o.verify_pattern, td->o.verify_pattern[0],
-		       MAX_PATTERN_SIZE);
+		memset(pattern, pattern[0], max_size);
 	}
 
-	td->o.verify_pattern_bytes = i;
+	*pattern_bytes = i;
+	return 0;
+}
+
+static int str_buffer_pattern_cb(void *data, const char *input)
+{
+	struct thread_data *td = data;
+	int ret;
+
+	ret = pattern_cb(td->o.buffer_pattern, MAX_PATTERN_SIZE, input,
+				&td->o.buffer_pattern_bytes);
+
+	if (!ret) {
+		td->o.refill_buffers = 0;
+		td->o.scramble_buffers = 0;
+		td->o.zero_buffers = 0;
+	}
+
+	return ret;
+}
+
+static int str_verify_pattern_cb(void *data, const char *input)
+{
+	struct thread_data *td = data;
+	int ret;
+
+	ret = pattern_cb(td->o.verify_pattern, MAX_PATTERN_SIZE, input,
+				&td->o.verify_pattern_bytes);
 
 	/*
 	 * VERIFY_META could already be set
 	 */
-	if (td->o.verify == VERIFY_NONE)
+	if (!ret && td->o.verify == VERIFY_NONE)
 		td->o.verify = VERIFY_PATTERN;
 
-	return 0;
+	return ret;
 }
 
 static int str_gtod_reduce_cb(void *data, int *il)
@@ -2947,6 +2974,15 @@
 		.group	= FIO_OPT_G_IO_BUF,
 	},
 	{
+		.name	= "buffer_pattern",
+		.lname	= "Buffer pattern",
+		.type	= FIO_OPT_STR,
+		.cb	= str_buffer_pattern_cb,
+		.help	= "Fill pattern for IO buffers",
+		.category = FIO_OPT_C_IO,
+		.group	= FIO_OPT_G_IO_BUF,
+	},
+	{
 		.name	= "buffer_compress_percentage",
 		.lname	= "Buffer compression percentage",
 		.type	= FIO_OPT_INT,