1# SPDX-License-Identifier: CDDL-1.0 2# 3# This file and its contents are supplied under the terms of the 4# Common Development and Distribution License ("CDDL"), version 1.0. 5# You may only use this file in accordance with the terms of version 6# 1.0 of the CDDL. 7# 8# A full copy of the text of the CDDL should have accompanied this 9# source. A copy of the CDDL is also available via the Internet at 10# http://www.illumos.org/license/CDDL. 11# 12 13# 14# Copyright (c) 2017, 2018 by Delphix. All rights reserved. 15# 16 17. $STF_SUITE/include/libtest.shlib 18. $STF_SUITE/tests/functional/removal/removal.kshlib 19 20# 21# In general all the tests related to the pool checkpoint can 22# be divided into two categories. TESTS that verify features 23# provided by the checkpoint (e.g. checkpoint_rewind) and tests 24# that stress-test the checkpoint (e.g. checkpoint_big_rewind). 25# 26# For the first group we don't really care about the size of 27# the pool or the individual file sizes within the filesystems. 28# This is why these tests run directly on pools that use a 29# "real disk vdev" (meaning not a file based one). These tests 30# use the $TESTPOOL pool that is created on top of $TESTDISK. 31# This pool is referred to as the "test pool" and thus all 32# the tests of this group use the testpool-related functions of 33# this file (not the nested_pools ones). 34# 35# For the second group we generally try to bring the pool to its 36# limits by increasing fragmentation, filling all allocatable 37# space, attempting to use vdevs that the checkpoint spacemap 38# cannot represent, etc. For these tests we need to control 39# almost all parameters of the pool and the vdevs that back it 40# so we create them based on file-based vdevs that we carefully 41# create within the $TESTPOOL pool. So most of these tests, in 42# order to create this nested pool sctructure, generally start 43# like this: 44# 1] We create the test pool ($TESTPOOL). 45# 2] We create a filesystem and we populate it with files of 46# some predetermined size. 47# 3] We use those files as vdevs for the pool that the test 48# will use ($NESTEDPOOL). 49# 4] Go on and let the test run and operate on $NESTEDPOOL. 50# 51 52# 53# These disks are used to back $TESTPOOL 54# 55TESTDISK="$(echo $DISKS | cut -d' ' -f1)" 56EXTRATESTDISK="$(echo $DISKS | cut -d' ' -f2)" 57 58FS0=$TESTPOOL/$TESTFS 59FS1=$TESTPOOL/$TESTFS1 60FS2=$TESTPOOL/$TESTFS2 61 62FS0FILE=/$FS0/$TESTFILE0 63FS1FILE=/$FS1/$TESTFILE1 64FS2FILE=/$FS2/$TESTFILE2 65 66# 67# The following are created within $TESTPOOL and 68# will be used to back $NESTEDPOOL 69# 70DISKFS=$TESTPOOL/disks 71FILEDISKDIR=/$DISKFS 72FILEDISK1=/$DISKFS/dsk1 73FILEDISK2=/$DISKFS/dsk2 74FILEDISKS="$FILEDISK1 $FILEDISK2" 75 76# 77# $NESTEDPOOL related variables 78# 79NESTEDPOOL=nestedpool 80NESTEDFS0=$NESTEDPOOL/$TESTFS 81NESTEDFS1=$NESTEDPOOL/$TESTFS1 82NESTEDFS2=$NESTEDPOOL/$TESTFS2 83NESTEDFS0FILE=/$NESTEDFS0/$TESTFILE0 84NESTEDFS1FILE=/$NESTEDFS1/$TESTFILE1 85NESTEDFS2FILE=/$NESTEDFS2/$TESTFILE2 86 87# 88# In the tests that stress-test the pool (second category 89# mentioned above), there exist some that need to bring 90# fragmentation at high percentages in a relatively short 91# period of time. In order to do that we set the following 92# parameters: 93# 94# * We use two disks of 1G each, to create a pool of size 2G. 95# The point is that 2G is not small nor large, and we also 96# want to have 2 disks to introduce indirect vdevs on our 97# setup. 98# * We enable compression and set the record size of all 99# filesystems to 8K. The point of compression is to 100# ensure that we are not filling up the whole pool (that's 101# what checkpoint_capacity is for), and the specific 102# record size is set to match the block size of randwritecomp 103# which is used to increase fragmentation by writing on 104# files. 105# * We always have 2 big files present of 512M each, which 106# should account for 40%~50% capacity by the end of each 107# test with fragmentation around 50~60%. 108# * At each file we attempt to do enough random writes to 109# touch every offset twice on average. 110# 111# Note that the amount of random writes per files are based 112# on the following calculation: 113# 114# ((512M / 8K) * 3) * 2 = ~400000 115# 116# Given that the file is 512M and one write is 8K, we would 117# need (512M / 8K) writes to go through the whole file. 118# Assuming though that each write has a compression ratio of 119# 3, then we want 3 times that to cover the same amount of 120# space. Finally, we multiply that by 2 since our goal is to 121# touch each offset twice on average. 122# 123# Examples of those tests are checkpoint_big_rewind and 124# checkpoint_discard_busy. 125# 126FILEDISKSIZE=1g 127DISKSIZE=1g 128BIGFILESIZE=512M 129RANDOMWRITES=400000 130 131 132# 133# Assumes create_test_pool has been called beforehand. 134# 135function setup_nested_pool 136{ 137 log_must zfs create $DISKFS 138 139 log_must truncate -s $DISKSIZE $FILEDISK1 140 log_must truncate -s $DISKSIZE $FILEDISK2 141 142 log_must zpool create -O sync=disabled $NESTEDPOOL $FILEDISKS 143} 144 145function setup_test_pool 146{ 147 log_must zpool create -O sync=disabled $TESTPOOL "$TESTDISK" 148} 149 150function setup_nested_pools 151{ 152 setup_test_pool 153 setup_nested_pool 154} 155 156function cleanup_nested_pool 157{ 158 if poolexists $NESTEDPOOL; then 159 log_must zpool destroy $NESTEDPOOL 160 fi 161 162 log_must rm -f $FILEDISKS 163} 164 165function cleanup_test_pool 166{ 167 if poolexists $TESTPOOL; then 168 log_must zpool destroy $TESTPOOL 169 fi 170 171 # 172 # We always clear the labels of all disks 173 # between tests so imports from zpool or 174 # or zdb do not get confused with leftover 175 # data from old pools. 176 # 177 for disk in $DISKS; do 178 zpool labelclear -f $disk 179 done 180} 181 182function cleanup_nested_pools 183{ 184 cleanup_nested_pool 185 cleanup_test_pool 186} 187 188# 189# Remove and re-add each vdev to ensure that data is 190# moved between disks and indirect mappings are created 191# 192function introduce_indirection 193{ 194 for disk in ${FILEDISKS[@]}; do 195 log_must zpool remove $NESTEDPOOL $disk 196 log_must wait_for_removal $NESTEDPOOL 197 log_mustnot vdevs_in_pool $NESTEDPOOL $disk 198 log_must zpool add $NESTEDPOOL $disk 199 done 200} 201 202FILECONTENTS0="Can't wait to be checkpointed!" 203FILECONTENTS1="Can't wait to be checkpointed too!" 204NEWFILECONTENTS0="I survived after the checkpoint!" 205NEWFILECONTENTS2="I was born after the checkpoint!" 206 207function populate_test_pool 208{ 209 log_must zfs create -o compression=lz4 -o recordsize=8k $FS0 210 log_must zfs create -o compression=lz4 -o recordsize=8k $FS1 211 212 echo $FILECONTENTS0 > $FS0FILE 213 echo $FILECONTENTS1 > $FS1FILE 214} 215 216function populate_nested_pool 217{ 218 log_must zfs create -o compression=lz4 -o recordsize=8k $NESTEDFS0 219 log_must zfs create -o compression=lz4 -o recordsize=8k $NESTEDFS1 220 221 echo $FILECONTENTS0 > $NESTEDFS0FILE 222 echo $FILECONTENTS1 > $NESTEDFS1FILE 223} 224 225function test_verify_pre_checkpoint_state 226{ 227 log_must zfs list $FS0 228 log_must zfs list $FS1 229 log_must [ "$(<$FS0FILE)" = "$FILECONTENTS0" ] 230 log_must [ "$(<$FS1FILE)" = "$FILECONTENTS1" ] 231 232 # 233 # If we've opened the checkpointed state of the 234 # pool as read-only without rewinding on-disk we 235 # can't really use zdb on it. 236 # 237 if [[ "$1" != "ro-check" ]] ; then 238 log_must zdb $TESTPOOL 239 fi 240 241 # 242 # Ensure post-checkpoint state is not present 243 # 244 log_mustnot zfs list $FS2 245 log_mustnot [ "$(<$FS0FILE)" = "$NEWFILECONTENTS0" ] 246} 247 248function nested_verify_pre_checkpoint_state 249{ 250 log_must zfs list $NESTEDFS0 251 log_must zfs list $NESTEDFS1 252 log_must [ "$(<$NESTEDFS0FILE)" = "$FILECONTENTS0" ] 253 log_must [ "$(<$NESTEDFS1FILE)" = "$FILECONTENTS1" ] 254 255 # 256 # If we've opened the checkpointed state of the 257 # pool as read-only without rewinding on-disk we 258 # can't really use zdb on it. 259 # 260 if [[ "$1" != "ro-check" ]] ; then 261 log_must zdb $NESTEDPOOL 262 fi 263 264 # 265 # Ensure post-checkpoint state is not present 266 # 267 log_mustnot zfs list $NESTEDFS2 268 log_mustnot [ "$(<$NESTEDFS0FILE)" = "$NEWFILECONTENTS0" ] 269} 270 271function test_change_state_after_checkpoint 272{ 273 log_must zfs destroy $FS1 274 log_must zfs create -o compression=lz4 -o recordsize=8k $FS2 275 276 echo $NEWFILECONTENTS0 > $FS0FILE 277 echo $NEWFILECONTENTS2 > $FS2FILE 278} 279 280function nested_change_state_after_checkpoint 281{ 282 log_must zfs destroy $NESTEDFS1 283 log_must zfs create -o compression=lz4 -o recordsize=8k $NESTEDFS2 284 285 echo $NEWFILECONTENTS0 > $NESTEDFS0FILE 286 echo $NEWFILECONTENTS2 > $NESTEDFS2FILE 287} 288 289function test_verify_post_checkpoint_state 290{ 291 log_must zfs list $FS0 292 log_must zfs list $FS2 293 log_must [ "$(<$FS0FILE)" = "$NEWFILECONTENTS0" ] 294 log_must [ "$(<$FS2FILE)" = "$NEWFILECONTENTS2" ] 295 296 log_must zdb $TESTPOOL 297 298 # 299 # Ensure pre-checkpointed state that was removed post-checkpoint 300 # is not present 301 # 302 log_mustnot zfs list $FS1 303 log_mustnot [ "$(<$FS0FILE)" = "$FILECONTENTS0" ] 304} 305 306function fragment_before_checkpoint 307{ 308 populate_nested_pool 309 log_must mkfile -n $BIGFILESIZE $NESTEDFS0FILE 310 log_must mkfile -n $BIGFILESIZE $NESTEDFS1FILE 311 log_must randwritecomp $NESTEDFS0FILE $RANDOMWRITES 312 log_must randwritecomp $NESTEDFS1FILE $RANDOMWRITES 313 314 # 315 # Display fragmentation on test log 316 # 317 log_must zpool list -v 318} 319 320function fragment_after_checkpoint_and_verify 321{ 322 log_must zfs destroy $NESTEDFS1 323 log_must zfs create -o compression=lz4 -o recordsize=8k $NESTEDFS2 324 log_must mkfile -n $BIGFILESIZE $NESTEDFS2FILE 325 log_must randwritecomp $NESTEDFS0FILE $RANDOMWRITES 326 log_must randwritecomp $NESTEDFS2FILE $RANDOMWRITES 327 328 # 329 # Display fragmentation on test log 330 # 331 log_must zpool list -v 332 333 # 334 # Typically we would just run zdb at this point and things 335 # would be fine. Unfortunately, if there is still any 336 # background I/O in the pool the zdb command can fail with 337 # checksum errors temporarily. 338 # 339 # Export the pool when running zdb so the pool is idle and 340 # the verification results are consistent. 341 # 342 log_must zpool export $NESTEDPOOL 343 log_must zdb -e -p $FILEDISKDIR $NESTEDPOOL 344 log_must zdb -e -p $FILEDISKDIR -kc $NESTEDPOOL 345 log_must zpool import -d $FILEDISKDIR $NESTEDPOOL 346} 347 348function wait_discard_finish 349{ 350 typeset pool="$1" 351 352 typeset status 353 status=$(zpool status $pool | grep "checkpoint:") 354 while [ "" != "$status" ]; do 355 sleep 5 356 status=$(zpool status $pool | grep "checkpoint:") 357 done 358} 359 360function test_wait_discard_finish 361{ 362 wait_discard_finish $TESTPOOL 363} 364 365function nested_wait_discard_finish 366{ 367 wait_discard_finish $NESTEDPOOL 368} 369 370# 371# Creating the setup for the second group of tests mentioned in 372# block comment of this file can take some time as we are doing 373# random writes to raise capacity and fragmentation before taking 374# the checkpoint. Thus we create this setup once and save the 375# disks of the nested pool in a temporary directory where we can 376# reuse it for each test that requires that setup. 377# 378SAVEDPOOLDIR="$TEST_BASE_DIR/ckpoint_saved_pool" 379 380function test_group_premake_nested_pools 381{ 382 setup_nested_pools 383 384 # 385 # Populate and fragment the pool. 386 # 387 fragment_before_checkpoint 388 389 # 390 # Export and save the pool for other tests. 391 # 392 log_must zpool export $NESTEDPOOL 393 log_must mkdir $SAVEDPOOLDIR 394 log_must cp $FILEDISKS $SAVEDPOOLDIR 395 396 # 397 # Reimport pool to be destroyed by 398 # cleanup_nested_pools function 399 # 400 log_must zpool import -d $FILEDISKDIR $NESTEDPOOL 401} 402 403function test_group_destroy_saved_pool 404{ 405 log_must rm -rf $SAVEDPOOLDIR 406} 407 408# 409# Recreate nested pool setup from saved pool. 410# 411function setup_nested_pool_state 412{ 413 setup_test_pool 414 415 log_must zfs create $DISKFS 416 log_must cp $SAVEDPOOLDIR/* $FILEDISKDIR 417 418 log_must zpool import -d $FILEDISKDIR $NESTEDPOOL 419} 420