1#!/bin/ksh -p
2#
3# CDDL HEADER START
4#
5# This file and its contents are supplied under the terms of the
6# Common Development and Distribution License ("CDDL"), version 1.0.
7# You may only use this file in accordance with the terms of version
8# 1.0 of the CDDL.
9#
10# A full copy of the text of the CDDL should have accompanied this
11# source.  A copy of the CDDL is also available via the Internet at
12# http://www.illumos.org/license/CDDL.
13#
14# CDDL HEADER END
15#
16
17#
18# Copyright (c) 2020 The FreeBSD Foundation [1]
19#
20# [1] Portions of this software were developed by Allan Jude
21#     under sponsorship from the FreeBSD Foundation.
22
23. $STF_SUITE/include/libtest.shlib
24
25#
26# DESCRIPTION:
27# ZFS should receive a ZSTD compressed block and be able to determine the level
28#
29# STRATEGY:
30# 1. Create a ZSTD compressed dataset (random level)
31# 2. Create and checksum a file on the compressed dataset
32# 3. Snapshot the compressed dataset
33# 4. Attempt to receive the snapshot into a new dataset
34# 5. Verify the checksum of the file is the same as the original
35# 6. Verify the compression level is correctly stored
36#
37
38verify_runnable "both"
39
40function cleanup
41{
42	datasetexists $TESTPOOL/$TESTFS1 && \
43		destroy_dataset $TESTPOOL/$TESTFS1 -r
44
45	datasetexists $TESTPOOL/$TESTFS2 && \
46		destroy_dataset $TESTPOOL/$TESTFS2 -r
47}
48
49log_onexit cleanup
50
51log_assert "ZFS should track compression level when receiving a ZSTD stream"
52
53typeset src_data="$STF_SUITE/tests/functional/cli_root/zfs_receive/zstd_test_data.txt"
54typeset snap="$TESTPOOL/$TESTFS1@snap"
55
56random_level=$((RANDOM%19 + 1))
57log_note "Randomly selected ZSTD level: $random_level"
58
59log_must zfs create -o compress=zstd-$random_level $TESTPOOL/$TESTFS1
60# Make a 5kb compressible file
61log_must eval cat $src_data $src_data $src_data $src_data $src_data \
62    "> /$TESTPOOL/$TESTFS1/$TESTFILE0"
63typeset checksum=$(md5digest /$TESTPOOL/$TESTFS1/$TESTFILE0)
64
65log_must zfs snapshot $snap
66
67# get object number of file
68read -r obj _ < <(ls -i /$TESTPOOL/$TESTFS1/$TESTFILE0)
69log_note "file /$TESTPOOL/$TESTFS1/$TESTFILE0 has object number $obj"
70
71output=$(zdb -Zddddddbbbbbb $TESTPOOL/$TESTFS1 $obj 2> /dev/null \
72    | grep -m 1 "L0 DVA")
73dva=$(sed -Ene 's/^.+DVA\[0\]=<([^>]+)>.*$/\1/p' <<< "$output")
74log_note "block 0 of /$TESTPOOL/$TESTFS1/$TESTFILE0 has a DVA of $dva"
75
76read -r zstd_size1 zstd_version1 zstd_level1 < <(sed -Ene 's/^.+ ZSTD:size=([^:]+):version=([^:]+):level=([^:]+):.*$/\1 \2 \3/p' <<< "$output")
77log_note "ZSTD src: size=$zstd_size1 version=$zstd_version1 level=$zstd_level1"
78
79log_note "Verify ZFS can receive the ZSTD compressed stream"
80log_must eval "zfs send -ec $snap | zfs receive $TESTPOOL/$TESTFS2"
81
82typeset cksum1=$(md5digest /$TESTPOOL/$TESTFS2/$TESTFILE0)
83[[ "$cksum1" == "$checksum" ]] || \
84	log_fail "Checksums differ ($cksum1 != $checksum)"
85
86# get object number of file
87read -r obj _ < <(ls -i /$TESTPOOL/$TESTFS2/$TESTFILE0)
88log_note "file /$TESTPOOL/$TESTFS2/$TESTFILE0 has object number $obj"
89
90output=$(zdb -Zddddddbbbbbb $TESTPOOL/$TESTFS2 $obj 2> /dev/null \
91    | grep -m 1 "L0 DVA")
92dva=$(sed -Ene 's/^.+DVA\[0\]=<([^>]+)>.*$/\1/p' <<< "$output")
93log_note "block 0 of /$TESTPOOL/$TESTFS2/$TESTFILE0 has a DVA of $dva"
94
95read -r zstd_size2 zstd_version2 zstd_level2 < <(sed -Ene 's/^.+ ZSTD:size=([^:]+):version=([^:]+):level=([^:]+):.*$/\1 \2 \3/p' <<< "$output")
96log_note "ZSTD dest: size=$zstd_size2 version=$zstd_version2 level=$zstd_level2"
97(( $zstd_size2 != $zstd_size1 )) && log_fail \
98"ZFS recv failed: compressed size differs ($zstd_size2 != $zstd_size1)"
99(( $zstd_level2 != $zstd_level1 )) && log_fail \
100"ZFS recv failed: compression level did not match header level ($zstd_level2 != $zstd_level1)"
101
102log_pass "ZFS can receive a ZSTD stream and determine the compression level"
103