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 dd if=/dev/urandom of=$TESTFILE bs=64k count=1 93log_must zpool sync 94 95# when DIO is disabled via tunable, statx will not return the dioalign result 96# and the program fails 97log_must set_tunable32 DIO_ENABLED 0 98 99for d in disabled standard always ; do 100 log_must zfs set direct=$d $TESTDS 101 assert_dioalign_failed $TESTFILE 102done 103 104# when DIO is enabled via tunable, behaviour is dependent on the direct= 105# property. 106log_must set_tunable32 DIO_ENABLED 1 107 108# when DIO is disabled via property, statx fails 109log_must zfs set direct=disabled $TESTDS 110assert_dioalign_failed $TESTFILE 111 112# when DIO is enabled, the result should be mem=pagesize, io=recordsize 113for d in standard always ; do 114 log_must zfs set direct=$d $TESTDS 115 assert_dioalign $TESTFILE $PAGE_SIZE 131072 116done 117 118# The IO size is the file's blocksize, unless it is in its first block and 119# could grow to the recordsize. Our test file is currently a single 64K block, 120# so any recordsize equal or larger than that should be used for the alignment. 121for krs in 64 128 256 512 ; do 122 typeset -i rs=$((krs * 1024)) 123 log_must zfs set recordsize=$rs $TESTDS 124 for d in standard always ; do 125 log_must zfs set direct=$d $TESTDS 126 assert_dioalign $TESTFILE $PAGE_SIZE $rs 127 done 128done 129 130# If the recordsize is smaller than the block size, then the file's block size 131# will always be used. 132for krs in 4 8 16 32 64 ; do 133 typeset -i rs=$((krs * 1024)) 134 log_must zfs set recordsize=$rs $TESTDS 135 for d in standard always ; do 136 log_must zfs set direct=$d $TESTDS 137 assert_dioalign $TESTFILE $PAGE_SIZE 65536 138 done 139done 140 141# Now we extend the file into its second block. This effectively locks in its 142# block size, which will always be returned regardless of recordsize changes. 143log_must zfs set recordsize=128K $TESTDS 144log_must dd if=/dev/urandom of=$TESTFILE bs=192K count=1 145log_must zpool sync 146 147# Confirm that no matter how we change the recordsize, the alignment remains at 148# the block size. 149for krs in 4 8 16 32 64 128 256 512 ; do 150 typeset -i rs=$((krs * 1024)) 151 log_must zfs set recordsize=$rs $TESTDS 152 for d in standard always ; do 153 log_must zfs set direct=$d $TESTDS 154 assert_dioalign $TESTFILE $PAGE_SIZE 131072 155 done 156done 157 158# reset for write tests 159log_must set_tunable32 DIO_STRICT 1 160log_must zfs set recordsize=16K $TESTDS 161log_must zfs set direct=standard $TESTDS 162 163# create an empty file, and fetch its alignment (which we know, so just test 164# for it). then, do some O_DIRECT writes with that alignment. they should 165# succeed. 166log_must rm -f $TESTFILE 167log_must touch $TESTFILE 168log_must zpool sync 169assert_dioalign $TESTFILE $PAGE_SIZE 16384 170log_must dd if=/dev/urandom of=$TESTFILE bs=16384 count=16 oflag=direct 171 172# same again, but writing with incorrect alignment, which should fail. 173log_must rm -f $TESTFILE 174log_must touch $TESTFILE 175log_must zpool sync 176assert_dioalign $TESTFILE $PAGE_SIZE 16384 177log_mustnot dd if=/dev/urandom of=$TESTFILE bs=1024 count=256 oflag=direct 178 179# same again, but without strict, which should succeed. 180log_must set_tunable32 DIO_STRICT 0 181log_must rm -f $TESTFILE 182log_must touch $TESTFILE 183log_must zpool sync 184assert_dioalign $TESTFILE $PAGE_SIZE 16384 185log_must dd if=/dev/urandom of=$TESTFILE bs=1024 count=256 oflag=direct 186 187log_pass $CLAIM 188