From patchwork Sat Aug 15 01:52:07 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 7020021 Return-Path: X-Original-To: patchwork-fstests@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 989D29F344 for ; Sat, 15 Aug 2015 01:55:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E5321206A6 for ; Sat, 15 Aug 2015 01:55:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3DC222069F for ; Sat, 15 Aug 2015 01:55:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754016AbbHOBwQ (ORCPT ); Fri, 14 Aug 2015 21:52:16 -0400 Received: from userp1040.oracle.com ([156.151.31.81]:20493 "EHLO userp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752305AbbHOBwO (ORCPT ); Fri, 14 Aug 2015 21:52:14 -0400 Received: from aserv0021.oracle.com (aserv0021.oracle.com [141.146.126.233]) by userp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id t7F1qAwg028482 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Sat, 15 Aug 2015 01:52:11 GMT Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by aserv0021.oracle.com (8.13.8/8.13.8) with ESMTP id t7F1qAQj017122 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL); Sat, 15 Aug 2015 01:52:10 GMT Received: from abhmp0018.oracle.com (abhmp0018.oracle.com [141.146.116.24]) by userv0121.oracle.com (8.13.8/8.13.8) with ESMTP id t7F1q9jp020177; Sat, 15 Aug 2015 01:52:09 GMT Received: from localhost (/24.21.154.84) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Fri, 14 Aug 2015 18:52:08 -0700 Subject: [PATCH 1/7] common: add routines to fuzz filesystems From: "Darrick J. Wong" To: david@fromorbit.com, darrick.wong@oracle.com Cc: linux-ext4@vger.kernel.org, fstests@vger.kernel.org, xfs@oss.sgi.com Date: Fri, 14 Aug 2015 18:52:07 -0700 Message-ID: <20150815015207.4333.10934.stgit@birch.djwong.org> In-Reply-To: <20150815015200.4333.9278.stgit@birch.djwong.org> References: <20150815015200.4333.9278.stgit@birch.djwong.org> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Source-IP: aserv0021.oracle.com [141.146.126.233] Sender: fstests-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org X-Spam-Status: No, score=-7.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Create common/populate with routines to support the new fuzz tests. Signed-off-by: Darrick J. Wong --- common/populate | 546 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 546 insertions(+) create mode 100644 common/populate -- To unsubscribe from this list: send the line "unsubscribe fstests" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/common/populate b/common/populate new file mode 100644 index 0000000..d166c24 --- /dev/null +++ b/common/populate @@ -0,0 +1,546 @@ +##/bin/bash +# Routines for populating a scratch fs, and helpers to exercise an FS +# once it's been fuzzed. +#----------------------------------------------------------------------- +# Copyright (c) 2015 Oracle. All Rights Reserved. +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# +# Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, +# Mountain View, CA 94043, USA, or: http://www.sgi.com +#----------------------------------------------------------------------- + +_require_xfs_io_command "falloc" +_require_xfs_io_command "fpunch" + +_require_xfs_db_blocktrash_z_command() { + test "${FSTYP}" = "xfs" || _notrun "cannot run xfs_db on ${FSTYP}" + $XFS_DB_PROG -x -f -c 'blocktrash -z' "${TEST_DEV}" | grep -q 'nothing on stack' || _notrun "blocktrash -z not supported" +} + +# Attempt to make files of "every" format for data, dirs, attrs etc. +# (with apologies to Eric Sandeen for mutating xfser.sh) + +# Create a large directory +__populate_create_dir() { + name="$1" + nr="$2" + missing="$3" + + mkdir -p "${name}" + seq 0 "${nr}" | while read d; do + creat=mkdir + test "$((d % 20))" -eq 0 && creat=touch + $creat "${name}/$(printf "%.08d" "$d")" + done + + test -z "${missing}" && return + seq 1 2 "${nr}" | while read d; do + rm -rf "${name}/$(printf "%.08d" "$d")" + done +} + +# Add a bunch of attrs to a file +__populate_create_attr() { + name="$1" + nr="$2" + missing="$3" + + touch "${name}" + seq 0 "${nr}" | while read d; do + setfattr -n "user.$(printf "%.08d" "$d")" -v "$(printf "%.08d" "$d")" "${name}" + done + + test -z "${missing}" && return + seq 1 2 "${nr}" | while read d; do + setfattr -x "user.$(printf "%.08d" "$d")" "${name}" + done +} + +# Fill up 60% of the remaining free space +__populate_fill_fs() { + dir="$1" + pct="$2" + test -z "${pct}" && pct=60 + + SRC_SZ="$(du -ks "${SRCDIR}" | cut -f 1)" + FS_SZ="$(( $(stat -f "${dir}" -c '%a * %S') / 1024 ))" + + NR="$(( (FS_SZ * ${pct} / 100) / SRC_SZ ))" + test "${NR}" -lt 1 && NR=1 + + seq 1 "${NR}" | while read nr; do + cp -pRdu "${SRCDIR}" "${dir}/test.${nr}" >> $seqres.full 2>&1 + done +} + +# Populate an XFS on the scratch device with (we hope) all known +# types of metadata block +_scratch_xfs_populate() { + _scratch_mount + blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")" + dblksz="$(xfs_info "${SCRATCH_MNT}" | grep naming.*bsize | sed -e 's/^.*bsize=//g' -e 's/\([0-9]*\).*$/\1/g')" + leaf_lblk="$((32 * 1073741824 / blksz))" + node_lblk="$((64 * 1073741824 / blksz))" + + # Data: + + # Regular files + # - FMT_EXTENTS + echo "+ extents file" + $XFS_IO_PROG -f -c "pwrite -S 0x61 0 ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS" + + # - FMT_BTREE + echo "+ btree extents file" + nr="$((blksz * 2 / 16))" + $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE" + for i in $(seq 1 2 ${nr}); do + $XFS_IO_PROG -f -c "fpunch $((i * blksz)) ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE" + done + + # Directories + # - INLINE + echo "+ inline dir" + __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE" 1 + + # - BLOCK + echo "+ block dir" + __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK" "$((dblksz / 40))" + + # - LEAF + echo "+ leaf dir" + __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_LEAF" "$((dblksz / 12))" + + # - NODE + echo "+ node dir" + __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_NODE" "$((16 * dblksz / 40))" true + + # - BTREE + __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BTREE" "$((128 * dblksz / 40))" true + + # Symlinks + # - FMT_LOCAL + echo "+ inline symlink" + ln -s target "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL" + + # - FMT_EXTENTS + echo "+ extents symlink" + ln -s "$(perl -e 'print "x" x 1023;')" "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS" + + # Char & block + echo "+ special" + mkdir devices + mknod "${SCRATCH_MNT}/S_IFCHR" c 1 1 + mknod "${SCRATCH_MNT}/S_IFBLK" c 1 1 + + # Attribute formats + # LOCAL + echo "+ local attr" + __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LOCAL" 1 + + # LEAF + echo "+ leaf attr" + __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LEAF" "$((blksz / 40))" + + # NODE + echo "+ node attr" + __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_NODE" "$((8 * blksz / 40))" + + # BTREE + echo "+ btree attr" + __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BTREE" "$((64 * blksz / 40))" true + + # FMT_EXTENTS with a remote less-than-a-block value + echo "+ attr extents with a remote less-than-a-block value" + touch "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE3K" + $XFS_IO_PROG -f -c "pwrite -S 0x43 0 3k" "${SCRATCH_MNT}/attrvalfile" > /dev/null + attr -q -s user.remotebtreeattrname "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE3K" < "${SCRATCH_MNT}/attrvalfile" + + # FMT_EXTENTS with a remote block-size value + echo "+ attr extents with a remote one-block value" + touch "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE4K" + $XFS_IO_PROG -f -c "pwrite -S 0x44 0 4k" "${SCRATCH_MNT}/attrvalfile" > /dev/null + attr -q -s user.remotebtreeattrname "${SCRATCH_MNT}/ATTR.FMT_EXTENTS_REMOTE4K" < "${SCRATCH_MNT}/attrvalfile" + rm -rf "${SCRATCH_MNT}/attrvalfile" + + # Make an unused inode + echo "+ empty file" + touch "${SCRATCH_MNT}/unused" + $XFS_IO_PROG -f -c 'fsync' "${SCRATCH_MNT}/unused" + rm -rf "${SCRATCH_MNT}/unused" + + # Copy some real files (xfs tests, I guess...) + echo "+ real files" + #__populate_fill_fs "${SCRATCH_MNT}" 40 + cp -pRdu --reflink=always "${SCRATCH_MNT}/S_IFREG.FMT_BTREE" "${SCRATCH_MNT}/S_IFREG.FMT_BTREE.REFLINK" 2> /dev/null + + umount "${SCRATCH_MNT}" +} + +# Populate an ext4 on the scratch device with (we hope) all known +# types of metadata block +_scratch_ext4_populate() { + _scratch_mount + blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")" + dblksz="${blksz}" + leaf_lblk="$((32 * 1073741824 / blksz))" + node_lblk="$((64 * 1073741824 / blksz))" + + # Data: + + # Regular files + # - FMT_INLINE + echo "+ inline file" + $XFS_IO_PROG -f -c "pwrite -S 0x61 0 1" "${SCRATCH_MNT}/S_IFREG.FMT_INLINE" + + # - FMT_EXTENTS + echo "+ extents file" + $XFS_IO_PROG -f -c "pwrite -S 0x61 0 ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS" + + # - FMT_ETREE + echo "+ extent tree file" + nr="$((blksz * 2 / 12))" + $XFS_IO_PROG -f -c "pwrite -S 0x62 0 $((blksz * nr))" "${SCRATCH_MNT}/S_IFREG.FMT_ETREE" + for i in $(seq 1 2 ${nr}); do + $XFS_IO_PROG -f -c "fpunch $((i * blksz)) ${blksz}" "${SCRATCH_MNT}/S_IFREG.FMT_ETREE" + done + + # Directories + # - INLINE + echo "+ inline dir" + __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE" 1 + + # - BLOCK + echo "+ block dir" + __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK" "$((dblksz / 24))" + + # - HTREE + echo "+ htree dir" + __populate_create_dir "${SCRATCH_MNT}/S_IFDIR.FMT_HTREE" "$((4 * dblksz / 24))" + + # Symlinks + # - FMT_LOCAL + echo "+ inline symlink" + ln -s target "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL" + + # - FMT_EXTENTS + echo "+ extents symlink" + ln -s "$(perl -e 'print "x" x 1023;')" "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS" + + # Char & block + echo "+ special" + mkdir devices + mknod "${SCRATCH_MNT}/S_IFCHR" c 1 1 + mknod "${SCRATCH_MNT}/S_IFBLK" c 1 1 + + # Attribute formats + # LOCAL + echo "+ local attr" + __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_LOCAL" 1 + + # BLOCK + echo "+ block attr" + __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BLOCK" "$((blksz / 40))" + + # Make an unused inode + echo "+ empty file" + touch "${SCRATCH_MNT}/unused" + $XFS_IO_PROG -f -c 'fsync' "${SCRATCH_MNT}/unused" + rm -rf "${SCRATCH_MNT}/unused" + + # Copy some real files (xfs tests, I guess...) + echo "+ real files" + __populate_fill_fs "${SCRATCH_MNT}" + cp -pRdu --reflink=always "${SCRATCH_MNT}/S_IFREG.FMT_ETREE" "${SCRATCH_MNT}/S_IREG.FMT_ETREE.REFLINK" 2> /dev/null + + umount "${SCRATCH_MNT}" +} + +# Find the inode number of a file +__populate_find_inode() { + name="$1" + inode="$(stat -c '%i' "${name}")" + echo "${inode}" +} + +# Check data fork format of XFS file +__populate_check_xfs_dformat() { + dev="$1" + inode="$2" + format="$3" + + fmt="$($XFS_DB_PROG -c "inode ${inode}" -c 'p core.format' "${dev}" | sed -e 's/^.*(\([a-z]*\)).*$/\1/g')" + test "${format}" = "${fmt}" || _fail "failed to create ino ${inode} dformat expected ${format} saw ${fmt}" +} + +# Check attr fork format of XFS file +__populate_check_xfs_aformat() { + dev="$1" + inode="$2" + format="$3" + + fmt="$($XFS_DB_PROG -c "inode ${inode}" -c 'p core.aformat' "${dev}" | sed -e 's/^.*(\([a-z]*\)).*$/\1/g')" + test "${format}" = "${fmt}" || _fail "failed to create ino ${inode} aformat expected ${format} saw ${fmt}" +} + +# Check structure of XFS directory +__populate_check_xfs_dir() { + dev="$1" + inode="$2" + dtype="$3" + + (test -n "${leaf_lblk}" && test -n "${node_lblk}") || _fail "must define leaf_lblk and node_lblk before calling __populate_check_xfs_dir" + datab=0 + leafb=0 + freeb=0 + #echo "== check dir ${inode} type ${dtype}" ; $XFS_DB_PROG -x -c "inode ${inode}" -c "bmap" "${SCRATCH_DEV}" + $XFS_DB_PROG -x -c "inode ${inode}" -c "dblock 0" -c "stack" "${SCRATCH_DEV}" | grep -q 'file data block is unmapped' || datab=1 + $XFS_DB_PROG -x -c "inode ${inode}" -c "dblock ${leaf_lblk}" -c "stack" "${SCRATCH_DEV}" | grep -q 'file data block is unmapped' || leafb=1 + $XFS_DB_PROG -x -c "inode ${inode}" -c "dblock ${node_lblk}" -c "stack" "${SCRATCH_DEV}" | grep -q 'file data block is unmapped' || freeb=1 + + case "${dtype}" in + "shortform"|"inline"|"local") + (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}" + ;; + "block") + (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}" + ;; + "leaf") + (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}" + ;; + "node"|"btree") + (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}" + ;; + *) + _fail "Unknown directory type ${dtype}" + esac +} + +# Check structure of XFS attr +__populate_check_xfs_attr() { + dev="$1" + inode="$2" + atype="$3" + + datab=0 + leafb=0 + #echo "== check attr ${inode} type ${dtype}" ; $XFS_DB_PROG -x -c "inode ${inode}" -c "bmap -a" "${SCRATCH_DEV}" + $XFS_DB_PROG -x -c "inode ${inode}" -c "ablock 0" -c "stack" "${SCRATCH_DEV}" | grep -q 'file attr block is unmapped' || datab=1 + $XFS_DB_PROG -x -c "inode ${inode}" -c "ablock 1" -c "stack" "${SCRATCH_DEV}" | grep -q 'file attr block is unmapped' || leafb=1 + + case "${atype}" in + "shortform"|"inline"|"local") + (test "${datab}" -eq 0 && test "${leafb}" -eq 0) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}" + ;; + "leaf") + (test "${datab}" -eq 1 && test "${leafb}" -eq 0) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}" + ;; + "node"|"btree") + (test "${datab}" -eq 1 && test "${leafb}" -eq 1) || _fail "failed to create ${atype} attr ino ${inode} datab ${datab} leafb ${leafb}" + ;; + *) + _fail "Unknown attribute type ${atype}" + esac +} + +# Check that populate created all the types of files we wanted +_scratch_xfs_populate_check() { + _scratch_mount + extents_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS")" + btree_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_BTREE")" + inline_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_INLINE")" + block_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK")" + leaf_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_LEAF")" + node_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_NODE")" + btree_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BTREE")" + local_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_LOCAL")" + extents_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS")" + bdev="$(__populate_find_inode "${SCRATCH_MNT}/S_IFBLK")" + cdev="$(__populate_find_inode "${SCRATCH_MNT}/S_IFCHR")" + local_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LOCAL")" + leaf_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LEAF")" + node_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_NODE")" + btree_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_BTREE")" + + blksz="$(stat -f -c '%s' "${SCRATCH_MNT}")" + dblksz="$(xfs_info "${SCRATCH_MNT}" | grep naming.*bsize | sed -e 's/^.*bsize=//g' -e 's/\([0-9]*\).*$/\1/g')" + leaf_lblk="$((32 * 1073741824 / blksz))" + node_lblk="$((64 * 1073741824 / blksz))" + umount "${SCRATCH_MNT}" + + __populate_check_xfs_dformat "${SCRATCH_DEV}" "${extents_file}" "extents" + __populate_check_xfs_dformat "${SCRATCH_DEV}" "${btree_file}" "btree" + __populate_check_xfs_dir "${SCRATCH_DEV}" "${inline_dir}" "inline" + __populate_check_xfs_dir "${SCRATCH_DEV}" "${block_dir}" "block" + __populate_check_xfs_dir "${SCRATCH_DEV}" "${leaf_dir}" "leaf" + __populate_check_xfs_dir "${SCRATCH_DEV}" "${node_dir}" "node" + __populate_check_xfs_dir "${SCRATCH_DEV}" "${btree_dir}" "btree" + __populate_check_xfs_dformat "${SCRATCH_DEV}" "${btree_dir}" "btree" + __populate_check_xfs_dformat "${SCRATCH_DEV}" "${bdev}" "dev" + __populate_check_xfs_dformat "${SCRATCH_DEV}" "${cdev}" "dev" + __populate_check_xfs_attr "${SCRATCH_DEV}" "${local_attr}" "local" + __populate_check_xfs_attr "${SCRATCH_DEV}" "${leaf_attr}" "leaf" + __populate_check_xfs_attr "${SCRATCH_DEV}" "${node_attr}" "node" + __populate_check_xfs_attr "${SCRATCH_DEV}" "${btree_attr}" "btree" + __populate_check_xfs_aformat "${SCRATCH_DEV}" "${btree_attr}" "btree" +} + +# Check data fork format of ext4 file +__populate_check_ext4_dformat() { + dev="$1" + inode="$2" + format="$3" + + extents=0 + etree=0 + debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'ETB[0-9]' -q && etree=1 + iflags="$(debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'Flags:' | sed -e 's/^.*Flags: \([0-9a-fx]*\).*$/\1/g')" + test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x80000);}')" -gt 0 && extents=1 + + case "${format}" in + "blockmap") + test "${extents}" -eq 0 || _fail "failed to create ino ${inode} with blockmap" + ;; + "extent"|"extents") + test "${extents}" -eq 1 || _fail "failed to create ino ${inode} with extents" + ;; + "etree") + (test "${extents}" -eq 1 && test "${etree}" -eq 1) || _fail "failed to create ino ${inode} with extent tree" + ;; + *) + _fail "Unknown dformat ${format}" + esac +} + +# Check attr fork format of ext4 file +__populate_check_ext4_aformat() { + dev="$1" + inode="$2" + format="$3" + + ablock=1 + debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'File ACL: 0' -q && ablock=0 + + case "${format}" in + "local"|"inline") + test "${ablock}" -eq 0 || _fail "failed to create inode ${inode} with ${format} xattr" + ;; + "block") + test "${extents}" -eq 1 || _fail "failed to create inode ${inode} with ${format} xattr" + ;; + *) + _fail "Unknown aformat ${format}" + esac +} + +# Check structure of ext4 dir +__populate_check_ext4_dir() { + dev="$1" + inode="$2" + dtype="$3" + + htree=0 + inline=0 + iflags="$(debugfs -R "stat <${inode}>" "${dev}" 2> /dev/null | grep 'Flags:' | sed -e 's/^.*Flags: \([0-9a-fx]*\).*$/\1/g')" + test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x1000);}')" -gt 0 && htree=1 + test "$(echo "${iflags}" | awk '{print and(strtonum($1), 0x10000000);}')" -gt 0 && inline=1 + + case "${dtype}" in + "inline") + (test "${inline}" -eq 1 && test "${htree}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}" + ;; + "block") + (test "${inline}" -eq 0 && test "${htree}" -eq 0) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}" + ;; + "htree") + (test "${inline}" -eq 0 && test "${htree}" -eq 1) || _fail "failed to create ${dtype} dir ino ${inode} htree ${htree} inline ${inline}" + ;; + *) + _fail "Unknown directory type ${dtype}" + ;; + esac +} + +# Check that populate created all the types of files we wanted +_scratch_ext4_populate_check() { + _scratch_mount + extents_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_EXTENTS")" + etree_file="$(__populate_find_inode "${SCRATCH_MNT}/S_IFREG.FMT_ETREE")" + block_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_BLOCK")" + htree_dir="$(__populate_find_inode "${SCRATCH_MNT}/S_IFDIR.FMT_HTREE")" + extents_slink="$(__populate_find_inode "${SCRATCH_MNT}/S_IFLNK.FMT_EXTENTS")" + local_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_LOCAL")" + block_attr="$(__populate_find_inode "${SCRATCH_MNT}/ATTR.FMT_BLOCK")" + umount "${SCRATCH_MNT}" + + __populate_check_ext4_dformat "${SCRATCH_DEV}" "${extents_file}" "extents" + __populate_check_ext4_dformat "${SCRATCH_DEV}" "${etree_file}" "etree" + __populate_check_ext4_dir "${SCRATCH_DEV}" "${block_dir}" "block" + __populate_check_ext4_dir "${SCRATCH_DEV}" "${htree_dir}" "htree" + __populate_check_ext4_dformat "${SCRATCH_DEV}" "${extents_slink}" "extents" + __populate_check_ext4_aformat "${SCRATCH_DEV}" "${local_attr}" "local" + __populate_check_ext4_aformat "${SCRATCH_DEV}" "${block_attr}" "block" +} + +# Populate a scratch FS and check the contents to make sure we got that +_scratch_populate() { + case "${FSTYP}" in + "xfs") + _scratch_xfs_populate + _scratch_xfs_populate_check + ;; + "ext4") + _scratch_ext4_populate + _scratch_ext4_populate_check + ;; + *) + _fail "Don't know how to populate a ${FSTYP} filesystem." + ;; + esac +} + +# Modify various files after a fuzzing operation +_scratch_fuzz_modify() { + nr="$1" + + test -z "${nr}" && nr=50000 + echo "+++ touch ${nr} files" + $XFS_IO_PROG -f -c "pwrite -S 0x63 0 ${BLK_SZ}" "/tmp/afile" > /dev/null + date="$(date)" + find "${SCRATCH_MNT}/" -type f 2> /dev/null | head -n "${nr}" | while read f; do + setfattr -n "user.date" -v "${date}" "$f" + cat "/tmp/afile" >> "$f" + mv "$f" "$f.longer" + done + rm -rf "/tmp/afile" + + echo "+++ create files" + cp -pRdu "${SRCDIR}" "${SCRATCH_MNT}/test.moo" + sync + + echo "+++ remove files" + rm -rf "${SCRATCH_MNT}/test.moo" + rm -rf "${SCRATCH_MNT}/test.1" +} + +# Try to access files after fuzzing +_scratch_fuzz_test() { + echo "+++ ls -laR" >> $seqres.full + ls -laR "${SCRATCH_MNT}/test.1/" >/dev/null 2>&1 + + echo "+++ cat files" >> $seqres.full + (find "${SCRATCH_MNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat) >/dev/null 2>&1 +} +