1# 2# CDDL HEADER START 3# 4# The contents of this file are subject to the terms of the 5# Common Development and Distribution License (the "License"). 6# You may not use this file except in compliance with the License. 7# 8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9# or https://opensource.org/licenses/CDDL-1.0. 10# See the License for the specific language governing permissions 11# and limitations under the License. 12# 13# When distributing Covered Code, include this CDDL HEADER in each 14# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15# If applicable, add the following below this CDDL HEADER, with the 16# fields enclosed by brackets "[]" replaced with your own identifying 17# information: Portions Copyright [yyyy] [name of copyright owner] 18# 19# CDDL HEADER END 20# 21 22# 23# Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24# Use is subject to license terms. 25# 26 27# 28# Copyright (c) 2013, 2016 by Delphix. All rights reserved. 29# 30 31. $STF_SUITE/tests/functional/reservation/reservation.cfg 32 33# 34# Function to set the reservation property of a dataset to 35# 'none' and verify that it is correctly set using both the 36# "normal" 'zfs get reservation' and the '-p' option which 37# gives a numerical value. 38# 39function zero_reservation 40{ 41 dataset=$1 42 43 log_must zfs set reservation=none $dataset 44 45 log_must eval 'resv_val="$(zfs get -Ho value reservation $dataset)"' 46 log_must [ $resv_val = "none" ] 47 48 log_must eval 'resv_val="$(zfs get -pHo value reservation $dataset)"' 49 log_must [ $resv_val -eq 0 ] 50 51 return 0 52} 53 54# 55# Utility function to see if two values are within a certain specified 56# limit of each other. Used primarily to check that a dataset's parent 57# is correctly accounting for space used/available. Need this function as 58# currently there is some slop in the way space is accounted (i.e. can't 59# do a direct comparison). 60# 61function within_limits 62{ 63 typeset valA=$1 64 typeset valB=$2 65 typeset delta=$3 66 67 if ((valA <= valB)); then 68 if (((valB - valA) <= delta)); then 69 return 0 70 fi 71 elif ((valB <= valA)); then 72 if (((valA - valB) <= delta)); then 73 return 0 74 fi 75 fi 76 77 return 1 78} 79 80# 81# Function to create and mount multiple filesystems. The filesystem 82# will be named according to the name specified with a suffix value 83# taken from the loop counter. 84# 85function create_multiple_fs # num_fs base_fs_name base_mnt_name 86{ 87 typeset -i iter=0 88 typeset -i count=$1 89 typeset FS_NAME=$2 90 typeset MNT_NAME=$3 91 92 while (($iter < $count)); do 93 log_must zfs create ${FS_NAME}$iter 94 log_must zfs set mountpoint=${MNT_NAME}$iter ${FS_NAME}$iter 95 ((iter = iter + 1)) 96 done 97} 98 99# 100# This function compute the largest volume size which is multiple of volume 101# block size (default 16K) and not greater than the largest expected volsize. 102# 103# $1 The largest expected volume size. 104# $2 The volume block size 105# 106function floor_volsize #<largest_volsize> [volblksize] 107{ 108 typeset largest_volsize=$1 109 typeset volblksize=${2:-16384} 110 111 if ((largest_volsize < volblksize)); then 112 log_fail "The largest_volsize must be greater than volblksize." 113 fi 114 typeset real_volsize 115 typeset n 116 117 ((n = largest_volsize / volblksize)) 118 ((largest_volsize = volblksize * n)) 119 120 print $largest_volsize 121} 122 123# 124# This function is a copy of a function by the same name in libzfs_dataset.c 125# Its purpose is to reserve additional space for volume metadata so volumes 126# don't unexpectedly run out of room. 127# 128# Note: This function can be used to do an estimate for a volume that has not 129# yet been created. In this case, $vol is not a volume, but rather a pool in 130# which a volume is going to be created. In this case, use default properties. 131# 132function volsize_to_reservation 133{ 134 typeset vol=$1 135 typeset volsize=$2 136 137 typeset -i DN_MAX_INDBLKSHIFT=17 138 typeset -i SPA_BLKPTRSHIFT=7 139 typeset -i SPA_DVAS_PER_BP=3 140 141 typeset DNODES_PER_LEVEL_SHIFT=$((DN_MAX_INDBLKSHIFT - \ 142 SPA_BLKPTRSHIFT)) 143 typeset DNODES_PER_LEVEL=$((1 << $DNODES_PER_LEVEL_SHIFT)) 144 145 if ds_is_volume $vol; then 146 typeset ncopies=$(get_prop copies $vol) 147 typeset volblocksize=$(get_prop volblocksize $vol) 148 else 149 typeset ncopies=1 150 typeset volblocksize=16384 151 fi 152 typeset nblocks=$((volsize / volblocksize)) 153 154 typeset numdb=7 155 while ((nblocks > 1)); do 156 ((nblocks += DNODES_PER_LEVEL - 1)) 157 ((nblocks /= DNODES_PER_LEVEL)) 158 ((numdb += nblocks)) 159 done 160 161 ((numdb *= SPA_DVAS_PER_BP < ncopies + 1 ? SPA_DVAS_PER_BP : \ 162 ncopies + 1)) 163 ((volsize *= ncopies)) 164 ((numdb *= 1 << DN_MAX_INDBLKSHIFT)) 165 ((volsize += numdb)) 166 echo $volsize 167} 168 169# 170# This function takes a pool name as an argument, and returns the largest (give 171# or take some slop) -V value that can be used to create a volume in that pool. 172# This is necessary because during volume creation, a reservation is created 173# that will be larger than the value specified with -V, and potentially larger 174# than the available space in the pool. See volsize_to_reservation(). 175# 176function largest_volsize_from_pool 177{ 178 typeset pool=$1 179 typeset poolsize=$(get_prop available $pool) 180 typeset volsize=$poolsize 181 typeset nvolsize 182 183 while :; do 184 # knock 50M off the volsize each time through 185 ((volsize -= 50 * 1024 * 1024)) 186 nvolsize=$(volsize_to_reservation $pool $volsize) 187 nvolsize=$(floor_volsize $nvolsize) 188 ((nvolsize < poolsize)) && break 189 done 190 echo $volsize 191} 192