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