summaryrefslogtreecommitdiff
path: root/tests/xfs/529
blob: cd176877f52713c27aa58831a402dfb1c1212e33 (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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2021 Chandan Babu R.  All Rights Reserved.
#
# FS QA Test 529
#
# Verify that XFS does not cause inode fork's extent count to overflow when
# adding a single extent while there's no possibility of splitting an existing
# mapping.

. ./common/preamble
_begin_fstest auto quick quota prealloc

# Import common functions.
. ./common/filter
. ./common/quota
. ./common/inject
. ./common/populate

# real QA test starts here

_supported_fs xfs
_require_scratch
_require_xfs_quota
_require_xfs_debug
_require_test_program "punch-alternating"
_require_xfs_io_command "falloc"
_require_xfs_io_error_injection "reduce_max_iextents"
_require_xfs_io_error_injection "bmap_alloc_minlen_extent"

echo "Format and mount fs"
_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
_scratch_mount -o uquota >> $seqres.full

# bmap_alloc_minlen_extent only applies to the datadev space allocator, so
# we force the filesystem not to use the realtime volume.
_xfs_force_bdev data $SCRATCH_MNT

bsize=$(_get_file_block_size $SCRATCH_MNT)

echo "* Delalloc to written extent conversion"

testfile=$SCRATCH_MNT/testfile

touch $testfile

echo "Inject reduce_max_iextents error tag"
_scratch_inject_error reduce_max_iextents 1

nr_blks=$((15 * 2))

echo "Create fragmented file"
for i in $(seq 0 2 $((nr_blks - 1))); do
	$XFS_IO_PROG -f -s -c "pwrite $((i * bsize)) $bsize" $testfile \
	       >> $seqres.full 2>&1
	[[ $? != 0 ]] && break
done

echo "Verify \$testfile's extent count"

nextents=$(_xfs_get_fsxattr nextents $testfile)
if (( $nextents > 10 )); then
	echo "Extent count overflow check failed: nextents = $nextents"
	exit 1
fi

echo "Disable reduce_max_iextents error tag"
_scratch_inject_error reduce_max_iextents 0

rm $testfile

echo "* Fallocate unwritten extents"

touch $testfile

echo "Inject reduce_max_iextents error tag"
_scratch_inject_error reduce_max_iextents 1

echo "Fallocate fragmented file"
for i in $(seq 0 2 $((nr_blks - 1))); do
	$XFS_IO_PROG -f -c "falloc $((i * bsize)) $bsize" $testfile \
	       >> $seqres.full 2>&1
	[[ $? != 0 ]] && break
done

echo "Verify \$testfile's extent count"

nextents=$(_xfs_get_fsxattr nextents $testfile)
if (( $nextents > 10 )); then
	echo "Extent count overflow check failed: nextents = $nextents"
	exit 1
fi

echo "Disable reduce_max_iextents error tag"
_scratch_inject_error reduce_max_iextents 0

rm $testfile

echo "* Directio write"

touch $testfile

echo "Inject reduce_max_iextents error tag"
_scratch_inject_error reduce_max_iextents 1

echo "Create fragmented file via directio writes"
for i in $(seq 0 2 $((nr_blks - 1))); do
	$XFS_IO_PROG -d -s -f -c "pwrite $((i * bsize)) $bsize" $testfile \
	       >> $seqres.full 2>&1
	[[ $? != 0 ]] && break
done

echo "Verify \$testfile's extent count"

nextents=$(_xfs_get_fsxattr nextents $testfile)
if (( $nextents > 10 )); then
	echo "Extent count overflow check failed: nextents = $nextents"
	exit 1
fi

echo "Disable reduce_max_iextents error tag"
_scratch_inject_error reduce_max_iextents 0

rm $testfile

# Check if XFS gracefully returns with an error code when we try to increase
# extent count of user quota inode beyond the pseudo max extent count limit.
echo "* Extend quota inodes"

echo "Consume free space"
fillerdir=$SCRATCH_MNT/fillerdir
nr_free_blks=$(stat -f -c '%f' $SCRATCH_MNT)
nr_free_blks=$((nr_free_blks * 90 / 100))

_fill_fs $((bsize * nr_free_blks)) $fillerdir $bsize 0 >> $seqres.full 2>&1

echo "Create fragmented filesystem"
for dentry in $(ls -1 $fillerdir/); do
	$here/src/punch-alternating $fillerdir/$dentry >> $seqres.full
done

echo "Inject reduce_max_iextents error tag"
_scratch_inject_error reduce_max_iextents 1

echo "Inject bmap_alloc_minlen_extent error tag"
_scratch_inject_error bmap_alloc_minlen_extent 1

nr_blks=20

# This is a rough calculation; It doesn't take block headers into
# consideration.
# gdb -batch vmlinux -ex 'print sizeof(struct xfs_dqblk)'
# $1 = 136
nr_quotas_per_block=$((bsize / 136))
nr_quotas=$((nr_quotas_per_block * nr_blks))

echo "Extend uquota file"
for i in $(seq 0 $nr_quotas_per_block $nr_quotas); do
	chown $i $fillerdir >> $seqres.full 2>&1
	[[ $? != 0 ]] && break
done

_scratch_unmount >> $seqres.full

echo "Verify uquota inode's extent count"
uquotino=$(_scratch_xfs_get_metadata_field 'uquotino' 'sb 0')

nextents=$(_scratch_get_iext_count $uquotino data || \
		   _fail "Unable to obtain inode fork's extent count")
if (( $nextents > 10 )); then
	echo "Extent count overflow check failed: nextents = $nextents"
	exit 1
fi

# success, all done
status=0
exit