diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -818,6 +818,8 @@ fs fusefs .. + nfs + .. tarfs .. tmpfs diff --git a/tests/sys/fs/Makefile b/tests/sys/fs/Makefile --- a/tests/sys/fs/Makefile +++ b/tests/sys/fs/Makefile @@ -12,6 +12,7 @@ .if ${COMPILER_FEATURES:Mc++14} && ${MK_GOOGLETEST} != "no" TESTS_SUBDIRS+= fusefs .endif +TESTS_SUBDIRS+= nfs TESTS_SUBDIRS+= tarfs TESTS_SUBDIRS+= tmpfs diff --git a/tests/sys/fs/nfs/Makefile b/tests/sys/fs/nfs/Makefile new file mode 100644 --- /dev/null +++ b/tests/sys/fs/nfs/Makefile @@ -0,0 +1,8 @@ +PACKAGE= tests + +TESTSDIR= ${TESTSBASE}/sys/fs/nfs +BINDIR= ${TESTSDIR} + +ATF_TESTS_SH+= nfs_test + +.include diff --git a/tests/sys/fs/nfs/nfs_test.sh b/tests/sys/fs/nfs/nfs_test.sh new file mode 100644 --- /dev/null +++ b/tests/sys/fs/nfs/nfs_test.sh @@ -0,0 +1,163 @@ +# +# Copyright (c) 2025 Dag-Erling Smørgrav +# +# SPDX-License-Identifier: BSD-2-Clause +# + +. $(atf_get_srcdir)/../../common/vnet.subr + +nfs_jail() { + local name=$1 + local path=$2 + local iface=$3 + local cidr=$4 + local f + + # Create directory hierarchy + mkdir -p "${path}" + atf_check mount -t tmpfs tmpfs "${path}" + atf_check -o ignore \ + mtree -deqU -f /etc/mtree/BSD.root.dist -p "${path}" + atf_check -o ignore \ + mtree -deqU -f /etc/mtree/BSD.usr.dist -p "${path}"/usr + atf_check -o ignore \ + mtree -deqU -f /etc/mtree/BSD.var.dist -p "${path}"/var + # Copy minimal system + tar cf - -C / --no-fflags \ + --exclude debug --exclude '*clang*' --exclude '*llvm*' \ + bin lib libexec usr/bin sbin usr/lib usr/libexec usr/sbin | + atf_check tar xf - -C "${path}" + # Grab stock versions of etc files + for f in group master.passwd netconfig rpc services ; do + atf_check cp -p /var/db/etcupdate/current/etc/$f \ + "${path}"/etc/$f + done + # Create the jail + atf_check jail -c name="${name}" path="${path}" persist \ + allow.mount allow.mount.devfs allow.mount.tmpfs allow.mount.nfs \ + allow.nfsd enforce_statfs=1 vnet vnet.interface="${iface}" \ + host.hostname="${name}" + unlist_interface "${iface}" + atf_check jexec "${name}" mount -t devfs devfs /dev + atf_check jexec "${name}" pwd_mkdb /etc/master.passwd + # Configure the jail's network + atf_check jexec "${name}" ifconfig lo0 inet 127.0.0.1/8 + atf_check jexec "${name}" ifconfig "${iface}" inet "${cidr}" up + cat >/etc/hosts <"${path}"/etc/syslog.conf < "${path}"/var/log/messages + atf_check jexec "${name}" syslogd -ss + # Start rpcbind + atf_check jexec "${name}" rpcbind +} + +nfs_setup() { + vnet_init + epair=$(vnet_mkepair) + + # Create the server jail + nfs_jail nfsd nfsd ${epair}a 192.0.2.1/24 + # Start mountd in server jail + echo "V4: /" >nfsd/etc/exports + atf_check jexec nfsd mountd /etc/exports + # Start nfsd in server jail + # RPC over UDP is currently not permitted in jails + atf_check jexec nfsd nfsd -t + + # Create the client jail + nfs_jail nfscl nfscl ${epair}b 192.0.2.2/24 +} + +nfs_cleanup() { + # Tear down the client jail + if [ -d nfscl ] ; then + jail -r nfscl || true + if [ -d nfscl/imp ] ; then + umount -f nfscl/imp || true + fi + umount -f nfscl/dev || true + umount -f nfscl || true + fi + # Tear down the server jail + if [ -d nfsd ] ; then + jail -r nfsd || true + if [ -d nfsd/exp ] ; then + umount -f nfsd/exp || true + fi + umount -f nfsd/dev || true + umount -f nfsd || true + fi + vnet_cleanup +} + +atf_test_case nfs_basic cleanup +nfs_basic_head() { + atf_set "descr" "Basic NFS function test" + atf_set "require.user" "root" + atf_set "require.kmods" "nfscl nfsd tmpfs" +} +nfs_basic_body() { + nfs_setup + + # On the server, create a mountpoint, mount a tmpfs, and + # export it + atf_check mkdir nfsd/exp + atf_check jexec nfsd mount -t tmpfs tmpfs /exp + atf_check jexec nfsd sed -i '' -e 'i\ +/exp -maproot=root -network=192.0.2.0/24' /etc/exports + atf_check jexec nfsd pkill -HUP mountd + + # On the client, create a mountpoint and mount the exported + # file system + atf_check mkdir nfscl/imp + atf_check jexec nfscl mount -t nfs 192.0.2.1:/exp /imp + + # Create file on server, check on client + echo "Hello, world!" >hello.txt + cp hello.txt nfsd/exp + atf_check -o file:hello.txt jexec nfscl cat /imp/hello.txt + + # Create file on client, check on server + echo "The Magic Words are Squeamish Ossifrage" >magic.txt + cp magic.txt nfscl/imp + atf_check -o file:magic.txt jexec nfsd cat /exp/magic.txt + + # Create directory on client, check on server + atf_check jexec nfscl mkdir /imp/dir + atf_check jexec nfsd test -d /exp/dir + + # Create symbolic link on client, check on server + atf_check jexec nfscl ln -s ../magic.txt /imp/dir/link.txt + atf_check -o ignore jexec nfsd readlink /exp/dir/link.txt + atf_check -o file:magic.txt jexec nfsd cat /exp/dir/link.txt + + # Create hard link on client, check on server + atf_check jexec nfscl ln -f /imp/hello.txt /imp/dir/link.txt + atf_check -s exit:1 jexec nfsd readlink /exp/dir/link.txt + atf_check -o file:hello.txt jexec nfsd cat /exp/dir/link.txt + + # Rename file on client, check on server + atf_check jexec nfscl mv /imp/hello.txt /imp/world.txt + atf_check -o file:hello.txt jexec nfsd cat /exp/world.txt + + # Delete file on client, check on server + atf_check jexec nfscl rm /imp/dir/link.txt + atf_check -s exit:1 -e ignore jexec nfsd cat /exp/dir/link.txt + + # Delete directory on client, check on server + atf_check jexec nfscl rmdir /imp/dir + atf_check -s exit:1 jexec nfsd test -d /exp/dir +} +nfs_basic_cleanup() { + nfs_cleanup +} + +atf_init_test_cases() { + atf_add_test_case nfs_basic +}