[LINUX][BLKBACK] Support temporary disconnection from frontend.
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 27 Jun 2006 17:08:46 +0000 (18:08 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 27 Jun 2006 17:08:46 +0000 (18:08 +0100)
Signed-off-by: Steven Smith <sos22@cam.ac.uk>
Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/drivers/xen/blkback/common.h
linux-2.6-xen-sparse/drivers/xen/blkback/interface.c
linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c

index 0ba7c588dd68b9cefa01d26de8e00f8c82e78779..d057f79242c92946df89b6f0aae350b8779d39c1 100644 (file)
@@ -95,6 +95,7 @@ typedef struct blkif_st {
 } blkif_t;
 
 blkif_t *blkif_alloc(domid_t domid);
+void blkif_disconnect(blkif_t *blkif);
 void blkif_free(blkif_t *blkif);
 int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn);
 
index 8f1bf4d2fef1bdfa66392191a21144fa1a35d34c..e5d67ea6339055a1954504a7688b3bbae8b661b5 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "common.h"
 #include <xen/evtchn.h>
+#include <linux/kthread.h>
 
 static kmem_cache_t *blkif_cachep;
 
@@ -139,22 +140,33 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
        return 0;
 }
 
-void blkif_free(blkif_t *blkif)
+void blkif_disconnect(blkif_t *blkif)
 {
+       if (blkif->xenblkd) {
+               kthread_stop(blkif->xenblkd);
+               blkif->xenblkd = NULL;
+       }
+
        atomic_dec(&blkif->refcnt);
        wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
+       atomic_inc(&blkif->refcnt);
 
-       /* Already disconnected? */
-       if (blkif->irq)
+       if (blkif->irq) {
                unbind_from_irqhandler(blkif->irq, blkif);
-
-       vbd_free(&blkif->vbd);
+               blkif->irq = 0;
+       }
 
        if (blkif->blk_ring.sring) {
                unmap_frontend_page(blkif);
                free_vm_area(blkif->blk_ring_area);
+               blkif->blk_ring.sring = NULL;
        }
+}
 
+void blkif_free(blkif_t *blkif)
+{
+       if (!atomic_dec_and_test(&blkif->refcnt))
+               BUG();
        kmem_cache_free(blkif_cachep, blkif);
 }
 
index 5c4233d249c2fc874a37eb1a339dd288c0846a45..5ee3a46982b5025b612f12d2ed7232a7d373e807 100644 (file)
@@ -105,9 +105,10 @@ static int blkback_remove(struct xenbus_device *dev)
                kfree(be->backend_watch.node);
                be->backend_watch.node = NULL;
        }
+
        if (be->blkif) {
-               if (be->blkif->xenblkd)
-                       kthread_stop(be->blkif->xenblkd);
+               blkif_disconnect(be->blkif);
+               vbd_free(&be->blkif->vbd);
                blkif_free(be->blkif);
                be->blkif = NULL;
        }
@@ -273,6 +274,7 @@ static void frontend_changed(struct xenbus_device *dev,
                break;
 
        case XenbusStateClosing:
+               blkif_disconnect(be->blkif);
                xenbus_switch_state(dev, XenbusStateClosing);
                break;