git: 81b7ebe32edd - main - stress2: Added a few regression tests
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 27 Feb 2024 10:05:53 UTC
The branch main has been updated by pho:
URL: https://cgit.FreeBSD.org/src/commit/?id=81b7ebe32edd4be705fe2d50c8d061191ba41573
commit 81b7ebe32edd4be705fe2d50c8d061191ba41573
Author: Peter Holm <pho@FreeBSD.org>
AuthorDate: 2024-02-27 10:05:26 +0000
Commit: Peter Holm <pho@FreeBSD.org>
CommitDate: 2024-02-27 10:05:26 +0000
stress2: Added a few regression tests
---
tools/test/stress2/misc/mapwrite.sh | 189 ++++++++++++++++++++++++++++++++++++
tools/test/stress2/misc/mmap41.sh | 160 ++++++++++++++++++++++++++++++
tools/test/stress2/misc/mmap42.sh | 101 +++++++++++++++++++
tools/test/stress2/misc/mmap43.sh | 182 ++++++++++++++++++++++++++++++++++
4 files changed, 632 insertions(+)
diff --git a/tools/test/stress2/misc/mapwrite.sh b/tools/test/stress2/misc/mapwrite.sh
new file mode 100755
index 000000000000..1fef81942b64
--- /dev/null
+++ b/tools/test/stress2/misc/mapwrite.sh
@@ -0,0 +1,189 @@
+#!/bin/sh
+
+# File corruption scenario
+
+# Test program by Rob Norris <rob norris klarasystems com>
+# Test program obtained from: https://gist.github.com/robn/9804c60cd0275086d26893d73e7af35c
+# https://github.com/openzfs/zfs/issues/15654
+
+[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
+
+. ../default.cfg
+
+set -u
+prog=$(basename "$0" .sh)
+cat > /tmp/$prog.c <<EOF
+/*
+ * Some kind of clone-related crasher. Not sure if legit or just outdated
+ * assertion.
+ *
+ * Creates clone, maps it, writes from map back into itself.
+ *
+ * Compile a recent (2.2+) ZFS with --enable-debug.
+ *
+ * cc -o mapwrite mapwrite.c
+ *
+ * echo 1 > /sys/modules/zfs/parameters/zfs_bclone_enabled
+ * zpool create tank ...
+ * cd /tank
+ * mapwrite
+ *
+ * [ 7.666305] VERIFY(arc_released(db->db_buf)) failed
+ * [ 7.666443] PANIC at dbuf.c:2150:dbuf_redirty()
+ * [ 7.666489] Showing stack for process 608
+ * [ 7.666534] CPU: 1 PID: 608 Comm: mapwrite Tainted: P O 5.10.170 #3
+ * [ 7.666610] Call Trace:
+ * [ 7.666646] dump_stack+0x57/0x6e
+ * [ 7.666717] spl_panic+0xd3/0xfb [spl]
+ * [ 7.667113] ? zfs_btree_find+0x16a/0x300 [zfs]
+ * [ 7.667278] ? range_tree_find_impl+0x55/0xa0 [zfs]
+ * [ 7.667333] ? _cond_resched+0x1a/0x50
+ * [ 7.667371] ? __kmalloc_node+0x14a/0x2b0
+ * [ 7.667415] ? spl_kmem_alloc_impl+0xb0/0xd0 [spl]
+ * [ 7.667555] ? __list_add+0x12/0x30 [zfs]
+ * [ 7.667681] spl_assert+0x17/0x20 [zfs]
+ * [ 7.667807] dbuf_redirty+0xad/0xb0 [zfs]
+ * [ 7.667963] dbuf_dirty+0xe76/0x1310 [zfs]
+ * [ 7.668011] ? mutex_lock+0xe/0x30
+ * [ 7.668133] ? dbuf_noread+0x112/0x240 [zfs]
+ * [ 7.668271] dmu_write_uio_dnode+0x101/0x1b0 [zfs]
+ * [ 7.668411] dmu_write_uio_dbuf+0x4a/0x70 [zfs]
+ * [ 7.668555] zfs_write+0x500/0xc80 [zfs]
+ * [ 7.668610] ? page_add_file_rmap+0xe/0xb0
+ * [ 7.668740] zpl_iter_write+0xe4/0x130 [zfs]
+ * [ 7.668803] new_sync_write+0x119/0x1b0
+ * [ 7.668843] vfs_write+0x1ce/0x260
+ * [ 7.668880] __x64_sys_pwrite64+0x91/0xc0
+ * [ 7.668918] do_syscall_64+0x30/0x40
+ * [ 7.668957] entry_SYSCALL_64_after_hwframe+0x61/0xc6
+ */
+
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#define DATASIZE (1024*1024)
+char data[DATASIZE];
+
+#define NDATA (512)
+
+#define FILE_NAME "file"
+#define CLONE_NAME "clone"
+
+static int
+_create_file(void)
+{
+ memset(data, 0x5a, DATASIZE);
+
+ int fd;
+ if ((fd = open(FILE_NAME, O_RDWR | O_CREAT | O_APPEND,
+ S_IRUSR | S_IWUSR)) < 0) {
+ perror("open '" FILE_NAME "'");
+ abort();
+ }
+
+ for (int i = 0; i < NDATA; i++) {
+ int nwr = write(fd, data, DATASIZE);
+ if (nwr < 0) {
+ perror("write");
+ abort();
+ }
+ if (nwr < DATASIZE) {
+ fprintf(stderr, "short write\n");
+ abort();
+ }
+ }
+
+ if (lseek(fd, 0, SEEK_SET) < 0) {
+ perror("lseek");
+ abort();
+ }
+
+ sync();
+
+ return (fd);
+}
+
+static int
+_clone_file(int sfd)
+{
+ int dfd;
+ if ((dfd = open(CLONE_NAME, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+ perror("open '" CLONE_NAME "'");
+ abort();
+ }
+
+ if (copy_file_range(sfd, 0, dfd, 0, DATASIZE * NDATA, 0) < 0) {
+ perror("copy_file_range");
+ abort();
+ }
+
+ return (dfd);
+}
+
+static void *
+_map_file(int fd)
+{
+ void *p = mmap(NULL, DATASIZE*NDATA, PROT_READ, MAP_SHARED, fd, 0);
+ if (p == MAP_FAILED) {
+ perror("mmap");
+ abort();
+ }
+
+ return (p);
+}
+
+static void
+_map_write(void *p, int fd)
+{
+ if (pwrite(fd, p, DATASIZE, 0) < 0) {
+ perror("pwrite");
+ abort();
+ }
+}
+
+int
+main(void)
+{
+ int sfd = _create_file();
+ int dfd = _clone_file(sfd);
+ void *p = _map_file(dfd);
+ _map_write(p, dfd);
+ return (0);
+}
+EOF
+mycc -o /tmp/$prog -Wall -Wextra -O2 /tmp/$prog.c || exit 1
+
+mount | grep -q "on $mntpoint " && umount -f $mntpoint
+mdconfig -l | grep -q md$mdstart && mdconfig -d -u $mdstart
+mdconfig -s 5g -u $mdstart
+
+newfs -n $newfs_flags /dev/md$mdstart > /dev/null
+mount /dev/md$mdstart $mntpoint
+
+mycc -o /tmp/swap -Wall -Wextra -O0 ../tools/swap.c || exit 1
+timeout -k 90 60 /tmp/swap -d 100 &
+for i in `jot 10`; do
+ capacity=`swapinfo | tail -1 | sed 's/.* //; s/%//'`
+ [ $capacity -gt 1 ] && break
+ sleep 2 # Wait for swapping
+done
+
+cd $mntpoint
+/tmp/$prog; s=$?
+pkill swap
+wait
+cmp $mntpoint/file $mntpoint/clone || { echo Fail; s=1; }
+cd -
+
+umount $mntpoint
+mdconfig -d -u $mdstart
+rm /tmp/$prog /tmp/$prog.c
+exit $s
diff --git a/tools/test/stress2/misc/mmap41.sh b/tools/test/stress2/misc/mmap41.sh
new file mode 100755
index 000000000000..5051681aaf31
--- /dev/null
+++ b/tools/test/stress2/misc/mmap41.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2024 Peter Holm <pho@FreeBSD.org>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+# Based on code from https://syzkaller.appspot.com/text?tag=ReproC&x=15d9baada80000
+# No problems seen
+
+. ../default.cfg
+
+prog=$(basename "$0" .sh)
+odir=`pwd`
+cd /tmp
+sed '1,/^EOF/d' < $odir/$0 > $prog.c
+mycc -o $prog -Wall -Wextra -O0 $prog.c -lpthread || exit 1
+rm -f $prog.c
+
+set -e
+mount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint
+[ -c /dev/md$mdstart ] && mdconfig -d -u $mdstart
+mdconfig -a -t swap -s 2g -u $mdstart
+newfs $newfs_flags md$mdstart > /dev/null
+mount /dev/md$mdstart $mntpoint
+set +e
+
+$odir/../testcases/swap/swap -t 2m -i 10 > /dev/null &
+cd $mntpoint
+/tmp/$prog
+cd $odir
+while pkill swap; do :; done
+wait
+
+for i in `jot 6`; do
+ mount | grep -q "on $mntpoint " || break
+ umount $mntpoint && break || sleep 10
+ [ $i -eq 6 ] &&
+ { echo FATAL; fstat -mf $mntpoint; exit 1; }
+done
+mdconfig -d -u $mdstart
+rm -f /tmp/$prog
+exit 0
+
+EOF
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define DEBUG 0 /* 1 to enable */
+#define THREADS 2
+
+static volatile int go;
+static int fd;
+static char *p, path[128];
+
+#define ADDR (void *) 0x20000000ul
+#define LEN 0x1000000ul
+
+void *
+thr(void *arg)
+{
+ struct iovec iov;
+ long n, w;
+ char *p1;
+
+ if (*(int *)arg == 0) {
+ while (go == 0)
+ usleep(100);
+ while (go == 1) {
+ if ((p1 = mmap(ADDR, LEN, PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+ err(1, "mmap() in %s", __func__);
+ usleep(arc4random() % 50);
+ if ((p1 = mmap(ADDR, LEN, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+ err(1, "mmap() in %s", __func__);
+ usleep(arc4random() % 10000);
+ }
+ } else {
+ while (go == 0)
+ usleep(100);
+ n = w = 0;
+ while (go == 1) {
+ iov.iov_base = p;
+ iov.iov_len = 0x100000;
+ if (pwritev(fd, &iov, 1, 0) != -1)
+ w++;
+ n++;
+ }
+ if (DEBUG == 1)
+ fprintf(stderr, "%ld out of %ld writes (%ld%%)\n", w, n, w * 100 / n);
+ }
+
+
+ return (0);
+}
+
+void
+test(void)
+{
+ pthread_t threads[THREADS];
+ int nr[THREADS];
+ int i, r;
+
+ sprintf(path, "mmap.%06d", getpid());
+ if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0622)) == -1)
+ err(1,"open()");
+
+
+ if ((p = mmap(ADDR, LEN, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+ err(1, "mmap() in %s", __func__);
+
+ go = 0;
+ for (i = 0; i < THREADS; i++) {
+ nr[i] = i;
+ if ((r = pthread_create(&threads[i], NULL, thr,
+ (void *)&nr[i])) != 0)
+ errc(1, r, "pthread_create()");
+ }
+
+ go = 1;
+ sleep(60);
+ go = 2;
+
+ for (i = 0; i < THREADS; i++) {
+ if ((r = pthread_join(threads[i], NULL)) != 0)
+ errc(1, r, "pthread_join(%d)", i);
+ }
+ close(fd);
+ if (DEBUG == 0) {
+ if (unlink(path) == -1)
+ err(1, "unlink(%s)", path);
+ }
+
+ _exit(0);
+}
+
+int
+main(void)
+{
+ pid_t pid;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if ((pid = fork()) == 0)
+ test();
+ if (waitpid(pid, NULL, 0) != pid)
+ err(1, "waitpid()");
+ }
+}
diff --git a/tools/test/stress2/misc/mmap42.sh b/tools/test/stress2/misc/mmap42.sh
new file mode 100755
index 000000000000..11235e581e73
--- /dev/null
+++ b/tools/test/stress2/misc/mmap42.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+
+# Test scenario by: kib@
+# Test program obtained from Kyle Evans <kevans@FreeBSD.org>
+
+# Demonstrate UFS SU file corruption:
+# ffs: on write into a buffer without content
+
+[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
+
+. ../default.cfg
+
+set -u
+prog=$(basename "$0" .sh)
+s=0
+cat > /tmp/$prog.c <<EOF
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define FILE "file"
+
+int
+main(void)
+{
+ struct stat sb;
+ ssize_t wsz;
+ size_t bufsz;
+ void *buf, *obuf;
+ int mfd, fd;
+ int done = 0;
+
+ mfd = open(FILE, O_RDONLY);
+ assert(mfd >= 0);
+
+ assert(fstat(mfd, &sb) == 0);
+ bufsz = sb.st_size;
+ buf = obuf = mmap(NULL, bufsz, PROT_READ, MAP_SHARED, mfd, 0);
+ assert(buf != MAP_FAILED);
+
+ /* O_RDWR */
+ fd = open(FILE, O_RDWR);
+ if (fd < 0)
+ err(1, "open");
+ assert(fd >= 0);
+
+again:
+ while (bufsz > 0) {
+ wsz = write(fd, buf, bufsz);
+ if (wsz < 0)
+ err(1, "write");
+ else if (wsz == 0)
+ fprintf(stderr, "Huh?\n");
+ bufsz -= wsz;
+ buf += wsz;
+ }
+
+ bufsz = sb.st_size;
+ buf = obuf;
+
+ if (++done < 2)
+ goto again;
+
+ close(fd);
+ munmap(obuf, sb.st_size);
+ close(mfd);
+ return (0);
+}
+EOF
+mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1
+
+mount | grep -q "on $mntpoint " && umount -f $mntpoint
+mdconfig -l | grep -q md$mdstart && mdconfig -d -u $mdstart
+mdconfig -s 32m -u $mdstart
+
+pagesize=$(sysctl -n hw.pagesize)
+newfs -Un -b $pagesize /dev/md$mdstart > /dev/null
+mount /dev/md$mdstart $mntpoint
+dd if=/dev/random of=/mnt/file.orig bs=${pagesize} count=1 status=none
+cp $mntpoint/file.orig $mntpoint/file
+cat $mntpoint/file $mntpoint/file > $mntpoint/file.post
+umount $mntpoint
+
+mount /dev/md$mdstart $mntpoint
+(cd $mntpoint; /tmp/$prog)
+
+if ! cmp $mntpoint/file $mntpoint/file.post; then
+ echo "Files differ"
+ ls -l $mntpoint/file $mntpoint/file.post
+ s=1
+fi
+
+umount $mntpoint
+mdconfig -d -u $mdstart
+rm /tmp/$prog /tmp/$prog.c
+exit $s
diff --git a/tools/test/stress2/misc/mmap43.sh b/tools/test/stress2/misc/mmap43.sh
new file mode 100755
index 000000000000..98f1de174d54
--- /dev/null
+++ b/tools/test/stress2/misc/mmap43.sh
@@ -0,0 +1,182 @@
+#!/bin/sh
+
+# Test program obtained from Kyle Evans <kevans@FreeBSD.org>
+
+# Demonstrate UFS SU file corruption
+
+[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
+
+. ../default.cfg
+
+set -u
+prog=$(basename "$0" .sh)
+log=/tmp/$prog.log
+rm -f $log
+cat > /tmp/$prog.c <<EOF
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define FILE "file"
+
+int
+main(void)
+{
+ struct stat sb;
+ ssize_t wsz;
+ size_t bufsz;
+ void *buf, *obuf;
+ int mfd, fd;
+ int done = 0;
+
+ mfd = open(FILE, O_RDONLY);
+ assert(mfd >= 0);
+
+ assert(fstat(mfd, &sb) == 0);
+ bufsz = sb.st_size;
+ buf = obuf = mmap(NULL, bufsz, PROT_READ, MAP_SHARED, mfd, 0);
+ assert(buf != MAP_FAILED);
+
+ /* O_RDWR */
+ fd = open(FILE, O_RDWR);
+ if (fd < 0)
+ err(1, "open");
+ assert(fd >= 0);
+
+again:
+ while (bufsz > 0) {
+ wsz = write(fd, buf, bufsz);
+ if (wsz < 0)
+ err(1, "write");
+ else if (wsz == 0)
+ fprintf(stderr, "Huh?\n");
+ bufsz -= wsz;
+ buf += wsz;
+ }
+
+ bufsz = sb.st_size;
+ buf = obuf;
+
+ if (++done < 2)
+ goto again;
+
+ close(fd);
+ munmap(obuf, sb.st_size);
+ close(mfd);
+ return (0);
+}
+EOF
+mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1
+
+cat > /tmp/$prog.serial.c <<EOF
+/* Fill a file with sequential numbers */
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc, char *argv[])
+{
+ size_t i, size;
+ long ix, *lp;
+ int fd;
+ char *file;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s <file> <file length in bytes>\n", argv[0]);
+ exit(1);
+ }
+ file = argv[1];
+ size = atol(argv[2]);
+
+ if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0)
+ err(1, "%s", file);
+
+ if (lseek(fd, size - 1, SEEK_SET) == -1)
+ err(1, "lseek error");
+
+ /* write a dummy byte at the last location */
+ if (write(fd, "\0", 1) != 1)
+ err(1, "write error");
+
+ if ((lp = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED)
+ err(1, "mmap()");
+
+ for (i = 0, ix = 0; i < size; i += sizeof(long), ix++)
+ lp[ix] = ix;
+
+ if (munmap(lp, size) == -1)
+ err(1, "munmap");
+ close(fd);
+}
+EOF
+mycc -o /tmp/$prog.serial -Wall -Wextra -O0 /tmp/$prog.serial.c || exit 1
+
+mount | grep -q "on $mntpoint " && umount -f $mntpoint
+mdconfig -l | grep -q md$mdstart && mdconfig -d -u $mdstart
+mdconfig -s 5g -u $mdstart
+
+newfs -n $newfs_flags /dev/md$mdstart > /dev/null
+mount /dev/md$mdstart $mntpoint
+
+here=`pwd`
+cd $mntpoint
+
+size=875998990
+pagesize=`sysctl -n hw.pagesize`
+tail=$((size % pagesize))
+/tmp/$prog.serial file $size
+
+cat file file > file.post
+mv file file.orig
+md5=`md5 < file.post`
+
+cp /usr/bin/sort /tmp/$prog.sort
+counter=1
+n=$((`sysctl -n hw.ncpu`))
+[ $n -gt 10 ] && n=10
+s=0
+start=`date +%s`
+while [ $((`date +%s` - start)) -lt 300 ]; do
+ st=`date +%s`
+ cp file.orig file
+ for i in `jot $n`; do
+ timeout -k 70s 1m /tmp/$prog.sort /dev/zero &
+ done
+ sleep $n
+ /tmp/$prog
+ while pkill $prog.sort; do sleep .2; done
+ wait
+ m=`md5 < file`
+ if [ $md5 != $m ]; then
+ echo "Failed @ iteration $counter"
+ ls -l
+ od -t x8 file > /var/tmp/$prog.file1
+ od -t x8 file.post > /var/tmp/$prog.file2
+ diff /var/tmp/$prog.file1 /var/tmp/$prog.file2 > $log
+ head -10 $log
+ rm /var/tmp/$prog.file1 /var/tmp/$prog.file2
+ s=1
+ break
+ fi
+ echo "`date +%T` Loop #$counter, elapsed $((`date +%s` - st)) seconds."
+ counter=$((counter + 1))
+done
+cd $here
+
+umount $mntpoint
+mdconfig -d -u $mdstart
+rm /tmp/$prog /tmp/$prog.c /tmp/$prog.sort
+[ $s -eq 0 ] &&
+ printf "OK File size is %9d, tail is %4d bytes. (%3d loops)\n" $size $tail $counter ||
+ printf "FAIL File size is %9d, tail is %4d bytes. (%3d loops)\n" $size $tail $counter
+exit $s