Adding ZTS test for O_APPEND
Commit 63b18e4
fixed an issue in zpl_aio_write() to make sure that
kiocb->ki_pos was updated correctly when opening a file with O_APPEND.
Adding a test to verify O_APPEND functionality with lseek can make
sure that all other distros/kernel versions also have the correct
behavior.
Also moved the threadappends_001_pos test into this append test
directory in functional ZTS directory. This way the two append tests
are together for organization purposes.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Brian Atkinson <batkinson@lanl.gov>
Closes #13424
This commit is contained in:
parent
3ed04d66aa
commit
f567d67fda
|
@ -40,6 +40,10 @@ tests = ['alloc_class_001_pos', 'alloc_class_002_neg', 'alloc_class_003_pos',
|
||||||
'alloc_class_013_pos']
|
'alloc_class_013_pos']
|
||||||
tags = ['functional', 'alloc_class']
|
tags = ['functional', 'alloc_class']
|
||||||
|
|
||||||
|
[tests/functional/append]
|
||||||
|
tests = ['file_append', 'threadsappend_001_pos']
|
||||||
|
tags = ['functional', 'append']
|
||||||
|
|
||||||
[tests/functional/arc]
|
[tests/functional/arc]
|
||||||
tests = ['dbufstats_001_pos', 'dbufstats_002_pos', 'dbufstats_003_pos',
|
tests = ['dbufstats_001_pos', 'dbufstats_002_pos', 'dbufstats_003_pos',
|
||||||
'arcstats_runtime_tuning']
|
'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']
|
'suid_write_to_none', 'suid_write_zil_replay']
|
||||||
tags = ['functional', 'suid']
|
tags = ['functional', 'suid']
|
||||||
|
|
||||||
[tests/functional/threadsappend]
|
|
||||||
tests = ['threadsappend_001_pos']
|
|
||||||
tags = ['functional', 'threadsappend']
|
|
||||||
|
|
||||||
[tests/functional/trim]
|
[tests/functional/trim]
|
||||||
tests = ['autotrim_integrity', 'autotrim_config', 'autotrim_trim_integrity',
|
tests = ['autotrim_integrity', 'autotrim_config', 'autotrim_trim_integrity',
|
||||||
'trim_integrity', 'trim_config', 'trim_l2arc']
|
'trim_integrity', 'trim_config', 'trim_l2arc']
|
||||||
|
|
|
@ -584,7 +584,7 @@ tests = ['suid_write_to_suid', 'suid_write_to_sgid', 'suid_write_to_suid_sgid',
|
||||||
'suid_write_to_none']
|
'suid_write_to_none']
|
||||||
tags = ['functional', 'suid']
|
tags = ['functional', 'suid']
|
||||||
|
|
||||||
[tests/functional/threadsappend]
|
[tests/functional/append]
|
||||||
tests = ['threadsappend_001_pos']
|
tests = ['threadsappend_001_pos']
|
||||||
tags = ['functional', 'threadsappend']
|
tags = ['functional', 'threadsappend']
|
||||||
|
|
||||||
|
|
|
@ -236,7 +236,7 @@ maybe = {
|
||||||
'snapshot/snapshot_010_pos': ['FAIL', 7961],
|
'snapshot/snapshot_010_pos': ['FAIL', 7961],
|
||||||
'snapused/snapused_004_pos': ['FAIL', 5513],
|
'snapused/snapused_004_pos': ['FAIL', 5513],
|
||||||
'tmpfile/setup': ['SKIP', tmpfile_reason],
|
'tmpfile/setup': ['SKIP', tmpfile_reason],
|
||||||
'threadsappend/threadsappend_001_pos': ['FAIL', 6136],
|
'append/threadsappend_001_pos': ['FAIL', 6136],
|
||||||
'trim/setup': ['SKIP', trim_reason],
|
'trim/setup': ['SKIP', trim_reason],
|
||||||
'upgrade/upgrade_projectquota_001_pos': ['SKIP', project_id_reason],
|
'upgrade/upgrade_projectquota_001_pos': ['SKIP', project_id_reason],
|
||||||
'user_namespace/setup': ['SKIP', user_ns_reason],
|
'user_namespace/setup': ['SKIP', user_ns_reason],
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
/devname2devid
|
/devname2devid
|
||||||
/dir_rd_update
|
/dir_rd_update
|
||||||
/draid
|
/draid
|
||||||
|
/file_append
|
||||||
/file_check
|
/file_check
|
||||||
/file_trunc
|
/file_trunc
|
||||||
/file_write
|
/file_write
|
||||||
|
|
|
@ -41,9 +41,9 @@ scripts_zfs_tests_bin_PROGRAMS += %D%/draid
|
||||||
libnvpair.la
|
libnvpair.la
|
||||||
%C%_draid_LDADD += $(ZLIB_LIBS)
|
%C%_draid_LDADD += $(ZLIB_LIBS)
|
||||||
|
|
||||||
|
|
||||||
EXTRA_DIST += $(addprefix %D%/,file/file_common.h)
|
EXTRA_DIST += $(addprefix %D%/,file/file_common.h)
|
||||||
scripts_zfs_tests_bin_PROGRAMS += %D%/file_check %D%/file_trunc %D%/file_write %D%/largest_file %D%/randwritecomp
|
scripts_zfs_tests_bin_PROGRAMS += %D%/file_append %D%/file_check %D%/file_trunc %D%/file_write %D%/largest_file %D%/randwritecomp
|
||||||
|
%C%_file_append_SOURCES = %D%/file/file_append.c
|
||||||
%C%_file_check_SOURCES = %D%/file/file_check.c
|
%C%_file_check_SOURCES = %D%/file/file_check.c
|
||||||
%C%_file_trunc_SOURCES = %D%/file/file_trunc.c
|
%C%_file_trunc_SOURCES = %D%/file/file_trunc.c
|
||||||
%C%_file_write_SOURCES = %D%/file/file_write.c
|
%C%_file_write_SOURCES = %D%/file/file_write.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 <unistd.h>
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
|
@ -179,6 +179,7 @@ export ZFSTEST_FILES='badsend
|
||||||
devname2devid
|
devname2devid
|
||||||
dir_rd_update
|
dir_rd_update
|
||||||
draid
|
draid
|
||||||
|
file_append
|
||||||
file_check
|
file_check
|
||||||
file_trunc
|
file_trunc
|
||||||
file_write
|
file_write
|
||||||
|
|
|
@ -385,6 +385,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||||
functional/alloc_class/alloc_class_013_pos.ksh \
|
functional/alloc_class/alloc_class_013_pos.ksh \
|
||||||
functional/alloc_class/cleanup.ksh \
|
functional/alloc_class/cleanup.ksh \
|
||||||
functional/alloc_class/setup.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/arcstats_runtime_tuning.ksh \
|
||||||
functional/arc/cleanup.ksh \
|
functional/arc/cleanup.ksh \
|
||||||
functional/arc/dbufstats_001_pos.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.ksh \
|
||||||
functional/suid/suid_write_to_suid_sgid.ksh \
|
functional/suid/suid_write_to_suid_sgid.ksh \
|
||||||
functional/suid/suid_write_zil_replay.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_config.ksh \
|
||||||
functional/trim/autotrim_integrity.ksh \
|
functional/trim/autotrim_integrity.ksh \
|
||||||
functional/trim/autotrim_trim_integrity.ksh \
|
functional/trim/autotrim_trim_integrity.ksh \
|
||||||
|
|
|
@ -21,14 +21,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
# Copyright (c) 2022 by Triad National Security, LCC
|
||||||
# Use is subject to license terms.
|
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
. ${STF_SUITE}/include/libtest.shlib
|
||||||
# Copyright (c) 2013 by Delphix. All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
. $STF_SUITE/include/libtest.shlib
|
|
||||||
|
|
||||||
default_cleanup
|
default_cleanup
|
|
@ -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."
|
|
@ -21,12 +21,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
# Copyright (c) 2022 by Triad National Security, LCC
|
||||||
# Use is subject to license terms.
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright (c) 2013 by Delphix. All rights reserved.
|
|
||||||
#
|
#
|
||||||
|
|
||||||
. $STF_SUITE/include/libtest.shlib
|
. $STF_SUITE/include/libtest.shlib
|
|
@ -1 +0,0 @@
|
||||||
/threadsappend
|
|
Loading…
Reference in New Issue