ZTS: Add L2ARC DWPD and parallel writes tests

Add four new functional tests to validate L2ARC DWPD rate limiting and
parallel write features:

- l2arc_dwpd_ratelimit_pos: Verifies DWPD rate limiting with different
  values (0, 100, 1000, 10000) and ordering
- l2arc_dwpd_reimport_pos: Verifies DWPD rate limiting persists after
  pool export/import
- l2arc_multidev_scaling_pos: Verifies parallel write scaling ratio
  (dual devices achieve ~2× single device throughput)
- l2arc_multidev_throughput_pos: Verifies absolute parallel write
  throughput scales with device count (~32MB/s per device)

Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Ameer Hamza <ahamza@ixsystems.com>
Closes #18093
This commit is contained in:
Ameer Hamza 2025-12-29 23:44:28 +05:00 committed by Brian Behlendorf
parent 48d3f7fac9
commit 13552d754f
10 changed files with 618 additions and 4 deletions

View File

@ -1130,7 +1130,8 @@ tags = ['functional', 'log_spacemap']
[tests/functional/l2arc]
tests = ['l2arc_arcstats_pos', 'l2arc_mfuonly_pos', 'l2arc_l2miss_pos',
'persist_l2arc_001_pos', 'persist_l2arc_002_pos',
'l2arc_dwpd_ratelimit_pos', 'l2arc_dwpd_reimport_pos', 'l2arc_multidev_scaling_pos',
'l2arc_multidev_throughput_pos', 'persist_l2arc_001_pos', 'persist_l2arc_002_pos',
'persist_l2arc_003_neg', 'persist_l2arc_004_pos', 'persist_l2arc_005_pos']
tags = ['functional', 'l2arc']

View File

@ -46,12 +46,12 @@ INITIALIZE_CHUNK_SIZE initialize_chunk_size zfs_initialize_chunk_size
INITIALIZE_VALUE initialize_value zfs_initialize_value
KEEP_LOG_SPACEMAPS_AT_EXPORT keep_log_spacemaps_at_export zfs_keep_log_spacemaps_at_export
LUA_MAX_MEMLIMIT lua.max_memlimit zfs_lua_max_memlimit
L2ARC_DWPD_LIMIT l2arc.dwpd_limit l2arc_dwpd_limit
L2ARC_MFUONLY l2arc.mfuonly l2arc_mfuonly
L2ARC_NOPREFETCH l2arc.noprefetch l2arc_noprefetch
L2ARC_REBUILD_BLOCKS_MIN_L2SIZE l2arc.rebuild_blocks_min_l2size l2arc_rebuild_blocks_min_l2size
L2ARC_REBUILD_ENABLED l2arc.rebuild_enabled l2arc_rebuild_enabled
L2ARC_TRIM_AHEAD l2arc.trim_ahead l2arc_trim_ahead
L2ARC_WRITE_BOOST l2arc.write_boost l2arc_write_boost
L2ARC_WRITE_MAX l2arc.write_max l2arc_write_max
LIVELIST_CONDENSE_NEW_ALLOC livelist.condense.new_alloc zfs_livelist_condense_new_alloc
LIVELIST_CONDENSE_SYNC_CANCEL livelist.condense.sync_cancel zfs_livelist_condense_sync_cancel

View File

@ -1660,6 +1660,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/l2arc/l2arc_arcstats_pos.ksh \
functional/l2arc/l2arc_l2miss_pos.ksh \
functional/l2arc/l2arc_mfuonly_pos.ksh \
functional/l2arc/l2arc_dwpd_ratelimit_pos.ksh \
functional/l2arc/l2arc_dwpd_reimport_pos.ksh \
functional/l2arc/l2arc_multidev_scaling_pos.ksh \
functional/l2arc/l2arc_multidev_throughput_pos.ksh \
functional/l2arc/persist_l2arc_001_pos.ksh \
functional/l2arc/persist_l2arc_002_pos.ksh \
functional/l2arc/persist_l2arc_003_neg.ksh \

View File

@ -55,12 +55,15 @@ function cleanup
log_must set_tunable32 L2ARC_WRITE_MAX $write_max
log_must set_tunable32 L2ARC_NOPREFETCH $noprefetch
log_must set_tunable32 L2ARC_DWPD_LIMIT $dwpd_limit
}
log_onexit cleanup
typeset write_max=$(get_tunable L2ARC_WRITE_MAX)
typeset noprefetch=$(get_tunable L2ARC_NOPREFETCH)
typeset dwpd_limit=$(get_tunable L2ARC_DWPD_LIMIT)
log_must set_tunable32 L2ARC_NOPREFETCH 0
log_must set_tunable32 L2ARC_DWPD_LIMIT 0
typeset VDEV="$VDIR/vdev.disk"
typeset VDEV_SZ=$(( 4 * 1024 * 1024 * 1024 ))

View File

@ -25,7 +25,8 @@ export SIZE=1G
export VDIR=$TESTDIR/disk.l2arc
export VDEV="$VDIR/a"
export VDEV_CACHE="$VDIR/b"
export VDEV1="$VDIR/c"
export VDEV_CACHE2="$VDIR/c"
export VDEV1="$VDIR/d"
# fio options
export DIRECTORY=/$TESTPOOL

View File

@ -0,0 +1,138 @@
#!/bin/ksh -p
# SPDX-License-Identifier: CDDL-1.0
#
# CDDL HEADER START
#
# 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.
#
# CDDL HEADER END
#
#
# Copyright (c) 2024. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/l2arc/l2arc.cfg
#
# DESCRIPTION:
# L2ARC DWPD rate limiting correctly limits write rate.
#
# STRATEGY:
# 1. Set DWPD limit before creating pool.
# 2. Create pool with cache device (L2ARC >= arc_c_max * 2).
# 3. Populate L2ARC to complete first pass - DWPD only limits writes
# after first pass, so we must fill L2ARC first.
# 4. Delete the file to free ARC and invalidate L2ARC entries.
# 5. Write fresh data - now DWPD rate limiting controls refill rate.
# 6. Measure L2ARC writes over test period.
# 7. Repeat 1-6 for DWPD values 0, 10000, 5000, 1800.
# 8. Verify DWPD=0 > DWPD=10000 > DWPD=5000 > DWPD=1800.
#
verify_runnable "global"
log_assert "L2ARC DWPD rate limiting correctly limits write rate."
function cleanup
{
if poolexists $TESTPOOL ; then
destroy_pool $TESTPOOL
fi
restore_tunable L2ARC_WRITE_MAX
restore_tunable L2ARC_NOPREFETCH
restore_tunable L2ARC_DWPD_LIMIT
restore_tunable ARC_MIN
restore_tunable ARC_MAX
}
log_onexit cleanup
# Save original tunables
save_tunable L2ARC_WRITE_MAX
save_tunable L2ARC_NOPREFETCH
save_tunable L2ARC_DWPD_LIMIT
save_tunable ARC_MIN
save_tunable ARC_MAX
# Test parameters
typeset cache_sz=900
typeset fill_mb=1500
typeset test_time=15
# Configure arc_max = 400MB so L2ARC (900MB) >= arc_c_max * 2 threshold
log_must set_tunable64 ARC_MAX $((400 * 1024 * 1024))
log_must set_tunable64 ARC_MIN $((200 * 1024 * 1024))
log_must set_tunable32 L2ARC_NOPREFETCH 0
log_must set_tunable32 L2ARC_WRITE_MAX $((200 * 1024 * 1024))
# Create larger main vdev to accommodate fill data
log_must truncate -s 5G $VDEV
log_must truncate -s ${cache_sz}M $VDEV_CACHE
typeset -A results
# Test each DWPD value with fresh pool.
# Minimum DWPD=1800 (18 DWPD) gives ~192KB/s (900MB*18/86400), enough to
# write one block (128KB) + log overhead (64KB) without accumulating budget.
for dwpd in 0 10000 5000 1800; do
log_must set_tunable32 L2ARC_DWPD_LIMIT $dwpd
if poolexists $TESTPOOL; then
destroy_pool $TESTPOOL
fi
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE
# Populate L2ARC in chunks to complete first pass
# (DWPD only limits after first pass)
log_must dd if=/dev/urandom of=/$TESTPOOL/fill1 bs=1M count=$((fill_mb/3))
log_must sleep 5
log_must dd if=/dev/urandom of=/$TESTPOOL/fill2 bs=1M count=$((fill_mb/3))
log_must sleep 5
log_must dd if=/dev/urandom of=/$TESTPOOL/fill3 bs=1M count=$((fill_mb/3))
log_must sleep 5
# Delete files to free ARC and invalidate L2ARC entries
log_must rm /$TESTPOOL/fill1 /$TESTPOOL/fill2 /$TESTPOOL/fill3
log_must sync
# Take baseline - L2ARC now has space for fresh data
baseline=$(kstat arcstats.l2_write_bytes)
log_note "Baseline for DWPD=$dwpd: ${baseline}"
# Write fresh data - DWPD rate limiting now controls refill rate
# Write arc_max worth of data since that's what flows through ARC
dd if=/dev/urandom of=/$TESTPOOL/test bs=1M count=400 &
dd_pid=$!
log_must sleep $test_time
kill $dd_pid 2>/dev/null
wait $dd_pid 2>/dev/null
log_must sleep 2
end=$(kstat arcstats.l2_write_bytes)
results[$dwpd]=$((end - baseline))
log_note "DWPD=$dwpd: delta=$((results[$dwpd] / 1024))KB"
done
# Verify ordering: higher DWPD = more writes, 0 = unlimited
if [[ ${results[0]} -le ${results[10000]} ]]; then
log_fail "DWPD=0 (unlimited) should write more than DWPD=10000"
fi
if [[ ${results[10000]} -le ${results[5000]} ]]; then
log_fail "DWPD=10000 should write more than DWPD=5000"
fi
if [[ ${results[5000]} -le ${results[1800]} ]]; then
log_fail "DWPD=5000 should write more than DWPD=1800"
fi
log_must zpool destroy $TESTPOOL
log_pass "L2ARC DWPD rate limiting correctly limits write rate."

View File

@ -0,0 +1,169 @@
#!/bin/ksh -p
# SPDX-License-Identifier: CDDL-1.0
#
# CDDL HEADER START
#
# 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.
#
# CDDL HEADER END
#
#
# Copyright (c) 2024. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/l2arc/l2arc.cfg
#
# DESCRIPTION:
# L2ARC DWPD rate limiting works after pool export/import.
#
# STRATEGY:
# 1. Set DWPD limit before creating pool.
# 2. Create pool with cache device (L2ARC >= arc_c_max * 2).
# 3. Fill L2ARC with staged writes and wait for first pass to complete.
# 4. Measure DWPD-limited writes with continuous workload.
# 5. Export and import pool.
# 6. Wait for rebuild, then fill L2ARC with staged writes.
# 7. Measure DWPD-limited writes again.
# 8. Verify rate limiting still works after import (non-zero writes).
#
verify_runnable "global"
log_assert "L2ARC DWPD rate limiting works after pool export/import."
function cleanup
{
if poolexists $TESTPOOL ; then
destroy_pool $TESTPOOL
fi
restore_tunable L2ARC_WRITE_MAX
restore_tunable L2ARC_NOPREFETCH
restore_tunable L2ARC_DWPD_LIMIT
restore_tunable L2ARC_REBUILD_BLOCKS_MIN_L2SIZE
restore_tunable ARC_MIN
restore_tunable ARC_MAX
}
log_onexit cleanup
# Save original tunables
save_tunable L2ARC_WRITE_MAX
save_tunable L2ARC_NOPREFETCH
save_tunable L2ARC_DWPD_LIMIT
save_tunable L2ARC_REBUILD_BLOCKS_MIN_L2SIZE
save_tunable ARC_MIN
save_tunable ARC_MAX
# Test parameters
typeset cache_sz=900
typeset fill_mb=1500
typeset test_time=15
# Set DWPD before pool creation (10000 = 100 DWPD)
log_must set_tunable32 L2ARC_DWPD_LIMIT 10000
log_must set_tunable32 L2ARC_REBUILD_BLOCKS_MIN_L2SIZE 0
# Configure arc_max = 400MB so L2ARC (900MB) >= arc_c_max * 2 threshold
log_must set_tunable64 ARC_MAX $((400 * 1024 * 1024))
log_must set_tunable64 ARC_MIN $((200 * 1024 * 1024))
log_must set_tunable32 L2ARC_NOPREFETCH 0
log_must set_tunable32 L2ARC_WRITE_MAX $((200 * 1024 * 1024))
# Create larger main vdev to accommodate fill data
log_must truncate -s 8G $VDEV
log_must truncate -s ${cache_sz}M $VDEV_CACHE
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE
# Staged fills to allow L2ARC to drain between writes
log_must dd if=/dev/urandom of=/$TESTPOOL/file1a bs=1M count=$((fill_mb/3))
log_must sleep 5
log_must dd if=/dev/urandom of=/$TESTPOOL/file1b bs=1M count=$((fill_mb/3))
log_must sleep 5
log_must dd if=/dev/urandom of=/$TESTPOOL/file1c bs=1M count=$((fill_mb/3))
log_must sleep 5
# Verify L2ARC is populated before export
typeset l2_size_before=$(kstat arcstats.l2_size)
log_note "L2ARC size before export: $((l2_size_before / 1024 / 1024))MB"
if [[ $l2_size_before -eq 0 ]]; then
log_fail "L2ARC not populated before export"
fi
# Measure DWPD-limited writes before export
baseline1=$(kstat arcstats.l2_write_bytes)
log_note "Baseline before export: ${baseline1}"
dd if=/dev/urandom of=/$TESTPOOL/file2 bs=1M count=2000 >/dev/null 2>&1 &
dd_pid=$!
log_must sleep $test_time
kill $dd_pid 2>/dev/null
wait $dd_pid 2>/dev/null
log_must sleep 2
end1=$(kstat arcstats.l2_write_bytes)
typeset writes_before=$((end1 - baseline1))
log_note "Writes before export: $((writes_before / 1024))KB"
# Verify L2ARC actually wrote data
if [[ $writes_before -eq 0 ]]; then
log_fail "No L2ARC writes before export - DWPD may be too restrictive"
fi
# Export and import pool
log_must zpool export $TESTPOOL
log_must zpool import -d $VDIR $TESTPOOL
# Wait for rebuild to complete
log_must sleep 5
# Verify L2ARC is populated after import
typeset l2_size_after=$(kstat arcstats.l2_size)
log_note "L2ARC size after import: $((l2_size_after / 1024 / 1024))MB"
if [[ $l2_size_after -eq 0 ]]; then
log_fail "L2ARC not populated after import"
fi
# Staged fills again after import
log_must dd if=/dev/urandom of=/$TESTPOOL/file3a bs=1M count=$((fill_mb/3))
log_must sleep 5
log_must dd if=/dev/urandom of=/$TESTPOOL/file3b bs=1M count=$((fill_mb/3))
log_must sleep 5
log_must dd if=/dev/urandom of=/$TESTPOOL/file3c bs=1M count=$((fill_mb/3))
log_must sleep 5
# Verify L2ARC is still populated after refill
l2_size=$(kstat arcstats.l2_size)
log_note "L2ARC size after refill: $((l2_size / 1024 / 1024))MB"
# Measure DWPD-limited writes after import
baseline2=$(kstat arcstats.l2_write_bytes)
log_note "Baseline after import: ${baseline2}"
dd if=/dev/urandom of=/$TESTPOOL/file4 bs=1M count=2000 >/dev/null 2>&1 &
dd_pid=$!
log_must sleep $test_time
kill $dd_pid 2>/dev/null
wait $dd_pid 2>/dev/null
log_must sleep 2
end2=$(kstat arcstats.l2_write_bytes)
typeset writes_after=$((end2 - baseline2))
log_note "Writes after import: $((writes_after / 1024))KB"
# Verify rate limiting persists after import
if [[ $writes_after -eq 0 ]]; then
log_fail "No writes after import - rate limiting may be broken"
fi
log_must zpool destroy $TESTPOOL
log_pass "L2ARC DWPD rate limiting works after pool export/import."

View File

@ -0,0 +1,162 @@
#!/bin/ksh -p
# SPDX-License-Identifier: CDDL-1.0
#
# CDDL HEADER START
#
# 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.
#
# CDDL HEADER END
#
#
# Copyright (c) 2024. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/l2arc/l2arc.cfg
#
# DESCRIPTION:
# L2ARC parallel writes scale with number of cache devices.
#
# STRATEGY:
# 1. Configure L2ARC write rate to 16MB/s per device.
# 2. Disable DWPD rate limiting to test pure parallel throughput.
# 3. Create pool with single 2100MB cache device.
# 4. Generate continuous writes, wait for L2ARC activity, measure over 25s.
# 5. Verify single-device throughput ~400MB (16MB/s × 25s).
# 6. Recreate pool with dual 2100MB cache devices.
# 7. Generate continuous writes, wait for L2ARC activity, measure over 25s.
# 8. Verify dual-device throughput ~800MB (2×16MB/s × 25s).
#
verify_runnable "global"
log_assert "L2ARC parallel writes scale with number of cache devices."
function cleanup
{
if poolexists $TESTPOOL ; then
destroy_pool $TESTPOOL
fi
restore_tunable L2ARC_WRITE_MAX
restore_tunable L2ARC_NOPREFETCH
restore_tunable L2ARC_DWPD_LIMIT
restore_tunable ARC_MIN
restore_tunable ARC_MAX
}
log_onexit cleanup
# Save original tunables
save_tunable L2ARC_WRITE_MAX
save_tunable L2ARC_NOPREFETCH
save_tunable L2ARC_DWPD_LIMIT
save_tunable ARC_MIN
save_tunable ARC_MAX
# Test parameters
typeset cache_sz=1000
typeset fill_mb=2500 # 2.5GB initial data
typeset test_time=12 # Measurement window: 16MB/s × 12s = ~200MB per device
# Disable DWPD to test pure parallel throughput
log_must set_tunable32 L2ARC_DWPD_LIMIT 0
# Set L2ARC_WRITE_MAX to 16MB/s to test parallel scaling
log_must set_tunable32 L2ARC_WRITE_MAX $((16 * 1024 * 1024))
log_must set_tunable32 L2ARC_NOPREFETCH 0
# Configure arc_max so L2ARC >= arc_c_max * 2 threshold for persistent markers
log_must set_tunable64 ARC_MAX $((400 * 1024 * 1024))
log_must set_tunable64 ARC_MIN $((200 * 1024 * 1024))
# Single device test
log_must truncate -s 4G $VDEV
log_must truncate -s ${cache_sz}M $VDEV_CACHE
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE
# Generate data in background
dd if=/dev/urandom of=/$TESTPOOL/file1 bs=1M count=$fill_mb &
typeset dd_pid=$!
# Wait for L2ARC to start writing
typeset l2_size=0
for i in {1..30}; do
l2_size=$(kstat arcstats.l2_size)
[[ $l2_size -gt 0 ]] && break
sleep 1
done
if [[ $l2_size -eq 0 ]]; then
kill $dd_pid 2>/dev/null
log_fail "L2ARC did not start writing (single device)"
fi
# Measure single-device write throughput
typeset start=$(kstat arcstats.l2_write_bytes)
log_must sleep $test_time
typeset end=$(kstat arcstats.l2_write_bytes)
kill $dd_pid 2>/dev/null
wait $dd_pid 2>/dev/null
typeset single_writes=$((end - start))
# expected = 16MB/s * 1 device * 25s = 400MB
typeset single_expected=$((16 * 1024 * 1024 * test_time))
log_note "Single-device writes: $((single_writes / 1024 / 1024))MB (expected ~$((single_expected / 1024 / 1024))MB)"
# Dual device test
log_must zpool destroy $TESTPOOL
log_must truncate -s ${cache_sz}M $VDEV_CACHE
log_must truncate -s ${cache_sz}M $VDEV_CACHE2
log_must zpool create -f $TESTPOOL $VDEV cache $VDEV_CACHE $VDEV_CACHE2
# Generate data in background
dd if=/dev/urandom of=/$TESTPOOL/file2 bs=1M count=$fill_mb &
dd_pid=$!
# Wait for L2ARC to start writing
l2_size=0
for i in {1..30}; do
l2_size=$(kstat arcstats.l2_size)
[[ $l2_size -gt 0 ]] && break
sleep 1
done
if [[ $l2_size -eq 0 ]]; then
kill $dd_pid 2>/dev/null
log_fail "L2ARC did not start writing (dual device)"
fi
# Measure parallel write throughput (2 feed threads active)
start=$(kstat arcstats.l2_write_bytes)
log_must sleep $test_time
end=$(kstat arcstats.l2_write_bytes)
kill $dd_pid 2>/dev/null
wait $dd_pid 2>/dev/null
typeset dual_writes=$((end - start))
# expected = 16MB/s * 2 devices * 25s = 800MB
typeset dual_expected=$((16 * 1024 * 1024 * 2 * test_time))
log_note "Dual-device writes: $((dual_writes / 1024 / 1024))MB (expected ~$((dual_expected / 1024 / 1024))MB)"
# Verify writes are within expected range (80-150%)
typeset single_min=$((single_expected * 80 / 100))
typeset dual_min=$((dual_expected * 80 / 100))
if [[ $single_writes -lt $single_min ]]; then
log_fail "Single-device writes $((single_writes / 1024 / 1024))MB below minimum $((single_min / 1024 / 1024))MB"
fi
if [[ $dual_writes -lt $dual_min ]]; then
log_fail "Dual-device writes $((dual_writes / 1024 / 1024))MB below minimum $((dual_min / 1024 / 1024))MB"
fi
log_must zpool destroy $TESTPOOL
log_pass "L2ARC parallel writes scale with number of cache devices."

View File

@ -0,0 +1,133 @@
#!/bin/ksh -p
# SPDX-License-Identifier: CDDL-1.0
#
# CDDL HEADER START
#
# 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.
#
# CDDL HEADER END
#
#
# Copyright (c) 2024. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/l2arc/l2arc.cfg
#
# DESCRIPTION:
# L2ARC parallel writes scale with number of cache devices.
#
# STRATEGY:
# 1. Disable DWPD rate limiting.
# 2. Create pool with 2 cache devices.
# 3. Write data and measure L2ARC throughput.
# 4. Verify throughput scales with device count (~16MB/s per device).
#
verify_runnable "global"
log_assert "L2ARC parallel writes scale with number of cache devices."
function cleanup
{
if poolexists $TESTPOOL ; then
destroy_pool $TESTPOOL
fi
restore_tunable L2ARC_WRITE_MAX
restore_tunable L2ARC_NOPREFETCH
restore_tunable L2ARC_DWPD_LIMIT
restore_tunable ARC_MIN
restore_tunable ARC_MAX
}
log_onexit cleanup
# Save original tunables
save_tunable L2ARC_WRITE_MAX
save_tunable L2ARC_NOPREFETCH
save_tunable L2ARC_DWPD_LIMIT
save_tunable ARC_MIN
save_tunable ARC_MAX
# Test parameters
typeset num_devs=2
typeset cache_sz=1000 # 2000MB total > 1900MB (arc_max*2) threshold
typeset test_time=10
typeset fill_mb=1500
typeset expected_rate=$((32 * 1024 * 1024)) # 32 MB/s per device
# Disable DWPD rate limiting
log_must set_tunable32 L2ARC_DWPD_LIMIT 0
# Set L2ARC_WRITE_MAX to 32MB/s per device (64MB/s total with 2 devices)
log_must set_tunable32 L2ARC_WRITE_MAX $expected_rate
log_must set_tunable32 L2ARC_NOPREFETCH 0
# Configure arc_max large enough to feed L2ARC
log_must set_tunable64 ARC_MAX $((950 * 1024 * 1024))
log_must set_tunable64 ARC_MIN $((512 * 1024 * 1024))
# Create cache devices (using letters e-f to follow cfg naming convention)
typeset cache_devs=""
for letter in e f; do
typeset dev="$VDIR/$letter"
log_must truncate -s ${cache_sz}M $dev
cache_devs="$cache_devs $dev"
done
log_must truncate -s 2G $VDEV
log_must zpool create -f $TESTPOOL $VDEV cache $cache_devs
# Generate data in background
dd if=/dev/urandom of=/$TESTPOOL/file1 bs=1M count=$fill_mb &
typeset dd_pid=$!
# Wait for L2ARC to start writing
typeset l2_size=0
for i in {1..30}; do
l2_size=$(kstat arcstats.l2_size)
[[ $l2_size -gt 0 ]] && break
sleep 1
done
if [[ $l2_size -eq 0 ]]; then
kill $dd_pid 2>/dev/null
log_fail "L2ARC did not start writing"
fi
# Measure L2ARC throughput over test window
typeset start=$(kstat arcstats.l2_write_bytes)
log_must sleep $test_time
typeset end=$(kstat arcstats.l2_write_bytes)
kill $dd_pid 2>/dev/null
wait $dd_pid 2>/dev/null
typeset bytes=$((end - start))
typeset bytes_mb=$((bytes / 1024 / 1024))
# expected = 32MB/s * 2 devices * 10 seconds = 640MB
typeset expected=$((expected_rate * num_devs * test_time))
typeset expected_mb=$((expected / 1024 / 1024))
log_note "L2ARC writes: ${bytes_mb}MB (expected ~${expected_mb}MB)"
# Verify writes are within expected range (75-150%)
typeset min_bytes=$((expected * 75 / 100))
typeset max_bytes=$((expected * 150 / 100))
if [[ $bytes -lt $min_bytes ]]; then
log_fail "Writes ${bytes_mb}MB below minimum $((min_bytes/1024/1024))MB"
fi
if [[ $bytes -gt $max_bytes ]]; then
log_fail "Writes ${bytes_mb}MB above maximum $((max_bytes/1024/1024))MB"
fi
log_must zpool destroy $TESTPOOL
log_pass "L2ARC parallel writes scale with number of cache devices."

View File

@ -50,16 +50,19 @@ function cleanup
log_must rm -f $VDEVS
log_must set_tunable32 L2ARC_TRIM_AHEAD $l2arc_trimahead
log_must set_tunable32 L2ARC_WRITE_MAX $l2arc_writemax
log_must set_tunable32 L2ARC_DWPD_LIMIT $l2arc_dwpdlimit
}
log_onexit cleanup
# The cache device $TRIM_VDEV2 has to be small enough, so that
# dev->l2ad_hand loops around and dev->l2ad_first=0. Otherwise
# dev->l2ad_hand loops around and dev->l2ad_first=0. Otherwise
# l2arc_evict() exits before evicting/trimming.
typeset l2arc_trimahead=$(get_tunable L2ARC_TRIM_AHEAD)
typeset l2arc_writemax=$(get_tunable L2ARC_WRITE_MAX)
typeset l2arc_dwpdlimit=$(get_tunable L2ARC_DWPD_LIMIT)
log_must set_tunable32 L2ARC_TRIM_AHEAD 1
log_must set_tunable32 L2ARC_WRITE_MAX $((64 * 1024 * 1024))
log_must set_tunable32 L2ARC_DWPD_LIMIT 0
VDEVS="$TRIM_VDEV1 $TRIM_VDEV2"
log_must truncate -s $((MINVDEVSIZE)) $TRIM_VDEV2
log_must truncate -s $((4 * MINVDEVSIZE)) $TRIM_VDEV1