generic: make 17[1-4] work well when btrfs compression is enabled
[xfstests-dev.git] / common / populate
1 ##/bin/bash
2 # Routines for populating a scratch fs, and helpers to exercise an FS
3 # once it's been fuzzed.
4 #-----------------------------------------------------------------------
5 #  Copyright (c) 2015 Oracle.  All Rights Reserved.
6 #  This program is free software; you can redistribute it and/or modify
7 #  it under the terms of the GNU General Public License as published by
8 #  the Free Software Foundation; either version 2 of the License, or
9 #  (at your option) any later version.
10 #
11 #  This program is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #  GNU General Public License for more details.
15 #
16 #  You should have received a copy of the GNU General Public License
17 #  along with this program; if not, write to the Free Software
18 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
19 #  USA
20 #
21 #  Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
22 #  Mountain View, CA 94043, USA, or: http://www.sgi.com
23 #-----------------------------------------------------------------------
24
25 _require_xfs_io_command "falloc"
26 _require_xfs_io_command "fpunch"
27
28 _require_xfs_db_blocktrash_z_command() {
29         test "${FSTYP}" = "xfs" || _notrun "cannot run xfs_db on ${FSTYP}"
30         $XFS_DB_PROG -x -f -c 'blocktrash -z' "${TEST_DEV}" | grep -q 'nothing on stack' || _notrun "blocktrash -z not supported"
31 }
32
33 # Attempt to make files of "every" format for data, dirs, attrs etc.
34 # (with apologies to Eric Sandeen for mutating xfser.sh)
35
36 # Create a large directory
37 __populate_create_dir() {
38         name="$1"
39         nr="$2"
40         missing="$3"
41
42         mkdir -p "${name}"
43         seq 0 "${nr}" | while read d; do
44                 creat=mkdir
45                 test "$((d % 20))" -eq 0 && creat=touch
46                 $creat "${name}/$(printf "%.08d" "$d")"
47         done
48
49         test -z "${missing}" && return
50         seq 1 2 "${nr}" | while read d; do
51                 rm -rf "${name}/$(printf "%.08d" "$d")"
52         done
53 }
54
55 # Add a bunch of attrs to a file
56 __populate_create_attr() {
57         name="$1"
58         nr="$2"
59         missing="$3"
60
61         touch "${name}"
62         seq 0 "${nr}" | while read d; do
63                 setfattr -n "user.$(printf "%.08d" "$d")" -v "$(printf "%.08d" "$d")" "${name}"
64         done
65
66         test -z "${missing}" && return
67         seq 1 2 "${nr}" | while read d; do
68                 setfattr -x "user.$(printf "%.08d" "$d")" "${name}"
69         done
70 }
71
72 # Fill up 60% of the remaining free space
73 __populate_fill_fs() {
74         dir="$1"
75         pct="$2"
76         test -z "${pct}" && pct=60
77
78         SRC_SZ="$(du -ks "${SRCDIR}" | cut -f 1)"
79         FS_SZ="$(( $(stat -f "${dir}" -c '%a * %S') / 1024 ))"
80
81         NR="$(( (FS_SZ * ${pct} / 100) / SRC_SZ ))"
82         test "${NR}" -lt 1 && NR=1
83
84         seq 1 "${NR}" | while read nr; do
85                 cp -pRdu "${SRCDIR}" "${dir}/test.${nr}" >> $seqres.full 2>&1
86         done
87 }
88
89 # Populate an XFS on the scratch device with (we hope) all known
90 # types of metadata block
91 _scratch_xfs_populate() {
92         _scratch_mount
93         blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
94         dblksz="$(xfs_info "${SCRATCH_MNT}" | grep naming.*bsize | sed -e 's/^.*bsize=//g' -e 's/\([0-9]*\).*$/\1/g')"
95         leaf_lblk="$((32 * 1073741824 / blksz))"
96         node_lblk="$((64 * 1073741824 / blksz))"
97
98         # Data:
99
100         # Regular files
101         # - FMT_EXTENTS
102         echo "+ extents file"
103         $XFS_IO_PROG -f -c "pwrite -S 0x61 0 ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS"
104
105         # - FMT_BTREE
106         echo "+ btree extents file"
107         nr="$((blksz * 2 / 16))"
108         $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE"
109         for i in $(seq 1 2 ${nr}); do
110                 $XFS_IO_PROG -f -c "fpunch $((i * blksz)) ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE"
111         done
112
113         # Directories
114         # - INLINE
115         echo "+ inline dir"
116         __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE" 1
117
118         # - BLOCK
119         echo "+ block dir"
120         __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK" "$((dblksz / 40))"
121
122         # - LEAF
123         echo "+ leaf dir"
124         __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_LEAF" "$((dblksz / 12))"
125
126         # - NODE
127         echo "+ node dir"
128         __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_NODE" "$((16 * dblksz / 40))" true
129
130         # - BTREE
131         __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BTREE" "$((128 * dblksz / 40))" true
132
133         # Symlinks
134         # - FMT_LOCAL
135         echo "+ inline symlink"
136         ln -s target "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL"
137
138         # - FMT_EXTENTS
139         echo "+ extents symlink"
140         ln -s "$(perl -e 'print "x" x 1023;')" "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS"
141
142         # Char & block
143         echo "+ special"
144         mknod "${SCRATCH_MNT}/S_IFCHR" c 1 1
145         mknod "${SCRATCH_MNT}/S_IFBLK" c 1 1
146
147         # Attribute formats
148         # LOCAL
149         echo "+ local attr"
150         __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LOCAL" 1
151
152         # LEAF
153         echo "+ leaf attr"
154         __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LEAF" "$((blksz / 40))"
155
156         # NODE
157         echo "+ node attr"
158         __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_NODE" "$((8 * blksz / 40))"
159
160         # BTREE
161         echo "+ btree attr"
162         __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BTREE" "$((64 * blksz / 40))" true
163
164         # FMT_EXTENTS with a remote less-than-a-block value
165         echo "+ attr extents with a remote less-than-a-block value"
166         touch "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE3K"
167         $XFS_IO_PROG -f -c "pwrite -S 0x43 0 3k" "${SCRATCH_MNT}/attrvalfile" > /dev/null
168         attr -q -s user.remotebtreeattrname "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE3K" < "${SCRATCH_MNT}/attrvalfile"
169
170         # FMT_EXTENTS with a remote block-size value
171         echo "+ attr extents with a remote one-block value"
172         touch "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE4K"
173         $XFS_IO_PROG -f -c "pwrite -S 0x44 0 4k" "${SCRATCH_MNT}/attrvalfile" > /dev/null
174         attr -q -s user.remotebtreeattrname "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE4K" < "${SCRATCH_MNT}/attrvalfile"
175         rm -rf "${SCRATCH_MNT}/attrvalfile"
176
177         # Make an unused inode
178         echo "+ empty file"
179         touch "${SCRATCH_MNT}/unused"
180         $XFS_IO_PROG -f -c 'fsync' "${SCRATCH_MNT}/unused"
181         rm -rf "${SCRATCH_MNT}/unused"
182
183         # Copy some real files (xfs tests, I guess...)
184         echo "+ real files"
185         #__populate_fill_fs "${SCRATCH_MNT}" 40
186         cp -pRdu --reflink=always "${SCRATCH_MNT}/S_IFREG.FMT_BTREE" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE.REFLINK" 2> /dev/null
187
188         umount "${SCRATCH_MNT}"
189 }
190
191 # Populate an ext4 on the scratch device with (we hope) all known
192 # types of metadata block
193 _scratch_ext4_populate() {
194         _scratch_mount
195         blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
196         dblksz="${blksz}"
197         leaf_lblk="$((32 * 1073741824 / blksz))"
198         node_lblk="$((64 * 1073741824 / blksz))"
199
200         # Data:
201
202         # Regular files
203         # - FMT_INLINE
204         echo "+ inline file"
205         $XFS_IO_PROG -f -c "pwrite -S 0x61 0 1" "${SCRATCH_MNT}/S_IFREG.FMT_INLINE"
206
207         # - FMT_EXTENTS
208         echo "+ extents file"
209         $XFS_IO_PROG -f -c "pwrite -S 0x61 0 ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS"
210
211         # - FMT_ETREE
212         echo "+ extent tree file"
213         nr="$((blksz * 2 / 12))"
214         $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/S_IFREG.FMT_ETREE"
215         for i in $(seq 1 2 ${nr}); do
216                 $XFS_IO_PROG -f -c "fpunch $((i * blksz)) ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_ETREE"
217         done
218
219         # Directories
220         # - INLINE
221         echo "+ inline dir"
222         __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE" 1
223
224         # - BLOCK
225         echo "+ block dir"
226         __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK" "$((dblksz / 24))"
227
228         # - HTREE
229         echo "+ htree dir"
230         __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_HTREE" "$((4 * dblksz / 24))"
231
232         # Symlinks
233         # - FMT_LOCAL
234         echo "+ inline symlink"
235         ln -s target "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL"
236
237         # - FMT_EXTENTS
238         echo "+ extents symlink"
239         ln -s "$(perl -e 'print "x" x 1023;')" "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS"
240
241         # Char & block
242         echo "+ special"
243         mknod "${SCRATCH_MNT}/S_IFCHR" c 1 1
244         mknod "${SCRATCH_MNT}/S_IFBLK" c 1 1
245
246         # Attribute formats
247         # LOCAL
248         echo "+ local attr"
249         __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LOCAL" 1
250
251         # BLOCK
252         echo "+ block attr"
253         __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BLOCK" "$((blksz / 40))"
254
255         # Make an unused inode
256         echo "+ empty file"
257         touch "${SCRATCH_MNT}/unused"
258         $XFS_IO_PROG -f -c 'fsync' "${SCRATCH_MNT}/unused"
259         rm -rf "${SCRATCH_MNT}/unused"
260
261         # Copy some real files (xfs tests, I guess...)
262         echo "+ real files"
263         __populate_fill_fs "${SCRATCH_MNT}"
264         cp -pRdu --reflink=always "${SCRATCH_MNT}/S_IFREG.FMT_ETREE" "${SCRATCH_MNT}/S_IREG.FMT_ETREE.REFLINK" 2> /dev/null
265
266         umount "${SCRATCH_MNT}"
267 }
268
269 # Find the inode number of a file
270 __populate_find_inode() {
271         name="$1"
272         inode="$(stat -c '%i' "${name}")"
273         echo "${inode}"
274 }
275
276 # Check data fork format of XFS file
277 __populate_check_xfs_dformat() {
278         inode="$1"
279         format="$2"
280
281         fmt="$(_scratch_xfs_db -c "inode ${inode}" -c 'p core.format' | sed -e 's/^.*(\([a-z]*\)).*$/\1/g')"
282         test "${format}" = "${fmt}" || _fail "failed to create ino ${inode} dformat expected ${format} saw ${fmt}"
283 }
284
285 # Check attr fork format of XFS file
286 __populate_check_xfs_aformat() {
287         inode="$1"
288         format="$2"
289
290         fmt="$(_scratch_xfs_db -c "inode ${inode}" -c 'p core.aformat' | sed -e 's/^.*(\([a-z]*\)).*$/\1/g')"
291         test "${format}" = "${fmt}" || _fail "failed to create ino ${inode} aformat expected ${format} saw ${fmt}"
292 }
293
294 # Check structure of XFS directory
295 __populate_check_xfs_dir() {
296         inode="$1"
297         dtype="$2"
298
299         (test -n "${leaf_lblk}" && test -n "${node_lblk}") || _fail "must define leaf_lblk and node_lblk before calling __populate_check_xfs_dir"
300         datab=0
301         leafb=0
302         freeb=0
303         #echo "== check dir ${inode} type ${dtype}" ; _scratch_xfs_db -x -c "inode ${inode}" -c "bmap"
304         _scratch_xfs_db -x -c "inode ${inode}" -c "dblock 0" -c "stack" | grep -q 'file data block is unmapped' || datab=1
305         _scratch_xfs_db -x -c "inode ${inode}" -c "dblock ${leaf_lblk}" -c "stack" | grep -q 'file data block is unmapped' || leafb=1
306         _scratch_xfs_db -x -c "inode ${inode}" -c "dblock ${node_lblk}" -c "stack" | grep -q 'file data block is unmapped' || freeb=1
307
308         case "${dtype}" in
309         "shortform"|"inline"|"local")
310                 (test "${datab}" -eq 0 && test "${leafb}" -eq 0 && test "${freeb}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} datab ${datab} leafb ${leafb} freeb ${freeb}"
311                 ;;
312         "block")
313                 (test "${datab}" -eq 1 && test "${leafb}" -eq 0 && test "${freeb}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} datab ${datab} leafb ${leafb} freeb ${freeb}"
314                 ;;
315         "leaf")
316                 (test "${datab}" -eq 1 && test "${leafb}" -eq 1 && test "${freeb}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} datab ${datab} leafb ${leafb} freeb ${freeb}"
317                 ;;
318         "node"|"btree")
319                 (test "${datab}" -eq 1 && test "${leafb}" -eq 1 && test "${freeb}" -eq 1) || _fail "failed to create ${dtype} dir ino ${inode} datab ${datab} leafb ${leafb} freeb ${freeb}"
320                 ;;
321         *)
322                 _fail "Unknown directory type ${dtype}"
323         esac
324 }
325
326 # Check structure of XFS attr
327 __populate_check_xfs_attr() {
328         inode="$1"
329         atype="$2"
330
331         datab=0
332         leafb=0
333         #echo "== check attr ${inode} type ${dtype}" ; _scratch_xfs_db -x -c "inode ${inode}" -c "bmap -a"
334         _scratch_xfs_db -x -c "inode ${inode}" -c "ablock 0" -c "stack" | grep -q 'file attr block is unmapped' || datab=1
335         _scratch_xfs_db -x -c "inode ${inode}" -c "ablock 1" -c "stack" | grep -q 'file attr block is unmapped' || leafb=1
336
337         case "${atype}" in
338         "shortform"|"inline"|"local")
339                 (test "${datab}" -eq 0 && test "${leafb}" -eq 0) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
340                 ;;
341         "leaf")
342                 (test "${datab}" -eq 1 && test "${leafb}" -eq 0) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
343                 ;;
344         "node"|"btree")
345                 (test "${datab}" -eq 1 && test "${leafb}" -eq 1) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
346                 ;;
347         *)
348                 _fail "Unknown attribute type ${atype}"
349         esac
350 }
351
352 # Check that populate created all the types of files we wanted
353 _scratch_xfs_populate_check() {
354         _scratch_mount
355         extents_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS")"
356         btree_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_BTREE")"
357         inline_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE")"
358         block_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK")"
359         leaf_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_LEAF")"
360         node_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_NODE")"
361         btree_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BTREE")"
362         local_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL")"
363         extents_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS")"
364         bdev="$(__populate_find_inode "${SCRATCH_MNT}/S_IFBLK")"
365         cdev="$(__populate_find_inode "${SCRATCH_MNT}/S_IFCHR")"
366         local_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LOCAL")"
367         leaf_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LEAF")"
368         node_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_NODE")"
369         btree_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_BTREE")"
370
371         blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
372         dblksz="$(xfs_info "${SCRATCH_MNT}" | grep naming.*bsize | sed -e 's/^.*bsize=//g' -e 's/\([0-9]*\).*$/\1/g')"
373         leaf_lblk="$((32 * 1073741824 / blksz))"
374         node_lblk="$((64 * 1073741824 / blksz))"
375         umount "${SCRATCH_MNT}"
376
377         __populate_check_xfs_dformat "${extents_file}" "extents"
378         __populate_check_xfs_dformat "${btree_file}" "btree"
379         __populate_check_xfs_dir "${inline_dir}" "inline"
380         __populate_check_xfs_dir "${block_dir}" "block"
381         __populate_check_xfs_dir "${leaf_dir}" "leaf"
382         __populate_check_xfs_dir "${node_dir}" "node"
383         __populate_check_xfs_dir "${btree_dir}" "btree"
384         __populate_check_xfs_dformat "${btree_dir}" "btree"
385         __populate_check_xfs_dformat "${bdev}" "dev"
386         __populate_check_xfs_dformat "${cdev}" "dev"
387         __populate_check_xfs_attr "${local_attr}" "local"
388         __populate_check_xfs_attr "${leaf_attr}" "leaf"
389         __populate_check_xfs_attr "${node_attr}" "node"
390         __populate_check_xfs_attr "${btree_attr}" "btree"
391         __populate_check_xfs_aformat "${btree_attr}" "btree"
392 }
393
394 # Check data fork format of ext4 file
395 __populate_check_ext4_dformat() {
396         dev="${SCRATCH_DEV}"
397         inode="$1"
398         format="$2"
399
400         extents=0
401         etree=0
402         debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'ETB[0-9]' -q && etree=1
403         iflags="$(debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'Flags:' | sed -e 's/^.*Flags: \([0-9a-fx]*\).*$/\1/g')"
404         test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x80000);}')" -gt 0 && extents=1
405
406         case "${format}" in
407         "blockmap")
408                 test "${extents}" -eq 0 || _fail "failed to create ino ${inode} with blockmap"
409                 ;;
410         "extent"|"extents")
411                 test "${extents}" -eq 1 || _fail "failed to create ino ${inode} with extents"
412                 ;;
413         "etree")
414                 (test "${extents}" -eq 1 && test "${etree}" -eq 1) || _fail "failed to create ino ${inode} with extent tree"
415                 ;;
416         *)
417                 _fail "Unknown dformat ${format}"
418         esac
419 }
420
421 # Check attr fork format of ext4 file
422 __populate_check_ext4_aformat() {
423         dev="${SCRATCH_DEV}"
424         inode="$1"
425         format="$2"
426
427         ablock=1
428         debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'File ACL: 0' -q && ablock=0
429
430         case "${format}" in
431         "local"|"inline")
432                 test "${ablock}" -eq 0 || _fail "failed to create inode ${inode} with ${format} xattr"
433                 ;;
434         "block")
435                 test "${extents}" -eq 1 || _fail "failed to create inode ${inode} with ${format} xattr"
436                 ;;
437         *)
438                 _fail "Unknown aformat ${format}"
439         esac
440 }
441
442 # Check structure of ext4 dir
443 __populate_check_ext4_dir() {
444         dev="${SCRATCH_DEV}"
445         inode="$1"
446         dtype="$2"
447
448         htree=0
449         inline=0
450         iflags="$(debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'Flags:' | sed -e 's/^.*Flags: \([0-9a-fx]*\).*$/\1/g')"
451         test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x1000);}')" -gt 0 && htree=1
452         test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x10000000);}')" -gt 0 && inline=1
453
454         case "${dtype}" in
455         "inline")
456                 (test "${inline}" -eq 1 && test "${htree}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
457                 ;;
458         "block")
459                 (test "${inline}" -eq 0 && test "${htree}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
460                 ;;
461         "htree")
462                 (test "${inline}" -eq 0 && test "${htree}" -eq 1) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
463                 ;;
464         *)
465                 _fail "Unknown directory type ${dtype}"
466                 ;;
467         esac
468 }
469
470 # Check that populate created all the types of files we wanted
471 _scratch_ext4_populate_check() {
472         _scratch_mount
473         extents_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS")"
474         etree_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_ETREE")"
475         block_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK")"
476         htree_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_HTREE")"
477         extents_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS")"
478         local_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LOCAL")"
479         block_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_BLOCK")"
480         umount "${SCRATCH_MNT}"
481
482         __populate_check_ext4_dformat "${extents_file}" "extents"
483         __populate_check_ext4_dformat "${etree_file}" "etree"
484         __populate_check_ext4_dir "${block_dir}" "block"
485         __populate_check_ext4_dir "${htree_dir}" "htree"
486         __populate_check_ext4_dformat "${extents_slink}" "extents"
487         __populate_check_ext4_aformat "${local_attr}" "local"
488         __populate_check_ext4_aformat "${block_attr}" "block"
489 }
490
491 # Populate a scratch FS and check the contents to make sure we got that
492 _scratch_populate() {
493         case "${FSTYP}" in
494         "xfs")
495                 _scratch_xfs_populate
496                 _scratch_xfs_populate_check
497                 ;;
498         "ext4")
499                 _scratch_ext4_populate
500                 _scratch_ext4_populate_check
501                 ;;
502         *)
503                 _fail "Don't know how to populate a ${FSTYP} filesystem."
504                 ;;
505         esac
506 }
507
508 # Modify various files after a fuzzing operation
509 _scratch_fuzz_modify() {
510         nr="$1"
511
512         test -z "${nr}" && nr=50000
513         echo "+++ touch ${nr} files"
514         $XFS_IO_PROG -f -c "pwrite -S 0x63 0 ${BLK_SZ}" "/tmp/afile" > /dev/null
515         date="$(date)"
516         find "${SCRATCH_MNT}/" -type f 2> /dev/null | head -n "${nr}" | while read f; do
517                 setfattr -n "user.date" -v "${date}" "$f"
518                 cat "/tmp/afile" >> "$f"
519                 mv "$f" "$f.longer"
520         done
521         rm -rf "/tmp/afile"
522
523         echo "+++ create files"
524         cp -pRdu "${SRCDIR}" "${SCRATCH_MNT}/test.moo"
525         sync
526
527         echo "+++ remove files"
528         rm -rf "${SCRATCH_MNT}/test.moo"
529         rm -rf "${SCRATCH_MNT}/test.1"
530 }
531
532 # Try to access files after fuzzing
533 _scratch_fuzz_test() {
534         echo "+++ ls -laR" >> $seqres.full
535         ls -laR "${SCRATCH_MNT}/test.1/" >/dev/null 2>&1
536
537         echo "+++ cat files" >> $seqres.full
538         (find "${SCRATCH_MNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat) >/dev/null 2>&1
539 }
540
541 # Fill a file system by repeatedly creating files in the given folder
542 # starting with the given file size.  Files are reduced in size when
543 # they can no longer fit until no more files can be created.
544 _fill_fs()
545 {
546         local file_size=$1
547         local dir=$2
548         local block_size=$3
549         local switch_user=$4
550         local file_count=1
551         local bytes_written=0
552         local use_falloc=1;
553
554         if [ $# -ne 4 ]; then
555                 echo "Usage: _fill_fs filesize dir blocksize switch_user"
556                 exit 1
557         fi
558
559         if [ $switch_user -eq 0 ]; then
560                 mkdir -p $dir
561         else
562                 _user_do "mkdir -p $dir"
563         fi
564         if [ ! -d $dir ]; then
565                 return 0;
566         fi
567
568         testio=`$XFS_IO_PROG -F -fc "falloc 0 $block_size" $dir/$$.xfs_io 2>&1`
569         echo $testio | grep -q "not found" && use_falloc=0
570         echo $testio | grep -q "Operation not supported" && use_falloc=0
571
572         if [ $file_size -lt $block_size ]; then
573                 $file_size = $block_size
574         fi
575
576         while [ $file_size -ge $block_size ]; do
577                 bytes_written=0
578                 if [ $switch_user -eq 0 ]; then
579                         if [ $use_falloc -eq 0 ]; then
580                                 $XFS_IO_PROG -fc "pwrite -b 8388608 0 $file_size" \
581                                         $dir/$file_count
582                         else
583                                 $XFS_IO_PROG -fc "falloc 0 $file_size" \
584                                         $dir/$file_count
585                         fi
586                 else
587                         if [ $use_falloc -eq 0 ]; then
588                                 _user_do "$XFS_IO_PROG -f -c \"pwrite -b 8388608 0 \
589                                         $file_size\" $dir/$file_count"
590                         else
591                                 _user_do "$XFS_IO_PROG -f -c \"falloc 0 \
592                                         $file_size\" $dir/$file_count"
593                         fi
594                 fi
595
596                 if [ -f $dir/$file_count ]; then
597                         bytes_written=$(stat -c '%s' $dir/$file_count)
598                 fi
599
600                 # If there was no room to make the file, then divide it in
601                 # half, and keep going
602                 if [ $bytes_written -lt $file_size ]; then
603                         file_size=$((file_size / 2))
604                 fi
605                 file_count=$((file_count + 1))
606         done
607 }