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.
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.
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
21 # Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
22 # Mountain View, CA 94043, USA, or: http://www.sgi.com
23 #-----------------------------------------------------------------------
26 _require_populate_commands() {
27 _require_xfs_io_command "falloc"
28 _require_xfs_io_command "fpunch"
29 _require_test_program "punch-alternating"
30 _require_command "$XFS_DB_PROG" "xfs_db"
33 _require_xfs_db_blocktrash_z_command() {
34 test "${FSTYP}" = "xfs" || _notrun "cannot run xfs_db on ${FSTYP}"
35 $XFS_DB_PROG -x -f -c 'blocktrash -z' "${TEST_DEV}" | grep -q 'nothing on stack' || _notrun "blocktrash -z not supported"
38 # Attempt to make files of "every" format for data, dirs, attrs etc.
39 # (with apologies to Eric Sandeen for mutating xfser.sh)
41 # Create a large directory
42 __populate_create_dir() {
48 seq 0 "${nr}" | while read d; do
50 test "$((d % 20))" -eq 0 && creat=touch
51 $creat "${name}/$(printf "%.08d" "$d")"
54 test -z "${missing}" && return
55 seq 1 2 "${nr}" | while read d; do
56 rm -rf "${name}/$(printf "%.08d" "$d")"
60 # Add a bunch of attrs to a file
61 __populate_create_attr() {
67 seq 0 "${nr}" | while read d; do
68 setfattr -n "user.$(printf "%.08d" "$d")" -v "$(printf "%.08d" "$d")" "${name}"
71 test -z "${missing}" && return
72 seq 1 2 "${nr}" | while read d; do
73 setfattr -x "user.$(printf "%.08d" "$d")" "${name}"
77 # Fill up some percentage of the remaining free space
78 __populate_fill_fs() {
81 test -z "${pct}" && pct=60
83 mkdir -p "${dir}/test/1"
84 cp -pRdu "${dir}"/S_IFREG* "${dir}/test/1/"
86 SRC_SZ="$(du -ks "${dir}/test/1" | cut -f 1)"
87 FS_SZ="$(( $(stat -f "${dir}" -c '%a * %S') / 1024 ))"
89 NR="$(( (FS_SZ * ${pct} / 100) / SRC_SZ ))"
92 echo "src_sz $SRC_SZ fs_sz $FS_SZ nr $NR"
93 seq 2 "${NR}" | while read nr; do
94 cp -pRdu "${dir}/test/1" "${dir}/test/${nr}"
98 # For XFS, force on all the quota options if quota is enabled
99 # and the user didn't feed us noquota.
100 _populate_xfs_qmount_option()
102 # User explicitly told us not to quota
103 if echo "${MOUNT_OPTIONS}" | grep -q 'noquota'; then
107 # Don't bother if we can't turn on quotas
108 if [ ! -f /proc/fs/xfs/xqmstat ]; then
111 elif [ "${USE_EXTERNAL}" = "yes" ] && [ ! -z "${SCRATCH_RTDEV}" ]; then
112 # Quotas not supported on rt filesystems
114 elif [ -z "${XFS_QUOTA_PROG}" ]; then
115 # xfs quota tools not installed
119 # Turn on all the quotas
120 if $XFS_INFO_PROG "${TEST_DIR}" | grep -q 'crc=1'; then
121 # v5 filesystems can have group & project quotas
122 quota="usrquota,grpquota,prjquota"
124 # v4 filesystems cannot mix group & project quotas
125 quota="usrquota,grpquota"
128 # Inject our quota mount options
129 if echo "${MOUNT_OPTIONS}" | grep -q "${quota}"; then
131 elif echo "${MOUNT_OPTIONS}" | egrep -q '(quota|noenforce)'; then
132 _qmount_option "${quota}"
134 export MOUNT_OPTIONS="$MOUNT_OPTIONS -o ${quota}"
135 echo "MOUNT_OPTIONS = $MOUNT_OPTIONS" >>$seqres.full
139 # Populate an XFS on the scratch device with (we hope) all known
140 # types of metadata block
141 _scratch_xfs_populate() {
151 _populate_xfs_qmount_option
153 blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
154 dblksz="$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep naming.*bsize | sed -e 's/^.*bsize=//g' -e 's/\([0-9]*\).*$/\1/g')"
155 leaf_lblk="$((32 * 1073741824 / blksz))"
156 node_lblk="$((64 * 1073741824 / blksz))"
160 # Fill up the root inode chunk
161 echo "+ fill root ino chunk"
162 seq 1 64 | while read f; do
163 $XFS_IO_PROG -f -c "truncate 0" "${SCRATCH_MNT}/dummy${f}"
168 echo "+ extents file"
169 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS"
172 echo "+ btree extents file"
173 nr="$((blksz * 2 / 16))"
174 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE"
175 ./src/punch-alternating "${SCRATCH_MNT}/S_IFREG.FMT_BTREE"
180 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE" 1
184 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK" "$((dblksz / 40))"
188 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_LEAF" "$((dblksz / 12))"
192 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_NODE" "$((16 * dblksz / 40))" true
196 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BTREE" "$((128 * dblksz / 40))" true
200 echo "+ inline symlink"
201 ln -s target "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL"
204 echo "+ extents symlink"
205 ln -s "$(perl -e 'print "x" x 1023;')" "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS"
209 mknod "${SCRATCH_MNT}/S_IFCHR" c 1 1
210 mknod "${SCRATCH_MNT}/S_IFBLK" c 1 1
212 # special file with an xattr
213 setfacl -P -m u:nobody:r ${SCRATCH_MNT}/S_IFCHR
218 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LOCAL" 1
222 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LEAF" "$((blksz / 40))"
226 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_NODE" "$((8 * blksz / 40))"
230 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BTREE" "$((64 * blksz / 40))" true
233 touch ${SCRATCH_MNT}/ATTR.TRUSTED
234 setfattr -n trusted.moo -v urk ${SCRATCH_MNT}/ATTR.TRUSTED
237 touch ${SCRATCH_MNT}/ATTR.SECURITY
238 setfattr -n security.foo -v bar ${SCRATCH_MNT}/ATTR.SECURITY
241 touch ${SCRATCH_MNT}/ATTR.SYSTEM
242 setfacl -m u:root:r ${SCRATCH_MNT}/ATTR.SYSTEM
244 # FMT_EXTENTS with a remote less-than-a-block value
245 echo "+ attr extents with a remote less-than-a-block value"
246 touch "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE3K"
247 $XFS_IO_PROG -f -c "pwrite -S 0x43 0 $((blksz - 300))" "${SCRATCH_MNT}/attrvalfile" > /dev/null
248 attr -q -s user.remotebtreeattrname "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE3K" < "${SCRATCH_MNT}/attrvalfile"
250 # FMT_EXTENTS with a remote block-size value
251 echo "+ attr extents with a remote one-block value"
252 touch "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE4K"
253 $XFS_IO_PROG -f -c "pwrite -S 0x44 0 ${blksz}" "${SCRATCH_MNT}/attrvalfile" > /dev/null
254 attr -q -s user.remotebtreeattrname "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE4K" < "${SCRATCH_MNT}/attrvalfile"
255 rm -rf "${SCRATCH_MNT}/attrvalfile"
257 # Make an unused inode
259 touch "${SCRATCH_MNT}/unused"
260 $XFS_IO_PROG -f -c 'fsync' "${SCRATCH_MNT}/unused"
261 rm -rf "${SCRATCH_MNT}/unused"
264 echo "+ freesp btree"
265 nr="$((blksz * 2 / 8))"
266 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/BNOBT"
267 ./src/punch-alternating "${SCRATCH_MNT}/BNOBT"
269 # Reverse-mapping btree
270 is_rmapbt="$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep -c 'rmapbt=1')"
271 if [ $is_rmapbt -gt 0 ]; then
272 echo "+ rmapbt btree"
273 nr="$((blksz * 2 / 24))"
274 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/RMAPBT"
275 ./src/punch-alternating "${SCRATCH_MNT}/RMAPBT"
278 # Realtime Reverse-mapping btree
279 is_rt="$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep -c 'rtextents=[1-9]')"
280 if [ $is_rmapbt -gt 0 ] && [ $is_rt -gt 0 ]; then
281 echo "+ rtrmapbt btree"
282 nr="$((blksz * 2 / 32))"
283 $XFS_IO_PROG -f -R -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/RTRMAPBT"
284 ./src/punch-alternating "${SCRATCH_MNT}/RTRMAPBT"
287 # Reference-count btree
288 is_reflink="$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep -c 'reflink=1')"
289 if [ $is_reflink -gt 0 ]; then
290 echo "+ reflink btree"
291 nr="$((blksz * 2 / 12))"
292 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/REFCOUNTBT"
293 cp --reflink=always "${SCRATCH_MNT}/REFCOUNTBT" "${SCRATCH_MNT}/REFCOUNTBT2"
294 ./src/punch-alternating "${SCRATCH_MNT}/REFCOUNTBT"
297 # Copy some real files (xfs tests, I guess...)
299 test $fill -ne 0 && __populate_fill_fs "${SCRATCH_MNT}" 5
301 umount "${SCRATCH_MNT}"
304 # Populate an ext4 on the scratch device with (we hope) all known
305 # types of metadata block
306 _scratch_ext4_populate() {
317 blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
319 leaf_lblk="$((32 * 1073741824 / blksz))"
320 node_lblk="$((64 * 1073741824 / blksz))"
327 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 1" "${SCRATCH_MNT}/S_IFREG.FMT_INLINE"
330 echo "+ extents file"
331 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS"
334 echo "+ extent tree file"
335 nr="$((blksz * 2 / 12))"
336 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/S_IFREG.FMT_ETREE"
337 ./src/punch-alternating "${SCRATCH_MNT}/S_IFREG.FMT_ETREE"
342 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE" 1
346 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK" "$((dblksz / 32))"
350 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_HTREE" "$((4 * dblksz / 24))"
354 echo "+ inline symlink"
355 ln -s target "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL"
358 echo "+ extents symlink"
359 ln -s "$(perl -e 'print "x" x 1023;')" "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS"
363 mknod "${SCRATCH_MNT}/S_IFCHR" c 1 1
364 mknod "${SCRATCH_MNT}/S_IFBLK" c 1 1
366 # special file with an xattr
367 setfacl -P -m u:nobody:r ${SCRATCH_MNT}/S_IFCHR
372 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LOCAL" 0
376 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BLOCK" "$((blksz / 40))"
379 touch ${SCRATCH_MNT}/ATTR.TRUSTED
380 setfattr -n trusted.moo -v urk ${SCRATCH_MNT}/ATTR.TRUSTED
383 touch ${SCRATCH_MNT}/ATTR.SECURITY
384 setfattr -n security.foo -v bar ${SCRATCH_MNT}/ATTR.SECURITY
387 touch ${SCRATCH_MNT}/ATTR.SYSTEM
388 setfacl -m u:root:r ${SCRATCH_MNT}/ATTR.SYSTEM
390 # Make an unused inode
392 touch "${SCRATCH_MNT}/unused"
393 $XFS_IO_PROG -f -c 'fsync' "${SCRATCH_MNT}/unused"
394 rm -rf "${SCRATCH_MNT}/unused"
396 # Copy some real files (xfs tests, I guess...)
398 test $fill -ne 0 && __populate_fill_fs "${SCRATCH_MNT}" 5
400 umount "${SCRATCH_MNT}"
403 # Find the inode number of a file
404 __populate_find_inode() {
406 inode="$(stat -c '%i' "${name}")"
410 # Check data fork format of XFS file
411 __populate_check_xfs_dformat() {
415 fmt="$(_scratch_xfs_db -c "inode ${inode}" -c 'p core.format' | sed -e 's/^.*(\([a-z]*\)).*$/\1/g')"
416 test "${format}" = "${fmt}" || _fail "failed to create ino ${inode} dformat expected ${format} saw ${fmt}"
419 # Check attr fork format of XFS file
420 __populate_check_xfs_aformat() {
424 fmt="$(_scratch_xfs_db -c "inode ${inode}" -c 'p core.aformat' | sed -e 's/^.*(\([a-z]*\)).*$/\1/g')"
425 test "${format}" = "${fmt}" || _fail "failed to create ino ${inode} aformat expected ${format} saw ${fmt}"
428 # Check structure of XFS directory
429 __populate_check_xfs_dir() {
433 (test -n "${leaf_lblk}" && test -n "${node_lblk}") || _fail "must define leaf_lblk and node_lblk before calling __populate_check_xfs_dir"
437 #echo "== check dir ${inode} type ${dtype}" ; _scratch_xfs_db -x -c "inode ${inode}" -c "bmap"
438 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock 0" -c "stack" | grep -q 'file data block is unmapped' || datab=1
439 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock ${leaf_lblk}" -c "stack" | grep -q 'file data block is unmapped' || leafb=1
440 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock ${node_lblk}" -c "stack" | grep -q 'file data block is unmapped' || freeb=1
443 "shortform"|"inline"|"local")
444 (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}"
447 (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}"
450 (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}"
453 (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}"
456 _fail "Unknown directory type ${dtype}"
460 # Check structure of XFS attr
461 __populate_check_xfs_attr() {
467 #echo "== check attr ${inode} type ${dtype}" ; _scratch_xfs_db -x -c "inode ${inode}" -c "bmap -a"
468 _scratch_xfs_db -x -c "inode ${inode}" -c "ablock 0" -c "stack" | grep -q 'file attr block is unmapped' || datab=1
469 _scratch_xfs_db -x -c "inode ${inode}" -c "ablock 1" -c "stack" | grep -q 'file attr block is unmapped' || leafb=1
472 "shortform"|"inline"|"local")
473 (test "${datab}" -eq 0 && test "${leafb}" -eq 0) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
476 (test "${datab}" -eq 1 && test "${leafb}" -eq 0) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
479 (test "${datab}" -eq 1 && test "${leafb}" -eq 1) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
482 _fail "Unknown attribute type ${atype}"
486 # Check that there's at least one per-AG btree with multiple levels
487 __populate_check_xfs_agbtree_height() {
489 nr_ags=$(_scratch_xfs_db -c 'sb 0' -c 'p agcount' | awk '{print $3}')
492 "bno"|"cnt"|"rmap"|"refcnt")
494 bt_prefix="${bt_type}"
505 _fail "Don't know about AG btree ${bt_type}"
509 seq 0 $((nr_ags - 1)) | while read ag; do
510 bt_level=$(_scratch_xfs_db -c "${hdr} ${ag}" -c "p ${bt_prefix}level" | awk '{print $3}')
511 if [ "${bt_level}" -gt 1 ]; then
515 test $? -eq 100 || _fail "Failed to create ${bt_type} of sufficient height!"
519 # Check that populate created all the types of files we wanted
520 _scratch_xfs_populate_check() {
522 extents_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS")"
523 btree_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_BTREE")"
524 inline_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE")"
525 block_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK")"
526 leaf_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_LEAF")"
527 node_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_NODE")"
528 btree_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BTREE")"
529 local_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL")"
530 extents_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS")"
531 bdev="$(__populate_find_inode "${SCRATCH_MNT}/S_IFBLK")"
532 cdev="$(__populate_find_inode "${SCRATCH_MNT}/S_IFCHR")"
533 local_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LOCAL")"
534 leaf_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LEAF")"
535 node_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_NODE")"
536 btree_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_BTREE")"
537 is_finobt=$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep -c 'finobt=1')
538 is_rmapbt=$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep -c 'rmapbt=1')
539 is_reflink=$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep -c 'reflink=1')
541 blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
542 dblksz="$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep naming.*bsize | sed -e 's/^.*bsize=//g' -e 's/\([0-9]*\).*$/\1/g')"
543 leaf_lblk="$((32 * 1073741824 / blksz))"
544 node_lblk="$((64 * 1073741824 / blksz))"
545 umount "${SCRATCH_MNT}"
547 __populate_check_xfs_dformat "${extents_file}" "extents"
548 __populate_check_xfs_dformat "${btree_file}" "btree"
549 __populate_check_xfs_dir "${inline_dir}" "inline"
550 __populate_check_xfs_dir "${block_dir}" "block"
551 __populate_check_xfs_dir "${leaf_dir}" "leaf"
552 __populate_check_xfs_dir "${node_dir}" "node"
553 __populate_check_xfs_dir "${btree_dir}" "btree"
554 __populate_check_xfs_dformat "${btree_dir}" "btree"
555 __populate_check_xfs_dformat "${bdev}" "dev"
556 __populate_check_xfs_dformat "${cdev}" "dev"
557 __populate_check_xfs_attr "${local_attr}" "local"
558 __populate_check_xfs_attr "${leaf_attr}" "leaf"
559 __populate_check_xfs_attr "${node_attr}" "node"
560 __populate_check_xfs_attr "${btree_attr}" "btree"
561 __populate_check_xfs_aformat "${btree_attr}" "btree"
562 __populate_check_xfs_agbtree_height "bno"
563 __populate_check_xfs_agbtree_height "cnt"
564 test $is_rmapbt -ne 0 && __populate_check_xfs_agbtree_height "rmap"
565 test $is_reflink -ne 0 && __populate_check_xfs_agbtree_height "refcnt"
568 # Check data fork format of ext4 file
569 __populate_check_ext4_dformat() {
576 debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'ETB[0-9]' -q && etree=1
577 iflags="$(debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'Flags:' | sed -e 's/^.*Flags: \([0-9a-fx]*\).*$/\1/g')"
578 test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x80000);}')" -gt 0 && extents=1
582 test "${extents}" -eq 0 || _fail "failed to create ino ${inode} with blockmap"
585 test "${extents}" -eq 1 || _fail "failed to create ino ${inode} with extents"
588 (test "${extents}" -eq 1 && test "${etree}" -eq 1) || _fail "failed to create ino ${inode} with extent tree"
591 _fail "Unknown dformat ${format}"
595 # Check attr fork format of ext4 file
596 __populate_check_ext4_aformat() {
602 debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'File ACL: 0' -q && ablock=0
606 test "${ablock}" -eq 0 || _fail "failed to create inode ${inode} with ${format} xattr"
609 test "${extents}" -eq 1 || _fail "failed to create inode ${inode} with ${format} xattr"
612 _fail "Unknown aformat ${format}"
616 # Check structure of ext4 dir
617 __populate_check_ext4_dir() {
624 iflags="$(debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'Flags:' | sed -e 's/^.*Flags: \([0-9a-fx]*\).*$/\1/g')"
625 test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x1000);}')" -gt 0 && htree=1
626 test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x10000000);}')" -gt 0 && inline=1
630 (test "${inline}" -eq 1 && test "${htree}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
633 (test "${inline}" -eq 0 && test "${htree}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
636 (test "${inline}" -eq 0 && test "${htree}" -eq 1) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
639 _fail "Unknown directory type ${dtype}"
644 # Check that populate created all the types of files we wanted
645 _scratch_ext4_populate_check() {
647 extents_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS")"
648 etree_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_ETREE")"
649 block_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK")"
650 htree_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_HTREE")"
651 extents_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS")"
652 local_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LOCAL")"
653 block_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_BLOCK")"
654 umount "${SCRATCH_MNT}"
656 __populate_check_ext4_dformat "${extents_file}" "extents"
657 __populate_check_ext4_dformat "${etree_file}" "etree"
658 __populate_check_ext4_dir "${block_dir}" "block"
659 __populate_check_ext4_dir "${htree_dir}" "htree"
660 __populate_check_ext4_dformat "${extents_slink}" "extents"
661 __populate_check_ext4_aformat "${local_attr}" "local"
662 __populate_check_ext4_aformat "${block_attr}" "block"
665 # Populate a scratch FS and check the contents to make sure we got that
666 _scratch_populate() {
669 _scratch_xfs_populate
670 _scratch_xfs_populate_check
672 "ext2"|"ext3"|"ext4")
673 _scratch_ext4_populate
674 _scratch_ext4_populate_check
677 _fail "Don't know how to populate a ${FSTYP} filesystem."
682 # Fill a file system by repeatedly creating files in the given folder
683 # starting with the given file size. Files are reduced in size when
684 # they can no longer fit until no more files can be created.
692 local bytes_written=0
695 if [ $# -ne 4 ]; then
696 echo "Usage: _fill_fs filesize dir blocksize switch_user"
700 if [ $switch_user -eq 0 ]; then
703 _user_do "mkdir -p $dir"
705 if [ ! -d $dir ]; then
709 testio=`$XFS_IO_PROG -F -fc "falloc 0 $block_size" $dir/$$.xfs_io 2>&1`
710 echo $testio | grep -q "not found" && use_falloc=0
711 echo $testio | grep -q "Operation not supported" && use_falloc=0
713 if [ $file_size -lt $block_size ]; then
714 $file_size = $block_size
717 while [ $file_size -ge $block_size ]; do
719 if [ $switch_user -eq 0 ]; then
720 if [ $use_falloc -eq 0 ]; then
721 $XFS_IO_PROG -fc "pwrite -b 8388608 0 $file_size" \
724 $XFS_IO_PROG -fc "falloc 0 $file_size" \
728 if [ $use_falloc -eq 0 ]; then
729 _user_do "$XFS_IO_PROG -f -c \"pwrite -b 8388608 0 \
730 $file_size\" $dir/$file_count"
732 _user_do "$XFS_IO_PROG -f -c \"falloc 0 \
733 $file_size\" $dir/$file_count"
737 if [ -f $dir/$file_count ]; then
738 bytes_written=$(stat -c '%s' $dir/$file_count)
741 # If there was no room to make the file, then divide it in
742 # half, and keep going
743 if [ $bytes_written -lt $file_size ]; then
744 file_size=$((file_size / 2))
746 file_count=$((file_count + 1))
750 # Populate a scratch FS from scratch or from a cached image.
751 _scratch_populate_cached() {
752 POPULATE_METADUMP="${TEST_DIR}/__populate.${FSTYP}"
753 POPULATE_METADUMP_DESCR="${TEST_DIR}/__populate.${FSTYP}.txt"
755 # Don't keep metadata images cached for more 48 hours...
756 rm -rf "$(find "${POPULATE_METADUMP}" -mtime +2 2>/dev/null)"
758 # Throw away cached image if it doesn't match our spec.
761 extra_descr="LOGDEV ${SCRATCH_LOGDEV} USE_EXTERNAL ${USE_EXTERNAL}"
762 # ext4 cannot e2image external logs, so we cannot restore
763 test -n "${SCRATCH_LOGDEV}" && rm -f "${POPULATE_METADUMP}"
766 extra_descr="LOGDEV ${SCRATCH_LOGDEV} USE_EXTERNAL ${USE_EXTERNAL} RTDEV ${SCRATCH_RTDEV}"
767 _populate_xfs_qmount_option
768 if echo "${MOUNT_OPTIONS}" | grep -q 'usrquota'; then
769 extra_descr="${extra_descr} QUOTAS"
775 meta_descr="FSTYP ${FSTYP} MKFS_OPTIONS ${MKFS_OPTIONS} SIZE $(blockdev --getsz "${SCRATCH_DEV}") ${extra_descr} ARGS $@"
776 cmp -s "${POPULATE_METADUMP_DESCR}" <(echo "${meta_descr}") || rm -rf "${POPULATE_METADUMP}"
778 # Do we have a cached image?
779 if [ -r "${POPULATE_METADUMP}" ]; then
782 xfs_mdrestore "${POPULATE_METADUMP}" "${SCRATCH_DEV}" && return
784 "ext2"|"ext3"|"ext4")
785 e2image -r "${POPULATE_METADUMP}" "${SCRATCH_DEV}" && return
790 # Oh well, just create one from scratch
792 echo "${meta_descr}" > "${POPULATE_METADUMP_DESCR}"
795 _scratch_xfs_populate $@
796 _scratch_xfs_populate_check
797 _scratch_metadump "${POPULATE_METADUMP}" -a -o
799 "ext2"|"ext3"|"ext4")
800 _scratch_ext4_populate $@
801 _scratch_ext4_populate_check
802 e2image -Q "${SCRATCH_DEV}" "${POPULATE_METADUMP}"
805 _fail "Don't know how to populate a ${FSTYP} filesystem."