ia64/xen-unstable

changeset 8196:485871ff1d39

Fix the block-sharing check for physical devices by using a lock to serialise
the check, reading from the store rather than /sys, and checking whether the
VM for apparently-conflicting uses is actually the same (i.e. this is a
migration or a reboot in progress).

This fixes recent failures in 12_block_attach_shared_domU and recloses bug #331.

This fix includes particularly skanky path slicing inside xenbus_probe, which
it would be nice to remove very soon.

The loopback device check still suffers from the problem that filenames over
64 characters long are truncated.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Fri Dec 02 15:48:44 2005 +0000 (2005-12-02)
parents df011cae33e9
children 30eb074a560a
files linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c tools/examples/block
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c	Fri Dec 02 15:39:13 2005 +0000
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c	Fri Dec 02 15:48:44 2005 +0000
     1.3 @@ -59,6 +59,8 @@ extern struct semaphore xenwatch_mutex;
     1.4  
     1.5  #define streq(a, b) (strcmp((a), (b)) == 0)
     1.6  
     1.7 +static char *kasprintf(const char *fmt, ...);
     1.8 +
     1.9  static struct notifier_block *xenstore_chain;
    1.10  
    1.11  /* If something in array of ids matches this device, return it. */
    1.12 @@ -226,8 +228,11 @@ static int xenbus_hotplug_backend(struct
    1.13  				  int num_envp, char *buffer, int buffer_size)
    1.14  {
    1.15  	struct xenbus_device *xdev;
    1.16 +	struct xenbus_driver *drv = NULL;
    1.17  	int i = 0;
    1.18  	int length = 0;
    1.19 +	char *basepath_end;
    1.20 +	char *frontend_id;
    1.21  
    1.22  	DPRINTK("");
    1.23  
    1.24 @@ -238,6 +243,9 @@ static int xenbus_hotplug_backend(struct
    1.25  	if (xdev == NULL)
    1.26  		return -ENODEV;
    1.27  
    1.28 +	if (dev->driver)
    1.29 +		drv = to_xenbus_driver(dev->driver);
    1.30 +
    1.31  	/* stuff we want to pass to /sbin/hotplug */
    1.32  	add_hotplug_env_var(envp, num_envp, &i,
    1.33  			    buffer, buffer_size, &length,
    1.34 @@ -247,6 +255,25 @@ static int xenbus_hotplug_backend(struct
    1.35  			    buffer, buffer_size, &length,
    1.36  			    "XENBUS_PATH=%s", xdev->nodename);
    1.37  
    1.38 +	add_hotplug_env_var(envp, num_envp, &i,
    1.39 +			    buffer, buffer_size, &length,
    1.40 +			    "XENBUS_BASE_PATH=%s", xdev->nodename);
    1.41 +
    1.42 +	basepath_end = strrchr(envp[i - 1], '/');
    1.43 +	length -= strlen(basepath_end);
    1.44 +	*basepath_end = '\0';
    1.45 +	basepath_end = strrchr(envp[i - 1], '/');
    1.46 +	length -= strlen(basepath_end);
    1.47 +	*basepath_end = '\0';
    1.48 +
    1.49 +	basepath_end++;
    1.50 +	frontend_id = kmalloc(strlen(basepath_end) + 1, GFP_KERNEL);
    1.51 +	strcpy(frontend_id, basepath_end);
    1.52 +	add_hotplug_env_var(envp, num_envp, &i,
    1.53 +			    buffer, buffer_size, &length,
    1.54 +			    "XENBUS_FRONTEND_ID=%s", frontend_id);
    1.55 +	kfree(frontend_id);
    1.56 +
    1.57  	/* terminate, set to next free slot, shrink available space */
    1.58  	envp[i] = NULL;
    1.59  	envp = &envp[i];
    1.60 @@ -254,9 +281,9 @@ static int xenbus_hotplug_backend(struct
    1.61  	buffer = &buffer[length];
    1.62  	buffer_size -= length;
    1.63  
    1.64 -	if (dev->driver && to_xenbus_driver(dev->driver)->hotplug)
    1.65 -		return to_xenbus_driver(dev->driver)->hotplug
    1.66 -			(xdev, envp, num_envp, buffer, buffer_size);
    1.67 +	if (drv && drv->hotplug)
    1.68 +		return drv->hotplug(xdev, envp, num_envp, buffer,
    1.69 +				    buffer_size);
    1.70  
    1.71  	return 0;
    1.72  }
     2.1 --- a/tools/examples/block	Fri Dec 02 15:39:13 2005 +0000
     2.2 +++ b/tools/examples/block	Fri Dec 02 15:48:44 2005 +0000
     2.3 @@ -89,39 +89,54 @@ check_sharing()
     2.4      fi
     2.5    done
     2.6  
     2.7 -##
     2.8 -## XXX SMH: the below causes live migration on localhost to fail sometimes
     2.9 -## since the source domain may still appear to be using a local device. 
    2.10 -## For now simply comment it out - a proper fix will come in due course. 
    2.11 +  for dom in $(xenstore-list "$XENBUS_BASE_PATH")
    2.12 +  do
    2.13 +    for dev in $(xenstore-list "$XENBUS_BASE_PATH/$dom")
    2.14 +    do
    2.15 +      d=$(xenstore_read_default \
    2.16 +            "$XENBUS_BASE_PATH/$dom/$dev/physical-device" "")
    2.17  
    2.18 -#   for file in /sys/devices/xen-backend/*/physical_device
    2.19 -#   do
    2.20 -#     if [ -e "$file" ] # Cope with no devices, i.e. the * above did not expand.
    2.21 -#     then
    2.22 -#       local d=$(cat "$file")
    2.23 -#       if [ "$d" == "$devmm" ]
    2.24 -#       then
    2.25 -#         if [ "$mode" == 'w' ]
    2.26 -#         then
    2.27 -#           echo 'guest'
    2.28 -#           return
    2.29 -#         else
    2.30 -#           local m=$(cat "${file/physical_device/mode}")
    2.31 +      if [ "$d" == "$devmm" ]
    2.32 +      then
    2.33 +        if [ "$mode" == 'w' ]
    2.34 +        then
    2.35 +          if ! same_vm $dom
    2.36 +          then
    2.37 +            echo 'guest'
    2.38 +            return
    2.39 +          fi
    2.40 +        else
    2.41 +          local m=$(xenstore_read "$XENBUS_BASE_PATH/$dom/$dev/mode")
    2.42 +          m=$(canonicalise_mode "$m")
    2.43  
    2.44 -#           if expr index "$m" 'w' >/dev/null
    2.45 -#           then
    2.46 -#             echo 'guest'
    2.47 -#             return
    2.48 -#           fi
    2.49 -#         fi
    2.50 -#       fi
    2.51 -#     fi
    2.52 -#   done
    2.53 +          if [ "$m" == 'w' ]
    2.54 +          then
    2.55 +            if ! same_vm $dom
    2.56 +            then
    2.57 +              echo 'guest'
    2.58 +              return
    2.59 +            fi
    2.60 +          fi
    2.61 +        fi
    2.62 +      fi
    2.63 +    done
    2.64 +  done
    2.65  
    2.66    echo 'ok'
    2.67  }
    2.68  
    2.69  
    2.70 +same_vm()
    2.71 +{
    2.72 +  local thisdom="$XENBUS_FRONTEND_ID"
    2.73 +  local otherdom="$1"
    2.74 +  local thisvm=$(xenstore-read "/local/domain/$thisdom/vm")
    2.75 +  local othervm=$(xenstore-read "/local/domain/otherdom/vm")
    2.76 +
    2.77 +  return [ "$thisvm" == "$othervm" ]
    2.78 +}
    2.79 +
    2.80 +
    2.81  ##
    2.82  # check_device_sharing dev mode
    2.83  #
    2.84 @@ -200,6 +215,7 @@ do_ebusy()
    2.85      m2='read-only '
    2.86    fi
    2.87  
    2.88 +  release_lock "block"
    2.89    ebusy \
    2.90  "${prefix}${m1}in ${dom}domain,
    2.91  and so cannot be mounted ${m2}${when}."
    2.92 @@ -224,8 +240,10 @@ case "$command" in
    2.93      case $t in 
    2.94        phy)
    2.95          dev=$(expand_dev $p)
    2.96 +        claim_lock "block"
    2.97          check_device_sharing "$dev" "$mode"
    2.98  	write_dev "$dev"
    2.99 +        release_lock "block"
   2.100  	exit 0
   2.101  	;;
   2.102  
   2.103 @@ -235,68 +253,62 @@ case "$command" in
   2.104          file=$(readlink -f "$p")
   2.105          mode=$(canonicalise_mode "$mode")
   2.106  
   2.107 +        claim_lock "block"
   2.108 +
   2.109          if [ "$mode" == 'w' ] && ! stat "$file" -c %A | grep -q w
   2.110          then
   2.111 +          release_lock "block"
   2.112            ebusy \
   2.113  "File $file is read-only, and so I will not
   2.114  mount it read-write in a guest domain."
   2.115          fi
   2.116  
   2.117 +        loopdev=''
   2.118 +        for dev in /dev/loop*
   2.119 +        do
   2.120 +          if [ ! -b "$dev" ]
   2.121 +          then
   2.122 +            continue
   2.123 +          fi
   2.124  
   2.125 -	while true
   2.126 -        do 
   2.127 -          loopdev=''
   2.128 -          for dev in /dev/loop*
   2.129 -          do
   2.130 -            if [ ! -b "$dev" ]
   2.131 +          f=$(losetup "$dev" 2>/dev/null) || f='()'
   2.132 +          f=$(echo "$f" | sed -e 's/.*(\(.*\)).*/\1/g')
   2.133 +
   2.134 +          if [ "$f" ]
   2.135 +          then
   2.136 +            # $dev is in use.  Check sharing.
   2.137 +            if [ "$mode" == '!' ]
   2.138              then
   2.139                continue
   2.140              fi
   2.141  
   2.142 -            f=$(losetup "$dev" 2>/dev/null) || f='()'
   2.143 -            f=$(echo "$f" | sed -e 's/.*(\(.*\)).*/\1/g')
   2.144 +            f=$(readlink -f "$f")
   2.145  
   2.146 -            log err "$file $f $dev"
   2.147 -
   2.148 -            if [ "$f" ]
   2.149 +            if [ "$f" == "$file" ]
   2.150              then
   2.151 -              # $dev is in use.  Check sharing.
   2.152 -              if [ "$mode" == '!' ]
   2.153 -              then
   2.154 -                continue
   2.155 -              fi
   2.156 -
   2.157 -              f=$(readlink -f "$f")
   2.158 +              check_file_sharing "$file" "$dev" "$mode"
   2.159 +            fi
   2.160 +          else
   2.161 +            # $dev is not in use, so we'll remember it for use later; we want
   2.162 +            # to finish the sharing check first.
   2.163  
   2.164 -              if [ "$f" == "$file" ]
   2.165 -              then
   2.166 -                check_file_sharing "$file" "$dev" "$mode"
   2.167 -              fi
   2.168 -            else
   2.169 -              # $dev is not in use, so we'll remember it for use later; we want
   2.170 -              # to finish the sharing check first.
   2.171 -              
   2.172 -              if [ "$loopdev" == '' ]
   2.173 -              then
   2.174 -                loopdev="$dev"
   2.175 -              fi
   2.176 +            if [ "$loopdev" == '' ]
   2.177 +            then
   2.178 +              loopdev="$dev"
   2.179              fi
   2.180 -          done
   2.181 +          fi
   2.182 +        done
   2.183  
   2.184 -          if [ "$loopdev" == '' ]
   2.185 -          then
   2.186 -            fatal 'Failed to find an unused loop device'
   2.187 -          fi
   2.188 -          if losetup "$loopdev" "$file"
   2.189 -          then
   2.190 -	    log err "mapped $file using $loopdev"
   2.191 -            xenstore_write "$XENBUS_PATH/node" "$loopdev"
   2.192 -            write_dev "$loopdev"
   2.193 -            exit 0
   2.194 -          else
   2.195 -            log err "losetup $loopdev $file failed, retry"
   2.196 -          fi
   2.197 -	done
   2.198 +        if [ "$loopdev" == '' ]
   2.199 +        then
   2.200 +          fatal 'Failed to find an unused loop device'
   2.201 +        fi
   2.202 +
   2.203 +        do_or_die losetup "$loopdev" "$file"
   2.204 +        xenstore_write "$XENBUS_PATH/node" "$loopdev"
   2.205 +        write_dev "$loopdev"
   2.206 +        release_lock "block"
   2.207 +        exit 0
   2.208  	;;
   2.209      esac
   2.210      ;;