xen/pvcalls: xenbus state handling
authorStefano Stabellini <sstabellini@kernel.org>
Thu, 6 Jul 2017 17:59:17 +0000 (10:59 -0700)
committerBoris Ostrovsky <boris.ostrovsky@oracle.com>
Thu, 31 Aug 2017 13:45:55 +0000 (09:45 -0400)
Introduce the code to handle xenbus state changes.

Implement the probe function for the pvcalls backend. Write the
supported versions, max-page-order and function-calls nodes to xenstore,
as required by the protocol.

Introduce stub functions for disconnecting/connecting to a frontend.

Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
drivers/xen/pvcalls-back.c

index 9044cf21b31c2fabb911c8d1500fc23f45ec6a48..72d2fce27a341f48297e9fc7b5d2a5fbd8c6034a 100644 (file)
 #include <xen/xenbus.h>
 #include <xen/interface/io/pvcalls.h>
 
+#define PVCALLS_VERSIONS "1"
+#define MAX_RING_ORDER XENBUS_MAX_RING_GRANT_ORDER
+
 struct pvcalls_back_global {
        struct list_head frontends;
        struct semaphore frontends_lock;
 } pvcalls_back_global;
 
+static int backend_connect(struct xenbus_device *dev)
+{
+       return 0;
+}
+
+static int backend_disconnect(struct xenbus_device *dev)
+{
+       return 0;
+}
+
 static int pvcalls_back_probe(struct xenbus_device *dev,
                              const struct xenbus_device_id *id)
 {
+       int err, abort;
+       struct xenbus_transaction xbt;
+
+again:
+       abort = 1;
+
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               pr_warn("%s cannot create xenstore transaction\n", __func__);
+               return err;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "versions", "%s",
+                           PVCALLS_VERSIONS);
+       if (err) {
+               pr_warn("%s write out 'versions' failed\n", __func__);
+               goto abort;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "max-page-order", "%u",
+                           MAX_RING_ORDER);
+       if (err) {
+               pr_warn("%s write out 'max-page-order' failed\n", __func__);
+               goto abort;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "function-calls",
+                           XENBUS_FUNCTIONS_CALLS);
+       if (err) {
+               pr_warn("%s write out 'function-calls' failed\n", __func__);
+               goto abort;
+       }
+
+       abort = 0;
+abort:
+       err = xenbus_transaction_end(xbt, abort);
+       if (err) {
+               if (err == -EAGAIN && !abort)
+                       goto again;
+               pr_warn("%s cannot complete xenstore transaction\n", __func__);
+               return err;
+       }
+
+       if (abort)
+               return -EFAULT;
+
+       xenbus_switch_state(dev, XenbusStateInitWait);
+
        return 0;
 }
 
+static void set_backend_state(struct xenbus_device *dev,
+                             enum xenbus_state state)
+{
+       while (dev->state != state) {
+               switch (dev->state) {
+               case XenbusStateClosed:
+                       switch (state) {
+                       case XenbusStateInitWait:
+                       case XenbusStateConnected:
+                               xenbus_switch_state(dev, XenbusStateInitWait);
+                               break;
+                       case XenbusStateClosing:
+                               xenbus_switch_state(dev, XenbusStateClosing);
+                               break;
+                       default:
+                               __WARN();
+                       }
+                       break;
+               case XenbusStateInitWait:
+               case XenbusStateInitialised:
+                       switch (state) {
+                       case XenbusStateConnected:
+                               backend_connect(dev);
+                               xenbus_switch_state(dev, XenbusStateConnected);
+                               break;
+                       case XenbusStateClosing:
+                       case XenbusStateClosed:
+                               xenbus_switch_state(dev, XenbusStateClosing);
+                               break;
+                       default:
+                               __WARN();
+                       }
+                       break;
+               case XenbusStateConnected:
+                       switch (state) {
+                       case XenbusStateInitWait:
+                       case XenbusStateClosing:
+                       case XenbusStateClosed:
+                               down(&pvcalls_back_global.frontends_lock);
+                               backend_disconnect(dev);
+                               up(&pvcalls_back_global.frontends_lock);
+                               xenbus_switch_state(dev, XenbusStateClosing);
+                               break;
+                       default:
+                               __WARN();
+                       }
+                       break;
+               case XenbusStateClosing:
+                       switch (state) {
+                       case XenbusStateInitWait:
+                       case XenbusStateConnected:
+                       case XenbusStateClosed:
+                               xenbus_switch_state(dev, XenbusStateClosed);
+                               break;
+                       default:
+                               __WARN();
+                       }
+                       break;
+               default:
+                       __WARN();
+               }
+       }
+}
+
 static void pvcalls_back_changed(struct xenbus_device *dev,
                                 enum xenbus_state frontend_state)
 {
+       switch (frontend_state) {
+       case XenbusStateInitialising:
+               set_backend_state(dev, XenbusStateInitWait);
+               break;
+
+       case XenbusStateInitialised:
+       case XenbusStateConnected:
+               set_backend_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateClosing:
+               set_backend_state(dev, XenbusStateClosing);
+               break;
+
+       case XenbusStateClosed:
+               set_backend_state(dev, XenbusStateClosed);
+               if (xenbus_dev_is_online(dev))
+                       break;
+               device_unregister(&dev->dev);
+               break;
+       case XenbusStateUnknown:
+               set_backend_state(dev, XenbusStateClosed);
+               device_unregister(&dev->dev);
+               break;
+
+       default:
+               xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+                                frontend_state);
+               break;
+       }
 }
 
 static int pvcalls_back_remove(struct xenbus_device *dev)