blob: d8648e96286e1b0491b05ed314b1446a5d168411 [file] [log] [blame]
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
#
# FS QA Test No. 020
#
# extended attributes
#
. ./common/preamble
_begin_fstest metadata attr udf auto quick
status=0 # success is the default!
# Import common functions.
. ./common/filter
. ./common/attr
_filter()
{
sed "s#$TEST_DIR[^ :]*#<TESTFILE>#g;
s#$tmp[^ :]*#<TMPFILE>#g" $1
}
_attr()
{
$ATTR_PROG $* 2>$tmp.err >$tmp.out
exit=$?
_filter $tmp.out
_filter $tmp.err 1>&2
return $exit
}
do_getfattr()
{
_getfattr $* 2>$tmp.err >$tmp.out
exit=$?
_filter $tmp.out
_filter $tmp.err 1>&2
return $exit
}
_attr_list()
{
file=$1
echo " *** print attributes"
if ! do_getfattr -d -e text --absolute-names $file
then
echo " !!! error return"
return 1
fi
}
# set fs-specific max_attrs and max_attrval_size values. The parameter
# @max_attrval_namelen is required for filesystems which take into account attr
# name lengths (including namespace prefix) when determining limits.
_attr_get_max()
{
local max_attrval_namelen="$1"
# set maximum total attr space based on fs type
case "$FSTYP" in
xfs|udf|pvfs2|9p|ceph|nfs)
max_attrs=1000
;;
ext2|ext3|ext4)
# For 4k blocksizes, most of the attributes have an attr_name of
# "attribute_NN" which is 12, and "value_NN" which is 8.
# But for larger block sizes, we start having extended
# attributes of the
# form "attribute_NNN" or "attribute_NNNN", and "value_NNN" and
# "value_NNNN", which causes the round(len(..), 4) to jump up by
# 4 bytes. So round_up(len(attr_name, 4)) becomes 16 instead of
# 12, and round_up(len(value, 4)) becomes 12 instead of 8.
#
# For 64K blocksize the calculation becomes
# max_attrs = (block_size - 32) / (16 + 12 + 16)
# or
# max_attrs = (block_size - 32) / 44
#
# For 4K blocksize:-
# max_attrs = (block_size - 32) / (16 + 8 + 12)
# or
# max_attrs = (block_size - 32) / 36
#
# Note (for 4K bs) above are exact calculations for attrs of
# type attribute_NN with values of type value_NN.
# With above calculations, for 4k blocksize max_attrs becomes
# 112.
# This means we can have few attrs of type attribute_NNN with
# values of
# type value_NNN. To avoid/handle this we need to add extra 4
# bytes of headroom.
#
# So for 4K, the calculations becomes:-
# max_attrs = (block_size - 32) / (16 + 8 + 12 + 4)
# or
# max_attrs = (block_size - 32) / 40
#
# Assume max ~1 block of attrs
BLOCK_SIZE=`_get_block_size $TEST_DIR`
if [ $BLOCK_SIZE -le 4096 ]; then
let max_attrs=$((($BLOCK_SIZE - 32) / (16 + 8 + 12 + 4)))
else
let max_attrs=$((($BLOCK_SIZE - 32) / (16 + 12 + 16 )))
fi
;;
*)
# Assume max ~1 block of attrs
BLOCK_SIZE=`_get_block_size $TEST_DIR`
# user.attribute_XXX="value.XXX" is about 32 bytes; leave some
# overhead
let max_attrs=$BLOCK_SIZE/40
esac
# Set max attr value size in bytes based on fs type
case "$FSTYP" in
btrfs)
_require_btrfs_command inspect-internal dump-super
local ns=$($BTRFS_UTIL_PROG inspect-internal dump-super \
$TEST_DEV | sed -n 's/nodesize\s*\(.*\)/\1/p')
[ -n "$ns" ] || _fail "failed to obtain nodesize"
# max == nodesize - sizeof(struct btrfs_header)
# - sizeof(struct btrfs_item)
# - sizeof(struct btrfs_dir_item) - name_len
max_attrval_size=$(( $ns - 156 - $max_attrval_namelen ))
;;
pvfs2)
max_attrval_size=8192
;;
xfs|udf|9p|ceph)
max_attrval_size=65536
;;
bcachefs)
max_attrval_size=1024
;;
nfs)
# NFS doesn't provide a way to find out the max_attrval_size for
# the underlying filesystem, so just use the lowest value above.
max_attrval_size=1024
;;
*)
# Assume max ~1 block of attrs
BLOCK_SIZE=`_get_block_size $TEST_DIR`
# leave a little overhead
let max_attrval_size=$BLOCK_SIZE-256
esac
}
# real QA test starts here
_supported_fs generic
_require_test
_require_attrs
testfile=$TEST_DIR/attribute_$$
echo "*** list non-existant file"
_attr_list $testfile
echo "*** list empty file"
touch $testfile
_attr_list $testfile
echo "*** query non-existant attribute"
_attr -g "nonexistant" $testfile 2>&1
echo "*** one attribute"
echo "fish" | _attr -s fish $testfile
_attr_list $testfile
echo "*** replace attribute"
echo "fish3" | _attr -s fish $testfile
_attr_list $testfile
echo "*** add attribute"
echo "fish2" | _attr -s snrub $testfile
_attr_list $testfile
echo "*** remove attribute"
_attr -r fish $testfile
_attr_list $testfile
max_attrval_name="long_attr" # add 5 for "user." prefix
_attr_get_max "$(( 5 + ${#max_attrval_name} ))"
echo "*** add lots of attributes"
v=0
while [ $v -lt $max_attrs ]
do
echo -n "value_$v" | attr -s "attribute_$v" $testfile >>$seqres.full
if [ $? -ne 0 ]
then
echo "!!! failed to add \"attribute_$v\""
exit 1
fi
let "v = v + 1"
done
echo "*** check"
# don't print it all out...
_getfattr --absolute-names $testfile \
| tee -a $seqres.full \
| $AWK_PROG '
/^#/ { next }
/^[ ]*$/ { next }
{ l++ }
END {print " *** " (l - 1) " attribute(s)" }' \
| sed s/$max_attrs/MAX_ATTRS/
echo "*** remove lots of attributes"
v=0
while [ $v -lt $max_attrs ]
do
if ! $ATTR_PROG -r "attribute_$v" $testfile >>$seqres.full
then
echo "!!! failed to remove \"attribute_$v\""
exit 1
fi
let "v = v + 1"
done
_attr_list $testfile
echo "*** really long value"
dd if=/dev/zero bs=1 count=$max_attrval_size 2>/dev/null \
| _attr -s "$max_attrval_name" $testfile >/dev/null
OCTAL_SIZE=`echo "obase=8; $max_attrval_size" | bc`
_attr -q -g "$max_attrval_name" $testfile | od -w1 -t x1 \
| sed -e "s/^0*$OCTAL_SIZE$/ATTRSIZE/"
_attr -r "$max_attrval_name" $testfile >/dev/null
echo "*** set/get/remove really long names (expect failure)"
short="XXXXXXXXXX"
long="$short$short$short$short$short$short$short$short$short$short"
vlong="$long$long$long"
_attr -s $vlong -V fish $testfile 2>&1 >/dev/null
_attr -g $vlong $testfile 2>&1 >/dev/null
_attr -r $vlong $testfile 2>&1 >/dev/null
echo "*** check final"
_attr_list $testfile
echo "*** delete"
rm -f $testfile
exit