Skip to content

Commit

Permalink
ZTS: Add dirty dnode stress test
Browse files Browse the repository at this point in the history
Add a test for the dirty dnode SEEK_HOLE/SEEK_DATA bug described in
openzfs#15526

The bug was fixed in openzfs#15571 and
was backported to 2.2.2 and 2.1.14.  This test case is just to
make sure it does not come back.

seekflood.c originally written by Rob Norris.

Signed-off-by: Tony Hutter <hutter2@llnl.gov>
  • Loading branch information
tonyhutter committed Dec 5, 2023
1 parent 6b65af1 commit d8973c3
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 17 deletions.
2 changes: 1 addition & 1 deletion tests/runfiles/common.run
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ tests = ['compress_001_pos', 'compress_002_pos', 'compress_003_pos',
tags = ['functional', 'compression']

[tests/functional/cp_files]
tests = ['cp_files_001_pos']
tests = ['cp_files_001_pos', 'cp_stress']
tags = ['functional', 'cp_files']

[tests/functional/crtime]
Expand Down
1 change: 1 addition & 0 deletions tests/zfs-tests/tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -1365,6 +1365,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/compression/setup.ksh \
functional/cp_files/cleanup.ksh \
functional/cp_files/cp_files_001_pos.ksh \
functional/cp_files/cp_stress.ksh \
functional/cp_files/setup.ksh \
functional/crtime/cleanup.ksh \
functional/crtime/crtime_001_pos.ksh \
Expand Down
64 changes: 64 additions & 0 deletions tests/zfs-tests/tests/functional/cp_files/cp_stress.ksh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#! /bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END

#
# Copyright (c) 2023 by Lawrence Livermore National Security, LLC.
#

. $STF_SUITE/include/libtest.shlib

#
# DESCRIPTION:
# This test is for the dirty dnode SEEK_HOLE/SEEK_DATA bug described in
# https://github.com/openzfs/zfs/issues/15526
#
# The bug was fixed in https://github.com/openzfs/zfs/pull/15571 and
# was backported to 2.2.2 and 2.1.14. This test case is just to
# make sure it does not come back.
#
# STRATEGY:
#
# 1. Run the 'seekflood' binary to create files with specific timing
# characteristics to trigger #15526.
# 2. Run seekflood multiple times as seekflood doesn't always trigger it.

verify_runnable "global"

function cleanup
{
rm -rf /$TESTDIR/cp_stress
}

log_assert "Run 'seekflood' binary multiple times to try to trigger #15526"

log_onexit cleanup

log_must mkdir /$TESTPOOL/cp_stress

MYPWD="$PWD"
cd /$TESTPOOL/cp_stress
CPUS=$(get_num_cpus)
for i in $(seq 1 10) ; do
log_must $STF_SUITE/tests/functional/cp_files/seekflood 2000 $CPUS
done
cd "$MYPWD"

log_pass "No corruption detected"
37 changes: 21 additions & 16 deletions tests/zfs-tests/tests/functional/cp_files/seekflood.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
*
*/

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <fcntl.h>
#include <unistd.h>
Expand All @@ -34,7 +36,7 @@
#include <sys/stat.h>
#include <sys/wait.h>

#define DATASIZE (1024*129)
#define DATASIZE (4096)
char data[DATASIZE];

static int
Expand All @@ -47,9 +49,9 @@ _open_file(int n, int wr)

if ((fd = open(buf, wr ? (O_WRONLY | O_CREAT) : O_RDONLY,
wr ? (S_IRUSR | S_IWUSR) : 0)) < 0) {
fprintf(stderr, "E: open '%s' (%s): %s\n",
fprintf(stderr, "Error: open '%s' (%s): %s\n",
buf, wr ? "write" : "read", strerror(errno));
abort();
exit(1);
}

return (fd);
Expand All @@ -61,12 +63,13 @@ _write_file(int n, int fd)
/* write a big ball of stuff */
ssize_t nwr = write(fd, data, DATASIZE);
if (nwr < 0) {
fprintf(stderr, "E: write '%d_%d': %s\n",
fprintf(stderr, "Error: write '%d_%d': %s\n",
getpid(), n, strerror(errno));
abort();
exit(1);
} else if (nwr < DATASIZE) {
fprintf(stderr, "E: write '%d_%d': short write\n", getpid(), n);
abort();
fprintf(stderr, "Error: write '%d_%d': short write\n", getpid(),
n);
exit(1);
}
}

Expand All @@ -75,9 +78,9 @@ _seek_file(int n, int fd)
{
struct stat st;
if (fstat(fd, &st) < 0) {
fprintf(stderr, "E: fstat '%d_%d': %s\n", getpid(), n,
fprintf(stderr, "Error: fstat '%d_%d': %s\n", getpid(), n,
strerror(errno));
abort();
exit(1);
}

/* zero sized file rightly has no data, so no point seeking it */
Expand All @@ -88,15 +91,16 @@ _seek_file(int n, int fd)
if (lseek(fd, 0, SEEK_DATA) < 0) {
if (errno == ENXIO)
return (1);
fprintf(stderr, "E: lseek '%d_%d': %s\n",
fprintf(stderr, "Error: lseek '%d_%d': %s\n",
getpid(), n, strerror(errno));
abort();
exit(2);
}

return (0);
}

int main(int argc, char **argv)
int
main(int argc, char **argv)
{
int nfiles = 0;
int nthreads = 0;
Expand Down Expand Up @@ -159,13 +163,14 @@ int main(int argc, char **argv)
}

if (crashed) {
fprintf(stderr, "E: child crashed; test failed\n");
abort();
fprintf(stderr, "Error: child crashed; test failed\n");
exit(1);
}

if (count) {
fprintf(stderr, "E: %d seek failures; test failed\n", count);
abort();
fprintf(stderr, "Error: %d seek failures; test failed\n",
count);
exit(1);
}

exit(0);
Expand Down

0 comments on commit d8973c3

Please sign in to comment.