[LTP] [PATCH v3] kernel/device-drivers/zram/zram01.sh : fill with compressible data

Ian Wienand iwienand@redhat.com
Thu Sep 21 03:12:40 CEST 2023


Hello,

I have a system (virtualized aarch64, 4.18.0 kernel) that is
consistently failing the zram01.sh test as it tries to divide the
memory stats by zero.  This has been reported before at [1] without
resolution.  f045fd1de6420cc6d7db2bda0cd86fb56ff5b1c1 put a retry loop
around the read of this value; this is essentially reverted here for
the reasons described below.

After some investigation [2] my conclusion is that this zero value
represents the pages allocated for compressed storage in the zram
device, and due to same-page deduplication the extant method of
filling with all-zeros can indeed lead us to not having any compressed
data to measure.

This is visible with the test being unstable with a divide-by-zero
error, but in the bigger picture means this test is not exercising the
compression path as desired.

The approach here is to separate the test into two parts, one that
keeps the existing behaviour but it now targeted explicitly at testing
the page de-deuplication path.  For the reasons described above, there
is no point in asserting the compression ratio of this test, so it is
modified do a sanity check on the count of de-deuplicated pages.

A second test is added that explicitly writes compressible data.  This
also adds the sync, as discussed in prior version [3] to increase the
reliability of testing.  We should not need to wait or re-read this
value, as we have explicitly made data suitable to be stored
compressed.

[1] https://lists.linux.it/pipermail/ltp/2019-July/013028.html
[2] https://lists.linux.it/pipermail/ltp/2023-August/034585.html
[3] https://lists.linux.it/pipermail/ltp/2023-August/034560.html

Signed-off-by: Ian Wienand <iwienand@redhat.com>
---
V2 -> V3: separate into two distinct tests

 .../kernel/device-drivers/zram/zram01.sh      | 118 +++++++++++++-----
 1 file changed, 85 insertions(+), 33 deletions(-)

diff --git a/testcases/kernel/device-drivers/zram/zram01.sh b/testcases/kernel/device-drivers/zram/zram01.sh
index 6bc305f2c..22c5e1927 100755
--- a/testcases/kernel/device-drivers/zram/zram01.sh
+++ b/testcases/kernel/device-drivers/zram/zram01.sh
@@ -4,9 +4,9 @@
 # Author: Alexey Kodanev <alexey.kodanev@oracle.com>
 #
 # Test creates several zram devices with different filesystems on them.
-# It fills each device with zeros and checks that compression works.
+# It fills each device and checks that compression works.
 
-TST_CNT=7
+TST_CNT=8
 TST_TESTFUNC="do_test"
 TST_NEEDS_CMDS="awk bc dd"
 TST_SETUP="setup"
@@ -105,36 +105,77 @@ zram_mount()
 	tst_res TPASS "mount of zram device(s) succeeded"
 }
 
-read_mem_used_total()
-{
-	echo $(awk '{print $3}' $1)
-}
-
-# Reads /sys/block/zram*/mm_stat until mem_used_total is not 0.
-check_read_mem_used_total()
+# Fill the filesystem with a file full of zeros.  This is to test the
+# same-page/deduplication path in the kernel.  After filling the file
+# with the same value, we should have a lot of pages recorded as
+# "same_pages"; we arbitrarily test against a small value here to
+# validate pages were deduplicated.
+zram_fill_fs()
 {
-	local file="$1"
-	local mem_used_total
+    local mm_stat same_pages
+    local b i
+
+    for i in $(seq $dev_start $dev_end); do
+	tst_res TINFO "filling zram$i with zero value"
+	b=0
+	while true; do
+	    dd conv=notrunc if=/dev/zero of=zram${i}/file \
+	       oflag=append count=1 bs=1024 status=none \
+	       >/dev/null 2>err.txt || break
+	    b=$(($b + 1))
+	done
+	if [ $b -eq 0 ]; then
+	    [ -s err.txt ] && tst_res TWARN "dd error: $(cat err.txt)"
+	    tst_brk TBROK "cannot fill zram with zero value $i"
+	fi
+	rm zram${i}/file
+	tst_res TPASS "zram$i was filled with '$b' KB"
+
+	if [ ! -f "/sys/block/zram$i/mm_stat" ]; then
+	    if [ $i -eq 0 ]; then
+		tst_res TCONF "zram compression ratio test requires zram mm_stat sysfs file"
+	    fi
+	    continue
+	fi
 
-	tst_res TINFO "$file"
-	cat $file >&2
+	mm_stat=$(cat "/sys/block/zram$i/mm_stat")
+	tst_res TINFO "stats for zram$i : $mm_stat"
 
-	mem_used_total=$(read_mem_used_total $file)
-	[ "$mem_used_total" -eq 0 ] && return 1
+	same_pages=`echo $mm_stat | awk '{print $6}'`
+	if [ "$same_pages" -lt 10 ]; then
+	    tst_res TFAIL "insufficient same_pages: $same_pages < 10"
+	fi
+	tst_res TPASS "same_pages: $same_pages"
 
-	return 0
+    done
 }
 
-zram_fill_fs()
+# Fill a file with compressible data.  The same-page deduplication
+# works on matching a single (unsigned long) value in a page, so by
+# splitting this up into (smaller than page size) 1KiB of alternating
+# 0x00 and 0xFF we avoid this, but make something that should be
+# highly compressible.  We check the stats after filling the file to
+# ensure that we see a high compression ratio.
+#
+# TODO: fio has an option to create binary data with a given level of
+#   compressibility.  For now we use a static value to avoid growing
+#   dependencies, but might be useful in the future to validate the
+#   compression behaviour more thoroughly.
+zram_fill_fs_compress()
 {
-	local mem_used_total
-	local b i r v
+	local mm_stat mem_used_total same_pages
+	local b f i r v
+
+	# convert all the 0x00's to 0xFF's.
+	dd if=/dev/zero count=1 bs=512 count=1 2>err.txt | tr "\000" "\377" > compressible
+	dd if=/dev/zero count=1 bs=512 count=1 >> compressible 2>err.txt
 
 	for i in $(seq $dev_start $dev_end); do
-		tst_res TINFO "filling zram$i (it can take long time)"
+		f='/dev/zero'
+		tst_res TINFO "filling zram$i with compressible data"
 		b=0
 		while true; do
-			dd conv=notrunc if=/dev/zero of=zram${i}/file \
+			dd conv=notrunc if=compressible of=zram${i}/file \
 				oflag=append count=1 bs=1024 status=none \
 				>/dev/null 2>err.txt || break
 			b=$(($b + 1))
@@ -145,18 +186,28 @@ zram_fill_fs()
 		fi
 		tst_res TPASS "zram$i was filled with '$b' KB"
 
-		if [ ! -f "/sys/block/zram$i/mm_stat" ]; then
-			if [ $i -eq 0 ]; then
-				tst_res TCONF "zram compression ratio test requires zram mm_stat sysfs file"
-			fi
-
-			continue
+		# The compression needs time to catch up so we get
+		# useful stats
+		sync
+
+		mm_stat=$(cat "/sys/block/zram$i/mm_stat")
+		tst_res TINFO "stats for zram$i : $mm_stat"
+
+		# This should not happen.  mem_used_total is the
+		# number of pages in the zsmalloc pool asssigned to
+		# this device.  If pages are active, they won't be
+		# stored compressed in this pool; so this might be
+		# zero if, for example, you have a single file of the
+		# same value that is mostly de-deuplicated, and you
+		# have the FS metadata active.  This testing path is
+		# deliberately making data that should be compressed
+		# and stored in the zsmalloc pool, however, so we do
+		# not expect to hit this case.
+		mem_used_total=`echo $mm_stat | awk '{print $3}'`
+		if [ $mem_used_total -eq 0 ]; then
+			test_res FAIL "/sys/block/zram$i/mm_stat reports 0 size : $(cat /sys/block/zram$i/mm_stat)"
+			return
 		fi
-
-		TST_RETRY_FUNC "check_read_mem_used_total /sys/block/zram$i/mm_stat" 0
-		mem_used_total=$(read_mem_used_total /sys/block/zram$i/mm_stat)
-		tst_res TINFO "mem_used_total: $mem_used_total"
-
 		v=$((100 * 1024 * $b / $mem_used_total))
 		r=$(echo "scale=2; $v / 100 " | bc)
 
@@ -164,9 +215,9 @@ zram_fill_fs()
 			tst_res TFAIL "compression ratio: $r:1"
 			break
 		fi
-
 		tst_res TPASS "compression ratio: $r:1"
 	done
+	rm compressible
 }
 
 do_test()
@@ -179,6 +230,7 @@ do_test()
 	 5) zram_makefs;;
 	 6) zram_mount;;
 	 7) zram_fill_fs;;
+	 8) zram_fill_fs_compress;;
 	esac
 }
 
-- 
2.41.0



More information about the ltp mailing list