aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/xenbus/xenbus_probe_frontend.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen/xenbus/xenbus_probe_frontend.c')
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c72
1 files changed, 54 insertions, 18 deletions
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index 3159a37d966d..6ed8a9df4472 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -1,6 +1,8 @@
-#define DPRINTK(fmt, args...) \
- pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \
- __func__, __LINE__, ##args)
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define DPRINTK(fmt, ...) \
+ pr_debug("(%s:%d) " fmt "\n", \
+ __func__, __LINE__, ##__VA_ARGS__)
#include <linux/kernel.h>
#include <linux/err.h>
@@ -29,18 +31,20 @@
#include "xenbus_probe.h"
+static struct workqueue_struct *xenbus_frontend_wq;
+
/* device/<type>/<id> => <type>-<id> */
static int frontend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)
{
nodename = strchr(nodename, '/');
if (!nodename || strlen(nodename + 1) >= XEN_BUS_ID_SIZE) {
- printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
+ pr_warn("bad frontend %s\n", nodename);
return -EINVAL;
}
strlcpy(bus_id, nodename + 1, XEN_BUS_ID_SIZE);
if (!strchr(bus_id, '/')) {
- printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
+ pr_warn("bus_id %s no slash\n", bus_id);
return -EINVAL;
}
*strchr(bus_id, '/') = '-';
@@ -89,9 +93,40 @@ static void backend_changed(struct xenbus_watch *watch,
xenbus_otherend_changed(watch, vec, len, 1);
}
+static void xenbus_frontend_delayed_resume(struct work_struct *w)
+{
+ struct xenbus_device *xdev = container_of(w, struct xenbus_device, work);
+
+ xenbus_dev_resume(&xdev->dev);
+}
+
+static int 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);
+
+ if (!xenbus_frontend_wq) {
+ pr_err("%s: no workqueue to process delayed resume\n",
+ xdev->nodename);
+ return -EFAULT;
+ }
+
+ INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
+ queue_work(xenbus_frontend_wq, &xdev->work);
+
+ return 0;
+ }
+
+ return xenbus_dev_resume(dev);
+}
+
static const struct dev_pm_ops xenbus_pm_ops = {
.suspend = xenbus_dev_suspend,
- .resume = xenbus_dev_resume,
+ .resume = xenbus_frontend_dev_resume,
.freeze = xenbus_dev_suspend,
.thaw = xenbus_dev_cancel,
.restore = xenbus_dev_resume,
@@ -201,15 +236,13 @@ static int print_device_status(struct device *dev, void *data)
if (!dev->driver) {
/* Information only: is this too noisy? */
- printk(KERN_INFO "XENBUS: Device with no driver: %s\n",
- xendev->nodename);
+ pr_info("Device with no driver: %s\n", xendev->nodename);
} else if (xendev->state < XenbusStateConnected) {
enum xenbus_state rstate = XenbusStateUnknown;
if (xendev->otherend)
rstate = xenbus_read_driver_state(xendev->otherend);
- printk(KERN_WARNING "XENBUS: Timeout connecting "
- "to device: %s (local state %d, remote state %d)\n",
- xendev->nodename, xendev->state, rstate);
+ pr_warn("Timeout connecting to device: %s (local state %d, remote state %d)\n",
+ xendev->nodename, xendev->state, rstate);
}
return 0;
@@ -223,12 +256,13 @@ static bool wait_loop(unsigned long start, unsigned int max_delay,
{
if (time_after(jiffies, start + (*seconds_waited+5)*HZ)) {
if (!*seconds_waited)
- printk(KERN_WARNING "XENBUS: Waiting for "
- "devices to initialise: ");
+ pr_warn("Waiting for devices to initialise: ");
*seconds_waited += 5;
- printk("%us...", max_delay - *seconds_waited);
- if (*seconds_waited == max_delay)
+ pr_cont("%us...", max_delay - *seconds_waited);
+ if (*seconds_waited == max_delay) {
+ pr_cont("\n");
return true;
+ }
}
schedule_timeout_interruptible(HZ/10);
@@ -309,7 +343,7 @@ static void xenbus_reset_wait_for_backend(char *be, int expected)
timeout = wait_event_interruptible_timeout(backend_state_wq,
backend_state == expected, 5 * HZ);
if (timeout <= 0)
- printk(KERN_INFO "XENBUS: backend %s timed out.\n", be);
+ pr_info("backend %s timed out\n", be);
}
/*
@@ -332,7 +366,7 @@ static void xenbus_reset_frontend(char *fe, char *be, int be_state)
be_watch.callback = xenbus_reset_backend_state_changed;
backend_state = XenbusStateUnknown;
- printk(KERN_INFO "XENBUS: triggering reconnect on %s\n", be);
+ pr_info("triggering reconnect on %s\n", be);
register_xenbus_watch(&be_watch);
/* fall through to forward backend to state XenbusStateInitialising */
@@ -351,7 +385,7 @@ static void xenbus_reset_frontend(char *fe, char *be, int be_state)
}
unregister_xenbus_watch(&be_watch);
- printk(KERN_INFO "XENBUS: reconnect done on %s\n", be);
+ pr_info("reconnect done on %s\n", be);
kfree(be_watch.node);
}
@@ -440,6 +474,8 @@ static int __init xenbus_probe_frontend_init(void)
register_xenstore_notifier(&xenstore_notifier);
+ xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+
return 0;
}
subsys_initcall(xenbus_probe_frontend_init);