Browse Source

[xen] Cope with unexpected initial backend states

Under some circumstances (e.g. if iPXE itself is booted via iSCSI, or
after an unclean reboot), the backend may not be in the expected
InitWait state when iPXE starts up.

There is no generic reset mechanism for Xenbus devices.  Recent
versions of xen-netback will gracefully perform all of the required
steps if the frontend sets its state to Initialising.  Older versions
(such as that found in XenServer 6.2.0) require the frontend to
transition through Closed before reaching Initialising.

Add a reset mechanism for netfront devices which does the following:

 - read current backend state

 - if backend state is anything other than InitWait, then set the
   frontend state to Closed and wait for the backend to also reach
   Closed

 - set the frontend state to Initialising and wait for the backend to
   reach InitWait.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
8b2942a7db
3 changed files with 66 additions and 11 deletions
  1. 64
    10
      src/drivers/net/netfront.c
  2. 1
    0
      src/include/ipxe/xenbus.h
  3. 1
    1
      src/interface/xen/xenbus.c

+ 64
- 10
src/drivers/net/netfront.c View File

@@ -62,6 +62,55 @@ FILE_LICENCE ( GPL2_OR_LATER );
62 62
  ******************************************************************************
63 63
  */
64 64
 
65
+/**
66
+ * Reset device
67
+ *
68
+ * @v netfront		Netfront device
69
+ * @ret rc		Return status code
70
+ */
71
+static int netfront_reset ( struct netfront_nic *netfront ) {
72
+	struct xen_device *xendev = netfront->xendev;
73
+	int state;
74
+	int rc;
75
+
76
+	/* Get current backend state */
77
+	if ( ( state = xenbus_backend_state ( xendev ) ) < 0 ) {
78
+		rc = state;
79
+		DBGC ( netfront, "NETFRONT %s could not read backend state: "
80
+		       "%s\n", xendev->key, strerror ( rc ) );
81
+		return rc;
82
+	}
83
+
84
+	/* If the backend is not already in InitWait, then mark
85
+	 * frontend as Closed to shut down the backend.
86
+	 */
87
+	if ( state != XenbusStateInitWait ) {
88
+
89
+		/* Set state to Closed */
90
+		xenbus_set_state ( xendev, XenbusStateClosed );
91
+
92
+		/* Wait for backend to reach Closed */
93
+		if ( ( rc = xenbus_backend_wait ( xendev,
94
+						  XenbusStateClosed ) ) != 0 ) {
95
+			DBGC ( netfront, "NETFRONT %s backend did not reach "
96
+			       "Closed: %s\n", xendev->key, strerror ( rc ) );
97
+			return rc;
98
+		}
99
+	}
100
+
101
+	/* Reset state to Initialising */
102
+	xenbus_set_state ( xendev, XenbusStateInitialising );
103
+
104
+	/* Wait for backend to reach InitWait */
105
+	if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateInitWait ) ) != 0){
106
+		DBGC ( netfront, "NETFRONT %s backend did not reach InitWait: "
107
+		       "%s\n", xendev->key, strerror ( rc ) );
108
+		return rc;
109
+	}
110
+
111
+	return 0;
112
+}
113
+
65 114
 /**
66 115
  * Fetch MAC address
67 116
  *
@@ -510,6 +559,10 @@ static int netfront_open ( struct net_device *netdev ) {
510 559
 	struct xen_device *xendev = netfront->xendev;
511 560
 	int rc;
512 561
 
562
+	/* Ensure device is in a suitable initial state */
563
+	if ( ( rc = netfront_reset ( netfront ) ) != 0 )
564
+		goto err_reset;
565
+
513 566
 	/* Create transmit descriptor ring */
514 567
 	if ( ( rc = netfront_create_ring ( netfront, &netfront->tx ) ) != 0 )
515 568
 		goto err_create_tx;
@@ -563,7 +616,7 @@ static int netfront_open ( struct net_device *netdev ) {
563 616
 	return 0;
564 617
 
565 618
  err_backend_wait:
566
-	xenbus_set_state ( xendev, XenbusStateInitialising );
619
+	netfront_reset ( netfront );
567 620
  err_set_state:
568 621
 	netfront_rm ( netfront, "feature-no-csum-offload" );
569 622
  err_feature_no_csum_offload:
@@ -575,6 +628,7 @@ static int netfront_open ( struct net_device *netdev ) {
575 628
  err_create_rx:
576 629
 	netfront_destroy_ring ( netfront, &netfront->tx, NULL );
577 630
  err_create_tx:
631
+ err_reset:
578 632
 	return rc;
579 633
 }
580 634
 
@@ -588,13 +642,10 @@ static void netfront_close ( struct net_device *netdev ) {
588 642
 	struct xen_device *xendev = netfront->xendev;
589 643
 	int rc;
590 644
 
591
-	/* Set state to Closed */
592
-	xenbus_set_state ( xendev, XenbusStateClosed );
593
-
594
-	/* Wait for backend to close, thereby ensuring that grant
595
-	 * references are no longer in use, etc.
645
+	/* Reset devic, thereby ensuring that grant references are no
646
+	 * longer in use, etc.
596 647
 	 */
597
-	if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateClosed ) ) != 0 ) {
648
+	if ( ( rc = netfront_reset ( netfront ) ) != 0 ) {
598 649
 		DBGC ( netfront, "NETFRONT %s could not disconnect from "
599 650
 		       "backend: %s\n", xendev->key, strerror ( rc ) );
600 651
 		/* Things will probably go _very_ badly wrong if this
@@ -609,9 +660,6 @@ static void netfront_close ( struct net_device *netdev ) {
609 660
 		netdev_link_down ( netdev );
610 661
 	}
611 662
 
612
-	/* Reset state to Initialising */
613
-	xenbus_set_state ( xendev, XenbusStateInitialising );
614
-
615 663
 	/* Delete flags */
616 664
 	netfront_rm ( netfront, "feature-no-csum-offload" );
617 665
 	netfront_rm ( netfront, "request-rx-copy" );
@@ -835,6 +883,12 @@ static int netfront_probe ( struct xen_device *xendev ) {
835 883
 	if ( ( rc = netfront_read_mac ( netfront, netdev->hw_addr ) ) != 0 )
836 884
 		goto err_read_mac;
837 885
 
886
+	/* Reset device.  Ignore failures; allow the device to be
887
+	 * registered so that reset errors can be observed by the user
888
+	 * when attempting to open the device.
889
+	 */
890
+	netfront_reset ( netfront );
891
+
838 892
 	/* Register network device */
839 893
 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
840 894
 		goto err_register_netdev;

+ 1
- 0
src/include/ipxe/xenbus.h View File

@@ -78,6 +78,7 @@ static inline void * xen_get_drvdata ( struct xen_device *xendev ) {
78 78
 }
79 79
 
80 80
 extern int xenbus_set_state ( struct xen_device *xendev, int state );
81
+extern int xenbus_backend_state ( struct xen_device *xendev );
81 82
 extern int xenbus_backend_wait ( struct xen_device *xendev, int state );
82 83
 extern int xenbus_probe ( struct xen_hypervisor *xen, struct device *parent );
83 84
 extern void xenbus_remove ( struct xen_hypervisor *xen, struct device *parent );

+ 1
- 1
src/interface/xen/xenbus.c View File

@@ -118,7 +118,7 @@ int xenbus_set_state ( struct xen_device *xendev, int state ) {
118 118
  * @v xendev		Xen device
119 119
  * @ret state		Backend state, or negative error
120 120
  */
121
-static int xenbus_backend_state ( struct xen_device *xendev ) {
121
+int xenbus_backend_state ( struct xen_device *xendev ) {
122 122
 	unsigned long state;
123 123
 	int rc;
124 124
 

Loading…
Cancel
Save