xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cp_files/cp_files_002_pos.ksh (revision df58e8b1506f241670be86a560fb6e8432043aee)
1#! /bin/ksh -p
2# SPDX-License-Identifier: CDDL-1.0
3#
4# CDDL HEADER START
5#
6# The contents of this file are subject to the terms of the
7# Common Development and Distribution License (the "License").
8# You may not use this file except in compliance with the License.
9#
10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11# or https://opensource.org/licenses/CDDL-1.0.
12# See the License for the specific language governing permissions
13# and limitations under the License.
14#
15# When distributing Covered Code, include this CDDL HEADER in each
16# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17# If applicable, add the following below this CDDL HEADER, with the
18# fields enclosed by brackets "[]" replaced with your own identifying
19# information: Portions Copyright [yyyy] [name of copyright owner]
20#
21# CDDL HEADER END
22#
23
24#
25# Copyright (c) 2024 by Lawrence Livermore National Security, LLC.
26#
27
28. $STF_SUITE/include/libtest.shlib
29. $STF_SUITE/tests/functional/bclone/bclone_common.kshlib
30
31#
32# DESCRIPTION:
33# Verify all cp --reflink modes work with modified file.
34#
35# STRATEGY:
36# 1. Verify "cp --reflink=never|auto|always" behaves as expected.
37#    Two different modes of operation are tested.
38#
39#    a. zfs_bclone_wait_dirty=0: FICLONE and FICLONERANGE fail with EINVAL
40#       when there are dirty blocks which cannot be immediately cloned.
41#       This is the default behavior.
42#
43#    b. zfs_bclone_wait_dirty=1: FICLONE and FICLONERANGE wait for
44#       dirty blocks to be written to disk allowing the clone to succeed.
45#       The downside to this is it may be slow which depending on the
46#       situtation may defeat the point of making a clone.
47#
48
49verify_runnable "global"
50
51if ! is_linux; then
52	log_unsupported "cp --reflink is a GNU coreutils option"
53fi
54
55function cleanup
56{
57	datasetexists $TESTPOOL/cp-reflink && \
58	    destroy_dataset $$TESTPOOL/cp-reflink -f
59	log_must restore_tunable BCLONE_WAIT_DIRTY
60}
61
62function verify_copy
63{
64	src_cksum=$(xxh128digest $1)
65	dst_cksum=$(xxh128digest $2)
66
67	if [[ "$src_cksum" != "$dst_cksum" ]]; then
68		log_must ls -l $CP_TESTDIR
69		log_fail "checksum mismatch ($src_cksum != $dst_cksum)"
70	fi
71}
72
73log_assert "Verify all cp --reflink modes work with modified file"
74
75log_onexit cleanup
76
77SRC_FILE=src.data
78DST_FILE=dst.data
79SRC_SIZE=$((1024 + $RANDOM % 1024))
80
81# A smaller recordsize is used merely to speed up the test.
82RECORDSIZE=4096
83
84log_must save_tunable BCLONE_WAIT_DIRTY
85
86log_must zfs create -o recordsize=$RECORDSIZE $TESTPOOL/cp-reflink
87CP_TESTDIR=$(get_prop mountpoint $TESTPOOL/cp-reflink)
88
89log_must cd $CP_TESTDIR
90
91# Never wait on dirty blocks (zfs_bclone_wait_dirty=0)
92log_must set_tunable32 BCLONE_WAIT_DIRTY 0
93
94for mode in "never" "auto" "always"; do
95	log_note "Checking 'cp --reflink=$mode'"
96
97	# Create a new file and immediately copy it.
98	log_must dd if=/dev/urandom of=$SRC_FILE bs=$RECORDSIZE count=$SRC_SIZE
99
100	if [[ "$mode" == "always" ]]; then
101		log_mustnot cp --reflink=$mode $SRC_FILE $DST_FILE
102		log_must ls -l $CP_TESTDIR
103	else
104		log_must cp --reflink=$mode $SRC_FILE $DST_FILE
105		verify_copy $SRC_FILE $DST_FILE
106	fi
107	log_must rm -f $DST_FILE
108
109	# Append to an existing file and immediately copy it.
110	sync_pool $TESTPOOL
111	log_must dd if=/dev/urandom of=$SRC_FILE bs=$RECORDSIZE seek=$SRC_SIZE \
112	    count=1 conv=notrunc
113	if [[ "$mode" == "always" ]]; then
114		log_mustnot cp --reflink=$mode $SRC_FILE $DST_FILE
115		log_must ls -l $CP_TESTDIR
116	else
117		log_must cp --reflink=$mode $SRC_FILE $DST_FILE
118		verify_copy $SRC_FILE $DST_FILE
119	fi
120	log_must rm -f $DST_FILE
121
122	# Overwrite a random range of an existing file and immediately copy it.
123	sync_pool $TESTPOOL
124	log_must dd if=/dev/urandom of=$SRC_FILE bs=$((RECORDSIZE / 2)) \
125            seek=$(($RANDOM % $SRC_SIZE)) count=$((1 + $RANDOM % 16)) conv=notrunc
126	if [[ "$mode" == "always" ]]; then
127		log_mustnot cp --reflink=$mode $SRC_FILE $DST_FILE
128		log_must ls -l $CP_TESTDIR
129	else
130		log_must cp --reflink=$mode $SRC_FILE $DST_FILE
131		verify_copy $SRC_FILE $DST_FILE
132	fi
133	log_must rm -f $SRC_FILE $DST_FILE
134done
135
136# Wait on dirty blocks (zfs_bclone_wait_dirty=1)
137log_must set_tunable32 BCLONE_WAIT_DIRTY 1
138
139for mode in "never" "auto" "always"; do
140	log_note "Checking 'cp --reflink=$mode'"
141
142	# Create a new file and immediately copy it.
143	log_must dd if=/dev/urandom of=$SRC_FILE bs=$RECORDSIZE count=$SRC_SIZE
144	log_must cp --reflink=$mode $SRC_FILE $DST_FILE
145	verify_copy $SRC_FILE $DST_FILE
146	log_must rm -f $DST_FILE
147
148	# Append to an existing file and immediately copy it.
149	log_must dd if=/dev/urandom of=$SRC_FILE bs=$RECORDSIZE seek=$SRC_SIZE \
150	    count=1 conv=notrunc
151	log_must cp --reflink=$mode $SRC_FILE $DST_FILE
152	verify_copy $SRC_FILE $DST_FILE
153	log_must rm -f $DST_FILE
154
155	# Overwrite a random range of an existing file and immediately copy it.
156	log_must dd if=/dev/urandom of=$SRC_FILE bs=$((RECORDSIZE / 2)) \
157            seek=$(($RANDOM % $SRC_SIZE)) count=$((1 + $RANDOM % 16)) conv=notrunc
158	log_must cp --reflink=$mode $SRC_FILE $DST_FILE
159	verify_copy $SRC_FILE $DST_FILE
160	log_must rm -f $SRC_FILE $DST_FILE
161done
162
163log_pass
164