Skip to content

Commit 1673a2b

Browse files
authored
Merge pull request #205 from bvanassche/master
zbd/014: Test recursive bio splitting
2 parents a051961 + 2f543de commit 1673a2b

File tree

2 files changed

+228
-0
lines changed

2 files changed

+228
-0
lines changed

tests/zbd/014

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: GPL-3.0+
3+
# Copyright (C) 2025 Google LLC
4+
#
5+
# Test the combination of inline encryption and bio splitting. About the values
6+
# of the parameters in this test:
7+
# - The zone size is 4 MiB and is larger than max_sectors_kb.
8+
# - The maximum bio size supported by the code in block/blk-crypto-fallback.c
9+
# is BIO_MAX_VECS * PAGE_SIZE or 1 MiB if the page size is 4 KiB.
10+
# - max_sectors_kb has been set to 512 KiB to cause further bio splitting.
11+
#
12+
# Without these two commits, this test triggers an I/O error:
13+
# - Commit e3290419d9be ("blk-crypto: convert to use
14+
# bio_submit_split_bioset()").
15+
# - Commit b2f5974079d8 ("block: fix ordering of recursive split IO").
16+
17+
. tests/zbd/rc
18+
. common/null_blk
19+
20+
DESCRIPTION="test inline encryption and bio splitting"
21+
22+
requires() {
23+
_have_driver f2fs
24+
_have_driver null_blk
25+
_have_program fscrypt
26+
_have_program getconf
27+
_have_program mkfs.f2fs
28+
for o in BLK_INLINE_ENCRYPTION_FALLBACK FS_ENCRYPTION_INLINE_CRYPT; do
29+
if ! _check_kernel_option "$o"; then
30+
SKIP_REASONS+=("Kernel option $o has not been enabled")
31+
fi
32+
done
33+
if [ ! -e /etc/fscrypt.conf ]; then
34+
SKIP_REASONS+=("/etc/fscrypt.conf is missing. 'fscrypt setup' must be run first.")
35+
fi
36+
}
37+
38+
# Start block I/O tracing with filter "$1".
39+
trace_block_io() {
40+
if [ -e /sys/kernel/tracing/tracing_on ]; then
41+
(
42+
set -e
43+
cd /sys/kernel/tracing
44+
lsof -t trace_pipe | xargs -r kill
45+
echo 1024 > buffer_size_kb
46+
echo nop > current_tracer
47+
echo 0 > tracing_on
48+
echo > trace
49+
echo 0 > events/enable
50+
echo 1 > events/block/enable
51+
echo 0 > events/block/block_dirty_buffer/enable
52+
echo 0 > events/block/block_plug/enable
53+
echo 0 > events/block/block_touch_buffer/enable
54+
echo 0 > events/block/block_unplug/enable
55+
# Set filter "$1" for all enabled block tracing events.
56+
grep -lw 1 events/block/*/enable |
57+
while read -r event_path; do
58+
filter_path="${event_path%enable}filter"
59+
echo "$1" > "$filter_path"
60+
done
61+
echo 1 > tracing_on
62+
echo "Tracing has been enabled" >>"$FULL"
63+
cat trace_pipe > "${FULL%.full}-block-trace.txt"
64+
)
65+
fi
66+
}
67+
68+
# Wait until trace_block_io() has enabled tracing.
69+
wait_until_tracing_started() {
70+
if [ -e /sys/kernel/tracing/tracing_on ]; then
71+
while [ "$(</sys/kernel/tracing/tracing_on)" = 0 ]; do
72+
sleep .1
73+
done
74+
fi
75+
}
76+
77+
# Stop tracing. $1 is the tracing PID.
78+
stop_tracing() {
79+
if [ -e /sys/kernel/tracing/tracing_on ]; then
80+
kill "$1"
81+
(
82+
set -e
83+
cd /sys/kernel/tracing
84+
echo 0 > tracing_on
85+
echo 0 > events/enable
86+
)
87+
fi
88+
}
89+
90+
# Report block I/O statistics. $1 is the output prefix. $2 and $3 are before and
91+
# after statistics that come from /sys/class/block/.../stat.
92+
report_stats() {
93+
local pfx=$1 before after
94+
read -r -a before <<<"$2"
95+
read -r -a after <<<"$3"
96+
local reads=$((after[0]-before[0]))
97+
local rmerge=$((after[1]-before[1]))
98+
local writes=$((after[4]-before[4]))
99+
local wmerge=$((after[5]-before[5]))
100+
echo "$pfx reads: $reads rmerge: $rmerge writes: $writes wmerge: $wmerge"
101+
}
102+
103+
# Convert block device name $1 into a Linux kernel device number.
104+
devno() {
105+
IFS=: read -r maj min <"/sys/class/block/$(basename "$1")/dev"
106+
# From <linux/kdev_t.h>: MINORBITS=20.
107+
echo $(((maj << 20) + min))
108+
}
109+
110+
run_test() {
111+
# From <linux/bio.h>: BIO_MAX_VECS=256.
112+
local bio_max_vecs=256
113+
114+
local page_size
115+
page_size=$(getconf PAGE_SIZE)
116+
117+
# In bytes.
118+
local max_inl_encr_bio_size=$((bio_max_vecs * page_size))
119+
120+
if umount /dev/nullb1 >>"$FULL" 2>&1; then :; fi
121+
_remove_null_blk_devices
122+
123+
# A small conventional block device for the F2FS metadata.
124+
local null_blk_params=(
125+
blocksize=4096
126+
discard=1
127+
max_sectors=$(((1 << 32) - 1))
128+
memory_backed=1
129+
size=64 # MiB
130+
submit_queues=1
131+
power=1
132+
)
133+
_configure_null_blk nullb1 "${null_blk_params[@]}"
134+
local cdev=/dev/nullb1
135+
136+
# A larger zoned block device for the data.
137+
local null_blk_params=(
138+
blocksize=4096
139+
completion_nsec=10000000 # 10 ms
140+
irqmode=2
141+
# Half of the maximum bio size supported by the inline
142+
# encryption fallback code.
143+
max_sectors=$((max_inl_encr_bio_size >> 10))
144+
memory_backed=1
145+
hw_queue_depth=1
146+
size=1024 # MiB
147+
submit_queues=1
148+
# Four times the maximum bio size supported by the inline
149+
# encryption fallback code.
150+
zone_size="$(((4 * max_inl_encr_bio_size) >> 20))"
151+
zoned=1
152+
power=1
153+
)
154+
_configure_null_blk nullb2 "${null_blk_params[@]}"
155+
local zdev_basename=nullb2
156+
local zdev=/dev/${zdev_basename}
157+
local zdev_devno
158+
zdev_devno=$(devno "$zdev")
159+
160+
{
161+
ls -ld "${cdev}" "${zdev}"
162+
echo "${zdev_basename} settings:"
163+
(
164+
cd "/sys/class/block/$zdev_basename/queue" &&
165+
grep -vw 0 ./*
166+
) || true
167+
} >>"${FULL}" 2>&1
168+
169+
trace_block_io "dev == ${zdev_devno}" &
170+
echo $! > "${trace_pid_file}"
171+
wait_until_tracing_started
172+
173+
{
174+
mkfs.f2fs -q -O encrypt -m "${cdev}" -c "${zdev}"
175+
mkdir -p "${mount_dir}"
176+
mount -o inlinecrypt -t f2fs "${cdev}" "${mount_dir}"
177+
local encrypted_dir="${mount_dir}/encrypted"
178+
mkdir -p "${encrypted_dir}"
179+
fscrypt setup "${mount_dir}" </dev/null
180+
local keyfile=$TMPDIR/keyfile
181+
dd if=/dev/zero of="$keyfile" bs=32 count=1 status=none
182+
fscrypt encrypt "${encrypted_dir}" --source=raw_key \
183+
--name=protector --key="$keyfile"
184+
fscrypt status "${encrypted_dir}"
185+
186+
local before after
187+
read -r -a before <"/sys/class/block/${zdev_basename}/stat"
188+
echo "Starting IO"
189+
local cmd="dd if=/dev/zero of=${encrypted_dir}/file bs=64M count=15 conv=fdatasync status=none"
190+
echo "$cmd"
191+
} >>"$FULL" 2>&1
192+
eval "$cmd"
193+
{
194+
ls -ld "${mount_dir}/encrypted/file"
195+
read -r -a after <"/sys/class/block/${zdev_basename}/stat"
196+
report_stats "zdev:" "${before[*]}" "${after[*]}"
197+
} >>"$FULL" 2>&1
198+
}
199+
200+
test() {
201+
echo "Running ${TEST_NAME}"
202+
203+
# Global variables.
204+
mount_dir="$TMPDIR/mnt"
205+
trace_pid_file="$TMPDIR/trace_pid"
206+
207+
(
208+
set -e
209+
run_test
210+
)
211+
# shellcheck disable=SC2181
212+
(($? != 0)) && fail=true
213+
214+
umount "${mount_dir}" >>"${FULL}" 2>&1
215+
local trace_pid
216+
trace_pid=$(cat "${trace_pid_file}" 2>/dev/null)
217+
[ -n "${trace_pid}" ] && stop_tracing "${trace_pid}"
218+
_exit_null_blk
219+
220+
if [ -z "$fail" ]; then
221+
echo "Test complete"
222+
else
223+
echo "Test failed"
224+
return 1
225+
fi
226+
}

tests/zbd/014.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Running zbd/014
2+
Test complete

0 commit comments

Comments
 (0)