Skip to content

Commit

Permalink
xen/pvcalls: xenbus state handling
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Boris Ostrovsky <[email protected]>
Reviewed-by: Juergen Gross <[email protected]>
CC: [email protected]
CC: [email protected]
Signed-off-by: Boris Ostrovsky <[email protected]>
  • Loading branch information
sstabellini authored and Boris Ostrovsky committed Aug 31, 2017
1 parent 9be0733 commit 0a9c75c
Showing 1 changed file with 155 additions and 0 deletions.
155 changes: 155 additions & 0 deletions drivers/xen/pvcalls-back.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,175 @@
#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)
Expand Down

0 comments on commit 0a9c75c

Please sign in to comment.