xref: /illumos-gate/usr/src/test/zfs-tests/tests/functional/reservation/reservation.shlib (revision b1e2e3fb17324e9ddf43db264a0c64da7756d9e6)
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 http://www.opensolaris.org/os/licensing.
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	typeset resv_val
42	dataset=$1
43
44	log_must zfs set reservation=none $dataset
45
46	resv_val=`zfs get -H reservation $dataset | awk '{print $3}'`
47	if [[ $? -ne 0 ]]; then
48		log_fail "Unable to get reservation prop on $dataset"
49	elif [[ $resv_val != "none" ]]; then
50		log_fail "Reservation not 'none' ($resv_val) as expected"
51	fi
52
53
54	resv_val=`zfs get -pH reservation $dataset | awk '{print $3}'`
55	if [[ $? -ne 0 ]]; then
56		log_fail "Unable to get reservation prop on $dataset"
57	elif [[ $resv_val -ne 0 ]]; then
58		log_fail "Reservation not 0 ($resv_val) as expected"
59	fi
60
61	return 0
62}
63
64#
65# Utility function to see if two values are within a certain specified
66# limit of each other. Used primarily to check that a dataset's parent
67# is correctly accounting for space used/available. Need this function as
68# currently there is some slop in the way space is accounted (i.e. can't
69# do a direct comparison).
70#
71function within_limits
72{
73	typeset -l valA=$1
74	typeset -l valB=$2
75	typeset -l delta=$3
76
77	if ((valA <= valB)); then
78		if (((valB - valA) <= delta)); then
79			return 0
80		fi
81	elif ((valB <= valA)); then
82		if (((valA - valB) <= delta)); then
83			return 0
84		fi
85	fi
86
87	return 1
88}
89
90#
91# Function to create and mount multiple filesystems. The filesystem
92# will be named according to the name specified with a suffix value
93# taken from the loop counter.
94#
95function create_multiple_fs # num_fs base_fs_name base_mnt_name
96{
97	typeset -i iter=0
98	typeset -i count=$1
99	typeset FS_NAME=$2
100	typeset MNT_NAME=$3
101
102	while  (($iter < $count)); do
103		log_must zfs create ${FS_NAME}$iter
104		log_must zfs set mountpoint=${MNT_NAME}$iter ${FS_NAME}$iter
105		((iter = iter + 1))
106	done
107}
108
109#
110# This function compute the largest volume size which is multiple of volume
111# block size (default 8K) and not greater than the largest expected volsize.
112#
113# $1 The largest expected volume size.
114# $2 The volume block size
115#
116function floor_volsize #<largest_volsize> [volblksize]
117{
118	typeset -l largest_volsize=$1
119	typeset -l volblksize=${2:-8192}
120
121	if ((largest_volsize < volblksize)); then
122		log_fail "The largest_volsize must be greater than volblksize."
123	fi
124	typeset -l real_volsize
125	typeset -l n
126
127	((n = largest_volsize / volblksize))
128	((largest_volsize = volblksize * n))
129
130	print $largest_volsize
131}
132
133#
134# This function is a copy of a function by the same name in libzfs_dataset.c
135# Its purpose is to reserve additional space for volume metadata so volumes
136# don't unexpectedly run out of room.
137#
138# Note: This function can be used to do an estimate for a volume that has not
139# yet been created. In this case, $vol is not a volume, but rather a pool in
140# which a volume is going to be created. In this case, use default properties.
141#
142function volsize_to_reservation
143{
144	typeset vol=$1
145	typeset -i volsize=$2
146
147	typeset -i DN_MAX_INDBLKSHIFT=17
148	typeset -i SPA_BLKPTRSHIFT=7
149	typeset -i SPA_DVAS_PER_BP=3
150
151	typeset -i DNODES_PER_LEVEL_SHIFT=$((DN_MAX_INDBLKSHIFT - \
152	    SPA_BLKPTRSHIFT))
153	typeset -i DNODES_PER_LEVEL=$((1 << $DNODES_PER_LEVEL_SHIFT))
154
155	if ds_is_volume $vol; then
156		typeset -i ncopies=$(get_prop copies $vol)
157		typeset -i volblocksize=$(get_prop volblocksize $vol)
158	else
159		typeset -i ncopies=1
160		typeset -i volblocksize=8192
161	fi
162	typeset -i nblocks=$((volsize / volblocksize))
163
164	typeset -i numdb=7
165	while ((nblocks > 1)); do
166		((nblocks += DNODES_PER_LEVEL - 1))
167		((nblocks /= DNODES_PER_LEVEL))
168		((numdb += nblocks))
169	done
170
171	((numdb *= SPA_DVAS_PER_BP < ncopies + 1 ? SPA_DVAS_PER_BP : \
172	    ncopies + 1))
173	((volsize *= ncopies))
174	((numdb *= 1 << DN_MAX_INDBLKSHIFT))
175	((volsize += numdb))
176	echo $volsize
177}
178
179#
180# This function takes a pool name as an argument, and returns the largest (give
181# or take some slop) -V value that can be used to create a volume in that pool.
182# This is necessary because during volume creation, a reservation is created
183# that will be larger than the value specified with -V, and potentially larger
184# than the available space in the pool. See volsize_to_reservation().
185#
186function largest_volsize_from_pool
187{
188	typeset pool=$1
189	typeset -i poolsize=$(get_prop available $pool)
190	typeset -i volsize=$poolsize
191	typeset -i nvolsize
192
193	while :; do
194		# knock 50M off the volsize each time through
195		((volsize -= 50 * 1024 * 1024))
196		nvolsize=$(volsize_to_reservation $pool $volsize)
197		nvolsize=$(floor_volsize $nvolsize)
198		((nvolsize < poolsize)) && break
199	done
200	echo $volsize
201}
202