t/zbd: set mq-deadline scheduler to device-mapper destination devices
authorShin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Wed, 13 Sep 2023 01:52:49 +0000 (10:52 +0900)
committerVincent Fu <vincent.fu@samsung.com>
Tue, 26 Sep 2023 13:00:13 +0000 (09:00 -0400)
When write workloads run on zoned block devices, mq-deadline scheduler is
required to ensure write operations are sequential. To fulfill this
requirement, the test script t/zbd/test-zbd-support sets mq-deadline to
the sysfs attribute "queue/scheduler". However, this preparation does
not work when the write target device is a bio based device-mapper
device. The device is bio based then I/O scheduler does not work.
Setting mq-deadline to the sysfs attribute has no effect. On top of
that, the sysfs attribute "queue/scheduler" is no longer available for
bio based device-mapper devices since Linux kernel version v6.5.

To ensure mq-deadline scheduler for bio based device-mapper devices,
improve the helper function set_io_scheduler. If the sysfs attribute
"queue/scheduler" is available, use it. Otherwise, check if the test
device is a zoned device-mapper (linear, flakey or crypt). If so, set
mq-deadline scheduler to destination devices of the device-mapper
device. To implement these, add some helper functions.

Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Link: https://lore.kernel.org/r/20230913015249.2226799-1-shinichiro.kawasaki@wdc.com
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
t/zbd/functions
t/zbd/test-zbd-support

index 4faa45a92df7831776acc752c7ae81e7440d9fb5..028df4040e626a5f2823d84bd36a158996fd0f84 100644 (file)
@@ -27,6 +27,17 @@ blkzone_reports_capacity() {
                "${blkzone}" report -c 1 -o 0 "${dev}" | grep -q 'cap '
 }
 
+has_command() {
+       local cmd="${1}"
+
+       cmd_path=$(type -p "${cmd}" 2>/dev/null)
+       if [ -z "${cmd_path}" ]; then
+               echo "${cmd} is not available"
+               return 1
+       fi
+       return 0
+}
+
 # Whether or not $1 (/dev/...) is a NVME ZNS device.
 is_nvme_zns() {
        local s
index c8f3eb614f996045a13a10f39f5ce095f673762b..0436d319dad29aebf422cf56e2d7357d5aabec29 100755 (executable)
@@ -46,6 +46,55 @@ ioengine() {
        fi
 }
 
+get_dev_path_by_id() {
+       for d in /sys/block/* /sys/block/*/*; do
+               if [[ ! -r "${d}/dev" ]]; then
+                       continue
+               fi
+               if [[ "${1}" == "$(<"${d}/dev")" ]]; then
+                       echo "/dev/${d##*/}"
+                       return 0
+               fi
+       done
+       return 1
+}
+
+dm_destination_dev_set_io_scheduler() {
+       local dev=$1 sched=$2
+       local dest_dev_id dest_dev path
+
+       has_command dmsetup || return 1
+
+       while read -r dest_dev_id; do
+               if ! dest_dev=$(get_dev_path_by_id "${dest_dev_id}"); then
+                       continue
+               fi
+               path=${dest_dev/dev/sys\/block}/queue/scheduler
+               if [[ ! -w ${path} ]]; then
+                       echo "Can not set scheduler of device mapper destination: ${dest_dev}"
+                       continue
+               fi
+               echo "${2}" > "${path}"
+       done < <(dmsetup table "$(<"/sys/block/$dev/dm/name")" |
+                        sed -n  's/.* \([0-9]*:[0-9]*\).*/\1/p')
+}
+
+dev_has_dm_map() {
+       local dev=${1} target_type=${2}
+       local dm_name
+
+       has_command dmsetup || return 1
+
+       dm_name=$(<"/sys/block/$dev/dm/name")
+       if ! dmsetup status "${dm_name}" | grep -qe "${target_type}"; then
+               return 1
+       fi
+       if dmsetup status "${dm_name}" | grep -v "${target_type}"; then
+               return 1
+       fi
+       return 0
+}
+
 set_io_scheduler() {
     local dev=$1 sched=$2
 
@@ -62,7 +111,17 @@ set_io_scheduler() {
        esac
     fi
 
-    echo "$sched" >"/sys/block/$dev/queue/scheduler"
+    if [ -w "/sys/block/$dev/queue/scheduler" ]; then
+       echo "$sched" >"/sys/block/$dev/queue/scheduler"
+    elif [ -r  "/sys/block/$dev/dm/name" ] &&
+                ( dev_has_dm_map "$dev" linear ||
+                  dev_has_dm_map "$dev" flakey ||
+                  dev_has_dm_map "$dev" crypt ); then
+       dm_destination_dev_set_io_scheduler "$dev" "$sched"
+    else
+       echo "can not set io scheduler"
+       exit 1
+    fi
 }
 
 check_read() {