1*aa870a19SDag-Erling Smørgrav# 2*aa870a19SDag-Erling Smørgrav# Copyright (c) 2025 Dag-Erling Smørgrav <des@FreeBSD.org> 3*aa870a19SDag-Erling Smørgrav# 4*aa870a19SDag-Erling Smørgrav# SPDX-License-Identifier: BSD-2-Clause 5*aa870a19SDag-Erling Smørgrav# 6*aa870a19SDag-Erling Smørgrav 7*aa870a19SDag-Erling Smørgrav# Create and mount a UFS filesystem on a small memory disk 8*aa870a19SDag-Erling Smørgravquot_setup() 9*aa870a19SDag-Erling Smørgrav{ 10*aa870a19SDag-Erling Smørgrav atf_check -o save:dev mdconfig -t malloc -s 16M 11*aa870a19SDag-Erling Smørgrav local dev=$(cat dev) 12*aa870a19SDag-Erling Smørgrav atf_check -o ignore newfs "$@" /dev/$dev 13*aa870a19SDag-Erling Smørgrav atf_check mkdir mnt 14*aa870a19SDag-Erling Smørgrav local mnt=$(realpath mnt) 15*aa870a19SDag-Erling Smørgrav atf_check mount /dev/$dev "$mnt" 16*aa870a19SDag-Erling Smørgrav echo "/dev/$dev: ($mnt)" >expect 17*aa870a19SDag-Erling Smørgrav printf "%5d\t%5d\t%-8s\n" 8 2 "#0" >>expect 18*aa870a19SDag-Erling Smørgrav} 19*aa870a19SDag-Erling Smørgrav 20*aa870a19SDag-Erling Smørgrav# Create a directory owned by a given UID 21*aa870a19SDag-Erling Smørgravquot_adduid() 22*aa870a19SDag-Erling Smørgrav{ 23*aa870a19SDag-Erling Smørgrav local uid=$1 24*aa870a19SDag-Erling Smørgrav atf_check install -d -o $uid -g 0 mnt/$uid 25*aa870a19SDag-Erling Smørgrav printf "%5d\t%5d\t%-8s\n" 4 1 "#$uid" >>expect 26*aa870a19SDag-Erling Smørgrav} 27*aa870a19SDag-Erling Smørgrav 28*aa870a19SDag-Erling Smørgrav# Perform the tests 29*aa870a19SDag-Erling Smørgravquot_test() 30*aa870a19SDag-Erling Smørgrav{ 31*aa870a19SDag-Erling Smørgrav local dev=$(cat dev) 32*aa870a19SDag-Erling Smørgrav # Create inodes owned by a large number of users to exercise 33*aa870a19SDag-Erling Smørgrav # hash collisions and rehashing. The code uses an open hash 34*aa870a19SDag-Erling Smørgrav # table that starts out with only 8 entries and doubles every 35*aa870a19SDag-Erling Smørgrav # time it fills up. 36*aa870a19SDag-Erling Smørgrav local uid 37*aa870a19SDag-Erling Smørgrav for uid in $(seq 1 32); do 38*aa870a19SDag-Erling Smørgrav quot_adduid $uid 39*aa870a19SDag-Erling Smørgrav done 40*aa870a19SDag-Erling Smørgrav # Also create inodes owned by users with long UIDs, up to the 41*aa870a19SDag-Erling Smørgrav # highest possible value (2^32 - 2, because chown(2) and 42*aa870a19SDag-Erling Smørgrav # friends interpret 2^32 - 1 as “leave unchanged”). 43*aa870a19SDag-Erling Smørgrav local shift 44*aa870a19SDag-Erling Smørgrav for shift in $(seq 6 32); do 45*aa870a19SDag-Erling Smørgrav quot_adduid $(((1 << shift) - 2)) 46*aa870a19SDag-Erling Smørgrav done 47*aa870a19SDag-Erling Smørgrav # Since quot operates directly on the underlying device, not 48*aa870a19SDag-Erling Smørgrav # on the mounted filesystem, we remount read-only to ensure 49*aa870a19SDag-Erling Smørgrav # that everything gets flushed to the memory disk. 50*aa870a19SDag-Erling Smørgrav atf_check mount -ur /dev/$dev 51*aa870a19SDag-Erling Smørgrav atf_check -o file:expect quot -fkN /dev/$dev 52*aa870a19SDag-Erling Smørgrav atf_check -o file:expect quot -fkN $(realpath mnt) 53*aa870a19SDag-Erling Smørgrav} 54*aa870a19SDag-Erling Smørgrav 55*aa870a19SDag-Erling Smørgrav# Unmount and release the memory disk 56*aa870a19SDag-Erling Smørgravquot_cleanup() 57*aa870a19SDag-Erling Smørgrav{ 58*aa870a19SDag-Erling Smørgrav if [ -d mnt ]; then 59*aa870a19SDag-Erling Smørgrav umount mnt || true 60*aa870a19SDag-Erling Smørgrav fi 61*aa870a19SDag-Erling Smørgrav if [ -f dev ]; then 62*aa870a19SDag-Erling Smørgrav mdconfig -d -u $(cat dev) || true 63*aa870a19SDag-Erling Smørgrav fi 64*aa870a19SDag-Erling Smørgrav} 65*aa870a19SDag-Erling Smørgrav 66*aa870a19SDag-Erling Smørgravatf_test_case ufs1 cleanup 67*aa870a19SDag-Erling Smørgravufs1_head() 68*aa870a19SDag-Erling Smørgrav{ 69*aa870a19SDag-Erling Smørgrav atf_set descr "Test quot on UFS1" 70*aa870a19SDag-Erling Smørgrav atf_set require.user root 71*aa870a19SDag-Erling Smørgrav} 72*aa870a19SDag-Erling Smørgravufs1_body() 73*aa870a19SDag-Erling Smørgrav{ 74*aa870a19SDag-Erling Smørgrav quot_setup -O1 75*aa870a19SDag-Erling Smørgrav quot_test 76*aa870a19SDag-Erling Smørgrav} 77*aa870a19SDag-Erling Smørgravufs1_cleanup() 78*aa870a19SDag-Erling Smørgrav{ 79*aa870a19SDag-Erling Smørgrav quot_cleanup 80*aa870a19SDag-Erling Smørgrav} 81*aa870a19SDag-Erling Smørgrav 82*aa870a19SDag-Erling Smørgravatf_test_case ufs2 cleanup 83*aa870a19SDag-Erling Smørgravufs2_head() 84*aa870a19SDag-Erling Smørgrav{ 85*aa870a19SDag-Erling Smørgrav atf_set descr "Test quot on UFS2" 86*aa870a19SDag-Erling Smørgrav atf_set require.user root 87*aa870a19SDag-Erling Smørgrav} 88*aa870a19SDag-Erling Smørgravufs2_body() 89*aa870a19SDag-Erling Smørgrav{ 90*aa870a19SDag-Erling Smørgrav quot_setup -O2 91*aa870a19SDag-Erling Smørgrav quot_test 92*aa870a19SDag-Erling Smørgrav} 93*aa870a19SDag-Erling Smørgravufs2_cleanup() 94*aa870a19SDag-Erling Smørgrav{ 95*aa870a19SDag-Erling Smørgrav quot_cleanup 96*aa870a19SDag-Erling Smørgrav} 97*aa870a19SDag-Erling Smørgrav 98*aa870a19SDag-Erling Smørgravatf_init_test_cases() 99*aa870a19SDag-Erling Smørgrav{ 100*aa870a19SDag-Erling Smørgrav atf_add_test_case ufs1 101*aa870a19SDag-Erling Smørgrav atf_add_test_case ufs2 102*aa870a19SDag-Erling Smørgrav} 103