diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index b8310264a89f..c625f33063c9 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -40,6 +40,10 @@ tests = ['alloc_class_001_pos', 'alloc_class_002_neg', 'alloc_class_003_pos', 'alloc_class_013_pos'] tags = ['functional', 'alloc_class'] +[tests/functional/append] +tests = ['file_append', 'threadsappend_001_pos'] +tags = ['functional', 'append'] + [tests/functional/arc] tests = ['dbufstats_001_pos', 'dbufstats_002_pos', 'dbufstats_003_pos', 'arcstats_runtime_tuning'] @@ -884,10 +888,6 @@ tests = ['suid_write_to_suid', 'suid_write_to_sgid', 'suid_write_to_suid_sgid', 'suid_write_to_none', 'suid_write_zil_replay'] tags = ['functional', 'suid'] -[tests/functional/threadsappend] -tests = ['threadsappend_001_pos'] -tags = ['functional', 'threadsappend'] - [tests/functional/trim] tests = ['autotrim_integrity', 'autotrim_config', 'autotrim_trim_integrity', 'trim_integrity', 'trim_config', 'trim_l2arc'] diff --git a/tests/runfiles/sanity.run b/tests/runfiles/sanity.run index 0ed693c2f4ae..f5dcfa5be4b7 100644 --- a/tests/runfiles/sanity.run +++ b/tests/runfiles/sanity.run @@ -584,7 +584,7 @@ tests = ['suid_write_to_suid', 'suid_write_to_sgid', 'suid_write_to_suid_sgid', 'suid_write_to_none'] tags = ['functional', 'suid'] -[tests/functional/threadsappend] +[tests/functional/append] tests = ['threadsappend_001_pos'] tags = ['functional', 'threadsappend'] diff --git a/tests/test-runner/bin/zts-report.py.in b/tests/test-runner/bin/zts-report.py.in index b0941a4d5f4b..0229d18e2829 100755 --- a/tests/test-runner/bin/zts-report.py.in +++ b/tests/test-runner/bin/zts-report.py.in @@ -235,7 +235,7 @@ maybe = { 'snapshot/snapshot_010_pos': ['FAIL', 7961], 'snapused/snapused_004_pos': ['FAIL', 5513], 'tmpfile/setup': ['SKIP', tmpfile_reason], - 'threadsappend/threadsappend_001_pos': ['FAIL', 6136], + 'append/threadsappend_001_pos': ['FAIL', 6136], 'trim/setup': ['SKIP', trim_reason], 'upgrade/upgrade_projectquota_001_pos': ['SKIP', project_id_reason], 'user_namespace/setup': ['SKIP', user_ns_reason], diff --git a/tests/zfs-tests/cmd/.gitignore b/tests/zfs-tests/cmd/.gitignore index e28fed8f12d8..c2ef0e8c8349 100644 --- a/tests/zfs-tests/cmd/.gitignore +++ b/tests/zfs-tests/cmd/.gitignore @@ -4,6 +4,7 @@ /devname2devid /dir_rd_update /draid +/file_append /file_check /file_trunc /file_write diff --git a/tests/zfs-tests/cmd/file/file_append.c b/tests/zfs-tests/cmd/file/file_append.c new file mode 100644 index 000000000000..32433e4fa2f6 --- /dev/null +++ b/tests/zfs-tests/cmd/file/file_append.c @@ -0,0 +1,206 @@ +/* + * 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 http://www.opensolaris.org/os/licensing. + * 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) 2022 by Triad National Security, LLC + */ + +#include "file_common.h" +#include +#include + +static char *filename = NULL; +static int expected_offset = -1; +static int blocksize = 131072; /* 128KiB */ +static int numblocks = 8; +static const char *execname = "file_append"; +static int use_odirect = 0; + +static void +usage(void) +{ + (void) fprintf(stderr, + "usage %s -f filename -e expected_offset [-b blocksize] \n" + " [-n numblocks] [-d use_odirect] [-h help]\n" + "\n" + "Opens a file using O_APPEND and writes numblocks blocksize\n" + "blocks to filename.\n" + "Checks if expected_offst == lseek(fd, 0, SEEK_CUR)).\n" + "\n" + " filename: File to open with O_APPEND and write to.\n" + " expected_offset: Expected file offset after writing\n" + " blocksize numblocks to filename\n" + " blocksize: Size of each block to writei (must be at\n" + " least >= 512). If using use_odirect (-d)\n" + " must be a mutltiple of _SC_PAGE_SIZE\n" + " numblocks: Total number of blocksized blocks to\n" + " write.\n" + " use_odirect: Open file using O_DIRECT.\n" + " help: Print usage information and exit.\n" + "\n" + " Required parameters:\n" + " filename\n" + " expected_offset\n" + "\n" + " Default values:\n" + " blocksize -> 131072 (128 KiB)\n" + " numblocks -> 8\n" + " use_odirect -> False\n", + execname); + (void) exit(1); +} + +static void +parse_options(int argc, char *argv[]) +{ + int c; + int errflag = 0; + extern char *optarg; + extern int optind, optopt; + + while ((c = getopt(argc, argv, "b:de:f:hn:")) != -1) { + switch (c) { + case 'b': + blocksize = atoi(optarg); + break; + case 'd': + use_odirect = 1; + break; + case 'e': + expected_offset = atoi(optarg); + break; + case 'f': + filename = optarg; + break; + case 'h': + (void) usage(); + break; + case 'n': + numblocks = atoi(optarg); + break; + case ':': + (void) fprintf(stderr, + "Option -%c requires an operand\n", + optopt); + errflag++; + break; + case '?': + default: + (void) fprintf(stderr, + "Unrecognized option: -%c\n", optopt); + errflag++; + break; + } + } + + if (errflag) + (void) usage(); + + if (use_odirect && ((blocksize % sysconf(_SC_PAGE_SIZE)) != 0)) { + (void) fprintf(stderr, + "blocksize parameter invalid when using O_DIRECT.\n"); + (void) usage(); + } + + if (blocksize < 512 || expected_offset < 0 || filename == NULL || + numblocks <= 0) { + (void) fprintf(stderr, + "Required parameters(s) missing or invalid value for " + "parameter.\n"); + (void) usage(); + } +} + +int +main(int argc, char *argv[]) +{ + int err; + const char *datapattern = "0xf00ba3"; + int fd = -1; + int fd_flags = O_WRONLY | O_CREAT | O_APPEND; + int buf_offset = 0; + char *buf; + + parse_options(argc, argv); + + if (use_odirect) + fd_flags |= O_DIRECT; + + fd = open(filename, fd_flags, 0666); + if (fd == -1) { + (void) fprintf(stderr, "%s: %s: ", execname, filename); + perror("open"); + (void) exit(2); + } + + err = posix_memalign((void **)&buf, sysconf(_SC_PAGE_SIZE), + blocksize); + + if (err != 0) { + (void) fprintf(stderr, + "%s: %s\n", execname, strerror(err)); + (void) exit(2); + } + + /* Putting known data pattern in buffer */ + int left = blocksize; + while (left) { + size_t amt = MIN(strlen(datapattern), left); + memcpy(&buf[buf_offset], datapattern, amt); + buf_offset += amt; + left -= amt; + } + + for (int i = 0; i < numblocks; i++) { + int wrote = write(fd, buf, blocksize); + + if (wrote != blocksize) { + if (wrote < 0) { + perror("write"); + } else { + (void) fprintf(stderr, + "%s: unexpected short write, wrote %d " + "byte, expected %d\n", execname, wrote, + blocksize); + } + (void) exit(2); + } + } + + /* Getting current file offset */ + off_t off = lseek(fd, 0, SEEK_CUR); + + if (off == -1) { + perror("output seek"); + (void) exit(2); + } else if (off != expected_offset) { + (void) fprintf(stderr, + "%s: expected offset %d but current offset in %s is set " + "to %ld\n", execname, expected_offset, filename, + (long int)off); + (void) exit(2); + } + + (void) close(fd); + free(buf); + + return (0); +} diff --git a/tests/zfs-tests/include/commands.cfg b/tests/zfs-tests/include/commands.cfg index 6e45d1ffc0af..d51518049e40 100644 --- a/tests/zfs-tests/include/commands.cfg +++ b/tests/zfs-tests/include/commands.cfg @@ -179,6 +179,7 @@ export ZFSTEST_FILES='badsend devname2devid dir_rd_update draid + file_append file_check file_trunc file_write diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am index 355ad727dfe2..2202d9026787 100644 --- a/tests/zfs-tests/tests/Makefile.am +++ b/tests/zfs-tests/tests/Makefile.am @@ -385,6 +385,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/alloc_class/alloc_class_013_pos.ksh \ functional/alloc_class/cleanup.ksh \ functional/alloc_class/setup.ksh \ + functional/append/file_append.ksh \ + functional/append/threadsappend_001_pos.ksh \ + functional/append/cleanup.ksh \ + functional/append/setup.ksh \ functional/arc/arcstats_runtime_tuning.ksh \ functional/arc/cleanup.ksh \ functional/arc/dbufstats_001_pos.ksh \ @@ -1842,9 +1846,6 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/suid/suid_write_to_suid.ksh \ functional/suid/suid_write_to_suid_sgid.ksh \ functional/suid/suid_write_zil_replay.ksh \ - functional/threadsappend/cleanup.ksh \ - functional/threadsappend/setup.ksh \ - functional/threadsappend/threadsappend_001_pos.ksh \ functional/trim/autotrim_config.ksh \ functional/trim/autotrim_integrity.ksh \ functional/trim/autotrim_trim_integrity.ksh \ diff --git a/tests/zfs-tests/tests/functional/threadsappend/cleanup.ksh b/tests/zfs-tests/tests/functional/append/cleanup.ksh similarity index 81% rename from tests/zfs-tests/tests/functional/threadsappend/cleanup.ksh rename to tests/zfs-tests/tests/functional/append/cleanup.ksh index 3166bd6ec16e..307feabd17c6 100755 --- a/tests/zfs-tests/tests/functional/threadsappend/cleanup.ksh +++ b/tests/zfs-tests/tests/functional/append/cleanup.ksh @@ -21,14 +21,9 @@ # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2022 by Triad National Security, LCC # -# -# Copyright (c) 2013 by Delphix. All rights reserved. -# - -. $STF_SUITE/include/libtest.shlib +. ${STF_SUITE}/include/libtest.shlib default_cleanup diff --git a/tests/zfs-tests/tests/functional/append/file_append.ksh b/tests/zfs-tests/tests/functional/append/file_append.ksh new file mode 100755 index 000000000000..b40d10c05edb --- /dev/null +++ b/tests/zfs-tests/tests/functional/append/file_append.ksh @@ -0,0 +1,73 @@ +#!/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 http://www.opensolaris.org/os/licensing. +# 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) 2022 by Triad National Security, LCC +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# Tests file offset using O_APPEND. +# +# STRATEGY: +# 1. Open file using O_APPEND +# 2. Write to the file using random number of blocks (1, 2, or 3) +# 3. Verify that the file offset is correct using lseek after the write +# 4. Repeat steps 2 and 3, 5 times +# 5. Close the file. +# 6. Repeat steps 1-5 but also open file with O_DIRECT +# + +verify_runnable "global" + +log_assert "Ensure file offset is updated correctly when opened with O_APPEND" + +mntpt=$(get_prop mountpoint $TESTPOOL/$TESTFS) +filename=$mntpt/append_file.txt +bs=131072 +ITERATIONS=5 +expected=0 + +# First test using buffered writes with O_APPEND +for i in $(seq $ITERATIONS); do + num_blocks=$(random_int_between 1 3) + expected=$((expected + ( bs * num_blocks))) + log_must file_append -f $filename -e $expected -b $bs -n $num_blocks + curr_offset=$expected +done + +log_must rm -f $filename + +expected=0 + +# Repeat same test using O_DIRECT writes with O_APPEND +for i in $(seq $ITERATIONS); do + num_blocks=$(random_int_between 1 3) + expected=$((expected + ( bs * num_blocks))) + log_must file_append -f $filename -e $expected -b $bs -n $num_blocks -d +done + +log_must rm -f $filename + +log_pass "File offset updated correctly when opening a file with O_APPEND." diff --git a/tests/zfs-tests/tests/functional/threadsappend/setup.ksh b/tests/zfs-tests/tests/functional/append/setup.ksh similarity index 85% rename from tests/zfs-tests/tests/functional/threadsappend/setup.ksh rename to tests/zfs-tests/tests/functional/append/setup.ksh index 4fc55cd47803..e692d7b1bc0c 100755 --- a/tests/zfs-tests/tests/functional/threadsappend/setup.ksh +++ b/tests/zfs-tests/tests/functional/append/setup.ksh @@ -21,12 +21,7 @@ # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# Copyright (c) 2013 by Delphix. All rights reserved. +# Copyright (c) 2022 by Triad National Security, LCC # . $STF_SUITE/include/libtest.shlib diff --git a/tests/zfs-tests/tests/functional/threadsappend/threadsappend_001_pos.ksh b/tests/zfs-tests/tests/functional/append/threadsappend_001_pos.ksh similarity index 100% rename from tests/zfs-tests/tests/functional/threadsappend/threadsappend_001_pos.ksh rename to tests/zfs-tests/tests/functional/append/threadsappend_001_pos.ksh diff --git a/tests/zfs-tests/tests/functional/threadsappend/.gitignore b/tests/zfs-tests/tests/functional/threadsappend/.gitignore deleted file mode 100644 index 4c8c8cdf34c1..000000000000 --- a/tests/zfs-tests/tests/functional/threadsappend/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/threadsappend