Commit cce94483 authored by Filipe Manco's avatar Filipe Manco Committed by David S. Miller
Browse files

xen-netback: fix error handling on netback_probe()



In case of error during netback_probe() (e.g. an entry missing on the
xenstore) netback_remove() is called on the new device, which will set
the device backend state to XenbusStateClosed by calling
set_backend_state(). However, the backend state wasn't initialized by
netback_probe() at this point, which will cause and invalid transaction
and set_backend_state() to BUG().

Initialize the backend state at the beginning of netback_probe() to
XenbusStateInitialising, and create two new valid state transitions on
set_backend_state(), from XenbusStateInitialising to XenbusStateClosed,
and from XenbusStateInitialising to XenbusStateInitWait.

Signed-off-by: default avatarFilipe Manco <filipe.manco@neclab.eu>
Acked-by: default avatarWei Liu <wei.liu2@citrix.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4253ef8f
Loading
Loading
Loading
Loading
+30 −16
Original line number Diff line number Diff line
@@ -271,6 +271,11 @@ static int netback_probe(struct xenbus_device *dev,
	be->dev = dev;
	dev_set_drvdata(&dev->dev, be);

	be->state = XenbusStateInitialising;
	err = xenbus_switch_state(dev, XenbusStateInitialising);
	if (err)
		goto fail;

	sg = 1;

	do {
@@ -383,11 +388,6 @@ static int netback_probe(struct xenbus_device *dev,

	be->hotplug_script = script;

	err = xenbus_switch_state(dev, XenbusStateInitWait);
	if (err)
		goto fail;

	be->state = XenbusStateInitWait;

	/* This kicks hotplug scripts, so do it immediately. */
	err = backend_create_xenvif(be);
@@ -492,18 +492,18 @@ static inline void backend_switch_state(struct backend_info *be,

/* Handle backend state transitions:
 *
 * The backend state starts in InitWait and the following transitions are
 * The backend state starts in Initialising and the following transitions are
 * allowed.
 *
 * InitWait -> Connected
 *
 *    ^    \         |
 *    |     \        |
 *    |      \       |
 *    |       \      |
 *    |        \     |
 *    |         \    |
 *    |          V   V
 * Initialising -> InitWait -> Connected
 *          \
 *           \        ^    \         |
 *            \       |     \        |
 *             \      |      \       |
 *              \     |       \      |
 *               \    |        \     |
 *                \   |         \    |
 *                 V  |          V   V
 *
 *                  Closed  <-> Closing
 *
@@ -515,6 +515,20 @@ static void set_backend_state(struct backend_info *be,
{
	while (be->state != state) {
		switch (be->state) {
		case XenbusStateInitialising:
			switch (state) {
			case XenbusStateInitWait:
			case XenbusStateConnected:
			case XenbusStateClosing:
				backend_switch_state(be, XenbusStateInitWait);
				break;
			case XenbusStateClosed:
				backend_switch_state(be, XenbusStateClosed);
				break;
			default:
				BUG();
			}
			break;
		case XenbusStateClosed:
			switch (state) {
			case XenbusStateInitWait: