xen/pvcalls: xenbus state handling

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>
This commit is contained in:
Stefano Stabellini 2017-07-06 10:59:17 -07:00 committed by Boris Ostrovsky
parent 9be07334f9
commit 0a9c75c2c7

View File

@ -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)