Notable upstream pull request merges:
 #15643 a9b937e06 For db_marker inherit the db pointer for AVL comparision
 #15644 e53e60c0b DMU: Fix lock leak on dbuf_hold() error
 #15653 86063d903 dbuf: Handle arcbuf assignment after block cloning
 #15656 86e115e21 dbuf: Set dr_data when unoverriding after clone

Obtained from:	OpenZFS
OpenZFS commit:	86e115e21e
This commit is contained in:
Martin Matuska 2023-12-15 14:17:23 +01:00
commit 5fb307d29b
22 changed files with 582 additions and 18 deletions

View file

@ -5,7 +5,7 @@
#
# Bad SCSI disks can often "disappear and reappear" causing all sorts of chaos
# as they flip between FAULTED and ONLINE. If
# ZED_POWER_OFF_ENCLOUSRE_SLOT_ON_FAULT is set in zed.rc, and the disk gets
# ZED_POWER_OFF_ENCLOSURE_SLOT_ON_FAULT is set in zed.rc, and the disk gets
# FAULTED, then power down the slot via sysfs:
#
# /sys/class/enclosure/<enclosure>/<slot>/power_status
@ -19,7 +19,7 @@
# Exit codes:
# 0: slot successfully powered off
# 1: enclosure not available
# 2: ZED_POWER_OFF_ENCLOUSRE_SLOT_ON_FAULT disabled
# 2: ZED_POWER_OFF_ENCLOSURE_SLOT_ON_FAULT disabled
# 3: vdev was not FAULTED
# 4: The enclosure sysfs path passed from ZFS does not exist
# 5: Enclosure slot didn't actually turn off after we told it to
@ -32,7 +32,7 @@ if [ ! -d /sys/class/enclosure ] ; then
exit 1
fi
if [ "${ZED_POWER_OFF_ENCLOUSRE_SLOT_ON_FAULT}" != "1" ] ; then
if [ "${ZED_POWER_OFF_ENCLOSURE_SLOT_ON_FAULT}" != "1" ] ; then
exit 2
fi

View file

@ -146,7 +146,7 @@ ZED_SYSLOG_SUBCLASS_EXCLUDE="history_event"
# Power off the drive's slot in the enclosure if it becomes FAULTED. This can
# help silence misbehaving drives. This assumes your drive enclosure fully
# supports slot power control via sysfs.
#ZED_POWER_OFF_ENCLOUSRE_SLOT_ON_FAULT=1
#ZED_POWER_OFF_ENCLOSURE_SLOT_ON_FAULT=1
##
# Ntfy topic

View file

@ -79,6 +79,7 @@ extern "C" {
* dbuf_states_t (see comment on dn_dbufs in dnode.h).
*/
typedef enum dbuf_states {
DB_MARKER = -2,
DB_SEARCH = -1,
DB_UNCACHED,
DB_FILL,

View file

@ -1919,7 +1919,6 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
dmu_buf_impl_t *db = dr->dr_dbuf;
blkptr_t *bp = &dr->dt.dl.dr_overridden_by;
uint64_t txg = dr->dr_txg;
boolean_t release;
ASSERT(MUTEX_HELD(&db->db_mtx));
/*
@ -1940,7 +1939,10 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
if (!BP_IS_HOLE(bp) && !dr->dt.dl.dr_nopwrite)
zio_free(db->db_objset->os_spa, txg, bp);
release = !dr->dt.dl.dr_brtwrite;
if (dr->dt.dl.dr_brtwrite) {
ASSERT0P(dr->dt.dl.dr_data);
dr->dt.dl.dr_data = db->db_buf;
}
dr->dt.dl.dr_override_state = DR_NOT_OVERRIDDEN;
dr->dt.dl.dr_nopwrite = B_FALSE;
dr->dt.dl.dr_brtwrite = B_FALSE;
@ -1954,7 +1956,7 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
* the buf thawed to save the effort of freezing &
* immediately re-thawing it.
*/
if (release)
if (dr->dt.dl.dr_data)
arc_release(dr->dt.dl.dr_data, db);
}
@ -2945,7 +2947,8 @@ dbuf_assign_arcbuf(dmu_buf_impl_t *db, arc_buf_t *buf, dmu_tx_t *tx)
while (db->db_state == DB_READ || db->db_state == DB_FILL)
cv_wait(&db->db_changed, &db->db_mtx);
ASSERT(db->db_state == DB_CACHED || db->db_state == DB_UNCACHED);
ASSERT(db->db_state == DB_CACHED || db->db_state == DB_UNCACHED ||
db->db_state == DB_NOFILL);
if (db->db_state == DB_CACHED &&
zfs_refcount_count(&db->db_holds) - 1 > db->db_dirtycnt) {
@ -2982,6 +2985,15 @@ dbuf_assign_arcbuf(dmu_buf_impl_t *db, arc_buf_t *buf, dmu_tx_t *tx)
arc_buf_destroy(db->db_buf, db);
}
db->db_buf = NULL;
} else if (db->db_state == DB_NOFILL) {
/*
* We will be completely replacing the cloned block. In case
* it was cloned in this transaction group, let's undirty the
* pending clone and mark the block as uncached. This will be
* as if the clone was never done.
*/
VERIFY(!dbuf_undirty(db, tx));
db->db_state = DB_UNCACHED;
}
ASSERT(db->db_buf == NULL);
dbuf_set_data(db, buf);

View file

@ -1501,9 +1501,9 @@ dmu_assign_arcbuf_by_dnode(dnode_t *dn, uint64_t offset, arc_buf_t *buf,
rw_enter(&dn->dn_struct_rwlock, RW_READER);
blkid = dbuf_whichblock(dn, 0, offset);
db = dbuf_hold(dn, blkid, FTAG);
rw_exit(&dn->dn_struct_rwlock);
if (db == NULL)
return (SET_ERROR(EIO));
rw_exit(&dn->dn_struct_rwlock);
/*
* We can only assign if the offset is aligned and the arc buf is the

View file

@ -99,6 +99,14 @@ dbuf_compare(const void *x1, const void *x2)
if (likely(cmp))
return (cmp);
if (d1->db_state == DB_MARKER) {
ASSERT3S(d2->db_state, !=, DB_MARKER);
return (TREE_PCMP(d1->db_parent, d2));
} else if (d2->db_state == DB_MARKER) {
ASSERT3S(d1->db_state, !=, DB_MARKER);
return (TREE_PCMP(d1, d2->db_parent));
}
if (d1->db_state == DB_SEARCH) {
ASSERT3S(d2->db_state, !=, DB_SEARCH);
return (-1);

View file

@ -482,7 +482,14 @@ dnode_evict_dbufs(dnode_t *dn)
zfs_refcount_is_zero(&db->db_holds)) {
db_marker->db_level = db->db_level;
db_marker->db_blkid = db->db_blkid;
db_marker->db_state = DB_SEARCH;
/*
* Insert a MARKER node with the same level and blkid.
* And to resolve any ties in dbuf_compare() use the
* pointer of the dbuf that we are evicting. Pass the
* address in db_parent.
*/
db_marker->db_state = DB_MARKER;
db_marker->db_parent = (void *)((uintptr_t)db - 1);
avl_insert_here(&dn->dn_dbufs, db_marker, db,
AVL_BEFORE);

View file

@ -598,7 +598,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]

View file

@ -43,7 +43,8 @@ tests = ['block_cloning_copyfilerange', 'block_cloning_copyfilerange_partial',
'block_cloning_disabled_ficlonerange',
'block_cloning_copyfilerange_cross_dataset',
'block_cloning_cross_enc_dataset',
'block_cloning_copyfilerange_fallback_same_txg']
'block_cloning_copyfilerange_fallback_same_txg',
'block_cloning_replay', 'block_cloning_replay_encrypted']
tags = ['functional', 'block_cloning']
[tests/functional/chattr:Linux]

View file

@ -301,6 +301,10 @@ elif sys.platform.startswith('linux'):
['SKIP', cfr_reason],
'block_cloning/block_cloning_copyfilerange_fallback':
['SKIP', cfr_reason],
'block_cloning/block_cloning_replay':
['SKIP', cfr_reason],
'block_cloning/block_cloning_replay_encrypted':
['SKIP', cfr_reason],
'block_cloning/block_cloning_copyfilerange_cross_dataset':
['SKIP', cfr_cross_reason],
'block_cloning/block_cloning_copyfilerange_fallback_same_txg':
@ -309,7 +313,6 @@ elif sys.platform.startswith('linux'):
['SKIP', cfr_cross_reason],
})
# Not all Github actions runners have scsi_debug module, so we may skip
# some tests which use it.
if os.environ.get('CI') == 'true':

View file

@ -13,6 +13,9 @@ scripts_zfs_tests_functional_hkdf_PROGRAMS = %D%/tests/functional/hkdf/hkdf_test
%C%_tests_functional_hkdf_hkdf_test_LDADD = \
libzpool.la
scripts_zfs_tests_functional_cp_filesdir = $(datadir)/$(PACKAGE)/zfs-tests/tests/functional/cp_files
scripts_zfs_tests_functional_cp_files_PROGRAMS = %D%/tests/functional/cp_files/seekflood
if BUILD_LINUX
scripts_zfs_tests_functional_tmpfiledir = $(datadir)/$(PACKAGE)/zfs-tests/tests/functional/tmpfile
scripts_zfs_tests_functional_tmpfile_PROGRAMS = \

View file

@ -452,6 +452,8 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/block_cloning/block_cloning_ficlonerange.ksh \
functional/block_cloning/block_cloning_ficlonerange_partial.ksh \
functional/block_cloning/block_cloning_cross_enc_dataset.ksh \
functional/block_cloning/block_cloning_replay.ksh \
functional/block_cloning/block_cloning_replay_encrypted.ksh \
functional/bootfs/bootfs_001_pos.ksh \
functional/bootfs/bootfs_002_neg.ksh \
functional/bootfs/bootfs_003_pos.ksh \
@ -1113,6 +1115,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zpool_import/zpool_import_missing_002_pos.ksh \
functional/cli_root/zpool_import/zpool_import_missing_003_pos.ksh \
functional/cli_root/zpool_import/zpool_import_rename_001_pos.ksh \
functional/cli_root/zpool_import/zpool_import_status.ksh \
functional/cli_root/zpool_initialize/cleanup.ksh \
functional/cli_root/zpool_initialize/zpool_initialize_attach_detach_add_remove.ksh \
functional/cli_root/zpool_initialize/zpool_initialize_fault_export_import_online.ksh \
@ -1366,6 +1369,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 \

View file

@ -53,6 +53,6 @@ function get_same_blocks
awk '/ L0 / { print l++ " " $3 " " $7 }' > $zdbout.a
zdb $KEY -vvvvv $3 -O $4 | \
awk '/ L0 / { print l++ " " $3 " " $7 }' > $zdbout.b
echo $(sort $zdbout.a $zdbout.b | uniq -d | cut -f1 -d' ')
echo $(sort -n $zdbout.a $zdbout.b | uniq -d | cut -f1 -d' ')
}

View file

@ -0,0 +1,131 @@
#!/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
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/block_cloning/block_cloning.kshlib
#
# DESCRIPTION:
# Verify slogs are replayed correctly for cloned files. This
# test is ported from slog_replay tests for block cloning.
#
# STRATEGY:
# 1. Create an empty file system (TESTFS)
# 2. Create regular files and sync
# 3. Freeze TESTFS
# 4. Clone the file
# 5. Unmount filesystem
# <At this stage TESTFS is frozen, the intent log contains a
# complete set of deltas to replay it>
# 6. Remount TESTFS <which replays the intent log>
# 7. Compare clone file with the original file
#
verify_runnable "global"
if [[ $(linux_version) -lt $(linux_version "4.5") ]]; then
log_unsupported "copy_file_range not available before Linux 4.5"
fi
export VDIR=$TEST_BASE_DIR/disk-bclone
export VDEV="$VDIR/a $VDIR/b $VDIR/c"
export LDEV="$VDIR/e $VDIR/f"
log_must rm -rf $VDIR
log_must mkdir -p $VDIR
log_must truncate -s $MINVDEVSIZE $VDEV $LDEV
claim="The slogs are replayed correctly for cloned files."
log_assert $claim
function cleanup
{
datasetexists $TESTPOOL && destroy_pool $TESTPOOL
rm -rf $TESTDIR $VDIR $VDIR2
}
log_onexit cleanup
#
# 1. Create an empty file system (TESTFS)
#
log_must zpool create -o feature@block_cloning=enabled $TESTPOOL $VDEV \
log mirror $LDEV
log_must zfs create $TESTPOOL/$TESTFS
#
# 2. TX_WRITE: Create two files and sync txg
#
log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS/file1 \
oflag=sync bs=128k count=4
log_must zfs set recordsize=16K $TESTPOOL/$TESTFS
log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS/file2 \
oflag=sync bs=16K count=2048
sync_pool $TESTPOOL
#
# 3. Checkpoint for ZIL Replay
#
log_must zpool freeze $TESTPOOL
#
# 4. TX_CLONE_RANGE: Clone the file
#
log_must clonefile -c /$TESTPOOL/$TESTFS/file1 /$TESTPOOL/$TESTFS/clone1
log_must clonefile -c /$TESTPOOL/$TESTFS/file2 /$TESTPOOL/$TESTFS/clone2
#
# 5. Unmount filesystem and export the pool
#
# At this stage TESTFS is frozen, the intent log contains a complete set
# of deltas to replay for clone files.
#
log_must zfs unmount /$TESTPOOL/$TESTFS
log_note "Verify transactions to replay:"
log_must zdb -iv $TESTPOOL/$TESTFS
log_must zpool export $TESTPOOL
#
# 6. Remount TESTFS <which replays the intent log>
#
# Import the pool to unfreeze it and claim log blocks. It has to be
# `zpool import -f` because we can't write a frozen pool's labels!
#
log_must zpool import -f -d $VDIR $TESTPOOL
#
# 7. Compare clone file with the original file
#
log_must have_same_content /$TESTPOOL/$TESTFS/file1 /$TESTPOOL/$TESTFS/clone1
log_must have_same_content /$TESTPOOL/$TESTFS/file2 /$TESTPOOL/$TESTFS/clone2
typeset blocks=$(get_same_blocks $TESTPOOL/$TESTFS file1 \
$TESTPOOL/$TESTFS clone1)
log_must [ "$blocks" = "0 1 2 3" ]
typeset blocks=$(get_same_blocks $TESTPOOL/$TESTFS file2 \
$TESTPOOL/$TESTFS clone2)
log_must [ "$blocks" = "$(seq -s " " 0 2047)" ]
log_pass $claim

View file

@ -0,0 +1,133 @@
#!/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
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/block_cloning/block_cloning.kshlib
#
# DESCRIPTION:
# Verify slogs are replayed correctly for encrypted cloned files.
# This test is ported from slog_replay tests for block cloning.
#
# STRATEGY:
# 1. Create an encrypted file system (TESTFS)
# 2. Create regular files and sync
# 3. Freeze TESTFS
# 4. Clone the file
# 5. Unmount filesystem
# <At this stage TESTFS is frozen, the intent log contains a
# complete set of deltas to replay it>
# 6. Remount encrypted TESTFS <which replays the intent log>
# 7. Compare clone file with the original file
#
verify_runnable "global"
if [[ $(linux_version) -lt $(linux_version "4.5") ]]; then
log_unsupported "copy_file_range not available before Linux 4.5"
fi
export VDIR=$TEST_BASE_DIR/disk-bclone
export VDEV="$VDIR/a $VDIR/b $VDIR/c"
export LDEV="$VDIR/e $VDIR/f"
log_must rm -rf $VDIR
log_must mkdir -p $VDIR
log_must truncate -s $MINVDEVSIZE $VDEV $LDEV
export PASSPHRASE="password"
claim="The slogs are replayed correctly for encrypted cloned files."
log_assert $claim
function cleanup
{
datasetexists $TESTPOOL && destroy_pool $TESTPOOL
rm -rf $TESTDIR $VDIR $VDIR2
}
log_onexit cleanup
#
# 1. Create an encrypted file system (TESTFS)
#
log_must zpool create -o feature@block_cloning=enabled $TESTPOOL $VDEV \
log mirror $LDEV
log_must eval "echo $PASSPHRASE | zfs create -o encryption=on" \
"-o keyformat=passphrase -o keylocation=prompt $TESTPOOL/$TESTFS"
#
# 2. TX_WRITE: Create two files and sync txg
#
log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS/file1 \
oflag=sync bs=128k count=4
log_must zfs set recordsize=16K $TESTPOOL/$TESTFS
log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS/file2 \
oflag=sync bs=16K count=2048
sync_pool $TESTPOOL
#
# 3. Checkpoint for ZIL Replay
#
log_must zpool freeze $TESTPOOL
#
# 4. TX_CLONE_RANGE: Clone the file
#
log_must clonefile -c /$TESTPOOL/$TESTFS/file1 /$TESTPOOL/$TESTFS/clone1
log_must clonefile -c /$TESTPOOL/$TESTFS/file2 /$TESTPOOL/$TESTFS/clone2
#
# 5. Unmount filesystem and export the pool
#
# At this stage TESTFS is frozen, the intent log contains a complete set
# of deltas to replay for clone files.
#
log_must zfs unmount /$TESTPOOL/$TESTFS
log_note "Verify transactions to replay:"
log_must zdb -iv $TESTPOOL/$TESTFS
log_must zpool export $TESTPOOL
#
# 6. Remount TESTFS <which replays the intent log>
#
# Import the pool to unfreeze it and claim log blocks. It has to be
# `zpool import -f` because we can't write a frozen pool's labels!
#
log_must eval "echo $PASSPHRASE | zpool import -l -f -d $VDIR $TESTPOOL"
#
# 7. Compare clone file with the original file
#
log_must have_same_content /$TESTPOOL/$TESTFS/file1 /$TESTPOOL/$TESTFS/clone1
log_must have_same_content /$TESTPOOL/$TESTFS/file2 /$TESTPOOL/$TESTFS/clone2
typeset blocks=$(get_same_blocks $TESTPOOL/$TESTFS file1 \
$TESTPOOL/$TESTFS clone1 $PASSPHRASE)
log_must [ "$blocks" = "0 1 2 3" ]
typeset blocks=$(get_same_blocks $TESTPOOL/$TESTFS file2 \
$TESTPOOL/$TESTFS clone2 $PASSPHRASE)
log_must [ "$blocks" = "$(seq -s " " 0 2047)" ]
log_pass $claim

View file

@ -0,0 +1 @@
seekflood

View file

@ -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 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:
#
# https://github.com/openzfs/zfs/issues/15526 identified a dirty dnode
# SEEK_HOLE/SEEK_DATA bug. https://github.com/openzfs/zfs/pull/15571
# fixed the bug, and was backported to 2.1.14 and 2.2.2.
#
# This test is to ensure that the bug, as understood, will not recur.
#
# STRATEGY:
#
# 1. Run the 'seekflood' binary, for creation of files with timing
# characteristics that can trigger #15526.
# 2. A single run is not always a trigger, so run repeatedly.
verify_runnable "global"
function cleanup
{
rm -rf /$TESTDIR/cp_stress
}
log_assert "Run the 'seekflood' binary repeatedly to try to trigger #15526"
log_onexit cleanup
log_must mkdir /$TESTPOOL/cp_stress
MYPWD="$PWD"
cd /$TESTPOOL/cp_stress
CPUS=$(get_num_cpus)
if is_freebsd ; then
# 'seekflood' takes longer on FreeBSD and can timeout the test
RUNS=3
else
RUNS=10
fi
for i in $(seq 1 $RUNS) ; do
# Each run takes around 12 seconds.
log_must $STF_SUITE/tests/functional/cp_files/seekflood 2000 $CPUS
done
cd "$MYPWD"
log_pass "No corruption detected"

View file

@ -0,0 +1,180 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2023, Rob Norris <robn@despairlabs.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define DATASIZE (4096)
char data[DATASIZE];
static int
_open_file(int n, int wr)
{
char buf[256];
int fd;
snprintf(buf, sizeof (buf), "testdata_%d_%d", getpid(), n);
if ((fd = open(buf, wr ? (O_WRONLY | O_CREAT) : O_RDONLY,
wr ? (S_IRUSR | S_IWUSR) : 0)) < 0) {
fprintf(stderr, "Error: open '%s' (%s): %s\n",
buf, wr ? "write" : "read", strerror(errno));
exit(1);
}
return (fd);
}
static void
_write_file(int n, int fd)
{
/* write a big ball of stuff */
ssize_t nwr = write(fd, data, DATASIZE);
if (nwr < 0) {
fprintf(stderr, "Error: write '%d_%d': %s\n",
getpid(), n, strerror(errno));
exit(1);
} else if (nwr < DATASIZE) {
fprintf(stderr, "Error: write '%d_%d': short write\n", getpid(),
n);
exit(1);
}
}
static int
_seek_file(int n, int fd)
{
struct stat st;
if (fstat(fd, &st) < 0) {
fprintf(stderr, "Error: fstat '%d_%d': %s\n", getpid(), n,
strerror(errno));
exit(1);
}
/*
* A zero-sized file correctly has no data, so seeking the file is
* pointless.
*/
if (st.st_size == 0)
return (0);
/* size is real, and we only write, so SEEK_DATA must find something */
if (lseek(fd, 0, SEEK_DATA) < 0) {
if (errno == ENXIO)
return (1);
fprintf(stderr, "Error: lseek '%d_%d': %s\n",
getpid(), n, strerror(errno));
exit(2);
}
return (0);
}
int
main(int argc, char **argv)
{
int nfiles = 0;
int nthreads = 0;
if (argc < 3 || (nfiles = atoi(argv[1])) == 0 ||
(nthreads = atoi(argv[2])) == 0) {
printf("usage: seekflood <nfiles> <threads>\n");
exit(1);
}
memset(data, 0x5a, DATASIZE);
/* fork off some flood threads */
for (int i = 0; i < nthreads; i++) {
if (!fork()) {
/* thread main */
/* create zero file */
int fd = _open_file(0, 1);
_write_file(0, fd);
close(fd);
int count = 0;
int h = 0, i, j, rfd, wfd;
for (i = 0; i < nfiles; i += 2, h++) {
j = i+1;
/* seek h, write i */
rfd = _open_file(h, 0);
wfd = _open_file(i, 1);
count += _seek_file(h, rfd);
_write_file(i, wfd);
close(rfd);
close(wfd);
/* seek i, write j */
rfd = _open_file(i, 0);
wfd = _open_file(j, 1);
count += _seek_file(i, rfd);
_write_file(j, wfd);
close(rfd);
close(wfd);
}
/* return count of failed seeks to parent */
exit(count < 256 ? count : 255);
}
}
/* wait for threads, take their seek fail counts from exit code */
int count = 0, crashed = 0;
for (int i = 0; i < nthreads; i++) {
int wstatus;
wait(&wstatus);
if (WIFEXITED(wstatus))
count += WEXITSTATUS(wstatus);
else
crashed++;
}
if (crashed) {
fprintf(stderr, "Error: child crashed; test failed\n");
exit(1);
}
if (count) {
fprintf(stderr, "Error: %d seek failures; test failed\n",
count);
exit(1);
}
exit(0);
}

View file

@ -44,6 +44,13 @@ if ! $(grep -q "CONFIG_IO_URING=y" /boot/config-$(uname -r)); then
log_unsupported "Requires io_uring support"
fi
if [ -e /etc/os-release ] ; then
source /etc/os-release
if [ -n "$REDHAT_SUPPORT_PRODUCT_VERSION" ] && ((floor($REDHAT_SUPPORT_PRODUCT_VERSION) == 9)) ; then
log_unsupported "Disabled on CentOS 9, fails with 'Operation not permitted'"
fi
fi
fio --ioengine=io_uring --parse-only || log_unsupported "fio io_uring support required"
function cleanup

View file

@ -113,7 +113,7 @@ function test_replace # <pool> <devices> <parity>
log_must zpool scrub -w $pool
log_must zpool status -v
log_must check_pool_status $pool "scan" "repaired 0B"
log_must check_pool_status $pool "scan" "with 0 errors"
}
log_must set_tunable32 EMBEDDED_SLOG_MIN_MS 99999

View file

@ -1113,7 +1113,7 @@
/* #undef ZFS_IS_GPL_COMPATIBLE */
/* Define the project alias string. */
#define ZFS_META_ALIAS "zfs-2.2.99-257-FreeBSD_g450f2d0b0"
#define ZFS_META_ALIAS "zfs-2.2.99-268-FreeBSD_g86e115e21"
/* Define the project author. */
#define ZFS_META_AUTHOR "OpenZFS"
@ -1143,7 +1143,7 @@
#define ZFS_META_NAME "zfs"
/* Define the project release. */
#define ZFS_META_RELEASE "257-FreeBSD_g450f2d0b0"
#define ZFS_META_RELEASE "268-FreeBSD_g86e115e21"
/* Define the project version. */
#define ZFS_META_VERSION "2.2.99"

View file

@ -1 +1 @@
#define ZFS_META_GITREV "zfs-2.2.99-257-g450f2d0b0"
#define ZFS_META_GITREV "zfs-2.2.99-268-g86e115e21"