aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--etc/mtree/BSD.tests.dist2
-rw-r--r--tests/sys/geom/class/Makefile1
-rw-r--r--tests/sys/geom/class/union/Makefile9
-rw-r--r--tests/sys/geom/class/union/conf.sh40
-rw-r--r--tests/sys/geom/class/union/union_test.sh338
5 files changed, 390 insertions, 0 deletions
diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist
index f6f55276284a..e216767170ab 100644
--- a/etc/mtree/BSD.tests.dist
+++ b/etc/mtree/BSD.tests.dist
@@ -795,6 +795,8 @@
..
stripe
..
+ union
+ ..
uzip
etalon
..
diff --git a/tests/sys/geom/class/Makefile b/tests/sys/geom/class/Makefile
index 4a21e039f185..10b01a043ddf 100644
--- a/tests/sys/geom/class/Makefile
+++ b/tests/sys/geom/class/Makefile
@@ -17,6 +17,7 @@ TESTS_SUBDIRS+= part
TESTS_SUBDIRS+= raid3
TESTS_SUBDIRS+= shsec
TESTS_SUBDIRS+= stripe
+TESTS_SUBDIRS+= union
TESTS_SUBDIRS+= uzip
${PACKAGE}FILES+= geom_subr.sh
diff --git a/tests/sys/geom/class/union/Makefile b/tests/sys/geom/class/union/Makefile
new file mode 100644
index 000000000000..5ab8055fd84c
--- /dev/null
+++ b/tests/sys/geom/class/union/Makefile
@@ -0,0 +1,9 @@
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/sys/geom/class/${.CURDIR:T}
+
+ATF_TESTS_SH+= union_test
+
+${PACKAGE}FILES+= conf.sh
+
+.include <bsd.test.mk>
diff --git a/tests/sys/geom/class/union/conf.sh b/tests/sys/geom/class/union/conf.sh
new file mode 100644
index 000000000000..1150c7204ad3
--- /dev/null
+++ b/tests/sys/geom/class/union/conf.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+class="union"
+base=$(atf_get ident)
+
+attach_md()
+{
+ local test_md
+
+ test_md=$(mdconfig -a "$@") || atf_fail "failed to allocate md(4)"
+ echo $test_md >> $TEST_MDS_FILE || exit
+ echo $test_md
+}
+
+gunion_test_cleanup()
+{
+ if mount | grep -q "/gunionmnt"; then
+ umount gunionmnt
+ fi
+ if mount | grep -q "/uppermnt"; then
+ umount uppermnt
+ fi
+ if mount | grep -q "/lowermnt"; then
+ umount lowermnt
+ fi
+
+ if [ -e "guniondev" ]; then
+ gunion destroy "$(cat guniondev)"
+ fi
+
+ geom_test_cleanup
+}
+
+gunion_test_setup()
+{
+ geom_atf_test_setup
+}
+
+ATF_TEST=true
+. `dirname $0`/../geom_subr.sh
diff --git a/tests/sys/geom/class/union/union_test.sh b/tests/sys/geom/class/union/union_test.sh
new file mode 100644
index 000000000000..1872847bdf58
--- /dev/null
+++ b/tests/sys/geom/class/union/union_test.sh
@@ -0,0 +1,338 @@
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2023 The FreeBSD Foundation
+#
+# This software was developed1 by Yan-Hao Wang <bses30074@gmail.com>
+# under sponsorship from the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+. $(atf_get_srcdir)/conf.sh
+
+atf_test_case create cleanup
+create_head()
+{
+ atf_set "descr" "Test gunion create and destroy"
+ atf_set "require.user" "root"
+}
+create_body()
+{
+ gunion_test_setup
+
+ upperdev="$(attach_md -s 1m)"
+ lowerdev="$(attach_md -s 1m)"
+ newfs -U "/dev/${lowerdev}"
+
+ atf_check gunion create "$upperdev" "$lowerdev"
+ guniondev="${upperdev}-${lowerdev}.union"
+ atf_check -o inline:"/dev/${guniondev}\n" ls "/dev/${guniondev}"
+ atf_check -o ignore fsck -p -f "/dev/${guniondev}"
+
+ atf_check gunion destroy "$guniondev"
+ atf_check -s not-exit:0 -o ignore -e ignore ls "/dev/${guniondev}"
+}
+create_cleanup()
+{
+ gunion_test_cleanup
+}
+
+atf_test_case basic cleanup
+basic_head()
+{
+ atf_set "descr" "Check gunion doesn't affect lowerdev status and lowerdev can't be mounted when being in a gunion"
+ atf_set "require.user" "root"
+}
+basic_body()
+{
+ gunion_test_setup
+
+ upperdev="$(attach_md -s 1m)"
+ lowerdev="$(attach_md -s 1m)"
+ newfs -U "/dev/${lowerdev}"
+ mkdir lowermnt
+ mkdir gunionmnt
+
+ mount "/dev/${lowerdev}" lowermnt
+ echo "lower file" > lower_file
+ cp lower_file lowermnt/lower_file
+ sync
+ umount lowermnt
+
+ gunion create "$upperdev" "$lowerdev"
+ guniondev="${upperdev}-${lowerdev}.union"
+ atf_check -s not-exit:0 -o ignore -e ignore mount "/dev/${lowerdev}" lowermnt
+
+ mount "/dev/${guniondev}" gunionmnt
+ echo "update lower file" >> gunionmnt/lower_file
+ echo "gunion file" > gunion_file
+ cp gunion_file gunionmnt/gunion_file
+ sync
+ umount gunionmnt
+
+ gunion destroy "$guniondev"
+ mount "/dev/${lowerdev}" lowermnt
+ checksum lowermnt/lower_file lower_file
+ atf_check -s not-exit:0 -o ignore -e ignore ls lowermnt/gunion_file
+}
+basic_cleanup()
+{
+ gunion_test_cleanup
+}
+
+atf_test_case commit cleanup
+commit_head()
+{
+ atf_set "descr" "Test basic gunion commit without option"
+ atf_set "require.user" "root"
+}
+commit_body()
+{
+ gunion_test_setup
+
+ upperdev="$(attach_md -s 1m)"
+ lowerdev="$(attach_md -s 1m)"
+ newfs -U "/dev/${lowerdev}"
+ mkdir lowermnt
+ mkdir gunionmnt
+
+ mount "/dev/${lowerdev}" lowermnt
+ echo "lower file" > lower_file
+ cp lower_file lowermnt/lower_file
+ sync
+ umount lowermnt
+
+ gunion create "$upperdev" "$lowerdev"
+ guniondev="${upperdev}-${lowerdev}.union"
+ mount "/dev/${guniondev}" gunionmnt
+ checksum gunionmnt/lower_file lower_file
+
+ echo "update lower file" >> lower_file
+ cp -f lower_file gunionmnt/lower_file
+ echo "gunion file" > gunion_file
+ cp gunion_file gunionmnt/gunion_file
+ sync
+ umount gunionmnt
+ atf_check gunion commit "$guniondev"
+ gunion destroy "$guniondev"
+
+ atf_check -o ignore fsck -p -f "/dev/${lowerdev}"
+ mount "/dev/${lowerdev}" lowermnt
+ checksum lowermnt/lower_file lower_file
+ checksum lowermnt/gunion_file gunion_file
+}
+commit_cleanup()
+{
+ gunion_test_cleanup
+}
+
+atf_test_case offset cleanup
+offset_head()
+{
+ atf_set "descr" "Test gunion create with -o offset option"
+ atf_set "require.user" "root"
+}
+offset_body()
+{
+ gunion_test_setup
+
+ upperdev="$(attach_md -s 1m)"
+ lowerdev="$(attach_md -s 1m)"
+ gpart create -s GPT "/dev/${lowerdev}"
+ gpart add -t freebsd-ufs "$lowerdev"
+ newfs "/dev/${lowerdev}p1"
+ gpt_entry_1=$(gpart show "/dev/${lowerdev}")
+ mkdir gunionmnt
+
+ secsize="$(diskinfo "/dev/${lowerdev}" | awk '{print $2}')"
+ p1_start_sector="$(gpart show -p "/dev/${lowerdev}" | grep ${lowerdev}p1 | awk '{print $1}')"
+ offset_size="$((secsize * p1_start_sector))"
+
+ gunion create -o "$offset_size" "$upperdev" "$lowerdev"
+ guniondev="${upperdev}-${lowerdev}.union"
+
+ atf_check -o ignore fsck -p -f "/dev/${guniondev}"
+ atf_check mount "/dev/${guniondev}" gunionmnt
+ umount gunionmnt
+ gunion destroy "$guniondev"
+
+ gpt_entry_2=$(gpart show "/dev/${lowerdev}")
+ atf_check_equal "$gpt_entry_1" "$gpt_entry_2"
+}
+offset_cleanup()
+{
+ gunion_test_cleanup
+}
+
+atf_test_case size cleanup
+size_head()
+{
+ atf_set "descr" "Test gunion create with -s size option"
+ atf_set "require.user" "root"
+}
+size_body()
+{
+ gunion_test_setup
+
+ upperdev="$(attach_md -s 2m)"
+ lowerdev="$(attach_md -s 1m)"
+ newfs -U "/dev/${lowerdev}"
+
+ gunion create -s 2m "$upperdev" "$lowerdev"
+ guniondev="${upperdev}-${lowerdev}.union"
+ echo "$guniondev" > guniondev
+
+ size="$(diskinfo "/dev/$guniondev" | awk '{print $3}')"
+ atf_check_equal "2097152" "$size" # 2 MB = 2097152 bytes
+}
+size_cleanup()
+{
+ gunion_test_cleanup
+}
+
+atf_test_case secsize cleanup
+secsize_head()
+{
+ atf_set "descr" "Test gunion create with -S secsize option"
+ atf_set "require.user" "root"
+}
+secsize_body()
+{
+ gunion_test_setup
+
+ upperdev="$(attach_md -s 1m)"
+ lowerdev="$(attach_md -s 1m)"
+ newfs -S 512 -U "/dev/${lowerdev}"
+ lower_secsize="$(diskinfo "/dev/${lowerdev}" | awk '{print $2}')"
+ atf_check_equal "512" "$lower_secsize"
+
+ gunion create -S 1024 "$upperdev" "$lowerdev"
+ guniondev="${upperdev}-${lowerdev}.union"
+ echo "$guniondev" > guniondev
+
+ secsize="$(diskinfo "/dev/${guniondev}" | awk '{print $2}')"
+ atf_check_equal "1024" "$secsize"
+}
+secsize_cleanup()
+{
+ gunion_test_cleanup
+}
+
+atf_test_case gunionname cleanup
+gunionname_head()
+{
+ atf_set "descr" "Test gunion create with -Z gunionname option"
+ atf_set "require.user" "root"
+}
+gunionname_body()
+{
+ gunion_test_setup
+
+ upperdev="$(attach_md -s 1m)"
+ lowerdev="$(attach_md -s 1m)"
+ newfs -U "/dev/${lowerdev}"
+
+ gunion create -Z gunion1 "$upperdev" "$lowerdev"
+ echo "gunion1.union" > guniondev
+ atf_check -o inline:"/dev/gunion1.union\n" ls /dev/gunion1.union
+}
+gunionname_cleanup()
+{
+ gunion_test_cleanup
+}
+
+atf_test_case revert cleanup
+revert_head()
+{
+ atf_set "descr" "Test gunion revert"
+ atf_set "require.user" "root"
+}
+revert_body()
+{
+ gunion_test_setup
+
+ upperdev="$(attach_md -s 1m)"
+ lowerdev="$(attach_md -s 1m)"
+ newfs -U "/dev/${lowerdev}"
+ mkdir lowermnt
+ mkdir gunionmnt
+
+ mount "/dev/${lowerdev}" lowermnt
+ echo "lower file" > lower_file
+ cp lower_file lowermnt/lower_file
+ sync
+ umount lowermnt
+
+ atf_check gunion create "$upperdev" "$lowerdev"
+ guniondev="${upperdev}-${lowerdev}.union"
+ mount "/dev/${guniondev}" gunionmnt
+
+ echo "update lower file" >> gunionmnt/lower_file
+ echo "gunion file" > gunion_file
+ cp gunion_file gunionmnt/gunion_file
+ sync
+ umount gunionmnt
+ atf_check gunion revert "$guniondev"
+
+ mount "/dev/${guniondev}" gunionmnt
+ checksum gunionmnt/lower_file lower_file
+ atf_check -s not-exit:0 -o ignore -e ignore ls gunionmnt/gunion_file
+
+ umount gunionmnt
+ gunion destroy "$guniondev"
+}
+revert_cleanup()
+{
+ gunion_test_cleanup
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case create
+ atf_add_test_case basic
+ atf_add_test_case commit
+ atf_add_test_case offset
+ atf_add_test_case size
+ atf_add_test_case secsize
+ atf_add_test_case gunionname
+ atf_add_test_case revert
+}
+
+checksum()
+{
+ src=$1
+ work=$2
+
+ if [ ! -e "$src" ]; then
+ atf_fail "file not exist"
+ fi
+ if [ ! -e "$work" ]; then
+ atf_fail "file not exist"
+ fi
+
+ src_checksum=$(md5 -q "$src")
+ work_checksum=$(md5 -q "$work")
+
+ if [ "$work_checksum" != "$src_checksum" ]; then
+ atf_fail "md5 checksum didn't match with ${src} and ${work}"
+ fi
+}