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# $FreeBSD$
24
25#
26# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
27# Use is subject to license terms.
28#
29# ident	"@(#)reservation.kshlib	1.3	09/01/12 SMI"
30#
31
32#
33# Function to set the reservation property of a dataset to
34# 'none' and verify that it is correctly set using both the
35# "normal" 'zfs get reservation' and the '-p' option which
36# gives a numerical value.
37#
38function zero_reservation
39{
40	typeset resv_val
41	dataset=$1
42
43	log_must $ZFS set reservation=none $dataset
44	log_must $ZFS set refreservation=none $dataset
45
46	resv_val=`$ZFS get -H refreservation $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 refreservation $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# Simple function to get the expected reservation for a ZVOL given the
135# volume size, block size, and number of copies.
136#
137# NB: This routine must be kept in sync with the ZFS library function
138# libzfs_dataset.c:zvol_volsize_to_reservation().  Refer to that function
139# for the logic behind the calculations.
140#
141function zvol_volsize_to_reservation
142{
143	typeset resv_val
144	typeset nblocks
145	typeset numdb
146	typeset volsize=$1
147	typeset volblocksize=$2
148	typeset ncopies=$3
149	typeset ncopies_bp
150	typeset DN_MAX_INDBLKSHIFT=17
151	typeset SPA_BLKPTRSHIFT=7
152	typeset SPA_DVAS_PER_BP=3
153	typeset DVAS_PER_BP
154	typeset DNODES_PER_LEVEL_SHIFT
155	typeset DNODES_PER_LEVEL
156	typeset DN_MAX_INDBLKS
157
158	(( DNODES_PER_LEVEL_SHIFT = DN_MAX_INDBLKSHIFT - SPA_BLKPTRSHIFT ))
159	(( DNODES_PER_LEVEL = 1 << DNODES_PER_LEVEL_SHIFT ))
160	(( DN_MAX_INDBLKS = 1 << DN_MAX_INDBLKSHIFT ))
161
162	resv_val=$volsize
163	(( nblocks = volsize / volblocksize ))
164	numdb=7
165	while (( nblocks > 1 )); do
166		(( nblocks = nblocks + DNODES_PER_LEVEL - 1 ))
167		(( nblocks = nblocks / DNODES_PER_LEVEL ))
168		(( numdb = numdb + nblocks ))
169	done
170	(( ncopies_bp = ncopies + 1 ))
171	DVAS_PER_BP=$(min $SPA_DVAS_PER_BP $ncopies_bp)
172	(( numdb = numdb * DVAS_PER_BP ))
173	(( resv_val = volsize * ncopies ))
174	(( numdb = numdb * DN_MAX_INDBLKS ))
175	(( resv_val = resv_val + numdb ))
176
177	$ECHO $resv_val
178	return 0
179}
180
181