ia64/xen-unstable

changeset 8065:8c3ed250366c

Check when using physical devices that the device is not already in use. Using
a device from two guests, or from dom 0 and a guest, can destroy the filesystem,
and this check prevents that. This should ensure that the xm tests
11_block_attach_shared_dom0 and 12_block_attach_shared_domU should pass.
Closes bug #331.

Devices may be shared only if all uses are read-only. If anyone has read-write
access to a device, then no sharing is allowed.

The mode in the config file may now have an exclamation mark appended, to
indicate that devices may be shared (i.e. that this new check should be
bypassed). This supports some network block devices, but is clearly dangerous
and should only be used when you know what you are doing.

The mode specified in the config file is now written explicitly to the store,
To implement this, the blkback driver has been changed to create two entries
in /sys describing each device in use. This means that we can determine which
devices are in use without crawling through the store.

The physical-device node has been changed to give the major and minor of the
device, separated by a colon. This means that we do not need to pack these
numbers into one, removing the restriction to 8 bit minors that we had in place
before.

The mode specified in the config file is now written explicitly to the store,
rather than using the presence or absence of a read-only node. This supports
the write-sharing override above.

If the device is in use, a new hotplug status of "busy" is written to the
store, and a message is written to a new hotplug-error node. Xend uses these
things for diagnosis.

The block scripts do not need to handle online or offline events, so this
support has been removed. These scripts can be called twice, depending upon
the hotplug config, so they now identify the second run and do not attempt to
set up the device again.

The device directories in the store are cleaned out before new details are
written there. This prevents stale information from messing up block device
hotplugging. This will be one cause of "blkback: changing physical device
not supported" messages.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Fri Nov 25 20:58:07 2005 +0000 (2005-11-25)
parents 701ec436d5ad
children 43e25c2653ee
files linux-2.6-xen-sparse/drivers/xen/blkback/common.h linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c tools/examples/block tools/examples/block-common.sh tools/python/xen/xend/server/DevController.py tools/python/xen/xend/server/blkif.py
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/blkback/common.h	Fri Nov 25 17:12:12 2005 +0000
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/blkback/common.h	Fri Nov 25 20:58:07 2005 +0000
     1.3 @@ -78,8 +78,8 @@ int blkif_map(blkif_t *blkif, unsigned l
     1.4  	} while (0)
     1.5  
     1.6  /* Create a vbd. */
     1.7 -int vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, u32 pdevice,
     1.8 -	       int readonly);
     1.9 +int vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, unsigned major,
    1.10 +	       unsigned minor, int readonly);
    1.11  void vbd_free(struct vbd *vbd);
    1.12  
    1.13  unsigned long vbd_size(struct vbd *vbd);
     2.1 --- a/linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c	Fri Nov 25 17:12:12 2005 +0000
     2.2 +++ b/linux-2.6-xen-sparse/drivers/xen/blkback/vbd.c	Fri Nov 25 20:58:07 2005 +0000
     2.3 @@ -9,10 +9,6 @@
     2.4  #include "common.h"
     2.5  #include <asm-xen/xenbus.h>
     2.6  
     2.7 -static inline dev_t vbd_map_devnum(u32 cookie)
     2.8 -{
     2.9 -	return MKDEV(BLKIF_MAJOR(cookie), BLKIF_MINOR(cookie));
    2.10 -}
    2.11  #define vbd_sz(_v)   ((_v)->bdev->bd_part ?				\
    2.12  	(_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity)
    2.13  #define bdev_put(_b) blkdev_put(_b)
    2.14 @@ -32,8 +28,8 @@ unsigned long vbd_secsize(struct vbd *vb
    2.15  	return bdev_hardsect_size(vbd->bdev);
    2.16  }
    2.17  
    2.18 -int vbd_create(blkif_t *blkif, blkif_vdev_t handle,
    2.19 -	       u32 pdevice, int readonly)
    2.20 +int vbd_create(blkif_t *blkif, blkif_vdev_t handle, unsigned major,
    2.21 +	       unsigned minor, int readonly)
    2.22  {
    2.23  	struct vbd *vbd;
    2.24  
    2.25 @@ -42,10 +38,10 @@ int vbd_create(blkif_t *blkif, blkif_vde
    2.26  	vbd->readonly = readonly;
    2.27  	vbd->type     = 0;
    2.28  
    2.29 -	vbd->pdevice  = pdevice;
    2.30 +	vbd->pdevice  = MKDEV(major, minor);
    2.31  
    2.32  	vbd->bdev = open_by_devnum(
    2.33 -		vbd_map_devnum(vbd->pdevice),
    2.34 +		vbd->pdevice,
    2.35  		vbd->readonly ? FMODE_READ : FMODE_WRITE);
    2.36  	if (IS_ERR(vbd->bdev)) {
    2.37  		DPRINTK("vbd_creat: device %08x doesn't exist.\n",
     3.1 --- a/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c	Fri Nov 25 17:12:12 2005 +0000
     3.2 +++ b/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c	Fri Nov 25 20:58:07 2005 +0000
     3.3 @@ -37,8 +37,9 @@ struct backend_info
     3.4  	blkif_t *blkif;
     3.5  	struct xenbus_watch backend_watch;
     3.6  
     3.7 -	long int pdev;
     3.8 -	long int readonly;
     3.9 +	unsigned major;
    3.10 +	unsigned minor;
    3.11 +	char *mode;
    3.12  };
    3.13  
    3.14  
    3.15 @@ -49,6 +50,25 @@ static void backend_changed(struct xenbu
    3.16  			    unsigned int);
    3.17  
    3.18  
    3.19 +static ssize_t show_physical_device(struct device *_dev, char *buf)
    3.20 +{
    3.21 +	struct xenbus_device *dev = to_xenbus_device(_dev);
    3.22 +	struct backend_info *be = dev->data;
    3.23 +	return sprintf(buf, "%x:%x\n", be->major, be->minor);
    3.24 +}
    3.25 +DEVICE_ATTR(physical_device, S_IRUSR | S_IRGRP | S_IROTH,
    3.26 +	    show_physical_device, NULL);
    3.27 +
    3.28 +
    3.29 +static ssize_t show_mode(struct device *_dev, char *buf)
    3.30 +{
    3.31 +	struct xenbus_device *dev = to_xenbus_device(_dev);
    3.32 +	struct backend_info *be = dev->data;
    3.33 +	return sprintf(buf, "%s\n", be->mode);
    3.34 +}
    3.35 +DEVICE_ATTR(mode, S_IRUSR | S_IRGRP | S_IROTH, show_mode, NULL);
    3.36 +
    3.37 +
    3.38  static int blkback_remove(struct xenbus_device *dev)
    3.39  {
    3.40  	struct backend_info *be = dev->data;
    3.41 @@ -64,6 +84,10 @@ static int blkback_remove(struct xenbus_
    3.42  		blkif_put(be->blkif);
    3.43  		be->blkif = NULL;
    3.44  	}
    3.45 +
    3.46 +	device_remove_file(&dev->dev, &dev_attr_physical_device);
    3.47 +	device_remove_file(&dev->dev, &dev_attr_mode);
    3.48 +
    3.49  	kfree(be);
    3.50  	dev->data = NULL;
    3.51  	return 0;
    3.52 @@ -73,7 +97,7 @@ static int blkback_remove(struct xenbus_
    3.53  /**
    3.54   * Entry point to this code when a new device is created.  Allocate the basic
    3.55   * structures, and watch the store waiting for the hotplug scripts to tell us
    3.56 - * the device's physical-device.  Switch to InitWait.
    3.57 + * the device's physical major and minor numbers.  Switch to InitWait.
    3.58   */
    3.59  static int blkback_probe(struct xenbus_device *dev,
    3.60  			 const struct xenbus_device_id *id)
    3.61 @@ -119,65 +143,72 @@ fail:
    3.62  
    3.63  /**
    3.64   * Callback received when the hotplug scripts have placed the physical-device
    3.65 - * node.  Read it and the read-only node, and create a vbd.  If the frontend
    3.66 - * is ready, connect.
    3.67 + * node.  Read it and the mode node, and create a vbd.  If the frontend is
    3.68 + * ready, connect.
    3.69   */
    3.70  static void backend_changed(struct xenbus_watch *watch,
    3.71  			    const char **vec, unsigned int len)
    3.72  {
    3.73  	int err;
    3.74 -	char *p;
    3.75 -	long pdev;
    3.76 +	unsigned major;
    3.77 +	unsigned minor;
    3.78  	struct backend_info *be
    3.79  		= container_of(watch, struct backend_info, backend_watch);
    3.80  	struct xenbus_device *dev = be->dev;
    3.81  
    3.82  	DPRINTK("");
    3.83  
    3.84 -	err = xenbus_scanf(NULL, dev->nodename,
    3.85 -			   "physical-device", "%li", &pdev);
    3.86 +	err = xenbus_scanf(NULL, dev->nodename, "physical-device", "%x:%x",
    3.87 +			   &major, &minor);
    3.88  	if (XENBUS_EXIST_ERR(err)) {
    3.89  		/* Since this watch will fire once immediately after it is
    3.90  		   registered, we expect this.  Ignore it, and wait for the
    3.91  		   hotplug scripts. */
    3.92  		return;
    3.93  	}
    3.94 -	if (err != 1) {
    3.95 +	if (err != 2) {
    3.96  		xenbus_dev_fatal(dev, err, "reading physical-device");
    3.97  		return;
    3.98  	}
    3.99 -	if (be->pdev && be->pdev != pdev) {
   3.100 +
   3.101 +	if (be->major && be->minor &&
   3.102 +	    (be->major != major || be->minor != minor)) {
   3.103  		printk(KERN_WARNING
   3.104 -		       "blkback: changing physical-device (from %ld to %ld) "
   3.105 -		       "not supported.\n", be->pdev, pdev);
   3.106 +		       "blkback: changing physical device (from %x:%x to "
   3.107 +		       "%x:%x) not supported.\n", be->major, be->minor,
   3.108 +		       major, minor);
   3.109  		return;
   3.110  	}
   3.111  
   3.112 -	/* If there's a read-only node, we're read only. */
   3.113 -	p = xenbus_read(NULL, dev->nodename, "read-only", NULL);
   3.114 -	if (!IS_ERR(p)) {
   3.115 -		be->readonly = 1;
   3.116 -		kfree(p);
   3.117 +	be->mode = xenbus_read(NULL, dev->nodename, "mode", NULL);
   3.118 +	if (IS_ERR(be->mode)) {
   3.119 +		err = PTR_ERR(be->mode);
   3.120 +		be->mode = NULL;
   3.121 +		xenbus_dev_fatal(dev, err, "reading mode");
   3.122 +		return;
   3.123  	}
   3.124  
   3.125 -	if (be->pdev == 0L) {
   3.126 +	if (be->major == 0 && be->minor == 0) {
   3.127  		/* Front end dir is a number, which is used as the handle. */
   3.128  
   3.129 -		long handle;
   3.130 +		char *p = strrchr(dev->otherend, '/') + 1;
   3.131 +		long handle = simple_strtoul(p, NULL, 0);
   3.132  
   3.133 -		p = strrchr(dev->otherend, '/') + 1;
   3.134 -		handle = simple_strtoul(p, NULL, 0);
   3.135 +		be->major = major;
   3.136 +		be->minor = minor;
   3.137  
   3.138 -		be->pdev = pdev;
   3.139 -
   3.140 -		err = vbd_create(be->blkif, handle, be->pdev, be->readonly);
   3.141 +		err = vbd_create(be->blkif, handle, major, minor,
   3.142 +				 (NULL == strchr(be->mode, 'w')));
   3.143  		if (err) {
   3.144 -			be->pdev = 0L;
   3.145 -			xenbus_dev_fatal(dev, err,
   3.146 -					 "creating vbd structure");
   3.147 +			be->major = 0;
   3.148 +			be->minor = 0;
   3.149 +			xenbus_dev_fatal(dev, err, "creating vbd structure");
   3.150  			return;
   3.151  		}
   3.152  
   3.153 +		device_create_file(&dev->dev, &dev_attr_physical_device);
   3.154 +		device_create_file(&dev->dev, &dev_attr_mode);
   3.155 +
   3.156  		maybe_connect(be);
   3.157  	}
   3.158  }
   3.159 @@ -230,7 +261,8 @@ static void frontend_changed(struct xenb
   3.160  
   3.161  static void maybe_connect(struct backend_info *be)
   3.162  {
   3.163 -	if (be->pdev != 0L && be->blkif->status == CONNECTED)
   3.164 +	if ((be->major != 0 || be->minor != 0) &&
   3.165 +	    be->blkif->status == CONNECTED)
   3.166  		connect(be);
   3.167  }
   3.168  
     4.1 --- a/tools/examples/block	Fri Nov 25 17:12:12 2005 +0000
     4.2 +++ b/tools/examples/block	Fri Nov 25 20:58:07 2005 +0000
     4.3 @@ -3,12 +3,6 @@
     4.4  dir=$(dirname "$0")
     4.5  . "$dir/block-common.sh"
     4.6  
     4.7 -case "$command" in
     4.8 -    online | offline)
     4.9 -        exit 0
    4.10 -        ;;
    4.11 -esac
    4.12 -
    4.13  expand_dev() {
    4.14    local dev
    4.15    case $1 in
    4.16 @@ -22,21 +16,122 @@ expand_dev() {
    4.17    echo -n $dev
    4.18  }
    4.19  
    4.20 -t=$(xenstore_read_default "$XENBUS_PATH"/type "MISSING")
    4.21 +
    4.22 +##
    4.23 +# check_sharing device device_major_minor writable
    4.24 +#
    4.25 +# Check whether the device requested is already in use.  To use the device in
    4.26 +# read-only mode, it may be in use in read-only mode, but may not be in use in
    4.27 +# read-write anywhere at all.  To use the device in read-write mode, it must
    4.28 +# not be in use anywhere at all.
    4.29 +#
    4.30 +check_sharing()
    4.31 +{
    4.32 +
    4.33 +  local dev="$1"
    4.34 +  local devmm="$2"
    4.35 +  local writable="$3"
    4.36 +  local file
    4.37 +
    4.38 +  if [ "$writable" ]
    4.39 +  then
    4.40 +    toskip="^$"
    4.41 +  else
    4.42 +    toskip="^[^ ]* [^ ]* [^ ]* ro "
    4.43 +  fi
    4.44 +
    4.45 +  for file in $(cat /proc/mounts | grep -v "$toskip" | cut -f 1 -d ' ')
    4.46 +  do
    4.47 +    if [ -e "$file" ]
    4.48 +    then
    4.49 +      local d=$(device_major_minor "$file")
    4.50 +
    4.51 +      if [ "$d" == "$devmm" ]
    4.52 +      then
    4.53 +        if [ "$writable" ]
    4.54 +        then
    4.55 +          m1=""
    4.56 +          m2=""
    4.57 +        else
    4.58 +          m1="read-write "
    4.59 +          m2="read-only "
    4.60 +        fi
    4.61 +
    4.62 +        ebusy \
    4.63 +"Device $dev is mounted ${m1}in the privileged domain,
    4.64 +and so cannot be mounted ${m2}by a guest."
    4.65 +      fi
    4.66 +    fi
    4.67 +  done
    4.68 +
    4.69 +  for file in /sys/devices/xen-backend/*/physical_device
    4.70 +  do
    4.71 +    if [ -e "$file" ] # Cope with no devices, i.e. the * above did not expand.
    4.72 +    then
    4.73 +      local d=$(cat "$file")
    4.74 +      if [ "$d" == "$devmm" ]
    4.75 +      then
    4.76 +        if [ "$writable" ]
    4.77 +        then
    4.78 +          ebusy \
    4.79 +"Device $dev is already mounted in a guest domain, and so
    4.80 +cannot be mounted read-write now."
    4.81 +        else
    4.82 +          local m=$(cat "${file/physical_device/mode}")
    4.83 +
    4.84 +          if expr index "$m" 'w' >/dev/null
    4.85 +          then
    4.86 +            ebusy \
    4.87 +"Device $dev is already mounted read-write in a guest domain,
    4.88 +and so cannot be mounted read-only again."
    4.89 +          fi
    4.90 +        fi
    4.91 +      fi
    4.92 +    fi
    4.93 +  done
    4.94 +}
    4.95 +
    4.96 +
    4.97 +check_device_sharing()
    4.98 +{
    4.99 +  local dev="$1"
   4.100 +  local devmm=$(device_major_minor "$dev")
   4.101 +  local mode=$(xenstore_read "$XENBUS_PATH/mode")
   4.102 +
   4.103 +  if ! expr index "$mode" 'w' >/dev/null
   4.104 +  then
   4.105 +    # No w implies read-only use; sharing with writers must be prevented.
   4.106 +    check_sharing "$dev" "$devmm" ""
   4.107 +  elif ! expr index "$mode" '!' >/dev/null
   4.108 +  then
   4.109 +    # No exclamation mark implies all sharing must be prevented.
   4.110 +    check_sharing "$dev" "$devmm" 1
   4.111 +  fi
   4.112 +}
   4.113 +
   4.114 +
   4.115 +t=$(xenstore_read_default "$XENBUS_PATH/type" "MISSING")
   4.116  
   4.117  case "$command" in 
   4.118    add)
   4.119 -    p=$(xenstore_read "$XENBUS_PATH"/params)
   4.120 +    phys=$(xenstore_read_default "$XENBUS_PATH/physical-device" "MISSING")
   4.121 +    if [ "$phys" != "MISSING" ]
   4.122 +    then
   4.123 +      # Depending upon the hotplug configuration, it is possible for this
   4.124 +      # script to be called twice, so just bail.
   4.125 +      exit 0
   4.126 +    fi
   4.127 +    p=$(xenstore_read "$XENBUS_PATH/params")
   4.128      case $t in 
   4.129        phy)
   4.130          dev=$(expand_dev $p)
   4.131 +        check_device_sharing "$dev"
   4.132  	write_dev "$dev"
   4.133  	exit 0
   4.134  	;;
   4.135  
   4.136        file)
   4.137  	for dev in /dev/loop* ; do
   4.138 -	  echo "dev is $dev, p is $p"
   4.139  	  if losetup $dev $p; then
   4.140  	    write_dev "$dev"
   4.141              exit 0
   4.142 @@ -54,7 +149,7 @@ case "$command" in
   4.143  	;;
   4.144  
   4.145        file)
   4.146 -        node=$(xenstore_read "$XENBUS_PATH"/node)
   4.147 +        node=$(xenstore_read "$XENBUS_PATH/node")
   4.148  	losetup -d $node
   4.149  	exit 0
   4.150  	;;
     5.1 --- a/tools/examples/block-common.sh	Fri Nov 25 17:12:12 2005 +0000
     5.2 +++ b/tools/examples/block-common.sh	Fri Nov 25 20:58:07 2005 +0000
     5.3 @@ -21,9 +21,7 @@ dir=$(dirname "$0")
     5.4  
     5.5  findCommand "$@"
     5.6  
     5.7 -if [ "$command" != "online" ]  &&
     5.8 -   [ "$command" != "offline" ] &&
     5.9 -   [ "$command" != "add" ]     &&
    5.10 +if [ "$command" != "add" ] &&
    5.11     [ "$command" != "remove" ]
    5.12  then
    5.13    log err "Invalid command: $command"
    5.14 @@ -34,28 +32,42 @@ fi
    5.15  XENBUS_PATH="${XENBUS_PATH:?}"
    5.16  
    5.17  
    5.18 +ebusy()
    5.19 +{
    5.20 +  xenstore_write "$XENBUS_PATH/hotplug-status" busy
    5.21 +  xenstore_write "$XENBUS_PATH/hotplug-error" "$*"
    5.22 +  log err "$@"
    5.23 +  exit 1
    5.24 +}
    5.25 +
    5.26 +
    5.27  ##
    5.28 -# Write physical-device = 0xMMmm and node = device to the store, where MM
    5.29 -# and mm are the major and minor numbers of device.
    5.30 +# Print the given device's major and minor numbers, written in hex and
    5.31 +# separated by a colon.
    5.32 +device_major_minor()
    5.33 +{
    5.34 +  stat -L -c %t:%T "$1"
    5.35 +}
    5.36 +
    5.37 +
    5.38 +##
    5.39 +# Write physical-device = MM,mm to the store, where MM and mm are the major 
    5.40 +# and minor numbers of device respectively.
    5.41  #
    5.42  # @param device The device from which major and minor numbers are read, which
    5.43  #               will be written into the store.
    5.44  #
    5.45  write_dev() {
    5.46 -  local major
    5.47 -  local minor
    5.48 -  local pdev
    5.49 +  local mm
    5.50    
    5.51 -  major=$(stat -L -c %t "$1")
    5.52 -  minor=$(stat -L -c %T "$1")
    5.53 +  mm=$(device_major_minor "$1")
    5.54   
    5.55 -  if [ -z $major  -o -z $minor ]; then
    5.56 +  if [ -z $mm ]
    5.57 +  then
    5.58      fatal "Backend device does not exist"
    5.59    fi
    5.60   
    5.61 -  pdev=$(printf "0x%02x%02x" "0x$major" "0x$minor")
    5.62 -  xenstore_write "$XENBUS_PATH"/physical-device "$pdev" \
    5.63 -                 "$XENBUS_PATH"/node "$1"
    5.64 +  xenstore_write "$XENBUS_PATH/physical-device" "$mm"
    5.65  
    5.66    success
    5.67  }
     6.1 --- a/tools/python/xen/xend/server/DevController.py	Fri Nov 25 17:12:12 2005 +0000
     6.2 +++ b/tools/python/xen/xend/server/DevController.py	Fri Nov 25 20:58:07 2005 +0000
     6.3 @@ -27,13 +27,16 @@ from xen.xend.xenstore.xswatch import xs
     6.4  
     6.5  DEVICE_CREATE_TIMEOUT = 5
     6.6  HOTPLUG_STATUS_NODE = "hotplug-status"
     6.7 +HOTPLUG_ERROR_NODE  = "hotplug-error"
     6.8  HOTPLUG_STATUS_ERROR = "error"
     6.9 +HOTPLUG_STATUS_BUSY  = "busy"
    6.10  
    6.11  Connected = 1
    6.12  Died      = 2
    6.13  Error     = 3
    6.14  Missing   = 4
    6.15  Timeout   = 5
    6.16 +Busy      = 6
    6.17  
    6.18  xenbusState = {
    6.19      'Unknown'      : 0,
    6.20 @@ -99,7 +102,8 @@ class DevController:
    6.21                  log.debug('DevController: writing %s to %s.', str(back),
    6.22                            backpath)
    6.23  
    6.24 -                t.remove2(backpath, HOTPLUG_STATUS_NODE)
    6.25 +                t.remove(frontpath)
    6.26 +                t.remove(backpath)
    6.27  
    6.28                  t.write2(frontpath, front)
    6.29                  t.write2(backpath,  back)
    6.30 @@ -125,23 +129,37 @@ class DevController:
    6.31          if status == Timeout:
    6.32              self.destroyDevice(devid)
    6.33              raise VmError("Device %s (%s) could not be connected. "
    6.34 -                          "Hotplug scripts not working" %
    6.35 +                          "Hotplug scripts not working." %
    6.36                            (devid, self.deviceClass))
    6.37  
    6.38          elif status == Error:
    6.39              self.destroyDevice(devid)
    6.40              raise VmError("Device %s (%s) could not be connected. "
    6.41 -                          "Backend device not found" %
    6.42 +                          "Backend device not found." %
    6.43                            (devid, self.deviceClass))
    6.44  
    6.45          elif status == Missing:
    6.46              raise VmError("Device %s (%s) could not be connected. "
    6.47 -                          "Device not found" % (devid, self.deviceClass))
    6.48 +                          "Device not found." % (devid, self.deviceClass))
    6.49  
    6.50          elif status == Died:
    6.51              self.destroyDevice(devid)
    6.52              raise VmError("Device %s (%s) could not be connected. "
    6.53 -                          "Device has died" % (devid, self.deviceClass))
    6.54 +                          "Device has died." % (devid, self.deviceClass))
    6.55 +
    6.56 +        elif status == Busy:
    6.57 +            err = None
    6.58 +            frontpath = self.frontendPath(devid)
    6.59 +            backpath = xstransact.Read(frontpath, "backend")
    6.60 +            if backpath:
    6.61 +                err = xstransact.Read(backpath, HOTPLUG_ERROR_NODE)
    6.62 +            if not err:
    6.63 +                err = "Busy."
    6.64 +                
    6.65 +            self.destroyDevice(devid)
    6.66 +            raise VmError("Device %s (%s) could not be connected.\n%s" %
    6.67 +                          (devid, self.deviceClass, err))
    6.68 +
    6.69  
    6.70  
    6.71      def reconfigureDevice(self, devid, config):
    6.72 @@ -384,6 +402,8 @@ def hotplugStatusCallback(statusPath, ev
    6.73          if status is not None:
    6.74              if status == HOTPLUG_STATUS_ERROR:
    6.75                  result['status'] = Error
    6.76 +            elif status == HOTPLUG_STATUS_BUSY:
    6.77 +                result['status'] = Busy
    6.78              else:
    6.79                  result['status'] = Connected
    6.80          else:
     7.1 --- a/tools/python/xen/xend/server/blkif.py	Fri Nov 25 17:12:12 2005 +0000
     7.2 +++ b/tools/python/xen/xend/server/blkif.py	Fri Nov 25 20:58:07 2005 +0000
     7.3 @@ -48,14 +48,12 @@ class BlkifController(DevController):
     7.4          devid = blkif.blkdev_name_to_number(dev)
     7.5  
     7.6          (typ, params) = string.split(sxp.child_value(config, 'uname'), ':', 1)
     7.7 -        back = { 'dev' : dev,
     7.8 -                 'type' : typ,
     7.9 -                 'params' : params
    7.10 +        back = { 'dev'    : dev,
    7.11 +                 'type'   : typ,
    7.12 +                 'params' : params,
    7.13 +                 'mode'   : sxp.child_value(config, 'mode', 'r')
    7.14                   }
    7.15  
    7.16 -        if 'r' == sxp.child_value(config, 'mode', 'r'):
    7.17 -            back['read-only'] = ""  # existence indicates read-only
    7.18 -
    7.19          front = { 'virtual-device' : "%i" % devid }
    7.20  
    7.21          return (devid, back, front)
    7.22 @@ -66,18 +64,16 @@ class BlkifController(DevController):
    7.23  
    7.24          result = DevController.configuration(self, devid)
    7.25  
    7.26 -        (dev, typ, params, ro) = self.readBackend(devid,
    7.27 -                                                  'dev', 'type', 'params',
    7.28 -                                                  'read-only')
    7.29 +        (dev, typ, params, mode) = self.readBackend(devid,
    7.30 +                                                    'dev', 'type', 'params',
    7.31 +                                                    'mode')
    7.32  
    7.33          if dev:
    7.34              result.append(['dev', dev])
    7.35          if typ and params:
    7.36              result.append(['uname', typ + ":" + params])
    7.37 -        if ro:
    7.38 -            result.append(['mode', 'r'])
    7.39 -        else:
    7.40 -            result.append(['mode', 'w'])
    7.41 +        if mode:
    7.42 +            result.append(['mode', mode])
    7.43  
    7.44          return result
    7.45