1#! /usr/local/bin/ksh93 -p 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 "@(#)inherit_001_pos.ksh 1.5 09/08/06 SMI" 30# 31 32. $STF_SUITE/include/libtest.kshlib 33. $STF_SUITE/tests/inheritance/inherit.kshlib 34 35############################################################################### 36# 37# __stc_assertion_start 38# 39# ID: inherit_001_pos 40# 41# DESCRIPTION: 42# Test that properties are correctly inherited using 'zfs set', 43# 'zfs inherit' and 'zfs inherit -r'. 44# 45# STRATEGY: 46# 1) Read a configX.cfg file and create the specified datasets 47# 2) Read a stateX.cfg file and execute the commands within it 48# and verify that the properties have the correct values 49# 3) Repeat steps 1-2 for each configX and stateX files found. 50# 51# TESTABILITY: explicit 52# 53# TEST_AUTOMATION_LEVEL: automated 54# 55# CODING_STATUS: COMPLETED (2005-07-04) 56# 57# __stc_assertion_end 58# 59################################################################################ 60 61verify_runnable "global" 62 63log_assert "Test properties are inherited correctly" 64 65# 66# Simple function to create specified datasets. 67# 68function create_dataset #name type disks 69{ 70 typeset dataset=$1 71 typeset type=$2 72 typeset disks=$3 73 74 if [[ $type == "POOL" ]]; then 75 create_pool "$dataset" "$disks" 76 elif [[ $type == "CTR" ]]; then 77 log_must $ZFS create $dataset 78 log_must $ZFS set canmount=off $dataset 79 elif [[ $type == "FS" ]]; then 80 log_must $ZFS create $dataset 81 else 82 log_fail "ERROR: Unrecognised type $type" 83 fi 84 85 list="$list $dataset" 86} 87 88# 89# Function to walk through all the properties in a 90# dataset, setting them to a 'local' value if required. 91# 92function init_props #dataset init_code 93{ 94 typeset dataset=$1 95 typeset init_code=$2 96 typeset new_val 97 typeset -i i=0 98 99 # 100 # Though the effect of '-' and 'default' is the same we 101 # call them out via a log_note to aid in debugging the 102 # config files 103 # 104 if [[ $init_code == "-" ]]; then 105 log_note "Leaving properties for $dataset unchanged." 106 [[ $def_recordsize == 0 ]] && \ 107 update_recordsize $dataset $init_code 108 return; 109 elif [[ $init_code == "default" ]]; then 110 log_note "Leaving properties for $dataset at default values." 111 [[ $def_recordsize == 0 ]] && \ 112 update_recordsize $dataset $init_code 113 return; 114 elif [[ $init_code == "local" ]]; then 115 log_note "Setting properties for $dataset to local values." 116 for (( ; i < ${#props[*]}; i += 2 )); do 117 if [[ ${props[i]} == "recordsize" ]]; then 118 update_recordsize $dataset $init_code 119 else 120 set_n_verify_prop ${props[i]} \ 121 ${local_val[((i/2))]} $dataset 122 fi 123 done 124 else 125 log_fail "ERROR: Unrecognised init code $init_code" 126 fi 127} 128 129# 130# We enter this function either to update the recordsize value 131# in the default array, or to update the local value array. 132# 133function update_recordsize { #dataset init_code 134 typeset dataset=$1 135 typeset init_code=$2 136 typeset idx=0 137 typeset record_val 138 139 # 140 # First need to find where the recordsize property is 141 # located in the arrays 142 # 143 for (( ; idx < ${#props[*]}; idx += 2 )); do 144 [[ ${props[idx]} == "recordsize" ]] && \ 145 break 146 done 147 148 (( idx = idx / 2 )) 149 record_val=`get_prop recordsize $dataset` 150 if [[ $init_code == "-" || \ 151 $init_code == "default" ]]; then 152 153 def_val[idx]=$record_val 154 def_recordsize=1 155 156 elif [[ $init_code == "local" ]]; then 157 158 log_must $ZFS set recordsize=$record_val $dataset 159 160 local_val[idx]=$record_val 161 fi 162} 163 164# 165# The mountpoint property is slightly different from other properties and 166# so is handled here. For all other properties if they are set to a specific 167# value at a higher level in the data hierarchy (i.e. checksum=on) then that 168# value propogates down the hierarchy unchanged, with the source field being 169# set to 'inherited from <higher dataset>'. 170# 171# The mountpoint property is different in that while the value propogates 172# down the hierarchy, the value at each level is determined by a combination 173# of the top-level value and the current level in the hierarchy. 174# 175# For example consider the case where we have a pool (called pool1), containing 176# a dataset (ctr) which in turn contains a filesystem (fs). If we set the 177# mountpoint of the pool to '/mnt2' then the mountpoints for the dataset and 178# filesystem are '/mnt2/ctr' and /mnt2/ctr/fs' respectively, with the 'source' 179# field being set to 'inherited from pool1'. 180# 181# So at the filesystem level to calculate what our mountpoint property should 182# be set to we walk back up the hierarchy sampling the mountpoint property at 183# each level and forming up the expected mountpoint value piece by piece until 184# we reach the level specified in the 'source' field, which in this example is 185# the top-level pool. 186# 187function get_mntpt_val #dataset src index 188{ 189 typeset dataset=$1 190 typeset src=$2 191 typeset idx=$3 192 typeset new_path="" 193 typeset dset 194 typeset mntpt="" 195 196 if [[ $src == "local" ]]; then 197 mntpt=${local_val[idx]} 198 elif [[ $src == "default" ]]; then 199 mntpt="$ZFSROOT/"$dataset 200 else 201 # Walk back up the hierarchy building up the 202 # expected mountpoint property value. 203 obj_name=${dataset##*/} 204 205 while [[ $src != $dataset ]]; do 206 dset=${dataset%/*} 207 208 mnt_val=`get_prop mountpoint $dset` 209 210 mod_prop_val=${mnt_val##*/} 211 new_path="/"$mod_prop_val$new_path 212 dataset=$dset 213 done 214 215 mntpt=$new_path"/"$obj_name 216 fi 217 print $mntpt 218} 219 220# 221# Simple function to verify that a property has the 222# expected value. 223# 224function verify_prop_val #property dataset src index 225{ 226 typeset dataset=$1 227 typeset prop=$2 228 typeset src=$3 229 typeset idx=$4 230 typeset new_path="" 231 typeset dset 232 typeset exp_val 233 typeset prop_val 234 235 prop_val=`get_prop $prop $dataset` 236 237 # mountpoint property is handled as a special case 238 if [[ $prop == "mountpoint" ]]; then 239 exp_val=`get_mntpt_val $dataset $src $idx` 240 else 241 if [[ $src == "local" ]]; then 242 exp_val=${local_val[idx]} 243 elif [[ $src == "default" ]]; then 244 exp_val=${def_val[idx]} 245 else 246 # 247 # We are inheriting the value from somewhere 248 # up the hierarchy. 249 # 250 exp_val=`get_prop $prop $src` 251 fi 252 fi 253 254 [ "$prop_val" = "$exp_val" ] && return 255 256 # After putback PSARC/2008/231 Apr,09,2008, the default value of 257 # aclinherit has changed to be 'restricted' instead of 'secure', 258 # but the old interface of 'secure' still exist 259 [ "$prop" = "aclinherit" ] && return 260 [ "$exp_val" = "secure" ] && return 261 [ "$prop_val" = "restricted" ] && return 262 263 log_fail "ERROR: Property $prop (source $src index $idx) for $dataset" \ 264 "was [$prop_val]; expected [$exp_val]" 265} 266 267# 268# Function to read the configX.cfg files and create the specified 269# dataset hierarchy 270# 271function scan_config #config-file 272{ 273 typeset config_file=$1 274 275 DISK=${DISKS%% *} 276 277 list="" 278 279 grep "^[^#]" $config_file | { 280 while read name type init ; do 281 create_dataset $name $type $DISK 282 init_props $name $init 283 done 284 } 285} 286 287function check_state 288{ 289 typeset i=$1 290 typeset j=$2 291 typeset op=$3 292 typeset target=$4 293 294 # 295 # The user can if they wish specify that no operation be performed 296 # (by specifying '-' rather than a command). This is not as 297 # useless as it sounds as it allows us to verify that the dataset 298 # hierarchy has been set up correctly as specified in the 299 # configX.cfg file (which includes 'set'ting properties at a higher 300 # level and checking that they propogate down to the lower levels. 301 # 302 # Note in a few places here, we use log_onfail, rather than 303 # log_must - this substantially reduces journal output. 304 # 305 if [[ $op != "-" ]]; then 306 # Unmount the test datasets if they are still mounted. 307 # Most often, they won't be, so discard the output 308 unmount_all_safe > /dev/null 2>&1 309 310 for p in ${props[i]} ${props[((i+1))]}; do 311 log_onfail $ZFS $op $p $target 312 done 313 fi 314 for check_obj in $list; do 315 read init_src final_src 316 317 for p in ${props[i]} ${props[((i+1))]}; do 318 verify_args="$check_obj $p $final_src" 319 320 log_onfail verify_prop_src $check_obj $p $final_src 321 log_onfail verify_prop_val $check_obj $p $final_src $j 322 done 323 done 324} 325 326# 327# Main function. Executes the commands specified in the stateX.cfg 328# files and then verifies that all the properties have the correct 329# values and 'source' fields. 330# 331function scan_state #state-file 332{ 333 typeset state_file=$1 334 typeset -i i=0 335 typeset -i j=0 336 337 log_note "Reading state from $state_file" 338 for (( ; i < ${#props[*]}; i += 2, j += 1 )); do 339 grep "^[^#]" $state_file | { 340 while IFS=: read target op; do 341 check_state $i $j "$op" "$target" 342 done 343 } 344 done 345} 346 347 348set -A props "checksum" "" \ 349 "compression" "compress" \ 350 "atime" "" \ 351 "exec" "" \ 352 "setuid" "" \ 353 "sharenfs" "" \ 354 "recordsize" "recsize" \ 355 "mountpoint" "" \ 356 "snapdir" "" \ 357 "aclmode" "" \ 358 "aclinherit" "" \ 359 "readonly" "rdonly" 360 361# 362# Note except for the mountpoint default value (which is handled in 363# the routine itself), each property specified in the 'props' array 364# above must have a corresponding entry in the two arrays below. 365# 366set -A def_val "on" \ 367 "off" \ 368 "on" \ 369 "on" \ 370 "on" \ 371 "off" \ 372 "" \ 373 "" \ 374 "hidden" \ 375 "discard" \ 376 "secure" \ 377 "off" 378 379set -A local_val "off" "on" "off" "off" \ 380 "off" "on" "" \ 381 "$TESTDIR" "visible" "groupmask" "discard" \ 382 "off" 383 384log_must $ZPOOL create $TESTPOOL ${DISKS%% *} 385 386# Append the "shareiscsi" property if it is supported 387$ZFS get shareiscsi $TESTPOOL > /dev/null 2>&1 388if [[ $? -eq 0 ]]; then 389 typeset -i i=${#props[*]} 390 props[i]="shareiscsi" 391 props[((i+1))]="" 392 def_val[((i/2))]="off" 393 local_val[((i/2))]="on" 394fi 395 396# Append the "devices" property if it is settable 397$ZFS set devices=off $TESTPOOL 398if [[ $? -eq 0 ]]; then 399 typeset -i i=${#props[*]} 400 props[i]="devices" 401 props[((i+1))]="" 402 def_val[((i/2))]="on" 403 local_val[((i/2))]="off" 404else 405 log_note "Setting devices=off is not supported on this system" 406fi 407 408log_must $ZPOOL destroy $TESTPOOL 409 410# 411# Global flag indicating whether the default record size had been 412# read. 413# 414typeset def_recordsize=0 415 416TDIR=$STF_SUITE/tests/inheritance 417set -A config_files $(ls $TDIR/config*[1-9]*.cfg) 418set -A state_files $(ls $TDIR/state*.cfg) 419 420# 421# Global list of datasets created. 422# 423list="" 424 425if [[ ${#config_files[*]} != ${#state_files[*]} ]]; then 426 log_fail "ERROR: Must have the same number of config files"\ 427 "(${#config_files[*]}) and state files ${#state_files[*]}" 428fi 429 430typeset -i fnum=0 431for (( ; fnum < ${#config_files[*]}; fnum += 1 )); do 432 default_cleanup_noexit 433 def_recordsize=0 434 435 log_note "*** Testing configuration ${config_files[fnum]}" 436 scan_config ${config_files[fnum]} 437 scan_state ${state_files[fnum]} 438done 439 440log_pass "Properties correctly inherited as expected" 441