1#!/bin/ksh -p 2# SPDX-License-Identifier: CDDL-1.0 3# 4# CDDL HEADER START 5# 6# The contents of this file are subject to the terms of the 7# Common Development and Distribution License (the "License"). 8# You may not use this file except in compliance with the License. 9# 10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11# or https://opensource.org/licenses/CDDL-1.0. 12# See the License for the specific language governing permissions 13# and limitations under the License. 14# 15# When distributing Covered Code, include this CDDL HEADER in each 16# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17# If applicable, add the following below this CDDL HEADER, with the 18# fields enclosed by brackets "[]" replaced with your own identifying 19# information: Portions Copyright [yyyy] [name of copyright owner] 20# 21# CDDL HEADER END 22# 23 24# 25# Copyright (c) 2025, Rob Norris <robn@despairlabs.com> 26# 27 28# 29# Uses the statx helper to test the results of the STATX_DIOALIGN request as we 30# manipulate DIO enable, dataset recordsize and file size and structure. 31# 32 33. $STF_SUITE/include/libtest.shlib 34 35verify_runnable "both" 36 37if ! is_linux ; then 38 log_unsupported "statx(2) only available on Linux" 39fi 40 41if [[ $(linux_version) -lt $(linux_version "6.1") ]] ; then 42 log_unsupported "STATX_DIOALIGN not available before Linux 6.1" 43fi 44 45CLAIM="STATX_DIOALIGN returns useful values when Direct IO is available." 46 47TESTDS=${TESTPOOL}/${TESTFS} 48TESTFILE=${TESTDIR}/${TESTFILE0} 49 50log_must save_tunable DIO_ENABLED 51log_must save_tunable DIO_STRICT 52typeset recordsize_saved=$(get_prop recordsize $TESTDS) 53typeset direct_saved=$(get_prop direct $TESTDS) 54 55function cleanup 56{ 57 rm -f ${TESTFILE} 58 zfs set recordsize=$recordsize_saved $TESTDS 59 zfs set direct=$direct_saved $TESTDS 60 restore_tunable DIO_ENABLED 61 restore_tunable DIO_STRICT 62} 63log_onexit cleanup 64 65# assert_dioalign <file> <memalign> <ioalign> 66function assert_dioalign 67{ 68 typeset file=$1 69 typeset -i memalign=$2 70 typeset -i ioalign=$3 71 72 typeset -a v=($(statx dioalign $file | cut -f2- -d' ')) 73 log_note "statx dioalign returned: $file: mem=${v[0]} io=${v[1]}" 74 log_must [ ${v[0]} -eq $memalign -a ${v[1]} -eq $ioalign ] 75} 76 77# assert_dioalign_failed <file> 78function assert_dioalign_failed 79{ 80 typeset file=$1 81 log_mustnot statx dioalign $file 82} 83 84log_assert $CLAIM 85 86# The mem alignment will always be PAGE_SIZE, so we need to know what that is. 87typeset -i PAGE_SIZE=$(getconf PAGE_SIZE) 88 89# Set recordsize to 128K, and make a 64K file (so only one block) for the 90# sizing tests below. 91log_must zfs set recordsize=128K $TESTDS 92log_must rm -f $TESTFILE 93log_must stride_dd -i /dev/urandom -o $TESTFILE -b 65536 -c 1 94log_must zpool sync 95 96# when DIO is disabled via tunable, statx will not return the dioalign result 97# and the program fails 98log_must set_tunable32 DIO_ENABLED 0 99 100for d in disabled standard always ; do 101 log_must zfs set direct=$d $TESTDS 102 assert_dioalign_failed $TESTFILE 103done 104 105# when DIO is enabled via tunable, behaviour is dependent on the direct= 106# property. 107log_must set_tunable32 DIO_ENABLED 1 108 109# when DIO is disabled via property, statx fails 110log_must zfs set direct=disabled $TESTDS 111assert_dioalign_failed $TESTFILE 112 113# when DIO is enabled, the result should be mem=pagesize, io=recordsize 114for d in standard always ; do 115 log_must zfs set direct=$d $TESTDS 116 assert_dioalign $TESTFILE $PAGE_SIZE 131072 117done 118 119# The IO size is the file's blocksize, unless it is in its first block and 120# could grow to the recordsize. Our test file is currently a single 64K block, 121# so any recordsize equal or larger than that should be used for the alignment. 122for krs in 64 128 256 512 ; do 123 typeset -i rs=$((krs * 1024)) 124 log_must zfs set recordsize=$rs $TESTDS 125 for d in standard always ; do 126 log_must zfs set direct=$d $TESTDS 127 assert_dioalign $TESTFILE $PAGE_SIZE $rs 128 done 129done 130 131# If the recordsize is smaller than the block size, then the file's block size 132# will always be used. 133for krs in 4 8 16 32 64 ; do 134 typeset -i rs=$((krs * 1024)) 135 log_must zfs set recordsize=$rs $TESTDS 136 for d in standard always ; do 137 log_must zfs set direct=$d $TESTDS 138 assert_dioalign $TESTFILE $PAGE_SIZE 65536 139 done 140done 141 142# Now we extend the file into its second block. This effectively locks in its 143# block size, which will always be returned regardless of recordsize changes. 144log_must zfs set recordsize=128K $TESTDS 145log_must stride_dd -i /dev/urandom -o $TESTFILE -b 196608 -c 1 146log_must zpool sync 147 148# Confirm that no matter how we change the recordsize, the alignment remains at 149# the block size. 150for krs in 4 8 16 32 64 128 256 512 ; do 151 typeset -i rs=$((krs * 1024)) 152 log_must zfs set recordsize=$rs $TESTDS 153 for d in standard always ; do 154 log_must zfs set direct=$d $TESTDS 155 assert_dioalign $TESTFILE $PAGE_SIZE 131072 156 done 157done 158 159# reset for write tests 160log_must set_tunable32 DIO_STRICT 1 161log_must zfs set recordsize=16K $TESTDS 162log_must zfs set direct=standard $TESTDS 163 164# create an empty file, and fetch its alignment (which we know, so just test 165# for it). then, do some O_DIRECT writes with that alignment. they should 166# succeed. 167log_must rm -f $TESTFILE 168log_must touch $TESTFILE 169log_must zpool sync 170assert_dioalign $TESTFILE $PAGE_SIZE 16384 171log_must stride_dd -i /dev/urandom -o $TESTFILE -b 16384 -c 16 -D 172 173# same again, but writing with incorrect alignment, which should fail. 174log_must rm -f $TESTFILE 175log_must touch $TESTFILE 176log_must zpool sync 177assert_dioalign $TESTFILE $PAGE_SIZE 16384 178log_mustnot stride_dd -i /dev/urandom -o $TESTFILE -b 1024 -c 256 -D 179 180# same again, but without strict, which should succeed. 181log_must set_tunable32 DIO_STRICT 0 182log_must rm -f $TESTFILE 183log_must touch $TESTFILE 184log_must zpool sync 185assert_dioalign $TESTFILE $PAGE_SIZE 16384 186log_must stride_dd -i /dev/urandom -o $TESTFILE -b 1024 -c 256 -D 187 188log_pass $CLAIM 189