2 # SPDX-License-Identifier: GPL-2.0+
3 # Copyright (c) 2015 Oracle. All Rights Reserved.
5 # Routines for populating a scratch fs, and helpers to exercise an FS
6 # once it's been fuzzed.
10 _require_populate_commands() {
11 _require_xfs_io_command "falloc"
12 _require_xfs_io_command "fpunch"
13 _require_test_program "punch-alternating"
14 _require_command "$XFS_DB_PROG" "xfs_db"
17 _require_xfs_db_blocktrash_z_command() {
18 test "${FSTYP}" = "xfs" || _notrun "cannot run xfs_db on ${FSTYP}"
19 $XFS_DB_PROG -x -f -c 'blocktrash -z' "${TEST_DEV}" | grep -q 'nothing on stack' || _notrun "blocktrash -z not supported"
22 # Attempt to make files of "every" format for data, dirs, attrs etc.
23 # (with apologies to Eric Sandeen for mutating xfser.sh)
25 # Create a large directory
26 __populate_create_dir() {
32 seq 0 "${nr}" | while read d; do
34 test "$((d % 20))" -eq 0 && creat=touch
35 $creat "${name}/$(printf "%.08d" "$d")"
38 test -z "${missing}" && return
39 seq 1 2 "${nr}" | while read d; do
40 rm -rf "${name}/$(printf "%.08d" "$d")"
44 # Add a bunch of attrs to a file
45 __populate_create_attr() {
51 seq 0 "${nr}" | while read d; do
52 setfattr -n "user.$(printf "%.08d" "$d")" -v "$(printf "%.08d" "$d")" "${name}"
55 test -z "${missing}" && return
56 seq 1 2 "${nr}" | while read d; do
57 setfattr -x "user.$(printf "%.08d" "$d")" "${name}"
61 # Fill up some percentage of the remaining free space
62 __populate_fill_fs() {
65 test -z "${pct}" && pct=60
67 mkdir -p "${dir}/test/1"
68 cp -pRdu "${dir}"/S_IFREG* "${dir}/test/1/"
70 SRC_SZ="$(du -ks "${dir}/test/1" | cut -f 1)"
71 FS_SZ="$(( $(stat -f "${dir}" -c '%a * %S') / 1024 ))"
73 NR="$(( (FS_SZ * ${pct} / 100) / SRC_SZ ))"
76 echo "src_sz $SRC_SZ fs_sz $FS_SZ nr $NR"
77 seq 2 "${NR}" | while read nr; do
78 cp -pRdu "${dir}/test/1" "${dir}/test/${nr}"
82 # For XFS, force on all the quota options if quota is enabled
83 # and the user didn't feed us noquota.
84 _populate_xfs_qmount_option()
86 # User explicitly told us not to quota
87 if echo "${MOUNT_OPTIONS}" | grep -q 'noquota'; then
91 # Don't bother if we can't turn on quotas
92 if [ ! -f /proc/fs/xfs/xqmstat ]; then
95 elif [ "${USE_EXTERNAL}" = "yes" ] && [ ! -z "${SCRATCH_RTDEV}" ]; then
96 # Quotas not supported on rt filesystems
98 elif [ -z "${XFS_QUOTA_PROG}" ]; then
99 # xfs quota tools not installed
103 # Turn on all the quotas
104 if $XFS_INFO_PROG "${TEST_DIR}" | grep -q 'crc=1'; then
105 # v5 filesystems can have group & project quotas
106 quota="usrquota,grpquota,prjquota"
108 # v4 filesystems cannot mix group & project quotas
109 quota="usrquota,grpquota"
112 # Inject our quota mount options
113 if echo "${MOUNT_OPTIONS}" | grep -q "${quota}"; then
115 elif echo "${MOUNT_OPTIONS}" | egrep -q '(quota|noenforce)'; then
116 _qmount_option "${quota}"
118 export MOUNT_OPTIONS="$MOUNT_OPTIONS -o ${quota}"
119 echo "MOUNT_OPTIONS = $MOUNT_OPTIONS" >>$seqres.full
123 # Populate an XFS on the scratch device with (we hope) all known
124 # types of metadata block
125 _scratch_xfs_populate() {
135 _populate_xfs_qmount_option
137 blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
138 dblksz="$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep naming.*bsize | sed -e 's/^.*bsize=//g' -e 's/\([0-9]*\).*$/\1/g')"
139 crc="$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep crc= | sed -e 's/^.*crc=//g' -e 's/\([0-9]*\).*$/\1/g')"
140 if [ $crc -eq 1 ]; then
145 leaf_lblk="$((32 * 1073741824 / blksz))"
146 node_lblk="$((64 * 1073741824 / blksz))"
150 # Fill up the root inode chunk
151 echo "+ fill root ino chunk"
152 seq 1 64 | while read f; do
153 $XFS_IO_PROG -f -c "truncate 0" "${SCRATCH_MNT}/dummy${f}"
158 echo "+ extents file"
159 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS"
162 echo "+ btree extents file"
163 nr="$((blksz * 2 / 16))"
164 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE"
165 ./src/punch-alternating "${SCRATCH_MNT}/S_IFREG.FMT_BTREE"
170 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE" 1
174 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK" "$((dblksz / 40))"
178 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_LEAF" "$((dblksz / 12))"
182 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_LEAFN" "$(( ((dblksz - leaf_hdr_size) / 8) - 3 ))"
186 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_NODE" "$((16 * dblksz / 40))" true
190 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BTREE" "$((128 * dblksz / 40))" true
194 echo "+ inline symlink"
195 ln -s target "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL"
198 echo "+ extents symlink"
199 ln -s "$(perl -e 'print "x" x 1023;')" "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS"
203 mknod "${SCRATCH_MNT}/S_IFCHR" c 1 1
204 mknod "${SCRATCH_MNT}/S_IFBLK" c 1 1
206 # special file with an xattr
207 setfacl -P -m u:nobody:r ${SCRATCH_MNT}/S_IFCHR
212 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LOCAL" 1
216 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LEAF" "$((blksz / 40))"
220 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_NODE" "$((8 * blksz / 40))"
224 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BTREE" "$((64 * blksz / 40))" true
227 touch ${SCRATCH_MNT}/ATTR.TRUSTED
228 setfattr -n trusted.moo -v urk ${SCRATCH_MNT}/ATTR.TRUSTED
231 touch ${SCRATCH_MNT}/ATTR.SECURITY
232 setfattr -n security.foo -v bar ${SCRATCH_MNT}/ATTR.SECURITY
235 touch ${SCRATCH_MNT}/ATTR.SYSTEM
236 setfacl -m u:root:r ${SCRATCH_MNT}/ATTR.SYSTEM
238 # FMT_EXTENTS with a remote less-than-a-block value
239 echo "+ attr extents with a remote less-than-a-block value"
240 touch "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE3K"
241 $XFS_IO_PROG -f -c "pwrite -S 0x43 0 $((blksz - 300))" "${SCRATCH_MNT}/attrvalfile" > /dev/null
242 attr -q -s user.remotebtreeattrname "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE3K" < "${SCRATCH_MNT}/attrvalfile"
244 # FMT_EXTENTS with a remote block-size value
245 echo "+ attr extents with a remote one-block value"
246 touch "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE4K"
247 $XFS_IO_PROG -f -c "pwrite -S 0x44 0 ${blksz}" "${SCRATCH_MNT}/attrvalfile" > /dev/null
248 attr -q -s user.remotebtreeattrname "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE4K" < "${SCRATCH_MNT}/attrvalfile"
249 rm -rf "${SCRATCH_MNT}/attrvalfile"
251 # Make an unused inode
253 touch "${SCRATCH_MNT}/unused"
254 $XFS_IO_PROG -f -c 'fsync' "${SCRATCH_MNT}/unused"
255 rm -rf "${SCRATCH_MNT}/unused"
258 echo "+ freesp btree"
259 nr="$((blksz * 2 / 8))"
260 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/BNOBT"
261 ./src/punch-alternating "${SCRATCH_MNT}/BNOBT"
263 # Reverse-mapping btree
264 is_rmapbt="$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep -c 'rmapbt=1')"
265 if [ $is_rmapbt -gt 0 ]; then
266 echo "+ rmapbt btree"
267 nr="$((blksz * 2 / 24))"
268 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/RMAPBT"
269 ./src/punch-alternating "${SCRATCH_MNT}/RMAPBT"
272 # Realtime Reverse-mapping btree
273 is_rt="$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep -c 'rtextents=[1-9]')"
274 if [ $is_rmapbt -gt 0 ] && [ $is_rt -gt 0 ]; then
275 echo "+ rtrmapbt btree"
276 nr="$((blksz * 2 / 32))"
277 $XFS_IO_PROG -f -R -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/RTRMAPBT"
278 ./src/punch-alternating "${SCRATCH_MNT}/RTRMAPBT"
281 # Reference-count btree
282 is_reflink="$($XFS_INFO_PROG "${SCRATCH_MNT}" | grep -c 'reflink=1')"
283 if [ $is_reflink -gt 0 ]; then
284 echo "+ reflink btree"
285 nr="$((blksz * 2 / 12))"
286 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/REFCOUNTBT"
287 cp --reflink=always "${SCRATCH_MNT}/REFCOUNTBT" "${SCRATCH_MNT}/REFCOUNTBT2"
288 ./src/punch-alternating "${SCRATCH_MNT}/REFCOUNTBT"
291 # Copy some real files (xfs tests, I guess...)
293 test $fill -ne 0 && __populate_fill_fs "${SCRATCH_MNT}" 5
295 umount "${SCRATCH_MNT}"
298 # Populate an ext4 on the scratch device with (we hope) all known
299 # types of metadata block
300 _scratch_ext4_populate() {
311 blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")"
313 leaf_lblk="$((32 * 1073741824 / blksz))"
314 node_lblk="$((64 * 1073741824 / blksz))"
321 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 1" "${SCRATCH_MNT}/S_IFREG.FMT_INLINE"
324 echo "+ extents file"
325 $XFS_IO_PROG -f -c "pwrite -S 0x61 0 ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS"
328 echo "+ extent tree file"
329 nr="$((blksz * 2 / 12))"
330 $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/S_IFREG.FMT_ETREE"
331 ./src/punch-alternating "${SCRATCH_MNT}/S_IFREG.FMT_ETREE"
336 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE" 1
340 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK" "$((dblksz / 32))"
344 __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_HTREE" "$((4 * dblksz / 24))"
348 echo "+ inline symlink"
349 ln -s target "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL"
352 echo "+ extents symlink"
353 ln -s "$(perl -e 'print "x" x 1023;')" "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS"
357 mknod "${SCRATCH_MNT}/S_IFCHR" c 1 1
358 mknod "${SCRATCH_MNT}/S_IFBLK" c 1 1
360 # special file with an xattr
361 setfacl -P -m u:nobody:r ${SCRATCH_MNT}/S_IFCHR
366 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LOCAL" 0
370 __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BLOCK" "$((blksz / 40))"
373 touch ${SCRATCH_MNT}/ATTR.TRUSTED
374 setfattr -n trusted.moo -v urk ${SCRATCH_MNT}/ATTR.TRUSTED
377 touch ${SCRATCH_MNT}/ATTR.SECURITY
378 setfattr -n security.foo -v bar ${SCRATCH_MNT}/ATTR.SECURITY
381 touch ${SCRATCH_MNT}/ATTR.SYSTEM
382 setfacl -m u:root:r ${SCRATCH_MNT}/ATTR.SYSTEM
384 # Make an unused inode
386 touch "${SCRATCH_MNT}/unused"
387 $XFS_IO_PROG -f -c 'fsync' "${SCRATCH_MNT}/unused"
388 rm -rf "${SCRATCH_MNT}/unused"
390 # Copy some real files (xfs tests, I guess...)
392 test $fill -ne 0 && __populate_fill_fs "${SCRATCH_MNT}" 5
394 umount "${SCRATCH_MNT}"
397 # Find the inode number of a file
398 __populate_find_inode() {
400 inode="$(stat -c '%i' "${name}")"
404 # Check data fork format of XFS file
405 __populate_check_xfs_dformat() {
409 fmt="$(_scratch_xfs_db -c "inode ${inode}" -c 'p core.format' | sed -e 's/^.*(\([a-z]*\)).*$/\1/g')"
410 test "${format}" = "${fmt}" || _fail "failed to create ino ${inode} dformat expected ${format} saw ${fmt}"
413 # Check attr fork format of XFS file
414 __populate_check_xfs_aformat() {
418 fmt="$(_scratch_xfs_db -c "inode ${inode}" -c 'p core.aformat' | sed -e 's/^.*(\([a-z]*\)).*$/\1/g')"
419 test "${format}" = "${fmt}" || _fail "failed to create ino ${inode} aformat expected ${format} saw ${fmt}"
422 # Check structure of XFS directory
423 __populate_check_xfs_dir() {
427 (test -n "${leaf_lblk}" && test -n "${node_lblk}") || _fail "must define leaf_lblk and node_lblk before calling __populate_check_xfs_dir"
431 #echo "== check dir ${inode} type ${dtype}" ; _scratch_xfs_db -x -c "inode ${inode}" -c "bmap"
432 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock 0" -c "stack" | grep -q 'file data block is unmapped' || datab=1
433 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock ${leaf_lblk}" -c "stack" | grep -q 'file data block is unmapped' || leafb=1
434 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock ${node_lblk}" -c "stack" | grep -q 'file data block is unmapped' || freeb=1
437 "shortform"|"inline"|"local")
438 (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}"
441 (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}"
444 (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}"
447 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock ${leaf_lblk}" -c "p lhdr.info.hdr.magic" | grep -q '0x3dff' && return
448 _scratch_xfs_db -x -c "inode ${inode}" -c "dblock ${leaf_lblk}" -c "p lhdr.info.magic" | grep -q '0xd2ff' && return
449 _fail "failed to create ${dtype} dir ino ${inode} datab ${datab} leafb ${leafb} freeb ${freeb}"
452 (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}"
455 _fail "Unknown directory type ${dtype}"
459 # Check structure of XFS attr
460 __populate_check_xfs_attr() {
466 #echo "== check attr ${inode} type ${dtype}" ; _scratch_xfs_db -x -c "inode ${inode}" -c "bmap -a"
467 _scratch_xfs_db -x -c "inode ${inode}" -c "ablock 0" -c "stack" | grep -q 'file attr block is unmapped' || datab=1
468 _scratch_xfs_db -x -c "inode ${inode}" -c "ablock 1" -c "stack" | grep -q 'file attr block is unmapped' || leafb=1
471 "shortform"|"inline"|"local")
472 (test "${datab}" -eq 0 && test "${leafb}" -eq 0) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
475 (test "${datab}" -eq 1 && test "${leafb}" -eq 0) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
478 (test "${datab}" -eq 1 && test "${leafb}" -eq 1) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}"
481 _fail "Unknown attribute type ${atype}"
485 # Check that there's at least one per-AG btree with multiple levels
486 __populate_check_xfs_agbtree_height() {
488 nr_ags=$(_scratch_xfs_db -c 'sb 0' -c 'p agcount' | awk '{print $3}')
491 "bno"|"cnt"|"rmap"|"refcnt")
493 bt_prefix="${bt_type}"
504 _fail "Don't know about AG btree ${bt_type}"
508 seq 0 $((nr_ags - 1)) | while read ag; do
509 bt_level=$(_scratch_xfs_db -c "${hdr} ${ag}" -c "p ${bt_prefix}level" | awk '{print $3}')
510 if [ "${bt_level}" -gt 1 ]; then
514 test $? -eq 100 || _fail "Failed to create ${bt_type} of sufficient height!"
518 # Check that populate created all the types of files we wanted
519 _scratch_xfs_populate_check() {
521 extents_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS")"
522 btree_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_BTREE")"
523 inline_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE")"
524 block_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK")"
525 leaf_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_LEAF")"
526 leafn_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_LEAFN")"
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 "${leafn_dir}" "leafn"
553 __populate_check_xfs_dir "${node_dir}" "node"
554 __populate_check_xfs_dir "${btree_dir}" "btree"
555 __populate_check_xfs_dformat "${btree_dir}" "btree"
556 __populate_check_xfs_dformat "${bdev}" "dev"
557 __populate_check_xfs_dformat "${cdev}" "dev"
558 __populate_check_xfs_attr "${local_attr}" "local"
559 __populate_check_xfs_attr "${leaf_attr}" "leaf"
560 __populate_check_xfs_attr "${node_attr}" "node"
561 __populate_check_xfs_attr "${btree_attr}" "btree"
562 __populate_check_xfs_aformat "${btree_attr}" "btree"
563 __populate_check_xfs_agbtree_height "bno"
564 __populate_check_xfs_agbtree_height "cnt"
565 test $is_rmapbt -ne 0 && __populate_check_xfs_agbtree_height "rmap"
566 test $is_reflink -ne 0 && __populate_check_xfs_agbtree_height "refcnt"
569 # Check data fork format of ext4 file
570 __populate_check_ext4_dformat() {
577 debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'ETB[0-9]' -q && etree=1
578 iflags="$(debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'Flags:' | sed -e 's/^.*Flags: \([0-9a-fx]*\).*$/\1/g')"
579 test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x80000);}')" -gt 0 && extents=1
583 test "${extents}" -eq 0 || _fail "failed to create ino ${inode} with blockmap"
586 test "${extents}" -eq 1 || _fail "failed to create ino ${inode} with extents"
589 (test "${extents}" -eq 1 && test "${etree}" -eq 1) || _fail "failed to create ino ${inode} with extent tree"
592 _fail "Unknown dformat ${format}"
596 # Check attr fork format of ext4 file
597 __populate_check_ext4_aformat() {
603 debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'File ACL: 0' -q && ablock=0
607 test "${ablock}" -eq 0 || _fail "failed to create inode ${inode} with ${format} xattr"
610 test "${extents}" -eq 1 || _fail "failed to create inode ${inode} with ${format} xattr"
613 _fail "Unknown aformat ${format}"
617 # Check structure of ext4 dir
618 __populate_check_ext4_dir() {
625 iflags="$(debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'Flags:' | sed -e 's/^.*Flags: \([0-9a-fx]*\).*$/\1/g')"
626 test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x1000);}')" -gt 0 && htree=1
627 test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x10000000);}')" -gt 0 && inline=1
631 (test "${inline}" -eq 1 && test "${htree}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
634 (test "${inline}" -eq 0 && test "${htree}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
637 (test "${inline}" -eq 0 && test "${htree}" -eq 1) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}"
640 _fail "Unknown directory type ${dtype}"
645 # Check that populate created all the types of files we wanted
646 _scratch_ext4_populate_check() {
648 extents_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS")"
649 etree_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_ETREE")"
650 block_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK")"
651 htree_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_HTREE")"
652 extents_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS")"
653 local_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LOCAL")"
654 block_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_BLOCK")"
655 umount "${SCRATCH_MNT}"
657 __populate_check_ext4_dformat "${extents_file}" "extents"
658 __populate_check_ext4_dformat "${etree_file}" "etree"
659 __populate_check_ext4_dir "${block_dir}" "block"
660 __populate_check_ext4_dir "${htree_dir}" "htree"
661 __populate_check_ext4_dformat "${extents_slink}" "extents"
662 __populate_check_ext4_aformat "${local_attr}" "local"
663 __populate_check_ext4_aformat "${block_attr}" "block"
666 # Populate a scratch FS and check the contents to make sure we got that
667 _scratch_populate() {
670 _scratch_xfs_populate
671 _scratch_xfs_populate_check
673 "ext2"|"ext3"|"ext4")
674 _scratch_ext4_populate
675 _scratch_ext4_populate_check
678 _fail "Don't know how to populate a ${FSTYP} filesystem."
683 # Fill a file system by repeatedly creating files in the given folder
684 # starting with the given file size. Files are reduced in size when
685 # they can no longer fit until no more files can be created.
693 local bytes_written=0
696 if [ $# -ne 4 ]; then
697 echo "Usage: _fill_fs filesize dir blocksize switch_user"
701 if [ $switch_user -eq 0 ]; then
704 _user_do "mkdir -p $dir"
706 if [ ! -d $dir ]; then
710 testio=`$XFS_IO_PROG -F -fc "falloc 0 $block_size" $dir/$$.xfs_io 2>&1`
711 echo $testio | grep -q "not found" && use_falloc=0
712 echo $testio | grep -q "Operation not supported" && use_falloc=0
714 if [ $file_size -lt $block_size ]; then
715 $file_size = $block_size
718 while [ $file_size -ge $block_size ]; do
720 if [ $switch_user -eq 0 ]; then
721 if [ $use_falloc -eq 0 ]; then
722 $XFS_IO_PROG -fc "pwrite -b 8388608 0 $file_size" \
725 $XFS_IO_PROG -fc "falloc 0 $file_size" \
729 if [ $use_falloc -eq 0 ]; then
730 _user_do "$XFS_IO_PROG -f -c \"pwrite -b 8388608 0 \
731 $file_size\" $dir/$file_count"
733 _user_do "$XFS_IO_PROG -f -c \"falloc 0 \
734 $file_size\" $dir/$file_count"
738 if [ -f $dir/$file_count ]; then
739 bytes_written=$(stat -c '%s' $dir/$file_count)
742 # If there was no room to make the file, then divide it in
743 # half, and keep going
744 if [ $bytes_written -lt $file_size ]; then
745 file_size=$((file_size / 2))
747 file_count=$((file_count + 1))
751 # Populate a scratch FS from scratch or from a cached image.
752 _scratch_populate_cached() {
753 POPULATE_METADUMP="${TEST_DIR}/__populate.${FSTYP}"
754 POPULATE_METADUMP_DESCR="${TEST_DIR}/__populate.${FSTYP}.txt"
756 # Don't keep metadata images cached for more 48 hours...
757 rm -rf "$(find "${POPULATE_METADUMP}" -mtime +2 2>/dev/null)"
759 # Throw away cached image if it doesn't match our spec.
762 extra_descr="LOGDEV ${SCRATCH_LOGDEV} USE_EXTERNAL ${USE_EXTERNAL}"
763 # ext4 cannot e2image external logs, so we cannot restore
764 test -n "${SCRATCH_LOGDEV}" && rm -f "${POPULATE_METADUMP}"
767 extra_descr="LOGDEV ${SCRATCH_LOGDEV} USE_EXTERNAL ${USE_EXTERNAL} RTDEV ${SCRATCH_RTDEV}"
768 _populate_xfs_qmount_option
769 if echo "${MOUNT_OPTIONS}" | grep -q 'usrquota'; then
770 extra_descr="${extra_descr} QUOTAS"
776 meta_descr="FSTYP ${FSTYP} MKFS_OPTIONS ${MKFS_OPTIONS} SIZE $(blockdev --getsz "${SCRATCH_DEV}") ${extra_descr} ARGS $@"
777 cmp -s "${POPULATE_METADUMP_DESCR}" <(echo "${meta_descr}") || rm -rf "${POPULATE_METADUMP}"
779 # Do we have a cached image?
780 if [ -r "${POPULATE_METADUMP}" ]; then
783 xfs_mdrestore "${POPULATE_METADUMP}" "${SCRATCH_DEV}" && return
785 "ext2"|"ext3"|"ext4")
786 e2image -r "${POPULATE_METADUMP}" "${SCRATCH_DEV}" && return
791 # Oh well, just create one from scratch
793 echo "${meta_descr}" > "${POPULATE_METADUMP_DESCR}"
796 _scratch_xfs_populate $@
797 _scratch_xfs_populate_check
798 _scratch_metadump "${POPULATE_METADUMP}" -a -o
800 "ext2"|"ext3"|"ext4")
801 _scratch_ext4_populate $@
802 _scratch_ext4_populate_check
803 e2image -Q "${SCRATCH_DEV}" "${POPULATE_METADUMP}"
806 _fail "Don't know how to populate a ${FSTYP} filesystem."