mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-03-10 12:26:27 +03:00
Fix activating large_microzap on receive
This ensures that the in-memory state of the feature is recorded and that `dsl_dataset_activate_feature` is not called when the feature is already active. Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Austin Wise <AustinWise@gmail.com> Closes #18143 Closes #18144
This commit is contained in:
parent
20f94ef24a
commit
4f180e095a
@ -997,24 +997,6 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
|
||||
numredactsnaps, tx);
|
||||
}
|
||||
|
||||
if (featureflags & DMU_BACKUP_FEATURE_LARGE_MICROZAP) {
|
||||
/*
|
||||
* The source has seen a large microzap at least once in its
|
||||
* life, so we activate the feature here to match. It's not
|
||||
* strictly necessary since a large microzap is usable without
|
||||
* the feature active, but if that object is sent on from here,
|
||||
* we need this info to know to add the stream feature.
|
||||
*
|
||||
* There may be no large microzap in the incoming stream, or
|
||||
* ever again, but this is a very niche feature and its very
|
||||
* difficult to spot a large microzap in the stream, so its
|
||||
* not worth the effort of trying harder to activate the
|
||||
* feature at first use.
|
||||
*/
|
||||
dsl_dataset_activate_feature(dsobj, SPA_FEATURE_LARGE_MICROZAP,
|
||||
(void *)B_TRUE, tx);
|
||||
}
|
||||
|
||||
dmu_buf_will_dirty(newds->ds_dbuf, tx);
|
||||
dsl_dataset_phys(newds)->ds_flags |= DS_FLAG_INCONSISTENT;
|
||||
|
||||
@ -1044,6 +1026,26 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
|
||||
newds->ds_feature[SPA_FEATURE_LONGNAME] = (void *)B_TRUE;
|
||||
}
|
||||
|
||||
if (featureflags & DMU_BACKUP_FEATURE_LARGE_MICROZAP &&
|
||||
!dsl_dataset_feature_is_active(newds, SPA_FEATURE_LARGE_MICROZAP)) {
|
||||
/*
|
||||
* The source has seen a large microzap at least once in its
|
||||
* life, so we activate the feature here to match. It's not
|
||||
* strictly necessary since a large microzap is usable without
|
||||
* the feature active, but if that object is sent on from here,
|
||||
* we need this info to know to add the stream feature.
|
||||
*
|
||||
* There may be no large microzap in the incoming stream, or
|
||||
* ever again, but this is a very niche feature and its very
|
||||
* difficult to spot a large microzap in the stream, so its
|
||||
* not worth the effort of trying harder to activate the
|
||||
* feature at first use.
|
||||
*/
|
||||
dsl_dataset_activate_feature(dsobj, SPA_FEATURE_LARGE_MICROZAP,
|
||||
(void *)B_TRUE, tx);
|
||||
newds->ds_feature[SPA_FEATURE_LARGE_MICROZAP] = (void *)B_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we actually created a non-clone, we need to create the objset
|
||||
* in our new dataset. If this is a raw send we postpone this until
|
||||
|
||||
@ -998,6 +998,7 @@ tests = ['recv_dedup', 'recv_dedup_encrypted_zvol', 'rsend_001_pos',
|
||||
'send_spill_block', 'send_holds', 'send_hole_birth', 'send_mixed_raw',
|
||||
'send-wR_encrypted_zvol', 'send_partial_dataset', 'send_invalid',
|
||||
'send_large_blocks_incremental', 'send_large_blocks_initial',
|
||||
'send_large_microzap_incremental', 'send_large_microzap_transitive',
|
||||
'send_doall', 'send_raw_spill_block', 'send_raw_ashift',
|
||||
'send_raw_large_blocks', 'send_leak_keymaps']
|
||||
tags = ['functional', 'rsend']
|
||||
|
||||
@ -114,6 +114,7 @@ BCLONE_WAIT_DIRTY bclone_wait_dirty zfs_bclone_wait_dirty
|
||||
DIO_ENABLED dio_enabled zfs_dio_enabled
|
||||
DIO_STRICT dio_strict zfs_dio_strict
|
||||
XATTR_COMPAT xattr_compat zfs_xattr_compat
|
||||
ZAP_MICRO_MAX_SIZE zap_micro_max_size zap_micro_max_size
|
||||
ZEVENT_LEN_MAX zevent.len_max zfs_zevent_len_max
|
||||
ZEVENT_RETAIN_MAX zevent.retain_max zfs_zevent_retain_max
|
||||
ZIO_SLOW_IO_MS zio.slow_io_ms zio_slow_io_ms
|
||||
|
||||
@ -2067,6 +2067,8 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||
functional/rsend/send_invalid.ksh \
|
||||
functional/rsend/send_large_blocks_incremental.ksh \
|
||||
functional/rsend/send_large_blocks_initial.ksh \
|
||||
functional/rsend/send_large_microzap_incremental.ksh \
|
||||
functional/rsend/send_large_microzap_transitive.ksh \
|
||||
functional/rsend/send_leak_keymaps.ksh \
|
||||
functional/rsend/send-L_toggle.ksh \
|
||||
functional/rsend/send_mixed_raw.ksh \
|
||||
|
||||
91
tests/zfs-tests/tests/functional/rsend/send_large_microzap_incremental.ksh
Executable file
91
tests/zfs-tests/tests/functional/rsend/send_large_microzap_incremental.ksh
Executable file
@ -0,0 +1,91 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
|
||||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2026 by Austin Wise. All rights reserved.
|
||||
#
|
||||
|
||||
. $STF_SUITE/tests/functional/rsend/rsend.kshlib
|
||||
. $STF_SUITE/include/properties.shlib
|
||||
|
||||
#
|
||||
# Description:
|
||||
# Ensure that it is possible to receive an incremental send of a snapshot that has the large microzap
|
||||
# feature active into a pool where the feature is already active.
|
||||
# Regression test for https://github.com/openzfs/zfs/issues/18143
|
||||
#
|
||||
# Strategy:
|
||||
# 1. Activate the large microzap feature in the source dataset.
|
||||
# 2. Create a snapshot.
|
||||
# 3. Send the snapshot from the first pool to a second pool.
|
||||
# 4. Create a second snapshot.
|
||||
# 5. Send the second snapshot incrementally to the second pool.
|
||||
#
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify incremental receive handles inactive large_blocks feature correctly."
|
||||
|
||||
function cleanup
|
||||
{
|
||||
restore_tunable ZAP_MICRO_MAX_SIZE
|
||||
cleanup_pool $POOL
|
||||
cleanup_pool $POOL2
|
||||
}
|
||||
|
||||
function assert_feature_state {
|
||||
typeset pool=$1
|
||||
typeset expected_state=$2
|
||||
|
||||
typeset actual_state=$(zpool get -H -o value feature@large_microzap $pool)
|
||||
log_note "Zpool $pool feature@large_microzap=$actual_state"
|
||||
if [[ "$actual_state" != "$expected_state" ]]; then
|
||||
log_fail "pool $pool feature@large_microzap=$actual_state (expected '$expected_state')"
|
||||
fi
|
||||
}
|
||||
|
||||
typeset src=$POOL/src
|
||||
typeset second=$POOL2/second
|
||||
|
||||
log_onexit cleanup
|
||||
|
||||
# Allow micro ZAPs to grow beyond SPA_OLD_MAXBLOCKSIZE.
|
||||
set_tunable64 ZAP_MICRO_MAX_SIZE 1048576
|
||||
|
||||
# Create a dataset with a large recordsize (1MB)
|
||||
log_must zfs create -o recordsize=1M $src
|
||||
typeset mntpnt=$(get_prop mountpoint $src)
|
||||
|
||||
# Activate the large_microzap feature by creating a micro ZAP that is larger than SPA_OLD_MAXBLOCKSIZE (128k)
|
||||
# but smaller than MZAP_MAX_SIZE (1MB). Each micro ZAP entry is 64 bytes (MZAP_ENT_LEN),
|
||||
# so 4096 files is about 256k.
|
||||
log_must eval "seq 1 4096 | xargs -I REPLACE_ME touch $mntpnt/REPLACE_ME"
|
||||
log_must zpool sync $POOL
|
||||
|
||||
# Assert initial state of pools
|
||||
assert_feature_state $POOL "active"
|
||||
assert_feature_state $POOL2 "enabled"
|
||||
|
||||
# Create initial snapshot and send to second pool.
|
||||
log_must zfs snapshot $src@snap
|
||||
log_must eval "zfs send -p -L $src@snap | zfs receive $second"
|
||||
log_must zpool sync $POOL2
|
||||
assert_feature_state $POOL2 "active"
|
||||
|
||||
# Create a second snapshot and send incrementally.
|
||||
# This ensures that the feature is not activated a second time, which would cause a panic.
|
||||
log_must zfs snapshot $src@snap2
|
||||
log_must eval "zfs send -L -i $src@snap $src@snap2 | zfs receive -F $second"
|
||||
|
||||
log_pass "Feature activation propagated successfully."
|
||||
100
tests/zfs-tests/tests/functional/rsend/send_large_microzap_transitive.ksh
Executable file
100
tests/zfs-tests/tests/functional/rsend/send_large_microzap_transitive.ksh
Executable file
@ -0,0 +1,100 @@
|
||||
#!/bin/ksh -p
|
||||
# SPDX-License-Identifier: CDDL-1.0
|
||||
|
||||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright (c) 2026 by Austin Wise. All rights reserved.
|
||||
#
|
||||
|
||||
. $STF_SUITE/tests/functional/rsend/rsend.kshlib
|
||||
. $STF_SUITE/include/properties.shlib
|
||||
|
||||
#
|
||||
# Description:
|
||||
# Ensures that sending a snapshot with the large microzap feature active propagates
|
||||
# the feature activation to the receiving pool. Also checks that the received snapshot also
|
||||
# correctly propagates the feature activation when sent to a third third pool.
|
||||
# Regression test for https://github.com/openzfs/zfs/issues/18143
|
||||
#
|
||||
# Strategy:
|
||||
# 1. Enable the large microzap feature in the source dataset.
|
||||
# 2. Create a snapshot.
|
||||
# 3. Send the snapshot from the first pool to a second pool.
|
||||
# 4. Send the snapshot from the second pool to a third pool.
|
||||
# 5. Verify that all pools have the large microzap feature active.
|
||||
#
|
||||
|
||||
verify_runnable "both"
|
||||
verify_disk_count "$DISKS" 3
|
||||
|
||||
log_assert "Verify incremental receive handles inactive large_blocks feature correctly."
|
||||
|
||||
function cleanup
|
||||
{
|
||||
restore_tunable ZAP_MICRO_MAX_SIZE
|
||||
cleanup_pool $POOL
|
||||
cleanup_pool $POOL2
|
||||
cleanup_pool $POOL3
|
||||
}
|
||||
|
||||
function assert_feature_state {
|
||||
typeset pool=$1
|
||||
typeset expected_state=$2
|
||||
|
||||
typeset actual_state=$(zpool get -H -o value feature@large_microzap $pool)
|
||||
log_note "Zpool $pool feature@large_microzap=$actual_state"
|
||||
if [[ "$actual_state" != "$expected_state" ]]; then
|
||||
log_fail "pool $pool feature@large_microzap=$actual_state (expected '$expected_state')"
|
||||
fi
|
||||
}
|
||||
|
||||
typeset src=$POOL/src
|
||||
typeset second=$POOL2/second
|
||||
typeset third=$POOL3/third
|
||||
|
||||
log_onexit cleanup
|
||||
|
||||
# Allow micro ZAPs to grow beyond SPA_OLD_MAXBLOCKSIZE.
|
||||
set_tunable64 ZAP_MICRO_MAX_SIZE 1048576
|
||||
|
||||
# Ensure the third pool exists.
|
||||
datasetexists $POOL3 || log_must zpool create $POOL3 $DISK3
|
||||
|
||||
# Create a dataset with a large recordsize (1MB)
|
||||
log_must zfs create -o recordsize=1M $src
|
||||
typeset mntpnt=$(get_prop mountpoint $src)
|
||||
|
||||
# Activate the large_microzap feature by creating a micro ZAP that is larger than SPA_OLD_MAXBLOCKSIZE (128k)
|
||||
# but smaller than MZAP_MAX_SIZE (1MB). Each micro ZAP entry is 64 bytes (MZAP_ENT_LEN),
|
||||
# so 4096 files is about 256k.
|
||||
log_must eval "seq 1 4096 | xargs -I REPLACE_ME touch $mntpnt/REPLACE_ME"
|
||||
log_must zpool sync $POOL
|
||||
|
||||
# Assert initial state of pools
|
||||
assert_feature_state $POOL "active"
|
||||
assert_feature_state $POOL2 "enabled"
|
||||
assert_feature_state $POOL3 "enabled"
|
||||
|
||||
# Create initial snapshot and send to second pool.
|
||||
log_must zfs snapshot $src@snap
|
||||
log_must eval "zfs send -p -L $src@snap | zfs receive $second"
|
||||
log_must zpool sync $POOL2
|
||||
assert_feature_state $POOL2 "active"
|
||||
|
||||
# Send to third pool from second. This ensures that the second pool correctly recorded that that
|
||||
# large_microzap feature was active when it received the first send stream.
|
||||
log_must eval "zfs send -p -L $second@snap | zfs receive $third"
|
||||
log_must zpool sync $POOL3
|
||||
assert_feature_state $POOL3 "active"
|
||||
|
||||
log_pass "Feature activation propagated successfully."
|
||||
Loading…
Reference in New Issue
Block a user