the other options related to buffer contents. The setting can
be any pattern of bytes, and can be prefixed with 0x for hex
values. It may also be a string, where the string must then
- be wrapped with "".
+ be wrapped with "", e.g.:
+
+ buffer_pattern="abcd"
+ or
+ buffer_pattern=-12
+ or
+ buffer_pattern=0xdeadface
+
+ Also you can combine everything together in any order:
+ buffer_pattern=0xdeadface"abcd"-12
dedupe_percentage=int If set, fio will generate this percentage of
identical buffers when writing. These buffers will be
buffer at the time(it can be either a decimal or a hex number).
The verify_pattern if larger than a 32-bit quantity has to
be a hex number that starts with either "0x" or "0X". Use
- with verify=meta.
+ with verify=meta. Also, verify_pattern supports %o format,
+ which means that for each block offset will be written and
+ then verifyied back, e.g.:
+
+ verify_pattern=%o
+
+ Or use combination of everything:
+ verify_pattern=0xff%o"abcd"-12
verify_fatal=bool Normally fio will keep checking the entire contents
before quitting on a block verification failure. If this
#include "verify.h"
#include "parse.h"
#include "lib/fls.h"
+#include "lib/pattern.h"
#include "options.h"
#include "crc/crc32c.h"
char client_sockaddr_str[INET6_ADDRSTRLEN] = { 0 };
+struct pattern_fmt_desc fmt_desc[] = {
+ {
+ .fmt = "%o",
+ .len = FIELD_SIZE(struct io_u *, offset),
+ .paste = paste_blockoff
+ }
+};
+
/*
* Check if mmap/mmaphuge has a :/foo/bar/file at the end. If so, return that.
*/
return strdup(p);
}
-static int converthexchartoint(char a)
-{
- int base;
-
- switch (a) {
- case '0'...'9':
- base = '0';
- break;
- case 'A'...'F':
- base = 'A' - 10;
- break;
- case 'a'...'f':
- base = 'a' - 10;
- break;
- default:
- base = 0;
- }
- return a - base;
-}
-
static int bs_cmp(const void *p1, const void *p2)
{
const struct bssplit *bsp1 = p1;
return add_dir_files(td, td->o.opendir);
}
-static int pattern_cb(char *pattern, unsigned int max_size,
- const char *input, unsigned int *pattern_bytes)
-{
- long off = 0;
- int i = 0, j = 0, len, k, base = 10;
- uint32_t pattern_length;
- char *loc1, *loc2;
-
- /*
- * Check if it's a string input
- */
- loc1 = strchr(input, '\"');
- if (loc1) {
- do {
- loc1++;
- if (*loc1 == '\0' || *loc1 == '\"')
- break;
-
- pattern[i] = *loc1;
- i++;
- } while (i < max_size);
-
- if (!i)
- return 1;
-
- goto fill;
- }
-
- /*
- * No string, find out if it's decimal or hexidecimal
- */
- loc1 = strstr(input, "0x");
- loc2 = strstr(input, "0X");
- if (loc1 || loc2)
- base = 16;
- off = strtol(input, NULL, base);
- if (off != LONG_MAX || errno != ERANGE) {
- while (off) {
- pattern[i] = off & 0xff;
- off >>= 8;
- i++;
- }
- } else {
- len = strlen(input);
- k = len - 1;
- if (base == 16) {
- if (loc1)
- j = loc1 - input + 2;
- else
- j = loc2 - input + 2;
- } else
- return 1;
- if (len - j < max_size * 2) {
- while (k >= j) {
- off = converthexchartoint(input[k--]);
- if (k >= j)
- off += (converthexchartoint(input[k--])
- * 16);
- pattern[i++] = (char) off;
- }
- }
- }
-
- /*
- * Fill the pattern all the way to the end. This greatly reduces
- * the number of memcpy's we have to do when verifying the IO.
- */
-fill:
- pattern_length = i;
- if (!i && !off)
- i = 1;
- 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_size.
- */
- while (i > 1 && i < max_size) {
- unsigned int b = min(pattern_length, max_size - i);
-
- memcpy(&pattern[i], &pattern[0], b);
- i += b;
- }
-
- if (i == 1) {
- /*
- * The code in verify_io_u_pattern assumes a single byte
- * pattern fills the whole verify pattern buffer.
- */
- memset(pattern, pattern[0], max_size);
- }
-
- *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);
+ /* FIXME: for now buffer pattern does not support formats */
+ ret = parse_and_fill_pattern(input, strlen(input), td->o.buffer_pattern,
+ MAX_PATTERN_SIZE, NULL, 0, NULL, NULL);
+ if (ret < 0)
+ return 1;
- if (!ret && td->o.buffer_pattern_bytes) {
- if (!td->o.compress_percentage)
- td->o.refill_buffers = 0;
- td->o.scramble_buffers = 0;
- td->o.zero_buffers = 0;
- } else {
- log_err("fio: failed parsing pattern `%s`\n", input);
- ret = 1;
- }
+ assert(ret != 0);
+ td->o.buffer_pattern_bytes = ret;
+ if (!td->o.compress_percentage)
+ td->o.refill_buffers = 0;
+ td->o.scramble_buffers = 0;
+ td->o.zero_buffers = 0;
- return ret;
+ return 0;
}
static int str_buffer_compress_cb(void *data, unsigned long long *il)
struct thread_data *td = data;
int ret;
- ret = pattern_cb(td->o.verify_pattern, MAX_PATTERN_SIZE, input,
- &td->o.verify_pattern_bytes);
+ td->o.verify_fmt_sz = ARRAY_SIZE(td->o.verify_fmt);
+ ret = parse_and_fill_pattern(input, strlen(input), td->o.verify_pattern,
+ MAX_PATTERN_SIZE, fmt_desc, sizeof(fmt_desc),
+ td->o.verify_fmt, &td->o.verify_fmt_sz);
+ if (ret < 0)
+ return 1;
+ assert(ret != 0);
+ td->o.verify_pattern_bytes = ret;
/*
* VERIFY_META could already be set
*/
- if (!ret && !fio_option_is_set(&td->o, verify))
+ if (!fio_option_is_set(&td->o, verify))
td->o.verify = VERIFY_PATTERN;
- return ret;
+ return 0;
}
static int str_gtod_reduce_cb(void *data, int *il)
return;
}
- if (io_u->buf_filled_len >= len) {
+ /* Skip if we were here and we do not need to patch pattern
+ * with format */
+ if (!td->o.verify_fmt_sz && io_u->buf_filled_len >= len) {
dprint(FD_VERIFY, "using already filled verify pattern b=%d len=%u\n",
o->verify_pattern_bytes, len);
return;
}
- (void)cpy_pattern(td->o.verify_pattern, td->o.verify_pattern_bytes, p, len);
+ (void)paste_format(td->o.verify_pattern, td->o.verify_pattern_bytes,
+ td->o.verify_fmt, td->o.verify_fmt_sz,
+ p, len, io_u);
io_u->buf_filled_len = len;
}
pattern = td->o.verify_pattern;
pattern_size = td->o.verify_pattern_bytes;
- if (pattern_size <= 1)
- pattern_size = MAX_PATTERN_SIZE;
+ assert(pattern_size != 0);
+
+ (void)paste_format_inplace(pattern, pattern_size,
+ td->o.verify_fmt, td->o.verify_fmt_sz, io_u);
+
buf = (void *) hdr + header_size;
len = get_hdr_inc(td, io_u) - header_size;
- mod = header_size % pattern_size;
+ mod = (get_hdr_inc(td, io_u) * vc->hdr_num + header_size) % pattern_size;
rc = cmp_pattern(pattern, pattern_size, mod, buf, len);
if (!rc)
td->verify_threads = NULL;
}
+int paste_blockoff(char *buf, unsigned int len, void *priv)
+{
+ struct io_u *io = priv;
+ unsigned long long off;
+
+ typecheck(typeof(off), io->offset);
+ off = cpu_to_le64((uint64_t)io->offset);
+ len = min(len, (unsigned int)sizeof(off));
+ memcpy(buf, &off, len);
+ return 0;
+}
+
struct all_io_list *get_all_io_list(int save_mask, size_t *sz)
{
struct all_io_list *rep;