1# 2# CDDL HEADER START 3# 4# This file and its contents are supplied under the terms of the 5# Common Development and Distribution License ("CDDL"), version 1.0. 6# You may only use this file in accordance with the terms of version 7# 1.0 of the CDDL. 8# 9# A full copy of the text of the CDDL should have accompanied this 10# source. A copy of the CDDL is also available via the Internet at 11# http://www.illumos.org/license/CDDL. 12# 13# CDDL HEADER END 14# 15 16# 17# Copyright (c) 2014, 2017 by Delphix. All rights reserved. 18# 19 20export REMOVEDISK=${DISKS%% *} 21export NOTREMOVEDISK=${DISKS##* } 22 23# 24# Waits for the pool to finish a removal. 25# 26function wait_for_removal # pool 27{ 28 typeset pool=$1 29 typeset callback=$2 30 31 while is_pool_removing $pool; do 32 sleep 1 33 done 34 35 # 36 # The pool state changes before the TXG finishes syncing; wait for 37 # the removal to be completed on disk. 38 # 39 sync 40 41 log_must is_pool_removed $pool 42 return 0 43} 44 45# 46# Removes the specified disk from its respective pool and 47# runs the callback while the removal is in progress. 48# 49# This function is mainly used to test how other operations 50# interact with device removal. After the callback is done, 51# the removal is unpaused and we wait for it to finish. 52# 53# Example usage: 54# 55# attempt_during_removal $TESTPOOL $DISK dd if=/dev/urandom \ 56# of=/$TESTPOOL/file count=1 57# 58function attempt_during_removal # pool disk callback [args] 59{ 60 typeset pool=$1 61 typeset disk=$2 62 typeset callback=$3 63 64 shift 3 65 mdb_ctf_set_int zfs_remove_max_bytes_pause 0t0 66 67 log_must zpool remove $pool $disk 68 69 # 70 # We want to make sure that the removal started 71 # before issuing the callback. 72 # 73 sync 74 log_must is_pool_removing $pool 75 76 log_must $callback "$@" 77 78 # 79 # Ensure that we still haven't finished the removal 80 # as expected. 81 # 82 log_must is_pool_removing $pool 83 84 mdb_ctf_set_int zfs_remove_max_bytes_pause -0t1 85 86 log_must wait_for_removal $pool 87 log_mustnot vdevs_in_pool $pool $disk 88 return 0 89} 90 91function indirect_vdev_mapping_size # pool 92{ 93 typeset pool=$1 94 zdb -P $pool | grep 'indirect vdev' | \ 95 sed -E 's/.*\(([0-9]+) in memory\).*/\1/g' 96} 97 98function random_write # file write_size 99{ 100 typeset file=$1 101 typeset block_size=$2 102 typeset file_size=$(stat -c%s $file 2>/dev/null) 103 typeset nblocks=$((file_size / block_size)) 104 105 [[ -w $file ]] || return 1 106 107 dd if=/dev/urandom of=$file conv=notrunc \ 108 bs=$block_size count=1 seek=$((RANDOM % nblocks)) >/dev/null 2>&1 109} 110 111function start_random_writer # file 112{ 113 typeset file=$1 114 ( 115 log_note "Starting writer for $file" 116 # This will fail when we destroy the pool. 117 while random_write $file $((2**12)); do 118 : 119 done 120 log_note "Stopping writer for $file" 121 ) & 122} 123 124function set_min_bytes # bytes 125{ 126 typeset bytes=$1 127 echo "zfs_condense_min_mapping_bytes/W 0t$bytes" | \ 128 mdb -kw 129} 130 131function test_removal_with_operation # callback [args] 132{ 133 # 134 # To ensure that the removal takes a while, we fragment the pool 135 # by writing random blocks and continue to do during the removal. 136 # 137 log_must mkfile 1g $TESTDIR/$TESTFILE0 138 for i in $(seq $((2**10))); do 139 random_write $TESTDIR/$TESTFILE0 $((2**12)) || \ 140 log_fail "Could not write to $TESTDIR/$TESTFILE0." 141 done 142 start_random_writer $TESTDIR/$TESTFILE0 1g 143 killpid=$! 144 145 log_must attempt_during_removal $TESTPOOL $REMOVEDISK "$@" 146 log_mustnot vdevs_in_pool $TESTPOOL $REMOVEDISK 147 log_must zdb -cd $TESTPOOL 148 149 kill $killpid 150 wait 151} 152