xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/tests/functional/syncfs/syncfs_suspend.ksh (revision 3a8960711f4319f9b894ea2453c89065ee1b3a10)
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, Klara, Inc.
26#
27
28. $STF_SUITE/include/libtest.shlib
29
30log_assert "syncfs() does not return success while the pool is suspended"
31
32typeset -i syncfs_pid=0
33
34function cleanup
35{
36	zinject -c all || true
37	zpool clear $TESTPOOL || true
38	test $syncfs_pid -gt 0 && kill -9 $syncfs_pid || true
39	destroy_pool $TESTPOOL
40}
41
42log_onexit cleanup
43
44DISK=${DISKS%% *}
45
46# create a single-disk pool, set failmode=wait
47log_must zpool create -o failmode=wait -f $TESTPOOL $DISK
48log_must zfs create -o recordsize=128k $TESTPOOL/$TESTFS
49
50# generate a write, then syncfs(), confirm success
51log_must touch /$TESTPOOL/$TESTFS/file1
52log_must sync -f /$TESTPOOL/$TESTFS
53
54# and again with no changes
55log_must sync -f /$TESTPOOL/$TESTFS
56
57# set up error injections to force the pool to suspend on next write
58log_must zinject -d $DISK -e io -T write $TESTPOOL
59log_must zinject -d $DISK -e nxio -T probe $TESTPOOL
60
61# generate another write
62log_must touch /$TESTPOOL/$TESTFS/file2
63
64# wait for the pool to suspend
65log_note "waiting for pool to suspend"
66typeset -i tries=10
67until [[ $(kstat_pool $TESTPOOL state) == "SUSPENDED" ]] ; do
68	if ((tries-- == 0)); then
69		log_fail "pool didn't suspend"
70	fi
71	sleep 1
72done
73
74# pool suspended. syncfs() in the background, as it may block
75sync -f /$TESTPOOL/$TESTFS &
76syncfs_pid=$!
77
78# give it a moment to get stuck
79sleep 1
80
81# depending on kernel version and pool config, syncfs should have either
82# returned an error, or be blocked in the kernel
83typeset -i blocked
84typeset -i rc
85if kill -0 $syncfs_pid ; then
86	blocked=1
87	log_note "syncfs() is blocked in the kernel"
88else
89	blocked=0
90	log_note "syncfs() returned while pool was suspended"
91
92	# exited, capture its error code directly
93	wait $syncfs_pid
94	rc=$?
95	syncfs_pid=0
96fi
97
98# bring the pool back online
99log_must zinject -c all
100log_must zpool clear $TESTPOOL
101
102if [[ $syncfs_pid -gt 0 ]] ; then
103	# it blocked, clean it up now
104	wait $syncfs_pid
105	rc=$?
106	syncfs_pid=0
107fi
108
109# if it returned when the pool was suspended, it must not claim success. if
110# it blocked and returned after the pool suspended, then we don't care about
111# the error (it depends on what happened after the pool resumed, which we're
112# not testing here)
113log_must test $blocked -eq 1 -o $rc -ne 0
114
115log_pass "syncfs() does not return success while the pool is suspended"
116