#ifdef HAVE_ATTR_ATTRIBUTES_H
#include <attr/attributes.h>
#endif
-#ifdef FALLOCATE
-#include <linux/falloc.h>
-#ifndef FALLOC_FL_PUNCH_HOLE
-/* Copy-paste from linux/falloc.h */
-#define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */
-#endif
+#ifdef HAVE_LINUX_FIEMAP_H
+#include <linux/fiemap.h>
#endif
#ifndef HAVE_ATTR_LIST
#define attr_list(path, buf, size, flags, cursor) (errno = -ENOSYS, -1)
OP_DWRITE,
OP_FALLOCATE,
OP_FDATASYNC,
+ OP_FIEMAP,
OP_FREESP,
OP_FSYNC,
OP_GETATTR,
OP_MKDIR,
OP_MKNOD,
OP_PUNCH,
+ OP_ZERO,
OP_READ,
OP_READLINK,
OP_RENAME,
char *path;
} pathname_t;
+struct print_flags {
+ unsigned long mask;
+ const char *name;
+};
+
+struct print_string {
+ char *buffer;
+ int len;
+ int max;
+};
+
#define FT_DIR 0
#define FT_DIRm (1 << FT_DIR)
#define FT_REG 1
void dwrite_f(int, long);
void fallocate_f(int, long);
void fdatasync_f(int, long);
+void fiemap_f(int, long);
void freesp_f(int, long);
void fsync_f(int, long);
void getattr_f(int, long);
void mkdir_f(int, long);
void mknod_f(int, long);
void punch_f(int, long);
+void zero_f(int, long);
void read_f(int, long);
void readlink_f(int, long);
void rename_f(int, long);
void write_f(int, long);
opdesc_t ops[] = {
+ /* { OP_ENUM, "name", function, freq, iswrite }, */
{ OP_ALLOCSP, "allocsp", allocsp_f, 1, 1 },
{ OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1 },
{ OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1 },
{ OP_DWRITE, "dwrite", dwrite_f, 4, 1 },
{ OP_FALLOCATE, "fallocate", fallocate_f, 1, 1 },
{ OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1 },
+ { OP_FIEMAP, "fiemap", fiemap_f, 1, 1 },
{ OP_FREESP, "freesp", freesp_f, 1, 1 },
{ OP_FSYNC, "fsync", fsync_f, 1, 1 },
{ OP_GETATTR, "getattr", getattr_f, 1, 0 },
{ OP_MKDIR, "mkdir", mkdir_f, 2, 1 },
{ OP_MKNOD, "mknod", mknod_f, 2, 1 },
{ OP_PUNCH, "punch", punch_f, 1, 1 },
+ { OP_ZERO, "zero", zero_f, 1, 1 },
{ OP_READ, "read", read_f, 1, 0 },
{ OP_READLINK, "readlink", readlink_f, 1, 0 },
{ OP_RENAME, "rename", rename_f, 2, 1 },
{ OP_SETXATTR, "setxattr", setxattr_f, 1, 1 },
{ OP_STAT, "stat", stat_f, 1, 0 },
{ OP_SYMLINK, "symlink", symlink_f, 2, 1 },
- { OP_SYNC, "sync", sync_f, 1, 0 },
+ { OP_SYNC, "sync", sync_f, 1, 1 },
{ OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
{ OP_UNLINK, "unlink", unlink_f, 1, 1 },
{ OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1 },
unsigned long seed = 0;
ino_t top_ino;
int verbose = 0;
+int verifiable_log = 0;
sig_atomic_t should_stop = 0;
+char *execute_cmd = NULL;
+int execute_freq = 1;
+struct print_string flag_str = {0};
void add_to_flist(int, int, int);
void append_pathname(pathname_t *, char *);
int nousage = 0;
xfs_error_injection_t err_inj;
struct sigaction action;
+ const char *allopts = "d:e:f:i:m:M:n:o:p:rs:S:vVwx:X:zH";
errrange = errtag = 0;
umask(0);
nops = sizeof(ops) / sizeof(ops[0]);
ops_end = &ops[nops];
myprog = argv[0];
- while ((c = getopt(argc, argv, "d:e:f:i:m:M:n:o:p:rs:S:vwzH")) != -1) {
+ while ((c = getopt(argc, argv, allopts)) != -1) {
switch (c) {
case 'd':
dirname = optarg;
case 'w':
write_freq();
break;
+ case 'x':
+ execute_cmd = optarg;
+ break;
case 'z':
zero_freq();
break;
i = 0;
if (optarg[0] == 'c')
i = 1;
- show_ops(1, NULL);
+ show_ops(i, NULL);
printf("\n");
nousage=1;
break;
+ case 'V':
+ verifiable_log = 1;
+ break;
+
+ case 'X':
+ execute_freq = strtoul(optarg, NULL, 0);
+ break;
case '?':
fprintf(stderr, "%s - invalid parameters\n",
myprog);
return 0;
}
+int
+add_string(struct print_string *str, const char *add)
+{
+ int len = strlen(add);
+
+ if (len <= 0)
+ return 0;
+
+ if (len > (str->max - 1) - str->len) {
+ str->len = str->max - 1;
+ return 0;
+ }
+
+ memcpy(str->buffer + str->len, add, len);
+ str->len += len;
+ str->buffer[str->len] = '\0';
+
+ return len;
+}
+
+char *
+translate_flags(int flags, const char *delim,
+ const struct print_flags *flag_array)
+{
+ int i, mask, first = 1;
+ const char *add;
+
+ if (!flag_str.buffer) {
+ flag_str.buffer = malloc(4096);
+ flag_str.max = 4096;
+ flag_str.len = 0;
+ }
+ if (!flag_str.buffer)
+ return NULL;
+ flag_str.len = 0;
+ flag_str.buffer[0] = '\0';
+
+ for (i = 0; flag_array[i].name && flags; i++) {
+ mask = flag_array[i].mask;
+ if ((flags & mask) != mask)
+ continue;
+
+ add = flag_array[i].name;
+ flags &= ~mask;
+ if (!first && delim)
+ add_string(&flag_str, delim);
+ else
+ first = 0;
+ add_string(&flag_str, add);
+ }
+
+ /* Check whether there are any leftover flags. */
+ if (flags) {
+ int ret;
+ char number[11];
+
+ if (!first && delim)
+ add_string(&flag_str, delim);
+
+ ret = snprintf(number, 11, "0x%x", flags) > 0;
+ if (ret > 0 && ret <= 11)
+ add_string(&flag_str, number);
+ }
+
+ return flag_str.buffer;
+}
+
void
add_to_flist(int ft, int id, int parent)
{
int opno;
int rval;
opdesc_t *p;
+ int dividend;
+ dividend = (operations + execute_freq) / (execute_freq + 1);
sprintf(buf, "p%x", procid);
(void)mkdir(buf, 0777);
if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) {
if (namerand)
namerand = random();
for (opno = 0; opno < operations; opno++) {
+ if (execute_cmd && opno && opno % dividend == 0) {
+ if (verbose)
+ printf("%d: execute command %s\n", opno,
+ execute_cmd);
+ rval = system(execute_cmd);
+ if (rval)
+ fprintf(stderr, "execute command failed with "
+ "%d\n", rval);
+ }
p = &ops[freq_table[random() % freq_table_size]];
p->func(opno, random());
/*
printf("Usage: %s -H or\n", myprog);
printf(" %s [-d dir][-e errtg][-f op_name=freq][-n nops]\n",
myprog);
- printf(" [-p nproc][-r len][-s seed][-v][-w][-z][-S]\n");
+ printf(" [-p nproc][-r len][-s seed][-v][-w][-x cmd][-z][-S][-X ncmd]\n");
printf("where\n");
printf(" -d dir specifies the base directory for operations\n");
printf(" -e errtg specifies error injection stuff\n");
printf(" -f op_name=freq changes the frequency of option name to freq\n");
printf(" the valid operation names are:\n");
- printf(" -i filenum get verbose output for this nth file object\n");
show_ops(-1, " ");
+ printf(" -i filenum get verbose output for this nth file object\n");
printf(" -m modulo uid/gid modulo for chown/chgrp (default 32)\n");
printf(" -n nops specifies the no. of operations per process (default 1)\n");
+ printf(" -o logfile specifies logfile name\n");
printf(" -p nproc specifies the no. of processes (default 1)\n");
printf(" -r specifies random name padding\n");
printf(" -s seed specifies the seed for the random generator (default random)\n");
printf(" -v specifies verbose mode\n");
printf(" -w zeros frequencies of non-write operations\n");
+ printf(" -x cmd execute command in the middle of operations\n");
printf(" -z zeros frequencies of all operations\n");
printf(" -S [c,t] prints the list of operations (omitting zero frequency) in command line or table style\n");
+ printf(" -V specifies verifiable logging mode (omitting inode numbers)\n");
+ printf(" -X ncmd number of calls to the -x command (default 1)\n");
printf(" -H prints usage and exits\n");
}
void inode_info(char *str, size_t sz, struct stat64 *s, int verbose)
{
if (verbose)
- snprintf(str, sz, "[%ld %ld %d %d %lld %lld]", (long)s->st_ino,
+ snprintf(str, sz, "[%ld %ld %d %d %lld %lld]",
+ verifiable_log ? -1: (long)s->st_ino,
(long)s->st_nlink, s->st_uid, s->st_gid,
(long long) s->st_blocks, (long long) s->st_size);
}
bsr.icount=1;
bsr.ubuffer=&t;
bsr.ocount=NULL;
-
e = xfsctl(".", fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
if (v)
printf("%d/%d: bulkstat1 %s ino %lld %d\n",
- procid, opno, good?"real":"random", (long long)ino, e);
+ procid, opno, good?"real":"random",
+ verifiable_log ? -1LL : (long long)ino, e);
close(fd);
}
struct stat64 stb;
int v;
char st[1024];
+ char *dio_env;
init_pathname(&f);
if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
close(fd);
return;
}
+
+ dio_env = getenv("XFS_DIO_MIN");
+ if (dio_env)
+ diob.d_mem = diob.d_miniosz = atoi(dio_env);
+
align = (__int64_t)diob.d_miniosz;
lr = ((__int64_t)random() << 32) + random();
off = (off64_t)(lr % stb.st_size);
struct stat64 stb;
int v;
char st[1024];
+ char *dio_env;
init_pathname(&f);
if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
close(fd);
return;
}
+
+ dio_env = getenv("XFS_DIO_MIN");
+ if (dio_env)
+ diob.d_mem = diob.d_miniosz = atoi(dio_env);
+
align = (__int64_t)diob.d_miniosz;
lr = ((__int64_t)random() << 32) + random();
off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
close(fd);
}
+
+#ifdef HAVE_LINUX_FALLOC_H
+struct print_flags falloc_flags [] = {
+ { FALLOC_FL_KEEP_SIZE, "KEEP_SIZE"},
+ { FALLOC_FL_PUNCH_HOLE, "PUNCH_HOLE"},
+ { FALLOC_FL_NO_HIDE_STALE, "NO_HIDE_STALE"},
+ { FALLOC_FL_COLLAPSE_RANGE, "COLLAPSE_RANGE"},
+ { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"},
+ { -1, NULL}
+};
+
+#define translate_falloc_flags(mode) \
+ ({translate_flags(mode, "|", falloc_flags);})
+#endif
+
void
-fallocate_f(int opno, long r)
+do_fallocate(int opno, long r, int mode)
{
-#ifdef FALLOCATE
+#ifdef HAVE_LINUX_FALLOC_H
int e;
pathname_t f;
int fd;
struct stat64 stb;
int v;
char st[1024];
- int mode = 0;
init_pathname(&f);
if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
if (v)
- printf("%d/%d: fallocate - no filename\n", procid, opno);
+ printf("%d/%d: do_fallocate - no filename\n", procid, opno);
free_pathname(&f);
return;
}
fd = open_path(&f, O_RDWR);
- e = fd < 0 ? errno : 0;
- check_cwd();
if (fd < 0) {
if (v)
- printf("%d/%d: fallocate - open %s failed %d\n",
- procid, opno, f.path, e);
+ printf("%d/%d: do_fallocate - open %s failed %d\n",
+ procid, opno, f.path, errno);
free_pathname(&f);
return;
}
+ check_cwd();
if (fstat64(fd, &stb) < 0) {
if (v)
- printf("%d/%d: fallocate - fstat64 %s failed %d\n",
+ printf("%d/%d: do_fallocate - fstat64 %s failed %d\n",
procid, opno, f.path, errno);
free_pathname(&f);
close(fd);
mode |= FALLOC_FL_KEEP_SIZE & random();
e = fallocate(fd, mode, (loff_t)off, (loff_t)len) < 0 ? errno : 0;
if (v)
- printf("%d/%d: fallocate(%d) %s %st %lld %lld %d\n",
- procid, opno, mode,
+ printf("%d/%d: fallocate(%s) %s %st %lld %lld %d\n",
+ procid, opno, translate_falloc_flags(mode),
f.path, st, (long long)off, (long long)len, e);
free_pathname(&f);
close(fd);
#endif
}
+void
+fallocate_f(int opno, long r)
+{
+#ifdef HAVE_LINUX_FALLOC_H
+ do_fallocate(opno, r, 0);
+#endif
+}
void
fdatasync_f(int opno, long r)
close(fd);
}
+#ifdef HAVE_LINUX_FIEMAP_H
+struct print_flags fiemap_flags[] = {
+ { FIEMAP_FLAG_SYNC, "SYNC"},
+ { FIEMAP_FLAG_XATTR, "XATTR"},
+ { -1, NULL}
+};
+
+#define translate_fiemap_flags(mode) \
+ ({translate_flags(mode, "|", fiemap_flags);})
+#endif
+
+void
+fiemap_f(int opno, long r)
+{
+#ifdef HAVE_LINUX_FIEMAP_H
+ int e;
+ pathname_t f;
+ int fd;
+ __int64_t lr;
+ off64_t off;
+ struct stat64 stb;
+ int v;
+ char st[1024];
+ int blocks_to_map;
+ struct fiemap *fiemap;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: fiemap - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_RDWR);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: fiemap - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ if (fstat64(fd, &stb) < 0) {
+ if (v)
+ printf("%d/%d: fiemap - fstat64 %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ inode_info(st, sizeof(st), &stb, v);
+ blocks_to_map = random() & 0xffff;
+ fiemap = (struct fiemap *)malloc(sizeof(struct fiemap) +
+ (blocks_to_map * sizeof(struct fiemap_extent)));
+ if (!fiemap) {
+ if (v)
+ printf("%d/%d: malloc failed \n", procid, opno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ lr = ((__int64_t)random() << 32) + random();
+ off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
+ off %= maxfsize;
+ fiemap->fm_flags = random() & (FIEMAP_FLAGS_COMPAT | 0x10000);
+ fiemap->fm_extent_count = blocks_to_map;
+ fiemap->fm_mapped_extents = random() & 0xffff;
+ fiemap->fm_start = off;
+ fiemap->fm_length = ((__int64_t)random() << 32) + random();
+
+ e = ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
+ if (v)
+ printf("%d/%d: ioctl(FIEMAP) %s%s %lld %lld (%s) %d\n",
+ procid, opno, f.path, st, (long long)fiemap->fm_start,
+ (long long) fiemap->fm_length,
+ translate_fiemap_flags(fiemap->fm_flags), e);
+ free(fiemap);
+ free_pathname(&f);
+ close(fd);
+#endif
+}
+
void
freesp_f(int opno, long r)
{
void
punch_f(int opno, long r)
{
-#ifdef FALLOCATE
- int e;
- pathname_t f;
- int fd;
- __int64_t lr;
- off64_t off;
- off64_t len;
- struct stat64 stb;
- int v;
- char st[1024];
- int mode = FALLOC_FL_PUNCH_HOLE;
+#ifdef HAVE_LINUX_FALLOC_H
+ do_fallocate(opno, r, FALLOC_FL_PUNCH_HOLE);
+#endif
+}
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: punch hole - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_RDWR);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: punch hole - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- if (fstat64(fd, &stb) < 0) {
- if (v)
- printf("%d/%d: punch hole - fstat64 %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- inode_info(st, sizeof(st), &stb, v);
- lr = ((__int64_t)random() << 32) + random();
- off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
- off %= maxfsize;
- len = (off64_t)(random() % (1024 * 1024));
- mode |= FALLOC_FL_KEEP_SIZE & random();
- e = fallocate(fd, mode, (loff_t)off, (loff_t)len) < 0 ? errno : 0;
- if (v)
- printf("%d/%d: punch hole(%d) %s %s %lld %lld %d\n",
- procid, opno, mode,
- f.path, st, (long long)off, (long long)len, e);
- free_pathname(&f);
- close(fd);
+void
+zero_f(int opno, long r)
+{
+#ifdef HAVE_LINUX_FALLOC_H
+ do_fallocate(opno, r, FALLOC_FL_ZERO_RANGE);
#endif
}