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