ia64/xen-unstable

changeset 8078:c08cfaf353c6

Added device-sharing checks for loopback-mounted files. The existing
check_sharing functions have been rejigged slightly so that the file-specific
stuff can share the code therein. This separates the actual test from the
generation of the error message, and introduces the canonicalise_mode function.

This also restores the broken teardown functionality for file: devices -- the
writing of XENBUS_PATH/node had been removed, but this is required for file
device teardown.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Sun Nov 27 00:56:34 2005 +0000 (2005-11-27)
parents cfcf9212a90b
children 2c54b2f0a676
files tools/examples/block
line diff
     1.1 --- a/tools/examples/block	Sun Nov 27 00:10:14 2005 +0000
     1.2 +++ b/tools/examples/block	Sun Nov 27 00:56:34 2005 +0000
     1.3 @@ -1,5 +1,7 @@
     1.4  #!/bin/sh
     1.5  
     1.6 +set -x
     1.7 +
     1.8  dir=$(dirname "$0")
     1.9  . "$dir/block-common.sh"
    1.10  
    1.11 @@ -17,8 +19,24 @@ expand_dev() {
    1.12  }
    1.13  
    1.14  
    1.15 +canonicalise_mode()
    1.16 +{
    1.17 +  local mode="$1"
    1.18 +
    1.19 +  if ! expr index "$mode" 'w' >/dev/null
    1.20 +  then
    1.21 +    echo 'ro'
    1.22 +  elif ! expr index "$mode" '!' >/dev/null
    1.23 +  then
    1.24 +    echo 'rw'
    1.25 +  else
    1.26 +    echo 'no'
    1.27 +  fi
    1.28 +}
    1.29 +
    1.30 +
    1.31  ##
    1.32 -# check_sharing device device_major_minor writable
    1.33 +# check_sharing device device_major_minor mode
    1.34  #
    1.35  # Check whether the device requested is already in use.  To use the device in
    1.36  # read-only mode, it may be in use in read-only mode, but may not be in use in
    1.37 @@ -27,13 +45,13 @@ expand_dev() {
    1.38  #
    1.39  check_sharing()
    1.40  {
    1.41 +  local dev="$1"
    1.42 +  local mode="$2"
    1.43  
    1.44 -  local dev="$1"
    1.45 -  local devmm="$2"
    1.46 -  local writable="$3"
    1.47 +  local devmm=$(device_major_minor "$dev")
    1.48    local file
    1.49  
    1.50 -  if [ "$writable" ]
    1.51 +  if [ "$mode" == 'rw' ]
    1.52    then
    1.53      toskip="^$"
    1.54    else
    1.55 @@ -48,18 +66,8 @@ check_sharing()
    1.56  
    1.57        if [ "$d" == "$devmm" ]
    1.58        then
    1.59 -        if [ "$writable" ]
    1.60 -        then
    1.61 -          m1=""
    1.62 -          m2=""
    1.63 -        else
    1.64 -          m1="read-write "
    1.65 -          m2="read-only "
    1.66 -        fi
    1.67 -
    1.68 -        ebusy \
    1.69 -"Device $dev is mounted ${m1}in the privileged domain,
    1.70 -and so cannot be mounted ${m2}by a guest."
    1.71 +        echo 'local'
    1.72 +        return
    1.73        fi
    1.74      fi
    1.75    done
    1.76 @@ -71,73 +79,182 @@ and so cannot be mounted ${m2}by a guest
    1.77        local d=$(cat "$file")
    1.78        if [ "$d" == "$devmm" ]
    1.79        then
    1.80 -        if [ "$writable" ]
    1.81 +        if [ "$mode" == 'rw' ]
    1.82          then
    1.83 -          ebusy \
    1.84 -"Device $dev is already mounted in a guest domain, and so
    1.85 -cannot be mounted read-write now."
    1.86 +          echo 'guest'
    1.87 +          return
    1.88          else
    1.89            local m=$(cat "${file/physical_device/mode}")
    1.90  
    1.91            if expr index "$m" 'w' >/dev/null
    1.92            then
    1.93 -            ebusy \
    1.94 -"Device $dev is already mounted read-write in a guest domain,
    1.95 -and so cannot be mounted read-only again."
    1.96 +            echo 'guest'
    1.97 +            return
    1.98            fi
    1.99          fi
   1.100        fi
   1.101      fi
   1.102    done
   1.103 +
   1.104 +  echo 'ok'
   1.105  }
   1.106  
   1.107  
   1.108  check_device_sharing()
   1.109  {
   1.110    local dev="$1"
   1.111 -  local devmm=$(device_major_minor "$dev")
   1.112 -  local mode=$(xenstore_read "$XENBUS_PATH/mode")
   1.113 +  local mode=$(canonicalise_mode "$2")
   1.114 +  local result
   1.115  
   1.116 -  if ! expr index "$mode" 'w' >/dev/null
   1.117 +  if [ "$mode" == 'no' ]
   1.118 +  then
   1.119 +    return 0
   1.120 +  fi
   1.121 +
   1.122 +  result=$(check_sharing "$dev" "$mode")
   1.123 +
   1.124 +  if [ "$result" != 'ok' ]
   1.125    then
   1.126 -    # No w implies read-only use; sharing with writers must be prevented.
   1.127 -    check_sharing "$dev" "$devmm" ""
   1.128 -  elif ! expr index "$mode" '!' >/dev/null
   1.129 +    do_ebusy "Device $dev is mounted " "$mode" "$result"
   1.130 +  fi
   1.131 +}
   1.132 +
   1.133 +
   1.134 +check_file_sharing()
   1.135 +{
   1.136 +  local file="$1"
   1.137 +  local dev="$2"
   1.138 +  local mode="$3"
   1.139 +
   1.140 +  result=$(check_sharing "$dev" "$mode")
   1.141 +
   1.142 +  if [ "$result" != 'ok' ]
   1.143    then
   1.144 -    # No exclamation mark implies all sharing must be prevented.
   1.145 -    check_sharing "$dev" "$devmm" 1
   1.146 +    do_ebusy "File $file is loopback-mounted through $dev,
   1.147 +which is mounted " "$mode" "$result"
   1.148    fi
   1.149  }
   1.150  
   1.151  
   1.152 -t=$(xenstore_read_default "$XENBUS_PATH/type" "MISSING")
   1.153 +do_ebusy()
   1.154 +{
   1.155 +  local prefix="$1"
   1.156 +  local mode="$2"
   1.157 +  local result="$3"
   1.158 +
   1.159 +  if [ "$result" == 'guest' ]
   1.160 +  then
   1.161 +    dom='a guest '
   1.162 +    when='now'
   1.163 +  else
   1.164 +    dom='the privileged '
   1.165 +    when='by a guest'
   1.166 +  fi
   1.167  
   1.168 -case "$command" in 
   1.169 +  if [ "$mode" == 'rw' ]
   1.170 +  then
   1.171 +    m1=''
   1.172 +    m2=''
   1.173 +  else
   1.174 +    m1='read-write '
   1.175 +    m2='read-only '
   1.176 +  fi
   1.177 +
   1.178 +  ebusy \
   1.179 +"${prefix}${m1}in ${dom}domain,
   1.180 +and so cannot be mounted ${m2}${when}."
   1.181 +}
   1.182 +
   1.183 +
   1.184 +t=$(xenstore_read_default "$XENBUS_PATH/type" 'MISSING')
   1.185 +
   1.186 +case "$command" in
   1.187    add)
   1.188 -    phys=$(xenstore_read_default "$XENBUS_PATH/physical-device" "MISSING")
   1.189 -    if [ "$phys" != "MISSING" ]
   1.190 +    phys=$(xenstore_read_default "$XENBUS_PATH/physical-device" 'MISSING')
   1.191 +    if [ "$phys" != 'MISSING' ]
   1.192      then
   1.193        # Depending upon the hotplug configuration, it is possible for this
   1.194        # script to be called twice, so just bail.
   1.195        exit 0
   1.196      fi
   1.197 +
   1.198      p=$(xenstore_read "$XENBUS_PATH/params")
   1.199 +    mode=$(xenstore_read "$XENBUS_PATH/mode")
   1.200 +
   1.201      case $t in 
   1.202        phy)
   1.203          dev=$(expand_dev $p)
   1.204 -        check_device_sharing "$dev"
   1.205 +        check_device_sharing "$dev" "$mode"
   1.206  	write_dev "$dev"
   1.207  	exit 0
   1.208  	;;
   1.209  
   1.210        file)
   1.211 -	for dev in /dev/loop* ; do
   1.212 -	  if losetup $dev $p; then
   1.213 -	    write_dev "$dev"
   1.214 -            exit 0
   1.215 -	  fi
   1.216 -	done
   1.217 -	exit 1
   1.218 +        # Canonicalise the file, for sharing check comparison, and the mode
   1.219 +        # for ease of use here.
   1.220 +        file=$(readlink -f "$p")
   1.221 +        mode=$(canonicalise_mode "$mode")
   1.222 +
   1.223 +        if [ "$mode" == 'rw' ] && ! stat "$file" -c %A | grep w >&/dev/null
   1.224 +        then
   1.225 +          ebusy \
   1.226 +"File $file is read-only, and so I will not
   1.227 +mount it read-write in a guest domain."
   1.228 +        fi
   1.229 +
   1.230 +        loopdev=''
   1.231 +
   1.232 +	for dev in /dev/loop*
   1.233 +        do
   1.234 +          if [ ! -b "$dev" ]
   1.235 +          then
   1.236 +            continue
   1.237 +          fi
   1.238 +
   1.239 +          f=$(losetup "$dev" 2>/dev/null) || f='()'
   1.240 +          f=$(echo "$f" | sed -e 's/.*(\(.*\)).*/\1/g')
   1.241 +
   1.242 +          log err "$file $f $dev"
   1.243 +
   1.244 +          if [ "$f" ]
   1.245 +          then
   1.246 +            # $dev is in use.  Check sharing.
   1.247 +
   1.248 +            if [ "$mode" == 'no' ]
   1.249 +            then
   1.250 +              continue
   1.251 +            fi
   1.252 +
   1.253 +            f=$(readlink -f "$f")
   1.254 +
   1.255 +            if [ "$f" == "$file" ]
   1.256 +            then
   1.257 +              check_file_sharing "$file" "$dev" "$mode"
   1.258 +            fi
   1.259 +          else
   1.260 +            # $dev is not in use, so we'll remember it for use later; we want
   1.261 +            # to finish the sharing check first.
   1.262 +            
   1.263 +            if [ "$loopdev" == '' ]
   1.264 +            then
   1.265 +              loopdev="$dev"
   1.266 +            fi
   1.267 +          fi
   1.268 +        done
   1.269 +
   1.270 +        if [ "$loopdev" == '' ]
   1.271 +        then
   1.272 +          fatal 'Failed to find an unused loop device'
   1.273 +        fi
   1.274 +
   1.275 +        if losetup "$loopdev" "$file"
   1.276 +        then
   1.277 +          xenstore_write "$XENBUS_PATH/node" "$loopdev"
   1.278 +          write_dev "$loopdev"
   1.279 +          exit 0
   1.280 +        else
   1.281 +          fatal "losetup $loopdev $file failed"
   1.282 +        fi
   1.283  	;;
   1.284      esac
   1.285      ;;
   1.286 @@ -150,7 +267,7 @@ case "$command" in
   1.287  
   1.288        file)
   1.289          node=$(xenstore_read "$XENBUS_PATH/node")
   1.290 -	losetup -d $node
   1.291 +	losetup -d "$node"
   1.292  	exit 0
   1.293  	;;
   1.294      esac