|
| 1 | +#!/bin/bash |
| 2 | +# SPDX-License-Identifier: GPL-3.0+ |
| 3 | +# Copyright (C) 2025 Google LLC |
| 4 | +# |
| 5 | +# There is a bug in the Linux kernel 6.10..6.15 zoned block device code that |
| 6 | +# triggers a deadlock between zoned writes and queue freezing. This test |
| 7 | +# triggers that deadlock. |
| 8 | + |
| 9 | +. tests/zbd/rc |
| 10 | +. common/null_blk |
| 11 | + |
| 12 | +DESCRIPTION="test stacked drivers and queue freezing" |
| 13 | +TIMED=1 |
| 14 | + |
| 15 | +requires() { |
| 16 | + _have_driver dm-crypt |
| 17 | + _have_driver null_blk |
| 18 | + _have_fio |
| 19 | + _have_program cryptsetup |
| 20 | +} |
| 21 | + |
| 22 | +# Trigger blk_mq_freeze_queue() repeatedly. "$1" must be a block device sysfs |
| 23 | +# attribute that triggers queue freezing. "$2" and "$3" are the values that will |
| 24 | +# be written into that sysfs attribute. |
| 25 | +queue_freeze_loop() { |
| 26 | + while true; do |
| 27 | + echo "$2" >"$1" |
| 28 | + sleep .1 |
| 29 | + echo "$3" >"$1" |
| 30 | + sleep .1 |
| 31 | + done |
| 32 | +} |
| 33 | + |
| 34 | +run_test() { |
| 35 | + # A small conventional block device for the LUKS header. |
| 36 | + local null_blk_params=( |
| 37 | + blocksize=4096 |
| 38 | + completion_nsec=0 |
| 39 | + memory_backed=1 |
| 40 | + size=4 # MiB |
| 41 | + submit_queues=1 |
| 42 | + power=1 |
| 43 | + ) |
| 44 | + _configure_null_blk nullb1 "${null_blk_params[@]}" |
| 45 | + local hdev=/dev/nullb1 |
| 46 | + |
| 47 | + # A larger zoned block device for the data. |
| 48 | + local null_blk_params=( |
| 49 | + blocksize=4096 |
| 50 | + completion_nsec=1000000 |
| 51 | + irqmode=2 |
| 52 | + max_sectors=$(((1 << 32) - 1)) |
| 53 | + memory_backed=1 |
| 54 | + size=1024 # MiB |
| 55 | + submit_queues=1 |
| 56 | + zoned=1 |
| 57 | + power=1 |
| 58 | + ) |
| 59 | + _configure_null_blk nullb2 "${null_blk_params[@]}" |
| 60 | + local zdev_basename=nullb2 |
| 61 | + local zdev=/dev/${zdev_basename} |
| 62 | + |
| 63 | + local luks_passphrase=this-passphrase-is-not-secret |
| 64 | + { echo "${luks_passphrase}" | |
| 65 | + cryptsetup luksFormat --batch-mode ${zdev} \ |
| 66 | + --header ${hdev}; } |
| 67 | + { echo "${luks_passphrase}" | |
| 68 | + cryptsetup luksOpen \ |
| 69 | + --batch-mode "${zdev}" "${luks_vol_name}" \ |
| 70 | + --header ${hdev}; } |
| 71 | + local luksdev="/dev/mapper/${luks_vol_name}" |
| 72 | + local dmdev |
| 73 | + dmdev="$(basename "$(readlink "${luksdev}")")" |
| 74 | + ls -ld "${hdev}" "${zdev}" "${luksdev}" "/dev/${dmdev}" >>"${FULL}" 2>&1 |
| 75 | + local max_sectors_zdev |
| 76 | + max_sectors_zdev=/sys/block/"${zdev_basename}"/queue/max_sectors_kb |
| 77 | + echo 4 > "${max_sectors_zdev}" |
| 78 | + echo "${zdev_basename}: max_sectors_kb=$(<"${max_sectors_zdev}")" >>"${FULL}" |
| 79 | + queue_freeze_loop /sys/block/"$dmdev"/queue/read_ahead_kb 4 8 & |
| 80 | + echo $! > "${loop_pid_filename}" |
| 81 | + local fio_args=( |
| 82 | + --bs=64M |
| 83 | + --direct=1 |
| 84 | + --filename="${luksdev}" |
| 85 | + --runtime="${TIMEOUT:-30}" |
| 86 | + --time_based |
| 87 | + --zonemode=zbd |
| 88 | + ) |
| 89 | + _run_fio_verify_io "${fio_args[@]}" >>"${FULL}" 2>&1 |
| 90 | +} |
| 91 | + |
| 92 | +test() { |
| 93 | + echo "Running ${TEST_NAME}" |
| 94 | + |
| 95 | + _remove_null_blk_devices |
| 96 | + |
| 97 | + local loop_pid_filename="${RESULTS_DIR}/${TEST_NAME}.loop_pid" |
| 98 | + local luks_vol_name=zbd-013 |
| 99 | + ( |
| 100 | + set -e |
| 101 | + run_test |
| 102 | + ) |
| 103 | + # shellcheck disable=SC2181 |
| 104 | + (($? != 0)) && fail=true |
| 105 | + |
| 106 | + local loop_pid |
| 107 | + loop_pid="$(cat "${loop_pid_filename}" 2>/dev/null)" |
| 108 | + kill "${loop_pid}" |
| 109 | + cryptsetup luksClose "${luks_vol_name}" |
| 110 | + _exit_null_blk |
| 111 | + |
| 112 | + if [ -z "$fail" ]; then |
| 113 | + echo "Test complete" |
| 114 | + else |
| 115 | + echo "Test failed" |
| 116 | + return 1 |
| 117 | + fi |
| 118 | +} |
0 commit comments