On Thu, 13 Jan 2022, Juergen Gross wrote:
> > @@ -907,6 +921,20 @@ static struct notifier_block xenbus_resume_nb = {
> >     .notifier_call = xenbus_resume_cb,
> >   };
> >   +static irqreturn_t xenbus_late_init(int irq, void *unused)
> > +{
> > +   int err = 0;
> > +   uint64_t v = 0;
> > +
> > +   err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
> > +   if (err || !v || !~v)
> > +           return IRQ_HANDLED;
> > +   xen_store_gfn = (unsigned long)v;
> > +
> > +   wake_up(&xb_waitq);
> > +   return IRQ_HANDLED;
> > +}
> > +
> 
> Hmm, wouldn't it be easier to use a static key in the already existing
> irq handler instead of switching the handler?

I did some prototyping and it is certainly not going to be "easier" :-)

- xenbus_irq is setup by xb_init_comms, but xb_init_comms cannot be
  re-used as-is because it assumes xen_store_interface to be != NULL
- also, it is too early to start xenbus_thread at that point

So it looks like we shouldn't call xb_init_comms from xenbus_init
because it would increase the number of "if" statements in xb_init_comms
quiet a bit. 

An alternative would be to leave xb_init_comms unmodified, but reuse the
same interrupt handler (wake_waiting) and xenbus_irq. However, that
doesn't work either because rebind_evtchn_irq fails when it is called
later on from xb_init_comms. (I haven't investigated why.) Also,
xenbus_irq could be allocated as zero, so the existing check in
xb_init_comms also fails. 

To give you a concrete idea, after several tries I managed to get a
dirty patch that works but I don't think the changes to xb_init_comms
are actually correct.

In conclusion I think it is best to keep the current approach.



diff --git a/drivers/xen/xenbus/xenbus_comms.c 
b/drivers/xen/xenbus/xenbus_comms.c
index e5fda0256feb..bad87c3a9f72 100644
--- a/drivers/xen/xenbus/xenbus_comms.c
+++ b/drivers/xen/xenbus/xenbus_comms.c
@@ -54,15 +54,9 @@ DEFINE_MUTEX(xb_write_mutex);
 /* Protect xenbus reader thread against save/restore. */
 DEFINE_MUTEX(xs_response_mutex);
 
-static int xenbus_irq;
+int xenbus_irq = -1;
 static struct task_struct *xenbus_task;
 
-static irqreturn_t wake_waiting(int irq, void *unused)
-{
-       wake_up(&xb_waitq);
-       return IRQ_HANDLED;
-}
-
 static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
 {
        return ((prod - cons) <= XENSTORE_RING_SIZE);
@@ -435,6 +429,7 @@ static int xenbus_thread(void *unused)
 /**
  * xb_init_comms - Set up interrupt handler off store event channel.
  */
+extern irqreturn_t wake_waiting(int irq, void *unused);
 int xb_init_comms(void)
 {
        struct xenstore_domain_interface *intf = xen_store_interface;
@@ -451,10 +446,10 @@ int xb_init_comms(void)
                        intf->rsp_cons = intf->rsp_prod;
        }
 
-       if (xenbus_irq) {
+       if (xenbus_irq > 0) {
                /* Already have an irq; assume we're resuming */
                rebind_evtchn_irq(xen_store_evtchn, xenbus_irq);
-       } else {
+       } else if (xenbus_irq < 0) {
                int err;
 
                err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting,
@@ -465,13 +460,13 @@ int xb_init_comms(void)
                }
 
                xenbus_irq = err;
+       }
 
-               if (!xenbus_task) {
-                       xenbus_task = kthread_run(xenbus_thread, NULL,
-                                                 "xenbus");
-                       if (IS_ERR(xenbus_task))
-                               return PTR_ERR(xenbus_task);
-               }
+       if (!xenbus_task) {
+               xenbus_task = kthread_run(xenbus_thread, NULL,
+                               "xenbus");
+               if (IS_ERR(xenbus_task))
+                       return PTR_ERR(xenbus_task);
        }
 
        return 0;
diff --git a/drivers/xen/xenbus/xenbus_probe.c 
b/drivers/xen/xenbus/xenbus_probe.c
index fe360c33ce71..ad8d640b75d2 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -65,6 +65,7 @@
 #include "xenbus.h"
 
 
+extern int xenbus_irq;
 int xen_store_evtchn;
 EXPORT_SYMBOL_GPL(xen_store_evtchn);
 
@@ -750,6 +751,11 @@ static void xenbus_probe(void)
 {
        xenstored_ready = 1;
 
+       if (!xen_store_interface) {
+               xen_store_interface = xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
+                                               XEN_PAGE_SIZE);
+       }
+
        /*
         * In the HVM case, xenbus_init() deferred its call to
         * xs_init() in case callbacks were not operational yet.
@@ -798,20 +804,22 @@ static int __init xenbus_probe_initcall(void)
 {
        /*
         * Probe XenBus here in the XS_PV case, and also XS_HVM unless we
-        * need to wait for the platform PCI device to come up.
+        * need to wait for the platform PCI device to come up or
+        * xen_store_interface is not ready.
         */
        if (xen_store_domain_type == XS_PV ||
            (xen_store_domain_type == XS_HVM &&
-            !xs_hvm_defer_init_for_callback()))
+            !xs_hvm_defer_init_for_callback() &&
+            xen_store_interface != NULL))
                xenbus_probe();
 
        /*
-        * For XS_LOCAL, spawn a thread which will wait for xenstored
-        * or a xenstore-stubdom to be started, then probe. It will be
-        * triggered when communication starts happening, by waiting
-        * on xb_waitq.
+        * For XS_LOCAL or when xen_store_interface is not ready, spawn a
+        * thread which will wait for xenstored or a xenstore-stubdom to be
+        * started, then probe.  It will be triggered when communication
+        * starts happening, by waiting on xb_waitq.
         */
-       if (xen_store_domain_type == XS_LOCAL) {
+       if (xen_store_domain_type == XS_LOCAL || xen_store_interface == NULL) {
                struct task_struct *probe_task;
 
                probe_task = kthread_run(xenbus_probe_thread, NULL,
@@ -907,6 +915,22 @@ static struct notifier_block xenbus_resume_nb = {
        .notifier_call = xenbus_resume_cb,
 };
 
+irqreturn_t wake_waiting(int irq, void *unused)
+{
+       int err = 0;
+       uint64_t v = 0;
+
+       if (!xen_store_gfn) {
+               err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
+               if (err || !v || !~v)
+                       return IRQ_HANDLED;
+               xen_store_gfn = (unsigned long)v;
+       }
+
+       wake_up(&xb_waitq);
+       return IRQ_HANDLED;
+}
+
 static int __init xenbus_init(void)
 {
        int err;
@@ -959,23 +983,37 @@ static int __init xenbus_init(void)
                 *
                 * Also recognize all bits set as an invalid value.
                 */
-               if (!v || !~v) {
+               if (!v) {
                        err = -ENOENT;
                        goto out_error;
                }
-               /* Avoid truncation on 32-bit. */
+               if (v == ~0ULL) {
+                       err = bind_evtchn_to_irqhandler(xen_store_evtchn,
+                                                       wake_waiting,
+                                                       0, "xenbus",
+                                                       &xb_waitq);
+                       if (err < 0) {
+                               pr_err("xenstore_late_init couldn't bind irq 
err=%d\n",
+                                      err);
+                               return err;
+                       }
+
+                       xenbus_irq = err;
+               } else {
+                       /* Avoid truncation on 32-bit. */
 #if BITS_PER_LONG == 32
-               if (v > ULONG_MAX) {
-                       pr_err("%s: cannot handle HVM_PARAM_STORE_PFN=%llx > 
ULONG_MAX\n",
-                              __func__, v);
-                       err = -EINVAL;
-                       goto out_error;
-               }
+                       if (v > ULONG_MAX) {
+                               pr_err("%s: cannot handle 
HVM_PARAM_STORE_PFN=%llx > ULONG_MAX\n",
+                                               __func__, v);
+                               err = -EINVAL;
+                               goto out_error;
+                       }
 #endif
-               xen_store_gfn = (unsigned long)v;
-               xen_store_interface =
-                       xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
-                                 XEN_PAGE_SIZE);
+                       xen_store_gfn = (unsigned long)v;
+                       xen_store_interface =
+                               xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
+                                         XEN_PAGE_SIZE);
+               }
                break;
        default:
                pr_warn("Xenstore state unknown\n");

Reply via email to