[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] Added device-sharing checks for loopback-mounted files. The existing



# HG changeset patch
# User emellor@xxxxxxxxxxxxxxxxxxxxxx
# Node ID c08cfaf353c60781f9b7baa5a8d91dfda6eca880
# Parent  cfcf9212a90bb01e5f343a3407b0d32d07ab45a3
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@xxxxxxxxxxxxx>

diff -r cfcf9212a90b -r c08cfaf353c6 tools/examples/block
--- a/tools/examples/block      Sun Nov 27 00:10:14 2005
+++ b/tools/examples/block      Sun Nov 27 00:56:34 2005
@@ -1,4 +1,6 @@
 #!/bin/sh
+
+set -x
 
 dir=$(dirname "$0")
 . "$dir/block-common.sh"
@@ -17,8 +19,24 @@
 }
 
 
+canonicalise_mode()
+{
+  local mode="$1"
+
+  if ! expr index "$mode" 'w' >/dev/null
+  then
+    echo 'ro'
+  elif ! expr index "$mode" '!' >/dev/null
+  then
+    echo 'rw'
+  else
+    echo 'no'
+  fi
+}
+
+
 ##
-# check_sharing device device_major_minor writable
+# check_sharing device device_major_minor mode
 #
 # Check whether the device requested is already in use.  To use the device in
 # read-only mode, it may be in use in read-only mode, but may not be in use in
@@ -27,13 +45,13 @@
 #
 check_sharing()
 {
-
   local dev="$1"
-  local devmm="$2"
-  local writable="$3"
+  local mode="$2"
+
+  local devmm=$(device_major_minor "$dev")
   local file
 
-  if [ "$writable" ]
+  if [ "$mode" == 'rw' ]
   then
     toskip="^$"
   else
@@ -48,18 +66,8 @@
 
       if [ "$d" == "$devmm" ]
       then
-        if [ "$writable" ]
-        then
-          m1=""
-          m2=""
-        else
-          m1="read-write "
-          m2="read-only "
-        fi
-
-        ebusy \
-"Device $dev is mounted ${m1}in the privileged domain,
-and so cannot be mounted ${m2}by a guest."
+        echo 'local'
+        return
       fi
     fi
   done
@@ -71,73 +79,182 @@
       local d=$(cat "$file")
       if [ "$d" == "$devmm" ]
       then
-        if [ "$writable" ]
-        then
-          ebusy \
-"Device $dev is already mounted in a guest domain, and so
-cannot be mounted read-write now."
+        if [ "$mode" == 'rw' ]
+        then
+          echo 'guest'
+          return
         else
           local m=$(cat "${file/physical_device/mode}")
 
           if expr index "$m" 'w' >/dev/null
           then
-            ebusy \
-"Device $dev is already mounted read-write in a guest domain,
-and so cannot be mounted read-only again."
+            echo 'guest'
+            return
           fi
         fi
       fi
     fi
   done
+
+  echo 'ok'
 }
 
 
 check_device_sharing()
 {
   local dev="$1"
-  local devmm=$(device_major_minor "$dev")
-  local mode=$(xenstore_read "$XENBUS_PATH/mode")
-
-  if ! expr index "$mode" 'w' >/dev/null
-  then
-    # No w implies read-only use; sharing with writers must be prevented.
-    check_sharing "$dev" "$devmm" ""
-  elif ! expr index "$mode" '!' >/dev/null
-  then
-    # No exclamation mark implies all sharing must be prevented.
-    check_sharing "$dev" "$devmm" 1
-  fi
-}
-
-
-t=$(xenstore_read_default "$XENBUS_PATH/type" "MISSING")
-
-case "$command" in 
+  local mode=$(canonicalise_mode "$2")
+  local result
+
+  if [ "$mode" == 'no' ]
+  then
+    return 0
+  fi
+
+  result=$(check_sharing "$dev" "$mode")
+
+  if [ "$result" != 'ok' ]
+  then
+    do_ebusy "Device $dev is mounted " "$mode" "$result"
+  fi
+}
+
+
+check_file_sharing()
+{
+  local file="$1"
+  local dev="$2"
+  local mode="$3"
+
+  result=$(check_sharing "$dev" "$mode")
+
+  if [ "$result" != 'ok' ]
+  then
+    do_ebusy "File $file is loopback-mounted through $dev,
+which is mounted " "$mode" "$result"
+  fi
+}
+
+
+do_ebusy()
+{
+  local prefix="$1"
+  local mode="$2"
+  local result="$3"
+
+  if [ "$result" == 'guest' ]
+  then
+    dom='a guest '
+    when='now'
+  else
+    dom='the privileged '
+    when='by a guest'
+  fi
+
+  if [ "$mode" == 'rw' ]
+  then
+    m1=''
+    m2=''
+  else
+    m1='read-write '
+    m2='read-only '
+  fi
+
+  ebusy \
+"${prefix}${m1}in ${dom}domain,
+and so cannot be mounted ${m2}${when}."
+}
+
+
+t=$(xenstore_read_default "$XENBUS_PATH/type" 'MISSING')
+
+case "$command" in
   add)
-    phys=$(xenstore_read_default "$XENBUS_PATH/physical-device" "MISSING")
-    if [ "$phys" != "MISSING" ]
+    phys=$(xenstore_read_default "$XENBUS_PATH/physical-device" 'MISSING')
+    if [ "$phys" != 'MISSING' ]
     then
       # Depending upon the hotplug configuration, it is possible for this
       # script to be called twice, so just bail.
       exit 0
     fi
+
     p=$(xenstore_read "$XENBUS_PATH/params")
+    mode=$(xenstore_read "$XENBUS_PATH/mode")
+
     case $t in 
       phy)
         dev=$(expand_dev $p)
-        check_device_sharing "$dev"
+        check_device_sharing "$dev" "$mode"
        write_dev "$dev"
        exit 0
        ;;
 
       file)
-       for dev in /dev/loop* ; do
-         if losetup $dev $p; then
-           write_dev "$dev"
-            exit 0
-         fi
-       done
-       exit 1
+        # Canonicalise the file, for sharing check comparison, and the mode
+        # for ease of use here.
+        file=$(readlink -f "$p")
+        mode=$(canonicalise_mode "$mode")
+
+        if [ "$mode" == 'rw' ] && ! stat "$file" -c %A | grep w >&/dev/null
+        then
+          ebusy \
+"File $file is read-only, and so I will not
+mount it read-write in a guest domain."
+        fi
+
+        loopdev=''
+
+       for dev in /dev/loop*
+        do
+          if [ ! -b "$dev" ]
+          then
+            continue
+          fi
+
+          f=$(losetup "$dev" 2>/dev/null) || f='()'
+          f=$(echo "$f" | sed -e 's/.*(\(.*\)).*/\1/g')
+
+          log err "$file $f $dev"
+
+          if [ "$f" ]
+          then
+            # $dev is in use.  Check sharing.
+
+            if [ "$mode" == 'no' ]
+            then
+              continue
+            fi
+
+            f=$(readlink -f "$f")
+
+            if [ "$f" == "$file" ]
+            then
+              check_file_sharing "$file" "$dev" "$mode"
+            fi
+          else
+            # $dev is not in use, so we'll remember it for use later; we want
+            # to finish the sharing check first.
+            
+            if [ "$loopdev" == '' ]
+            then
+              loopdev="$dev"
+            fi
+          fi
+        done
+
+        if [ "$loopdev" == '' ]
+        then
+          fatal 'Failed to find an unused loop device'
+        fi
+
+        if losetup "$loopdev" "$file"
+        then
+          xenstore_write "$XENBUS_PATH/node" "$loopdev"
+          write_dev "$loopdev"
+          exit 0
+        else
+          fatal "losetup $loopdev $file failed"
+        fi
        ;;
     esac
     ;;
@@ -150,7 +267,7 @@
 
       file)
         node=$(xenstore_read "$XENBUS_PATH/node")
-       losetup -d $node
+       losetup -d "$node"
        exit 0
        ;;
     esac

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.