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