diff options
Diffstat (limited to 'drivers/xen/xenbus/xenbus_probe_frontend.c')
-rw-r--r-- | drivers/xen/xenbus/xenbus_probe_frontend.c | 206 |
1 files changed, 21 insertions, 185 deletions
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 3159a37d966..ed2ba474a56 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/kthread.h> | 13 | #include <linux/kthread.h> |
14 | #include <linux/mutex.h> | 14 | #include <linux/mutex.h> |
15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
16 | #include <linux/module.h> | ||
17 | 16 | ||
18 | #include <asm/page.h> | 17 | #include <asm/page.h> |
19 | #include <asm/pgtable.h> | 18 | #include <asm/pgtable.h> |
@@ -21,7 +20,6 @@ | |||
21 | #include <xen/xenbus.h> | 20 | #include <xen/xenbus.h> |
22 | #include <xen/events.h> | 21 | #include <xen/events.h> |
23 | #include <xen/page.h> | 22 | #include <xen/page.h> |
24 | #include <xen/xen.h> | ||
25 | 23 | ||
26 | #include <xen/platform_pci.h> | 24 | #include <xen/platform_pci.h> |
27 | 25 | ||
@@ -54,12 +52,6 @@ static int xenbus_probe_frontend(struct xen_bus_type *bus, const char *type, | |||
54 | char *nodename; | 52 | char *nodename; |
55 | int err; | 53 | int err; |
56 | 54 | ||
57 | /* ignore console/0 */ | ||
58 | if (!strncmp(type, "console", 7) && !strncmp(name, "0", 1)) { | ||
59 | DPRINTK("Ignoring buggy device entry console/0"); | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", bus->root, type, name); | 55 | nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", bus->root, type, name); |
64 | if (!nodename) | 56 | if (!nodename) |
65 | return -ENOMEM; | 57 | return -ENOMEM; |
@@ -136,7 +128,7 @@ static int read_backend_details(struct xenbus_device *xendev) | |||
136 | return xenbus_read_otherend_details(xendev, "backend-id", "backend"); | 128 | return xenbus_read_otherend_details(xendev, "backend-id", "backend"); |
137 | } | 129 | } |
138 | 130 | ||
139 | static int is_device_connecting(struct device *dev, void *data, bool ignore_nonessential) | 131 | static int is_device_connecting(struct device *dev, void *data) |
140 | { | 132 | { |
141 | struct xenbus_device *xendev = to_xenbus_device(dev); | 133 | struct xenbus_device *xendev = to_xenbus_device(dev); |
142 | struct device_driver *drv = data; | 134 | struct device_driver *drv = data; |
@@ -153,41 +145,16 @@ static int is_device_connecting(struct device *dev, void *data, bool ignore_none | |||
153 | if (drv && (dev->driver != drv)) | 145 | if (drv && (dev->driver != drv)) |
154 | return 0; | 146 | return 0; |
155 | 147 | ||
156 | if (ignore_nonessential) { | ||
157 | /* With older QEMU, for PVonHVM guests the guest config files | ||
158 | * could contain: vfb = [ 'vnc=1, vnclisten=0.0.0.0'] | ||
159 | * which is nonsensical as there is no PV FB (there can be | ||
160 | * a PVKB) running as HVM guest. */ | ||
161 | |||
162 | if ((strncmp(xendev->nodename, "device/vkbd", 11) == 0)) | ||
163 | return 0; | ||
164 | |||
165 | if ((strncmp(xendev->nodename, "device/vfb", 10) == 0)) | ||
166 | return 0; | ||
167 | } | ||
168 | xendrv = to_xenbus_driver(dev->driver); | 148 | xendrv = to_xenbus_driver(dev->driver); |
169 | return (xendev->state < XenbusStateConnected || | 149 | return (xendev->state < XenbusStateConnected || |
170 | (xendev->state == XenbusStateConnected && | 150 | (xendev->state == XenbusStateConnected && |
171 | xendrv->is_ready && !xendrv->is_ready(xendev))); | 151 | xendrv->is_ready && !xendrv->is_ready(xendev))); |
172 | } | 152 | } |
173 | static int essential_device_connecting(struct device *dev, void *data) | ||
174 | { | ||
175 | return is_device_connecting(dev, data, true /* ignore PV[KBB+FB] */); | ||
176 | } | ||
177 | static int non_essential_device_connecting(struct device *dev, void *data) | ||
178 | { | ||
179 | return is_device_connecting(dev, data, false); | ||
180 | } | ||
181 | 153 | ||
182 | static int exists_essential_connecting_device(struct device_driver *drv) | 154 | static int exists_connecting_device(struct device_driver *drv) |
183 | { | 155 | { |
184 | return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, | 156 | return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, |
185 | essential_device_connecting); | 157 | is_device_connecting); |
186 | } | ||
187 | static int exists_non_essential_connecting_device(struct device_driver *drv) | ||
188 | { | ||
189 | return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, | ||
190 | non_essential_device_connecting); | ||
191 | } | 158 | } |
192 | 159 | ||
193 | static int print_device_status(struct device *dev, void *data) | 160 | static int print_device_status(struct device *dev, void *data) |
@@ -218,23 +185,6 @@ static int print_device_status(struct device *dev, void *data) | |||
218 | /* We only wait for device setup after most initcalls have run. */ | 185 | /* We only wait for device setup after most initcalls have run. */ |
219 | static int ready_to_wait_for_devices; | 186 | static int ready_to_wait_for_devices; |
220 | 187 | ||
221 | static bool wait_loop(unsigned long start, unsigned int max_delay, | ||
222 | unsigned int *seconds_waited) | ||
223 | { | ||
224 | if (time_after(jiffies, start + (*seconds_waited+5)*HZ)) { | ||
225 | if (!*seconds_waited) | ||
226 | printk(KERN_WARNING "XENBUS: Waiting for " | ||
227 | "devices to initialise: "); | ||
228 | *seconds_waited += 5; | ||
229 | printk("%us...", max_delay - *seconds_waited); | ||
230 | if (*seconds_waited == max_delay) | ||
231 | return true; | ||
232 | } | ||
233 | |||
234 | schedule_timeout_interruptible(HZ/10); | ||
235 | |||
236 | return false; | ||
237 | } | ||
238 | /* | 188 | /* |
239 | * On a 5-minute timeout, wait for all devices currently configured. We need | 189 | * On a 5-minute timeout, wait for all devices currently configured. We need |
240 | * to do this to guarantee that the filesystems and / or network devices | 190 | * to do this to guarantee that the filesystems and / or network devices |
@@ -258,14 +208,19 @@ static void wait_for_devices(struct xenbus_driver *xendrv) | |||
258 | if (!ready_to_wait_for_devices || !xen_domain()) | 208 | if (!ready_to_wait_for_devices || !xen_domain()) |
259 | return; | 209 | return; |
260 | 210 | ||
261 | while (exists_non_essential_connecting_device(drv)) | 211 | while (exists_connecting_device(drv)) { |
262 | if (wait_loop(start, 30, &seconds_waited)) | 212 | if (time_after(jiffies, start + (seconds_waited+5)*HZ)) { |
263 | break; | 213 | if (!seconds_waited) |
264 | 214 | printk(KERN_WARNING "XENBUS: Waiting for " | |
265 | /* Skips PVKB and PVFB check.*/ | 215 | "devices to initialise: "); |
266 | while (exists_essential_connecting_device(drv)) | 216 | seconds_waited += 5; |
267 | if (wait_loop(start, 270, &seconds_waited)) | 217 | printk("%us...", 300 - seconds_waited); |
268 | break; | 218 | if (seconds_waited == 300) |
219 | break; | ||
220 | } | ||
221 | |||
222 | schedule_timeout_interruptible(HZ/10); | ||
223 | } | ||
269 | 224 | ||
270 | if (seconds_waited) | 225 | if (seconds_waited) |
271 | printk("\n"); | 226 | printk("\n"); |
@@ -274,13 +229,15 @@ static void wait_for_devices(struct xenbus_driver *xendrv) | |||
274 | print_device_status); | 229 | print_device_status); |
275 | } | 230 | } |
276 | 231 | ||
277 | int xenbus_register_frontend(struct xenbus_driver *drv) | 232 | int __xenbus_register_frontend(struct xenbus_driver *drv, |
233 | struct module *owner, const char *mod_name) | ||
278 | { | 234 | { |
279 | int ret; | 235 | int ret; |
280 | 236 | ||
281 | drv->read_otherend_details = read_backend_details; | 237 | drv->read_otherend_details = read_backend_details; |
282 | 238 | ||
283 | ret = xenbus_register_driver_common(drv, &xenbus_frontend); | 239 | ret = xenbus_register_driver_common(drv, &xenbus_frontend, |
240 | owner, mod_name); | ||
284 | if (ret) | 241 | if (ret) |
285 | return ret; | 242 | return ret; |
286 | 243 | ||
@@ -289,133 +246,12 @@ int xenbus_register_frontend(struct xenbus_driver *drv) | |||
289 | 246 | ||
290 | return 0; | 247 | return 0; |
291 | } | 248 | } |
292 | EXPORT_SYMBOL_GPL(xenbus_register_frontend); | 249 | EXPORT_SYMBOL_GPL(__xenbus_register_frontend); |
293 | |||
294 | static DECLARE_WAIT_QUEUE_HEAD(backend_state_wq); | ||
295 | static int backend_state; | ||
296 | |||
297 | static void xenbus_reset_backend_state_changed(struct xenbus_watch *w, | ||
298 | const char **v, unsigned int l) | ||
299 | { | ||
300 | xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i", &backend_state); | ||
301 | printk(KERN_DEBUG "XENBUS: backend %s %s\n", | ||
302 | v[XS_WATCH_PATH], xenbus_strstate(backend_state)); | ||
303 | wake_up(&backend_state_wq); | ||
304 | } | ||
305 | |||
306 | static void xenbus_reset_wait_for_backend(char *be, int expected) | ||
307 | { | ||
308 | long timeout; | ||
309 | timeout = wait_event_interruptible_timeout(backend_state_wq, | ||
310 | backend_state == expected, 5 * HZ); | ||
311 | if (timeout <= 0) | ||
312 | printk(KERN_INFO "XENBUS: backend %s timed out.\n", be); | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * Reset frontend if it is in Connected or Closed state. | ||
317 | * Wait for backend to catch up. | ||
318 | * State Connected happens during kdump, Closed after kexec. | ||
319 | */ | ||
320 | static void xenbus_reset_frontend(char *fe, char *be, int be_state) | ||
321 | { | ||
322 | struct xenbus_watch be_watch; | ||
323 | |||
324 | printk(KERN_DEBUG "XENBUS: backend %s %s\n", | ||
325 | be, xenbus_strstate(be_state)); | ||
326 | |||
327 | memset(&be_watch, 0, sizeof(be_watch)); | ||
328 | be_watch.node = kasprintf(GFP_NOIO | __GFP_HIGH, "%s/state", be); | ||
329 | if (!be_watch.node) | ||
330 | return; | ||
331 | |||
332 | be_watch.callback = xenbus_reset_backend_state_changed; | ||
333 | backend_state = XenbusStateUnknown; | ||
334 | |||
335 | printk(KERN_INFO "XENBUS: triggering reconnect on %s\n", be); | ||
336 | register_xenbus_watch(&be_watch); | ||
337 | |||
338 | /* fall through to forward backend to state XenbusStateInitialising */ | ||
339 | switch (be_state) { | ||
340 | case XenbusStateConnected: | ||
341 | xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosing); | ||
342 | xenbus_reset_wait_for_backend(be, XenbusStateClosing); | ||
343 | |||
344 | case XenbusStateClosing: | ||
345 | xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosed); | ||
346 | xenbus_reset_wait_for_backend(be, XenbusStateClosed); | ||
347 | |||
348 | case XenbusStateClosed: | ||
349 | xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateInitialising); | ||
350 | xenbus_reset_wait_for_backend(be, XenbusStateInitWait); | ||
351 | } | ||
352 | |||
353 | unregister_xenbus_watch(&be_watch); | ||
354 | printk(KERN_INFO "XENBUS: reconnect done on %s\n", be); | ||
355 | kfree(be_watch.node); | ||
356 | } | ||
357 | |||
358 | static void xenbus_check_frontend(char *class, char *dev) | ||
359 | { | ||
360 | int be_state, fe_state, err; | ||
361 | char *backend, *frontend; | ||
362 | |||
363 | frontend = kasprintf(GFP_NOIO | __GFP_HIGH, "device/%s/%s", class, dev); | ||
364 | if (!frontend) | ||
365 | return; | ||
366 | |||
367 | err = xenbus_scanf(XBT_NIL, frontend, "state", "%i", &fe_state); | ||
368 | if (err != 1) | ||
369 | goto out; | ||
370 | |||
371 | switch (fe_state) { | ||
372 | case XenbusStateConnected: | ||
373 | case XenbusStateClosed: | ||
374 | printk(KERN_DEBUG "XENBUS: frontend %s %s\n", | ||
375 | frontend, xenbus_strstate(fe_state)); | ||
376 | backend = xenbus_read(XBT_NIL, frontend, "backend", NULL); | ||
377 | if (!backend || IS_ERR(backend)) | ||
378 | goto out; | ||
379 | err = xenbus_scanf(XBT_NIL, backend, "state", "%i", &be_state); | ||
380 | if (err == 1) | ||
381 | xenbus_reset_frontend(frontend, backend, be_state); | ||
382 | kfree(backend); | ||
383 | break; | ||
384 | default: | ||
385 | break; | ||
386 | } | ||
387 | out: | ||
388 | kfree(frontend); | ||
389 | } | ||
390 | |||
391 | static void xenbus_reset_state(void) | ||
392 | { | ||
393 | char **devclass, **dev; | ||
394 | int devclass_n, dev_n; | ||
395 | int i, j; | ||
396 | |||
397 | devclass = xenbus_directory(XBT_NIL, "device", "", &devclass_n); | ||
398 | if (IS_ERR(devclass)) | ||
399 | return; | ||
400 | |||
401 | for (i = 0; i < devclass_n; i++) { | ||
402 | dev = xenbus_directory(XBT_NIL, "device", devclass[i], &dev_n); | ||
403 | if (IS_ERR(dev)) | ||
404 | continue; | ||
405 | for (j = 0; j < dev_n; j++) | ||
406 | xenbus_check_frontend(devclass[i], dev[j]); | ||
407 | kfree(dev); | ||
408 | } | ||
409 | kfree(devclass); | ||
410 | } | ||
411 | 250 | ||
412 | static int frontend_probe_and_watch(struct notifier_block *notifier, | 251 | static int frontend_probe_and_watch(struct notifier_block *notifier, |
413 | unsigned long event, | 252 | unsigned long event, |
414 | void *data) | 253 | void *data) |
415 | { | 254 | { |
416 | /* reset devices in Connected or Closed state */ | ||
417 | if (xen_hvm_domain()) | ||
418 | xenbus_reset_state(); | ||
419 | /* Enumerate devices in xenstore and watch for changes. */ | 255 | /* Enumerate devices in xenstore and watch for changes. */ |
420 | xenbus_probe_devices(&xenbus_frontend); | 256 | xenbus_probe_devices(&xenbus_frontend); |
421 | register_xenbus_watch(&fe_watch); | 257 | register_xenbus_watch(&fe_watch); |