staticint xenbus_frontend_dev_resume(struct device *dev)
{ /* * If xenstored is running in this domain, we cannot access the backend * state at the moment, so we need to defer xenbus_dev_resume
*/ if (xen_store_domain_type == XS_LOCAL) { struct xenbus_device *xdev = to_xenbus_device(dev);
/* * A device with no driver will never connect. We care only about * devices which should currently be in the process of connecting.
*/ if (!dev->driver) return 0;
/* Is this search limited to a particular driver? */ if (drv && (dev->driver != drv)) return 0;
xendrv = to_xenbus_driver(dev->driver);
if (ignore_nonessential && xendrv->not_essential) return 0;
/* Is this operation limited to a particular driver? */ if (drv && (dev->driver != drv)) return 0;
if (!dev->driver) { /* Information only: is this too noisy? */
pr_info("Device with no driver: %s\n", xendev->nodename);
} elseif (xendev->state < XenbusStateConnected) { enum xenbus_state rstate = XenbusStateUnknown; if (xendev->otherend)
rstate = xenbus_read_driver_state(xendev->otherend);
pr_warn("Timeout connecting to device: %s (local state %d, remote state %d)\n",
xendev->nodename, xendev->state, rstate);
}
return 0;
}
/* We only wait for device setup after most initcalls have run. */ staticint ready_to_wait_for_devices;
staticbool wait_loop(unsignedlong start, unsignedint max_delay, unsignedint *seconds_waited)
{ if (time_after(jiffies, start + (*seconds_waited+5)*HZ)) { if (!*seconds_waited)
pr_warn("Waiting for devices to initialise: ");
*seconds_waited += 5;
pr_cont("%us...", max_delay - *seconds_waited); if (*seconds_waited == max_delay) {
pr_cont("\n"); returntrue;
}
}
schedule_timeout_interruptible(HZ/10);
returnfalse;
} /* * On a 5-minute timeout, wait for all devices currently configured. We need * to do this to guarantee that the filesystems and / or network devices * needed for boot are available, before we can allow the boot to proceed. * * This needs to be on a late_initcall, to happen after the frontend device * drivers have been initialised, but before the root fs is mounted. * * A possible improvement here would be to have the tools add a per-device * flag to the store entry, indicating whether it is needed at boot time. * This would allow people who knew what they were doing to accelerate their * boot slightly, but of course needs tools or manual intervention to set up * those flags correctly.
*/ staticvoid wait_for_devices(struct xenbus_driver *xendrv)
{ unsignedlong start = jiffies; struct device_driver *drv = xendrv ? &xendrv->driver : NULL; unsignedint seconds_waited = 0;
if (!ready_to_wait_for_devices || !xen_domain()) return;
while (exists_non_essential_connecting_device(drv)) if (wait_loop(start, 30, &seconds_waited)) break;
/* Skips PVKB and PVFB check.*/ while (exists_essential_connecting_device(drv)) if (wait_loop(start, 270, &seconds_waited)) break;
staticvoid xenbus_reset_wait_for_backend(char *be, int expected)
{ long timeout;
timeout = wait_event_interruptible_timeout(backend_state_wq,
backend_state == expected, 5 * HZ); if (timeout <= 0)
pr_info("backend %s timed out\n", be);
}
/* * Reset frontend if it is in Connected or Closed state. * Wait for backend to catch up. * State Connected happens during kdump, Closed after kexec.
*/ staticvoid xenbus_reset_frontend(char *fe, char *be, int be_state)
{ struct xenbus_watch be_watch;
printk(KERN_DEBUG "XENBUS: backend %s %s\n",
be, xenbus_strstate(be_state));
pr_info("triggering reconnect on %s\n", be);
register_xenbus_watch(&be_watch);
/* fall through to forward backend to state XenbusStateInitialising */ switch (be_state) { case XenbusStateConnected:
xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosing);
xenbus_reset_wait_for_backend(be, XenbusStateClosing);
fallthrough;
case XenbusStateClosing:
xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosed);
xenbus_reset_wait_for_backend(be, XenbusStateClosed);
fallthrough;
case XenbusStateClosed:
xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateInitialising);
xenbus_reset_wait_for_backend(be, XenbusStateInitWait);
}
unregister_xenbus_watch(&be_watch);
pr_info("reconnect done on %s\n", be);
kfree(be_watch.node);
}
staticvoid xenbus_reset_state(void)
{ char **devclass, **dev; int devclass_n, dev_n; int i, j;
devclass = xenbus_directory(XBT_NIL, "device", "", &devclass_n); if (IS_ERR(devclass)) return;
for (i = 0; i < devclass_n; i++) {
dev = xenbus_directory(XBT_NIL, "device", devclass[i], &dev_n); if (IS_ERR(dev)) continue; for (j = 0; j < dev_n; j++)
xenbus_check_frontend(devclass[i], dev[j]);
kfree(dev);
}
kfree(devclass);
}
staticint frontend_probe_and_watch(struct notifier_block *notifier, unsignedlong event, void *data)
{ /* reset devices in Connected or Closed state */ if (xen_hvm_domain())
xenbus_reset_state(); /* Enumerate devices in xenstore and watch for changes. */
xenbus_probe_devices(&xenbus_frontend);
register_xenbus_watch(&fe_watch);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.