debuggers.hg

view tools/hotplug/Linux/block @ 20993:4a4caf3c052d

hotplug: ignore xenstore-read error

The failure to read "backend/tap/<domid>/*" in the xenstore is a usual
case since the domain is gone after xenstore-ls command is executed.
The error should be ignored.

Signed-off-by: Kouya Shimura <kouya@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Feb 16 09:28:39 2010 +0000 (2010-02-16)
parents c3d3e3c8e5f4
children 611a36481e92
line source
1 #!/bin/bash
3 dir=$(dirname "$0")
4 . "$dir/block-common.sh"
6 expand_dev() {
7 local dev
8 case $1 in
9 /*)
10 dev=$1
11 ;;
12 *)
13 dev=/dev/$1
14 ;;
15 esac
16 echo -n $dev
17 }
19 find_free_loopback_helper() {
20 local next_devnum=0
21 local busy_devnum
22 while read busy_devnum; do
23 if [ "$next_devnum" != "$busy_devnum" ]; then
24 break
25 fi
26 let next_devnum=$next_devnum+1
27 done
28 echo "/dev/loop${next_devnum}"
29 }
31 # Not all distros have "losetup -f"
32 find_free_loopback_dev() {
33 local loopdev
34 loopdev=$(losetup -a | sed -e 's+^/dev/loop++' -e 's/:.*//' | find_free_loopback_helper)
35 if [ -n "$loopdev" ] && [ -b "$loopdev" ]; then
36 echo "$loopdev"
37 fi
38 }
40 ##
41 # check_sharing device mode
42 #
43 # Check whether the device requested is already in use. To use the device in
44 # read-only mode, it may be in use in read-only mode, but may not be in use in
45 # read-write anywhere at all. To use the device in read-write mode, it must
46 # not be in use anywhere at all.
47 #
48 # Prints one of
49 #
50 # 'local': the device may not be used because it is mounted in the current
51 # (i.e. the privileged domain) in a way incompatible with the
52 # requested mode;
53 # 'guest': the device may not be used because it already mounted by a guest
54 # in a way incompatible with the requested mode; or
55 # 'ok': the device may be used.
56 #
57 check_sharing()
58 {
59 local dev="$1"
60 local mode="$2"
62 local devmm=$(device_major_minor "$dev")
63 local file
65 if [ "$mode" = 'w' ]
66 then
67 toskip="^$"
68 else
69 toskip="^[^ ]* [^ ]* [^ ]* ro[, ]"
70 fi
72 for file in $(cat /proc/mounts | grep -v "$toskip" | cut -f 1 -d ' ')
73 do
74 if [ -e "$file" ]
75 then
76 local d=$(device_major_minor "$file")
78 if [ "$d" = "$devmm" ]
79 then
80 echo 'local'
81 return
82 fi
83 fi
84 done
86 local base_path="$XENBUS_BASE_PATH/$XENBUS_TYPE"
87 for dom in $(xenstore-list "$base_path")
88 do
89 for dev in $(xenstore-list "$base_path/$dom")
90 do
91 d=$(xenstore_read_default "$base_path/$dom/$dev/physical-device" "")
93 if [ "$d" = "$devmm" ]
94 then
95 if [ "$mode" = 'w' ]
96 then
97 if ! same_vm $dom
98 then
99 echo 'guest'
100 return
101 fi
102 else
103 local m=$(xenstore_read_default "$base_path/$dom/$dev/mode" "")
104 m=$(canonicalise_mode "$m")
106 if [ "$m" = 'w' ]
107 then
108 if ! same_vm $dom
109 then
110 echo 'guest'
111 return
112 fi
113 fi
114 fi
115 fi
116 done
117 done
119 echo 'ok'
120 }
123 ##
124 # check_device_sharing dev mode
125 #
126 # Perform the sharing check for the given physical device and mode.
127 #
128 check_device_sharing()
129 {
130 local dev="$1"
131 local mode=$(canonicalise_mode "$2")
132 local result
134 if [ "x$mode" = 'x!' ]
135 then
136 return 0
137 fi
139 result=$(check_sharing "$dev" "$mode")
141 if [ "$result" != 'ok' ]
142 then
143 do_ebusy "Device $dev is mounted " "$mode" "$result"
144 fi
145 }
148 ##
149 # check_device_sharing file dev mode
150 #
151 # Perform the sharing check for the given file mounted through the given
152 # loopback interface, in the given mode.
153 #
154 check_file_sharing()
155 {
156 local file="$1"
157 local dev="$2"
158 local mode="$3"
160 result=$(check_sharing "$dev" "$mode")
162 if [ "$result" != 'ok' ]
163 then
164 do_ebusy "File $file is loopback-mounted through $dev,
165 which is mounted " "$mode" "$result"
166 fi
167 }
170 ##
171 # do_ebusy prefix mode result
172 #
173 # Helper function for check_device_sharing check_file_sharing, calling ebusy
174 # with an error message constructed from the given prefix, mode, and result
175 # from a call to check_sharing.
176 #
177 do_ebusy()
178 {
179 local prefix="$1"
180 local mode="$2"
181 local result="$3"
183 if [ "$result" = 'guest' ]
184 then
185 dom='a guest '
186 when='now'
187 else
188 dom='the privileged '
189 when='by a guest'
190 fi
192 if [ "$mode" = 'w' ]
193 then
194 m1=''
195 m2=''
196 else
197 m1='read-write '
198 m2='read-only '
199 fi
201 release_lock "block"
202 ebusy \
203 "${prefix}${m1}in ${dom}domain,
204 and so cannot be mounted ${m2}${when}."
205 }
208 t=$(xenstore_read_default "$XENBUS_PATH/type" 'MISSING')
210 case "$command" in
211 add)
212 phys=$(xenstore_read_default "$XENBUS_PATH/physical-device" 'MISSING')
213 if [ "$phys" != 'MISSING' ]
214 then
215 # Depending upon the hotplug configuration, it is possible for this
216 # script to be called twice, so just bail.
217 exit 0
218 fi
220 if [ -n "$t" ]
221 then
222 p=$(xenstore_read "$XENBUS_PATH/params")
223 mode=$(xenstore_read "$XENBUS_PATH/mode")
224 fi
225 FRONTEND_ID=$(xenstore_read "$XENBUS_PATH/frontend-id")
226 FRONTEND_UUID=$(xenstore_read_default \
227 "/local/domain/$FRONTEND_ID/vm" 'unknown')
229 case $t in
230 phy)
231 dev=$(expand_dev $p)
233 if [ -L "$dev" ]
234 then
235 dev=$(readlink -f "$dev") || fatal "$dev link does not exist."
236 fi
237 test -e "$dev" || fatal "$dev does not exist."
238 test -b "$dev" || fatal "$dev is not a block device."
240 claim_lock "block"
241 check_device_sharing "$dev" "$mode"
242 write_dev "$dev"
243 release_lock "block"
244 exit 0
245 ;;
247 file)
248 # Canonicalise the file, for sharing check comparison, and the mode
249 # for ease of use here.
250 file=$(readlink -f "$p") || fatal "$p does not exist."
251 test -f "$file" || fatal "$file does not exist."
252 mode=$(canonicalise_mode "$mode")
254 claim_lock "block"
256 # Avoid a race with the remove if the path has been deleted, or
257 # otherwise changed from "InitWait" state e.g. due to a timeout
258 xenbus_state=$(xenstore_read_default "$XENBUS_PATH/state" 'unknown')
259 if [ "$xenbus_state" != '2' ]
260 then
261 release_lock "block"
262 fatal "Path closed or removed during hotplug add: $XENBUS_PATH state: $xenbus_state"
263 fi
265 if [ "$mode" = 'w' ] && ! stat "$file" -c %A | grep -q w
266 then
267 release_lock "block"
268 ebusy \
269 "File $file is read-only, and so I will not
270 mount it read-write in a guest domain."
271 fi
273 if [ "x$mode" != 'x!' ]
274 then
275 inode=$(stat -c '%i' $file)
276 dev=$(stat -c '%D' $file)
277 if [ -z "$inode" ] || [ -z "$dev" ]
278 then
279 fatal "Unable to lookup $file: dev: $dev inode: $inode"
280 fi
282 shared_list=$(losetup -a | grep ' \[0*'${dev}'\]:'${inode} |
283 cut -d : -f 1)
284 for dev in "$shared_list"
285 do
286 if [ -n "$dev" ]
287 then
288 check_file_sharing "$file" "$dev" "$mode"
289 fi
290 done
291 fi
293 loopdev=$(losetup -f 2>/dev/null || find_free_loopback_dev)
294 if [ "$loopdev" = '' ]
295 then
296 release_lock "block"
297 fatal 'Failed to find an unused loop device'
298 fi
300 if LANG=C losetup -h 2>&1 | grep read-only >/dev/null
301 then
302 roflag="-$mode"; roflag="${roflag#-w}"; roflag="${roflag#-!}"
303 else
304 roflag=''
305 fi
306 do_or_die losetup $roflag "$loopdev" "$file"
307 xenstore_write "$XENBUS_PATH/node" "$loopdev"
308 write_dev "$loopdev"
309 release_lock "block"
310 exit 0
311 ;;
313 "")
314 claim_lock "block"
315 success
316 release_lock "block"
317 ;;
318 esac
319 ;;
321 remove)
322 case $t in
323 phy)
324 exit 0
325 ;;
327 file)
328 claim_lock "block"
329 node=$(xenstore_read "$XENBUS_PATH/node")
330 losetup -d "$node"
331 release_lock "block"
332 exit 0
333 ;;
335 "")
336 exit 0
337 ;;
338 esac
339 ;;
341 esac
343 # If we've reached here, $t is neither phy nor file, so fire a helper script.
344 [ -x ${XEN_SCRIPT_DIR}/block-"$t" ] && \
345 ${XEN_SCRIPT_DIR}/block-"$t" "$command" $node