summaryrefslogtreecommitdiff
path: root/tests/xfs/438
blob: 0425c5b1f640e72cd690bd737300636b4492dc91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2018 Huawei Technologies Co., Ltd. All Rights Reserved.
#
# FS QA Test No. 438
#
# Test for XFS umount hang problem caused by the unceasing push
# of dquot log item in AIL. Because xfs_qm_dqflush_done() will
# not be invoked, so each time xfsaild initiates the push,
# the push will return early after checking xfs_dqflock_nowait().
#
# xfs_qm_dqflush_done() should be invoked by xfs_buf_do_callbacks().
# However after the first write and the retried write of dquota buffer
# get the same IO error, XFS will let xfsaild to restart the write and
# xfs_buf_do_callbacks() will not be inovked.
#
# This test emulates the write error by using dm-flakey. The log
# area of the XFS filesystem is excluded from the range covered by
# dm-flakey, so the XFS will not be shutdown prematurely.
#
# Fixed by upstream commit 373b058 ("xfs: Properly retry failed dquot
# items in case of error during buffer writeback")
. ./common/preamble
_begin_fstest auto quick quota freeze

# Override the default cleanup function.
_cleanup()
{
	# Make sure $SCRATCH_MNT is unfreezed
	xfs_freeze -u $SCRATCH_MNT 2>/dev/null
	[ -z "${interval}" ] || \
		sysctl -w fs.xfs.xfssyncd_centisecs=${interval} >/dev/null 2>&1
	cd /
	rm -f $tmp.*
	_unmount_flakey >/dev/null 2>&1
	_cleanup_flakey > /dev/null 2>&1
}

# inject IO write error for the XFS filesystem except its log section
make_xfs_scratch_flakey_table()
{
	local tgt=flakey
	local opt="0 1 1 error_writes"
	local dev=${SCRATCH_DEV}
	local dev_sz=$(blockdev --getsz $dev)

	# If using an external log device, just making the writing of
	# entire data/metadata area fail forever.
	if [ "${USE_EXTERNAL}" = "yes" -a ! -z "$SCRATCH_LOGDEV" ]; then
		echo "0 ${dev_sz} $tgt $dev 0 $opt"
		return
	fi

	local blk_sz=$(_scratch_xfs_get_sb_field blocksize)
	local log_ofs=$(_scratch_xfs_get_sb_field logstart)
	local log_sz=$(_scratch_xfs_get_sb_field logblocks)
	local table=""
	local ofs=0
	local sz

	log_ofs=$(_scratch_xfs_db -r -c "convert fsb ${log_ofs} bb" | \
			  $AWK_PROG '{gsub("[()]", "", $2); print $2}')
	let "log_sz *= blk_sz / 512"

	# Add a flakey target for the area before the log section
	# to make the data/metadata write fail forever
	if [ "$ofs" -lt "${log_ofs}" ]; then
		let "sz = log_ofs - ofs"
		table="$ofs $sz $tgt $dev $ofs $opt"
	fi

	# Add a linear target for the log section, so the log write
	# will work normally
	table="$table\n${log_ofs} ${log_sz} linear $dev ${log_ofs}"

	# Add a flakey target for the area after the log section
	# to make the data/metadata write fail forever
	let "ofs = log_ofs + log_sz"
	if [ "$ofs" -lt "${dev_sz}" ]; then
		let "sz = dev_sz - ofs"
		table="$table\n$ofs $sz $tgt $dev $ofs $opt"
	fi

	echo -e $table
}

# Import common functions.
. ./common/dmflakey
. ./common/quota

_supported_fs xfs

# due to the injection of write IO error, the fs will be inconsistent
_require_scratch_nocheck
_require_flakey_with_error_writes
_require_user
_require_xfs_quota
_require_freeze

echo "Silence is golden"

_scratch_mkfs > $seqres.full 2>&1

# no error will be injected
_init_flakey
$DMSETUP_PROG info >> $seqres.full
$DMSETUP_PROG table >> $seqres.full

# save the old value for _cleanup()
interval=$(sysctl -n fs.xfs.xfssyncd_centisecs 2>/dev/null)
# shorten the time waiting for the push of ail items
sysctl -w fs.xfs.xfssyncd_centisecs=100 >> $seqres.full 2>&1

_qmount_option "usrquota"
_mount_flakey

# We need to set the quota limitation twice, and inject the write error
# after the second setting. If we try to inject the write error after
# the first setting, the initialization of the dquota buffer will get
# IO error and also be retried, and during the umount process the
# write will be ended, and xfs_qm_dqflush_done() will be inovked, and
# the umount will exit normally.
$XFS_QUOTA_PROG -x -c "limit -u isoft=500 $qa_user" $SCRATCH_MNT
$XFS_QUOTA_PROG -x -c "report -ih" $SCRATCH_MNT >> $seqres.full

# ensure the initialization of the dquota buffer is done
xfs_freeze -f $SCRATCH_MNT
xfs_freeze -u $SCRATCH_MNT

# inject write IO error
FLAKEY_TABLE_ERROR=$(make_xfs_scratch_flakey_table)
_load_flakey_table ${FLAKEY_ERROR_WRITES}
$DMSETUP_PROG info >> $seqres.full
$DMSETUP_PROG table >> $seqres.full

# update the dquota buffer
$XFS_QUOTA_PROG -x -c "limit -u isoft=400 $qa_user" $SCRATCH_MNT
$XFS_QUOTA_PROG -x -c "report -ih" $SCRATCH_MNT >> $seqres.full

sync

# wait for the push of the dquota log item in AIL and
# the completion of the retried write of dquota buffer
sleep 2

_unmount_flakey

_cleanup_flakey

# success, all done
status=0
exit