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 log_must zpool wait -t remove $pool 32 33 # 34 # The pool state changes before the TXG finishes syncing; wait for 35 # the removal to be completed on disk. 36 # 37 sync_pool $pool 38 39 log_must is_pool_removed $pool 40 return 0 41} 42 43# 44# Removes the specified disk from its respective pool and 45# runs the callback while the removal is in progress. 46# 47# This function is mainly used to test how other operations 48# interact with device removal. After the callback is done, 49# the removal is unpaused and we wait for it to finish. 50# 51# Example usage: 52# 53# attempt_during_removal $TESTPOOL $DISK dd if=/dev/urandom \ 54# of=/$TESTPOOL/file count=1 55# 56function attempt_during_removal # pool disk callback [args] 57{ 58 typeset pool=$1 59 typeset disk=$2 60 typeset callback=$3 61 62 shift 3 63 log_onexit_push set_tunable32 REMOVAL_SUSPEND_PROGRESS 0 64 set_tunable32 REMOVAL_SUSPEND_PROGRESS 1 65 66 log_must zpool remove $pool $disk 67 68 # 69 # We want to make sure that the removal started 70 # before issuing the callback. 71 # 72 sync 73 log_must is_pool_removing $pool 74 75 log_must $callback "$@" 76 77 # 78 # Ensure that we still haven't finished the removal 79 # as expected. 80 # 81 log_must is_pool_removing $pool 82 83 set_tunable32 REMOVAL_SUSPEND_PROGRESS 0 84 log_onexit_pop 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_size $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 test_removal_with_operation # callback [args] 125{ 126 # 127 # To ensure that the removal takes a while, we fragment the pool 128 # by writing random blocks and continue to do during the removal. 129 # 130 log_must mkfile 1g $TESTDIR/$TESTFILE0 131 for i in $(seq $((2**10))); do 132 random_write $TESTDIR/$TESTFILE0 $((2**12)) || \ 133 log_fail "Could not write to $TESTDIR/$TESTFILE0." 134 done 135 start_random_writer $TESTDIR/$TESTFILE0 1g 136 killpid=$! 137 138 log_must attempt_during_removal $TESTPOOL $REMOVEDISK "$@" 139 log_mustnot vdevs_in_pool $TESTPOOL $REMOVEDISK 140 log_must zdb -cd $TESTPOOL 141 142 kill $killpid 143 wait 144 145 verify_pool $TESTPOOL 146} 147 148# 149# Kill the background job use by the test_removal_with_operation function. 150# 151function test_removal_with_operation_kill 152{ 153 kill $killpid 154 wait $killpid 155 return 0 156} 157