@@ -255,6 +255,11 @@ Test control:
load applied to the system during a test by the specified multiple.
- Set TIME_FACTOR to a nonzero positive integer to increase the amount of
time that a test runs by the specified multiple.
+ - For tests that are a member of the "soak" group, setting SOAK_DURATION
+ allows the test runner to specify exactly how long the test should continue
+ running. This setting overrides TIME_FACTOR. Floating point numbers are
+ allowed, and the unit suffixes m(inutes), h(ours), d(ays), and w(eeks) are
+ supported.
Misc:
- If you wish to disable UDF verification test set the environment variable
@@ -366,6 +366,18 @@ if ! . ./common/rc; then
exit 1
fi
+# If the test config specified a soak test duration, see if there are any
+# unit suffixes that need converting to an integer seconds count.
+if [ -n "$SOAK_DURATION" ]; then
+ SOAK_DURATION="$(echo "$SOAK_DURATION" | \
+ sed -e 's/^\([.0-9]*\)\([a-z]\)*/\1 \2/g' | \
+ $AWK_PROG -f $here/src/soak_duration.awk)"
+ if [ $? -ne 0 ]; then
+ status=1
+ exit 1
+ fi
+fi
+
if [ -n "$subdir_xfile" ]; then
for d in $SRC_GROUPS $FSTYP; do
[ -f $SRC_DIR/$d/$subdir_xfile ] || continue
@@ -57,11 +57,13 @@ export SOAK_PROC=3 # -p option to fsstress
export SOAK_STRESS=10000 # -n option to fsstress
export SOAK_PASSES=-1 # count of repetitions of fsstress (while soaking)
export EMAIL=root@localhost # where auto-qa will send its status messages
+
export HOST_OPTIONS=${HOST_OPTIONS:=local.config}
export CHECK_OPTIONS=${CHECK_OPTIONS:="-g auto"}
export BENCH_PASSES=${BENCH_PASSES:=5}
export TIME_FACTOR=${TIME_FACTOR:=1}
export LOAD_FACTOR=${LOAD_FACTOR:=1}
+export SOAK_DURATION=${SOAK_DURATION:=}
export DEBUGFS_MNT=${DEBUGFS_MNT:="/sys/kernel/debug"}
# some constants for overlayfs setup
@@ -1351,7 +1351,12 @@ _scratch_xfs_stress_scrub() {
fi
local start="$(date +%s)"
- local end="$((start + (30 * TIME_FACTOR) ))"
+ local end
+ if [ -n "$SOAK_DURATION" ]; then
+ end="$((start + SOAK_DURATION))"
+ else
+ end="$((start + (30 * TIME_FACTOR) ))"
+ fi
local scrub_startat="$((start + scrub_delay))"
test "$scrub_startat" -gt "$((end - 10))" &&
scrub_startat="$((end - 10))"
@@ -67,6 +67,7 @@ __generate_report_vars() {
REPORT_VARS["CPUS"]="$(getconf _NPROCESSORS_ONLN 2>/dev/null)"
REPORT_VARS["MEM_KB"]="$(grep MemTotal: /proc/meminfo | awk '{print $2}')"
REPORT_VARS["SWAP_KB"]="$(grep SwapTotal: /proc/meminfo | awk '{print $2}')"
+ test -n "$SOAK_DURATION" && REPORT_VARS["SOAK_DURATION"]="$SOAK_DURATION"
test -e /sys/devices/system/node/possible && \
REPORT_VARS["NUMA_NODES"]="$(cat /sys/devices/system/node/possible 2>/dev/null)"
@@ -118,7 +118,8 @@ send btrfs send/receive
shrinkfs decreasing the size of a filesystem
shutdown FS_IOC_SHUTDOWN ioctl
snapshot btrfs snapshots
-soak long running soak tests of any kind
+soak long running soak tests whose runtime can be controlled
+ directly by setting the SOAK_DURATION variable
spaceman xfs_spaceman functional tests
splice splice system call
stress fsstress filesystem exerciser
@@ -386,6 +386,8 @@ char *execute_cmd = NULL;
int execute_freq = 1;
struct print_string flag_str = {0};
+struct timespec deadline = { 0 };
+
void add_to_flist(int, int, int, int);
void append_pathname(pathname_t *, char *);
int attr_list_path(pathname_t *, char *, const int);
@@ -459,6 +461,34 @@ void sg_handler(int signum)
}
}
+bool
+keep_looping(int i, int loops)
+{
+ int ret;
+
+ if (deadline.tv_nsec) {
+ struct timespec now;
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &now);
+ if (ret) {
+ perror("CLOCK_MONOTONIC");
+ return false;
+ }
+
+ return now.tv_sec <= deadline.tv_sec;
+ }
+
+ if (!loops)
+ return true;
+
+ return i < loops;
+}
+
+static struct option longopts[] = {
+ {"duration", optional_argument, 0, 256},
+ { }
+};
+
int main(int argc, char **argv)
{
char buf[10];
@@ -478,13 +508,14 @@ int main(int argc, char **argv)
struct sigaction action;
int loops = 1;
const char *allopts = "cd:e:f:i:l:m:M:n:o:p:rRs:S:vVwx:X:zH";
+ long long duration;
errrange = errtag = 0;
umask(0);
nops = sizeof(ops) / sizeof(ops[0]);
ops_end = &ops[nops];
myprog = argv[0];
- while ((c = getopt(argc, argv, allopts)) != -1) {
+ while ((c = getopt_long(argc, argv, allopts, longopts, NULL)) != -1) {
switch (c) {
case 'c':
cleanup = 1;
@@ -579,6 +610,26 @@ int main(int argc, char **argv)
case 'X':
execute_freq = strtoul(optarg, NULL, 0);
break;
+ case 256: /* --duration */
+ if (!optarg) {
+ fprintf(stderr, "Specify time with --duration=\n");
+ exit(87);
+ }
+ duration = strtoll(optarg, NULL, 0);
+ if (duration < 1) {
+ fprintf(stderr, "%lld: invalid duration\n", duration);
+ exit(88);
+ }
+
+ i = clock_gettime(CLOCK_MONOTONIC, &deadline);
+ if (i) {
+ perror("CLOCK_MONOTONIC");
+ exit(89);
+ }
+
+ deadline.tv_sec += duration;
+ deadline.tv_nsec = 1;
+ break;
case '?':
fprintf(stderr, "%s - invalid parameters\n",
myprog);
@@ -721,7 +772,7 @@ int main(int argc, char **argv)
}
}
#endif
- for (i = 0; !loops || (i < loops); i++)
+ for (i = 0; keep_looping(i, loops); i++)
doproc();
#ifdef AIO
if(io_destroy(io_ctx) != 0) {
@@ -1121,6 +1172,26 @@ dirid_to_fent(int dirid)
return NULL;
}
+bool
+keep_running(opnum_t opno, opnum_t operations)
+{
+ int ret;
+
+ if (deadline.tv_nsec) {
+ struct timespec now;
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &now);
+ if (ret) {
+ perror("CLOCK_MONOTONIC");
+ return false;
+ }
+
+ return now.tv_sec <= deadline.tv_sec;
+ }
+
+ return opno < operations;
+}
+
void
doproc(void)
{
@@ -1149,7 +1220,7 @@ doproc(void)
srandom(seed);
if (namerand)
namerand = random();
- for (opno = 0; opno < operations; opno++) {
+ for (opno = 0; keep_running(opno, operations); opno++) {
if (execute_cmd && opno && opno % dividend == 0) {
if (verbose)
printf("%lld: execute command %s\n", opno,
@@ -1935,6 +2006,7 @@ usage(void)
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");
+ printf(" --duration=s ignore any -n setting and run for this many seconds\n");
}
void
@@ -193,6 +193,8 @@ int fsx_rw(int rw, int fd, char *buf, unsigned len, unsigned offset);
#define fsxread(a,b,c,d) fsx_rw(READ, a,b,c,d)
#define fsxwrite(a,b,c,d) fsx_rw(WRITE, a,b,c,d)
+struct timespec deadline;
+
const char *replayops = NULL;
const char *recordops = NULL;
FILE * fsxlogf = NULL;
@@ -2457,6 +2459,7 @@ usage(void)
-Z: O_DIRECT (use -R, -W, -r and -w too)\n\
--replay-ops opsfile: replay ops from recorded .fsxops file\n\
--record-ops[=opsfile]: dump ops file also on success. optionally specify ops file name\n\
+ --duration=seconds: ignore any -N setting and run for this many seconds\n\
fname: this filename is REQUIRED (no default)\n");
exit(90);
}
@@ -2739,9 +2742,33 @@ __test_fallocate(int mode, const char *mode_str)
#endif
}
+bool
+keep_running(void)
+{
+ int ret;
+
+ if (deadline.tv_nsec) {
+ struct timespec now;
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &now);
+ if (ret) {
+ perror("CLOCK_MONOTONIC");
+ return false;
+ }
+
+ return now.tv_sec <= deadline.tv_sec;
+ }
+
+ if (numops == -1)
+ return true;
+
+ return numops-- != 0;
+}
+
static struct option longopts[] = {
{"replay-ops", required_argument, 0, 256},
{"record-ops", optional_argument, 0, 255},
+ {"duration", optional_argument, 0, 254},
{ }
};
@@ -2753,6 +2780,7 @@ main(int argc, char **argv)
char logfile[PATH_MAX];
struct stat statbuf;
int o_flags = O_RDWR|O_CREAT|O_TRUNC;
+ long long duration;
logfile[0] = 0;
dname[0] = 0;
@@ -2950,6 +2978,26 @@ main(int argc, char **argv)
o_direct = O_DIRECT;
o_flags |= O_DIRECT;
break;
+ case 254: /* --duration */
+ if (!optarg) {
+ fprintf(stderr, "Specify time with --duration=\n");
+ exit(87);
+ }
+ duration = strtoll(optarg, NULL, 0);
+ if (duration < 1) {
+ fprintf(stderr, "%lld: invalid duration\n", duration);
+ exit(88);
+ }
+
+ i = clock_gettime(CLOCK_MONOTONIC, &deadline);
+ if (i) {
+ perror("CLOCK_MONOTONIC");
+ exit(89);
+ }
+
+ deadline.tv_sec += duration;
+ deadline.tv_nsec = 1;
+ break;
case 255: /* --record-ops */
if (optarg)
snprintf(opsfile, sizeof(opsfile), "%s", optarg);
@@ -3145,7 +3193,7 @@ main(int argc, char **argv)
if (xchg_range_calls)
xchg_range_calls = test_xchg_range();
- while (numops == -1 || numops--)
+ while (keep_running())
if (!test())
break;
new file mode 100644
@@ -0,0 +1,23 @@
+#!/usr/bin/awk
+#
+# Convert time interval specifications with suffixes to an integer number of
+# seconds.
+{
+ nr = $1;
+ if ($2 == "" || $2 ~ /s/) # seconds
+ ;
+ else if ($2 ~ /m/) # minutes
+ nr *= 60;
+ else if ($2 ~ /h/) # hours
+ nr *= 3600;
+ else if ($2 ~ /d/) # days
+ nr *= 86400;
+ else if ($2 ~ /w/) # weeks
+ nr *= 604800;
+ else {
+ printf("%s: unknown suffix\n", $2);
+ exit 1;
+ }
+
+ printf("%d\n", nr);
+}
@@ -8,7 +8,7 @@
# bugs in the write path.
#
. ./common/preamble
-_begin_fstest auto rw long_rw stress
+_begin_fstest auto rw long_rw stress soak
# Override the default cleanup function.
_cleanup()
@@ -33,7 +33,10 @@ _scratch_mount >> $seqres.full 2>&1
nr_cpus=$((LOAD_FACTOR * 4))
nr_ops=$((25000 * nr_cpus * TIME_FACTOR))
-$FSSTRESS_PROG $FSSTRESS_AVOID -w -d $SCRATCH_MNT -n $nr_ops -p $nr_cpus >> $seqres.full
+fsstress_args=(-w -d $SCRATCH_MNT -n $nr_ops -p $nr_cpus)
+test -n "$SOAK_DURATION" && fsstress_args+=(--duration="$SOAK_DURATION")
+
+$FSSTRESS_PROG $FSSTRESS_AVOID "${fsstress_args[@]}" >> $seqres.full
# success, all done
status=0
@@ -35,6 +35,7 @@ fsx_args+=(-r $min_dio_sz)
fsx_args+=(-t $min_dio_sz)
fsx_args+=(-w $min_dio_sz)
fsx_args+=(-Z)
+test -n "$SOAK_DURATION" && fsx_args+=(--duration="$SOAK_DURATION")
run_fsx "${fsx_args[@]}" | sed -e '/^fsx.*/d'
@@ -29,6 +29,7 @@ fsx_args+=(-N $nr_ops)
fsx_args+=(-p $((nr_ops / 100)))
fsx_args+=(-o $op_sz)
fsx_args+=(-l $file_sz)
+test -n "$SOAK_DURATION" && fsx_args+=(--duration="$SOAK_DURATION")
run_fsx "${fsx_args[@]}" | sed -e '/^fsx.*/d'
@@ -49,6 +49,7 @@ for verb in attr_remove removefattr; do
done
args+=('-f' "setfattr=20")
args+=('-f' "attr_set=60") # sets larger xattrs
+test -n "$DURATION" && args+=(--duration="$DURATION")
$FSSTRESS_PROG "${args[@]}" $FSSTRESS_AVOID -d $SCRATCH_MNT -n $nr_ops -p $nr_cpus >> $seqres.full