xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/tests/functional/stat/statx_dioalign.ksh (revision b1c1ee4429fcca8f69873a8be66184e68e1b19d7)
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