Author: gibbs
Date: Wed Sep 21 00:02:44 2011
New Revision: 225705
URL: http://svn.freebsd.org/changeset/base/225705

Log:
  Add suspend/resume support to the Xen blkfront driver.
  
  Sponsored by: BQ Internet
  
  sys/dev/xen/blkfront/block.h:
  sys/dev/xen/blkfront/blkfront.c:
        Remove now unused blkif_vdev_t from the blkfront soft.
  
  sys/dev/xen/blkfront/blkfront.c:
        o In blkfront_suspend(), indicate the desire to suspend
          by changing the softc connected state to SUSPENDED, and
          then wait for any I/O pending on the remote peer to
          drain.  Cancel suspend processing if I/O does not
          drain within 30 seconds.
        o Enable and update blkfront_resume().  Since I/O is
          drained prior to the suspension of the VM, the complicated
          recovery process performed by other Xen blkfront
          implementations is avoided.  We simply tear down the
          connection to our old peer, and then re-connect.
        o In blkif_initialize(), fix a resource leak and botched
          return if we cannot allocate shadow memory for our
          requests.
        o In blkfront_backend_changed(), correct our response to
          the XenbusStateInitialised state.  This state indicates
          that our backend peer has published sufficient data for
          blkfront to publish ring information and other XenStore
          data, not that a connection can occur.  Blkfront now
          will only perform connection processing in response to
          the XenbusStateConnected state.  This corrects an issue
          where blkfront connected before the backend was ready
          during resume processing.
  
  Approved by:  re
  MFC after:    1 week

Modified:
  head/sys/dev/xen/blkfront/blkfront.c
  head/sys/dev/xen/blkfront/block.h

Modified: head/sys/dev/xen/blkfront/blkfront.c
==============================================================================
--- head/sys/dev/xen/blkfront/blkfront.c        Tue Sep 20 23:44:34 2011        
(r225704)
+++ head/sys/dev/xen/blkfront/blkfront.c        Wed Sep 21 00:02:44 2011        
(r225705)
@@ -77,11 +77,8 @@ static int blkfront_detach(device_t);
 static int setup_blkring(struct xb_softc *);
 static void blkif_int(void *);
 static void blkfront_initialize(struct xb_softc *);
-#if 0
-static void blkif_recover(struct xb_softc *);
-#endif
 static int blkif_completion(struct xb_command *);
-static void blkif_free(struct xb_softc *, int);
+static void blkif_free(struct xb_softc *);
 static void blkif_queue_cb(void *, bus_dma_segment_t *, int, int);
 
 MALLOC_DEFINE(M_XENBLOCKFRONT, "xbd", "Xen Block Front driver data");
@@ -452,9 +449,6 @@ blkfront_attach(device_t dev)
        sc->vdevice = vdevice;
        sc->connected = BLKIF_STATE_DISCONNECTED;
 
-       /* Front end dir is a number, which is used as the id. */
-       sc->handle = strtoul(strrchr(xenbus_get_node(dev),'/')+1, NULL, 0);
-
        /* Wait for backend device to publish its protocol capabilities. */
        xenbus_set_state(dev, XenbusStateInitialising);
 
@@ -465,29 +459,40 @@ static int
 blkfront_suspend(device_t dev)
 {
        struct xb_softc *sc = device_get_softc(dev);
+       int retval;
+       int saved_state;
 
        /* Prevent new requests being issued until we fix things up. */
        mtx_lock(&sc->xb_io_lock);
+       saved_state = sc->connected;
        sc->connected = BLKIF_STATE_SUSPENDED;
+
+       /* Wait for outstanding I/O to drain. */
+       retval = 0;
+       while (TAILQ_EMPTY(&sc->cm_busy) == 0) {
+               if (msleep(&sc->cm_busy, &sc->xb_io_lock,
+                          PRIBIO, "blkf_susp", 30 * hz) == EWOULDBLOCK) {
+                       retval = EBUSY;
+                       break;
+               }
+       }
        mtx_unlock(&sc->xb_io_lock);
 
-       return (0);
+       if (retval != 0)
+               sc->connected = saved_state;
+
+       return (retval);
 }
 
 static int
 blkfront_resume(device_t dev)
 {
-#if 0
        struct xb_softc *sc = device_get_softc(dev);
 
        DPRINTK("blkfront_resume: %s\n", xenbus_get_node(dev));
 
-/* XXX This can't work!!! */
-       blkif_free(sc, 1);
+       blkif_free(sc);
        blkfront_initialize(sc);
-       if (sc->connected == BLKIF_STATE_SUSPENDED)
-               blkif_recover(sc);
-#endif
        return (0);
 }
 
@@ -499,8 +504,10 @@ blkfront_initialize(struct xb_softc *sc)
        int error;
        int i;
 
-       if (xenbus_get_state(sc->xb_dev) != XenbusStateInitialising)
-                return;
+       if (xenbus_get_state(sc->xb_dev) != XenbusStateInitialising) {
+               /* Initialization has already been performed. */
+               return;
+       }
 
        /*
         * Protocol defaults valid even if negotiation for a
@@ -593,8 +600,10 @@ blkfront_initialize(struct xb_softc *sc)
        sc->shadow = malloc(sizeof(*sc->shadow) * sc->max_requests,
                            M_XENBLOCKFRONT, M_NOWAIT|M_ZERO);
        if (sc->shadow == NULL) {
+               bus_dma_tag_destroy(sc->xb_io_dmat);
                xenbus_dev_fatal(sc->xb_dev, error,
                                 "Cannot allocate request structures\n");
+               return;
        }
 
        for (i = 0; i < sc->max_requests; i++) {
@@ -755,10 +764,10 @@ blkfront_backend_changed(device_t dev, X
                break;
 
        case XenbusStateInitWait:
+       case XenbusStateInitialised:
                blkfront_initialize(sc);
                break;
 
-       case XenbusStateInitialised:
        case XenbusStateConnected:
                blkfront_initialize(sc);
                blkfront_connect(sc);
@@ -775,7 +784,7 @@ blkfront_backend_changed(device_t dev, X
 }
 
 /* 
-** Invoked when the backend is finally 'ready' (and has told produced 
+** Invoked when the backend is finally 'ready' (and has published
 ** the details about the physical device - #sectors, size, etc). 
 */
 static void 
@@ -809,13 +818,15 @@ blkfront_connect(struct xb_softc *sc)
        if (!err || feature_barrier)
                sc->xb_flags |= XB_BARRIER;
 
-       device_printf(dev, "%juMB <%s> at %s",
-           (uintmax_t) sectors / (1048576 / sector_size),
-           device_get_desc(dev),
-           xenbus_get_node(dev));
-       bus_print_child_footer(device_get_parent(dev), dev);
+       if (sc->xb_disk == NULL) {
+               device_printf(dev, "%juMB <%s> at %s",
+                   (uintmax_t) sectors / (1048576 / sector_size),
+                   device_get_desc(dev),
+                   xenbus_get_node(dev));
+               bus_print_child_footer(device_get_parent(dev), dev);
 
-       xlvbd_add(sc, sectors, sc->vdevice, binfo, sector_size);
+               xlvbd_add(sc, sectors, sc->vdevice, binfo, sector_size);
+       }
 
        (void)xenbus_set_state(dev, XenbusStateConnected); 
 
@@ -825,7 +836,6 @@ blkfront_connect(struct xb_softc *sc)
        xb_startio(sc);
        sc->xb_flags |= XB_READY;
        mtx_unlock(&sc->xb_io_lock);
-       
 }
 
 /**
@@ -859,7 +869,7 @@ blkfront_detach(device_t dev)
 
        DPRINTK("blkfront_remove: %s removed\n", xenbus_get_node(dev));
 
-       blkif_free(sc, 0);
+       blkif_free(sc);
        mtx_destroy(&sc->xb_io_lock);
 
        return 0;
@@ -1140,6 +1150,9 @@ xb_startio(struct xb_softc *sc)
 
        mtx_assert(&sc->xb_io_lock, MA_OWNED);
 
+       if (sc->connected != BLKIF_STATE_CONNECTED)
+               return;
+
        while (RING_FREE_REQUESTS(&sc->ring) >= sc->max_request_blocks) {
                if (sc->xb_flags & XB_FROZEN)
                        break;
@@ -1174,7 +1187,7 @@ blkif_int(void *xsc)
 
        mtx_lock(&sc->xb_io_lock);
 
-       if (unlikely(sc->connected != BLKIF_STATE_CONNECTED)) {
+       if (unlikely(sc->connected == BLKIF_STATE_DISCONNECTED)) {
                mtx_unlock(&sc->xb_io_lock);
                return;
        }
@@ -1232,19 +1245,21 @@ blkif_int(void *xsc)
 
        xb_startio(sc);
 
+       if (unlikely(sc->connected == BLKIF_STATE_SUSPENDED))
+               wakeup(&sc->cm_busy);
+
        mtx_unlock(&sc->xb_io_lock);
 }
 
 static void 
-blkif_free(struct xb_softc *sc, int suspend)
+blkif_free(struct xb_softc *sc)
 {
        uint8_t *sring_page_ptr;
        int i;
        
        /* Prevent new requests being issued until we fix things up. */
        mtx_lock(&sc->xb_io_lock);
-       sc->connected = suspend ? 
-               BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; 
+       sc->connected = BLKIF_STATE_DISCONNECTED; 
        mtx_unlock(&sc->xb_io_lock);
 
        /* Free resources associated with old device channel. */
@@ -1276,6 +1291,12 @@ blkif_free(struct xb_softc *sc, int susp
                }
                free(sc->shadow, M_XENBLOCKFRONT);
                sc->shadow = NULL;
+
+               bus_dma_tag_destroy(sc->xb_io_dmat);
+               
+               xb_initq_free(sc);
+               xb_initq_ready(sc);
+               xb_initq_complete(sc);
        }
                
        if (sc->irq) {
@@ -1292,21 +1313,6 @@ blkif_completion(struct xb_command *s)
        return (BLKIF_SEGS_TO_BLOCKS(s->nseg));
 }
 
-#if 0
-static void 
-blkif_recover(struct xb_softc *sc)
-{
-       /*
-        * XXX The whole concept of not quiescing and completing all i/o
-        * during suspend, and then hoping to recover and replay the
-        * resulting abandoned I/O during resume, is laughable.  At best,
-        * it invalidates the i/o ordering rules required by just about
-        * every filesystem, and at worst it'll corrupt data.  The code
-        * has been removed until further notice.
-        */
-}
-#endif
-
 /* ** Driver registration ** */
 static device_method_t blkfront_methods[] = { 
        /* Device interface */ 

Modified: head/sys/dev/xen/blkfront/block.h
==============================================================================
--- head/sys/dev/xen/blkfront/block.h   Tue Sep 20 23:44:34 2011        
(r225704)
+++ head/sys/dev/xen/blkfront/block.h   Wed Sep 21 00:02:44 2011        
(r225705)
@@ -142,7 +142,6 @@ struct xb_softc {
 #define XB_READY       (1 << 2)        /* Is ready */
 #define XB_FROZEN      (1 << 3)        /* Waiting for resources */
        int                     vdevice;
-       blkif_vdev_t            handle;
        int                     connected;
        u_int                   ring_pages;
        uint32_t                max_requests;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to