From: Darrick J. Wong <djwong@xxxxxxxxxx> Currently, we set a large number of extended attributes when trying to force the attr fork to be in BTREE format. This doesn't work reliably because userspace has no control over where xattr leaf and dabtree blocks are mapped, and contiguous mappings can prevent the file from having a btree format attr fork. However, we /do/ have one small knob for controlling attr fork mappings in the form of creating remote value xattrs and then deleting them to leave holes in the mappings. Create a separate helper function that exploits this property to try to create a sparse attr fork with enough mappings to give us the btree attr fork that we want. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- common/populate | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/common/populate b/common/populate index b6f510f396..144a3f5186 100644 --- a/common/populate +++ b/common/populate @@ -155,6 +155,57 @@ __populate_create_attr() { done } +# Create an extended attr structure and ensure that the fork is btree format +__populate_xfs_create_btree_attr() { + local name="$1" + local isize="$2" + local dblksz="$3" + local icore_size="$(_xfs_get_inode_core_bytes $SCRATCH_MNT)" + # We need enough extents to guarantee that the attr fork is in btree + # format. Cycling the mount to use xfs_db is too slow, so watch for + # when the number of holes that we can punch in the attr fork by + # deleting remote xattrs exceeds the number of extent mappings that can + # fit in the inode core. + local max_nextents="$(((isize - icore_size) / 16))" + local nr + local i + local incr + local bigval + + # Add about one block's worth of attrs in betweeen creating punchable + # remote value blocks. + incr=$(( (dblksz / 16) / 100 * 100 )) + bigval="$(perl -e "print \"@\" x $dblksz;")" + + touch "${name}" + + # We cannot control the mapping behaviors of the attr fork leaf and + # dabtree blocks, but we do know that remote values are stored in a + # single extent, and that those mappings are removed if the xattr is + # deleted. + # + # The extended attribute structure tends to grow from offset zero + # upwards, so we try to set up a sparse attr fork mapping by + # iteratively creating at least one leaf block's worth of local attrs, + # and then one remote attr, until the number of remote xattrs exceeds + # the number of mappings that fit in the inode core... + for ((nr = 0; nr < (incr * max_nextents); nr += incr)); do + # Simulate a getfattr dump file so we can bulk-add attrs. + ( + echo "# file: ${name}"; + seq --format "user.%08g=\"abcdefgh\"" "${nr}" "$((nr + incr + 1))" + echo "user.v$(printf "%.08d" "$nr")=\"${bigval}\"" + echo + ) | setfattr --restore - + done + + # ... and in the second loop we delete all the remote attrs to + # fragment the attr fork mappings. + for ((i = 0; i < nr; i += incr)); do + setfattr -x "user.v$(printf "%.08d" "$i")" "${name}" + done +} + # Fill up some percentage of the remaining free space __populate_fill_fs() { dir="$1" @@ -327,7 +378,7 @@ _scratch_xfs_populate() { # BTREE echo "+ btree attr" - __populate_create_attr "${SCRATCH_MNT}/ATTR.FMT_BTREE" "$((64 * blksz / 40))" true + __populate_xfs_create_btree_attr "${SCRATCH_MNT}/ATTR.FMT_BTREE" "$isize" "$dblksz" # trusted namespace touch ${SCRATCH_MNT}/ATTR.TRUSTED