1# vim: filetype=sh
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22
23#
24# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26#
27# ident	"@(#)reservation.kshlib	1.3	09/01/12 SMI"
28#
29
30#
31# Function to set the reservation property of a dataset to
32# 'none' and verify that it is correctly set using both the
33# "normal" 'zfs get reservation' and the '-p' option which
34# gives a numerical value.
35#
36function zero_reservation
37{
38	typeset resv_val
39	dataset=$1
40
41	log_must $ZFS set reservation=none $dataset
42	log_must $ZFS set refreservation=none $dataset
43
44	resv_val=`$ZFS get -H refreservation $dataset | awk '{print $3}'`
45	if [[ $? -ne 0 ]]; then
46		log_fail "Unable to get reservation prop on $dataset"
47	elif [[ $resv_val != "none" ]]; then
48		log_fail "Reservation not 'none' ($resv_val) as expected"
49	fi
50
51
52	resv_val=`$ZFS get -pH refreservation $dataset | awk '{print $3}'`
53	if [[ $? -ne 0 ]]; then
54		log_fail "Unable to get reservation prop on $dataset"
55	elif [[ $resv_val -ne 0 ]]; then
56		log_fail "Reservation not 0 ($resv_val) as expected"
57	fi
58
59	return 0
60}
61
62#
63# Utility function to see if two values are within a certain specified
64# limit of each other. Used primarily to check that a dataset's parent
65# is correctly accounting for space used/available. Need this function as
66# currently there is some slop in the way space is accounted (i.e. can't
67# do a direct comparison).
68#
69function within_limits
70{
71	typeset -l valA=$1
72	typeset -l valB=$2
73	typeset -l delta=$3
74
75	if (( valA <= valB )); then
76		if (( (valB - valA) <= delta )); then
77                	return 0
78		fi
79	elif (( valB <= valA )); then
80		if (( (valA - valB) <= delta )); then
81			return 0
82		fi
83	fi
84
85	return 1
86}
87
88#
89# Function to create and mount multiple filesystems. The filesystem
90# will be named according to the name specified with a suffix value
91# taken from the loop counter.
92#
93function create_multiple_fs # num_fs base_fs_name base_mnt_name
94{
95        typeset -i iter=0
96        typeset -i count=$1
97        typeset FS_NAME=$2
98        typeset MNT_NAME=$3
99
100        while  (( $iter < $count )); do
101                log_must $ZFS create ${FS_NAME}$iter
102                log_must $ZFS set mountpoint=${MNT_NAME}$iter ${FS_NAME}$iter
103                (( iter = iter + 1 ))
104        done
105}
106
107#
108# This function compute the largest volume size which is multiple of volume
109# block size (default 8K) and not greater than the largest expected volsize.
110#
111# $1 The largest expected volume size.
112# $2 The volume block size
113#
114function floor_volsize #<largest_volsize> [volblksize]
115{
116	typeset -l largest_volsize=$1
117	typeset -l volblksize=${2:-8192}
118
119	if (( largest_volsize < volblksize )); then
120		log_fail "The largest_volsize must be greater than volblksize."
121	fi
122	typeset -l real_volsize
123	typeset -l n
124
125	(( n = largest_volsize / volblksize ))
126	(( largest_volsize = volblksize * n ))
127
128	print $largest_volsize
129}
130
131#
132# Simple function to get the expected reservation for a ZVOL given the
133# volume size, block size, and number of copies.
134#
135# NB: This routine must be kept in sync with the ZFS library function
136# libzfs_dataset.c:zvol_volsize_to_reservation().  Refer to that function
137# for the logic behind the calculations.
138#
139function zvol_volsize_to_reservation
140{
141	typeset resv_val
142	typeset nblocks
143	typeset numdb
144	typeset volsize=$1
145	typeset volblocksize=$2
146	typeset ncopies=$3
147	typeset ncopies_bp
148	typeset DN_MAX_INDBLKSHIFT=17
149	typeset SPA_BLKPTRSHIFT=7
150	typeset SPA_DVAS_PER_BP=3
151	typeset DVAS_PER_BP
152	typeset DNODES_PER_LEVEL_SHIFT
153	typeset DNODES_PER_LEVEL
154	typeset DN_MAX_INDBLKS
155
156	(( DNODES_PER_LEVEL_SHIFT = DN_MAX_INDBLKSHIFT - SPA_BLKPTRSHIFT ))
157	(( DNODES_PER_LEVEL = 1 << DNODES_PER_LEVEL_SHIFT ))
158	(( DN_MAX_INDBLKS = 1 << DN_MAX_INDBLKSHIFT ))
159
160	resv_val=$volsize
161	(( nblocks = volsize / volblocksize ))
162	numdb=7
163	while (( nblocks > 1 )); do
164		(( nblocks = nblocks + DNODES_PER_LEVEL - 1 ))
165		(( nblocks = nblocks / DNODES_PER_LEVEL ))
166		(( numdb = numdb + nblocks ))
167	done
168	(( ncopies_bp = ncopies + 1 ))
169	DVAS_PER_BP=$(min $SPA_DVAS_PER_BP $ncopies_bp)
170	(( numdb = numdb * DVAS_PER_BP ))
171	(( resv_val = volsize * ncopies ))
172	(( numdb = numdb * DN_MAX_INDBLKS ))
173	(( resv_val = resv_val + numdb ))
174
175	$ECHO $resv_val
176	return 0
177}
178
179