]> xenbits.xensource.com Git - people/ssmith/nc2-2.6.27.bak/.git/commitdiff
patch blktap-shutdown-cleanup2
authorSteven Smith <ssmith@weybridge.uk.xensource.com>
Thu, 28 May 2009 10:54:19 +0000 (11:54 +0100)
committerSteven Smith <ssmith@weybridge.uk.xensource.com>
Thu, 28 May 2009 10:54:19 +0000 (11:54 +0100)
drivers/xen/blktap/backdev.c
drivers/xen/blktap/backdev.h
drivers/xen/blktap/blktap.c
drivers/xen/blktap/blktap.h
drivers/xen/blktap/xenbus.c

index 1b9bd1beb0246ab149333c0ad7fe3770e537fd87..9281dcf61ed0e17c92204b47b8cbb56d96b09842 100644 (file)
@@ -23,6 +23,7 @@
 DEFINE_SPINLOCK(backdev_io_lock);
 
 static int backdev_major;
+static int umap_uaddr(struct mm_struct *mm, unsigned long address);
 
 int
 register_backdev(void)
@@ -40,13 +41,45 @@ register_backdev(void)
        return 0;
 }
 
+void
+backdev_end_requests(struct tap_blkif *info)
+{
+       int pending_idx, usr_idx, mmap_idx;
+       pending_req_t *pending_req;
+       struct request *req;
+       int ret, i;
+
+       spin_lock_irq(&backdev_io_lock);
+       for (usr_idx = 0; usr_idx < MAX_PENDING_REQS; usr_idx++) {
+               if (info->idx_map[usr_idx] == INVALID_REQ)
+                       continue;
+               pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
+               mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
+               pending_req = &pending_reqs[mmap_idx][pending_idx];
+               blkif_put(info->blkif);
+               if (pending_req->inuse != 2)
+                       continue;
+               for (i = 0; i < pending_req->nr_pages; i++)
+                       umap_uaddr(&init_mm, idx_to_kaddr(mmap_idx,
+                                                         pending_idx, i));
+               req = (struct request *)(unsigned long)pending_req->id;
+               /* See NOTE in do_backdev_request. */
+               ret = end_that_request_first(req, 1, req->hard_nr_sectors);
+               BUG_ON(ret);
+               end_that_request_last(req, 1);
+       }
+       if (info->backdev) {
+               info->backdev->gd->queue->queuedata = NULL;
+               blk_start_queue(info->backdev->gd->queue);
+       }
+       spin_unlock_irq(&backdev_io_lock);
+}
+
 int
 destroy_backdev(struct tap_blkif *uinfo)
 {
        struct backdev_info *info = uinfo->backdev;
 
-       info->destroy = 1;
-
        DPRINTK("destroy backdev %d users %d\n", uinfo->minor, info->users);
        if (info->users)
                return -EBUSY;
@@ -61,6 +94,9 @@ destroy_backdev(struct tap_blkif *uinfo)
 
        blk_cleanup_queue(info->gd->queue);
 
+       if (uinfo->blkif->xenblkd)
+           wake_up_process(uinfo->blkif->xenblkd);
+
        blkif_put(uinfo->blkif);
 
        uinfo->backdev = NULL;
@@ -71,10 +107,18 @@ destroy_backdev(struct tap_blkif *uinfo)
        return 0;
 }
 
+int
+backdev_users(struct tap_blkif *uinfo)
+{
+       return uinfo->backdev && (uinfo->backdev->users != 0);
+}
+
 static int
 backdev_open(struct inode *inode, struct file *filep)
 {
        struct backdev_info *info = inode->i_bdev->bd_disk->private_data;
+       if (info->uinfo == NULL || info->uinfo->remove_requested)
+               return -ENOENT;
        info->users++;
        return 0;
 }
@@ -84,7 +128,7 @@ backdev_release(struct inode *inode, struct file *filep)
 {
        struct backdev_info *info = inode->i_bdev->bd_disk->private_data;
        info->users--;
-       if (info->destroy)
+       if (info->uinfo->remove_requested)
                destroy_backdev(info->uinfo);
        return 0;
 }
@@ -247,7 +291,7 @@ process_backdev_request(struct tap_blkif *uinfo, struct backdev_info *info)
            end_request(req, 0);
            continue;
        }
-       if (info->destroy) {
+       if (uinfo->remove_requested) {
            DPRINTK("device no longer in use %d\n", info->uinfo->minor);
            end_request(req, 0);
            continue;
@@ -370,14 +414,21 @@ static void
 do_backdev_request(request_queue_t *rq)
 {
        struct backdev_info *info;
+       struct request *req;
 
        info = rq->queuedata;
-       if (info->uinfo) {
-               info->uinfo->blkif->waiting_reqs = 1;
-               wake_up(&info->uinfo->blkif->wq);
-               DPRINTK("got requests for dev %d wake %p\n",
-                       info->uinfo->minor, info->uinfo->blkif);
+       if (info == NULL || info->uinfo == NULL ||
+           info->uinfo->remove_requested) {
+               /* NOTE: we pretend that the request succeeded because
+                * this seems better than returning block device
+                * errors to dom0 given that the linux filesystem code
+                * doesn't seem to handle these too gracefully. */
+               while ((req = elv_next_request(rq)))
+                       end_request(req, 1);
+               return;
        }
+       info->uinfo->blkif->waiting_reqs = 1;
+       wake_up(&info->uinfo->blkif->wq);
 }
 
 void
index 78f273302cc301d32c0f2b7e20e4e9eb77f787c1..c25086cf8ea486bf9a59328890c88187e6765f07 100644 (file)
@@ -4,7 +4,6 @@ struct pending_req;
 
 struct backdev_info {
        int users;
-       int destroy;
        struct gendisk *gd;
        struct tap_blkif *uinfo;
 };
@@ -15,3 +14,5 @@ extern int destroy_backdev(struct tap_blkif *);
 extern void backdev_finish_req(struct tap_blkif *, int, blkif_response_t *,
                               struct pending_req *);
 extern void backdev_restart_queue(struct tap_blkif *);
+extern int backdev_users(struct tap_blkif *);
+extern void backdev_end_requests(struct tap_blkif *);
index 649ca507702fb8d329e5efc61cb837f6f8fd19b9..f6e6cbecffebeef0b00b8bc15f6f6ad600d9cbc0 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/delay.h>
 #include <linux/nsproxy.h>
 #include <asm/tlbflush.h>
+#include <linux/syscalls.h>
 
 #include "blktap.h"
 #include "backdev.h"
@@ -250,11 +251,10 @@ static void blktap_vm_close(struct vm_area_struct *vma)
        ClearPageReserved(virt_to_page(info->ufe_ring.sring));
        free_page((unsigned long)info->ufe_ring.sring);
 
-       kfree(info->idx_map);
-       info->idx_map = NULL;
-
        info->vma = NULL;
        clear_bit(2, &info->dev_inuse);
+       if (info->blkif->xenblkd)
+               wake_up_process(info->blkif->xenblkd);
 
        up_write(&info->vm_update_sem);
 }
@@ -362,7 +362,6 @@ associate_blkif(domid_t domid, int xenbus_id, blkif_t *blkif)
                if (info && info->trans.domid == domid &&
                    info->trans.busid == xenbus_id) {
                        info->blkif = blkif;
-                       info->status = RUNNING;
                        return info;
                }
        }
@@ -511,6 +510,9 @@ static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
        vma->vm_mm->context.has_foreign_mappings = 1;
 #endif
 
+       info->pid = current->pid;
+       DPRINTK("blktap: mapping pid is %d\n", info->pid);
+
        info->vma = vma;
        return 0;
 
@@ -558,12 +560,7 @@ static int blktap_ioctl(struct inode *inode, struct file *filp,
                return 0;
 
        case BLKTAP_IOCTL_SENDPID:
-               if (info) {
-                       info->pid = (pid_t)arg;
-                       info->pid_ns = current->nsproxy->pid_ns;
-                       DPRINTK("blktap: pid received %p:%d\n",
-                               info->pid_ns, info->pid);
-               }
+               /* deprecated */
                return 0;
 
        case BLKTAP_IOCTL_NEWINTF:
@@ -880,13 +877,12 @@ int tap_blkif_schedule(void *arg)
 
                wait_event_interruptible(
                        blkif->wq,
-                       blkif->waiting_reqs || kthread_should_stop());
+                       blkif->waiting_reqs || info->vma == NULL ||
+                       (info->remove_requested && backdev_users(info) == 0));
                wait_event_interruptible(
                        pending_free_wq,
-                       !list_empty(&pending_free) || kthread_should_stop());
-
-               if (kthread_should_stop())
-                       break;
+                       !list_empty(&pending_free) || info->vma == NULL ||
+                       (info->remove_requested && backdev_users(info) == 0));
 
                blkif->waiting_reqs = 0;
                smp_mb(); /* clear flag *before* checking for work */
@@ -902,6 +898,11 @@ int tap_blkif_schedule(void *arg)
                else
                        backdev_restart_queue(info);
 
+               if (info->remove_requested && backdev_users(info) == 0) {
+                       sys_kill(info->pid, SIGTERM);
+                       info->remove_requested = 0;
+               }
+
                up_read(&info->vm_update_sem);
 
                if (log_stats && time_after(jiffies, blkif->st_print))
@@ -913,12 +914,18 @@ int tap_blkif_schedule(void *arg)
        if (debug_lvl)
                printk(KERN_DEBUG "%s: exiting\n", current->comm);
 
-       destroy_backdev(info);
+       backdev_end_requests(info);
+       if (info->backdev)
+               destroy_backdev(info);
 
+       kfree(info->idx_map);
+       info->idx_map = NULL;
+
+       tap_blkif_free(blkif);
        blkif->xenblkd = NULL;
-       blkif_put(blkif);
 
        clear_bit(3, &info->dev_inuse);
+       info->remove_requested = 0;
 
        return 0;
 }
@@ -956,6 +963,12 @@ static int blktap_read_ufe_ring(tap_blkif_t *info)
                usr_idx = (int)res.id;
                DPRINTK("response %d id %x idx_map %p\n", rc, usr_idx,
                        info->idx_map);
+               if (usr_idx >= MAX_PENDING_REQS ||
+                   info->idx_map[usr_idx] == INVALID_REQ) {
+                       WPRINTK("Request %d/%d invalid [%x], tapdisk %d%p\n",
+                               rc, rp, usr_idx, info->pid, info->vma);
+                       continue;
+               }
                pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
                mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
 
@@ -1317,6 +1330,9 @@ static void make_response(blkif_t *blkif, u64 id,
        int more_to_do = 0;
        int notify;
 
+       if (!tap_blkif_connected(blkif))
+               return;
+
        resp.id        = id;
        resp.operation = op;
        resp.status    = st;
index a5d095b4c2029d958d354e0f6f1478ad7c9b8890..f93fe6eac1049f4013b350676c40b4fb677bb56e 100644 (file)
@@ -49,20 +49,17 @@ typedef struct tap_blkif {
        unsigned long rings_vstart;   /*Kernel memory mapping                */
        unsigned long user_vstart;    /*User memory mapping                  */
        unsigned long dev_inuse;      /*One process opens device at a time.  */
-       unsigned long dev_pending;    /*In process of being opened           */
-       unsigned long ring_ok;        /*make this ring->state                */
        blkif_front_ring_t ufe_ring;  /*Rings up to user space.              */
        wait_queue_head_t wait;       /*for poll                             */
        int minor;                    /*Minor number for tapdisk device      */
        pid_t pid;                    /*tapdisk process id                   */
        struct pid_namespace *pid_ns; /*... and its corresponding namespace  */
-       enum { RUNNING, CLEANSHUTDOWN } status; /*Detect a clean userspace 
-                                                 shutdown                   */
        unsigned long *idx_map;       /*Record the user ring id to kern 
                                        [req id, idx] tuple                  */
        blkif_t *blkif;               /*Associate blkif with tapdev          */
        struct domid_translate trans; /*Translation from domid to bus.       */
        struct backdev_info *backdev; /*Backend domain device info           */
+       int remove_requested;         /*Xenbus triggered remove requested    */
 } tap_blkif_t;
 
 /*
index 1196795c32a92016232104d1e07bb3dbfafea6ee..b044c8afdf762de9dd6c74a0b10597d3a45a3812 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/kthread.h>
 #include <xen/xenbus.h>
 #include "common.h"
+#include "blktap.h"
 
 
 struct backend_info
@@ -175,14 +176,28 @@ static int blktap_remove(struct xenbus_device *dev)
        if (be->backend_watch.node) {
                unregister_xenbus_watch(&be->backend_watch);
                kfree(be->backend_watch.node);
-               be->backend_watch.node = NULL;
        }
        if (be->blkif) {
-               if (be->blkif->xenblkd)
-                       kthread_stop(be->blkif->xenblkd);
-               tap_blkif_free(be->blkif);
-               be->blkif = NULL;
+               if (be->blkif->xenblkd == NULL) {
+                       if (atomic_read(&be->blkif->refcnt) != 1)
+                               WPRINTK("refcnt is %d, expected 1",
+                                       atomic_read(&be->blkif->refcnt));
+                       /* If the kthread was never started, free tap_blkif. */
+                       tap_blkif_free(be->blkif);
+               } else {
+                       struct tap_blkif *info = be->blkif->tapif;
+
+                       down_write(&info->vm_update_sem);
+                       tap_blkif_unmap(be->blkif);
+                       be->blkif->be = NULL;
+                       up_write(&info->vm_update_sem);
+
+                       be->blkif->tapif->remove_requested = 1;
+                       wake_up_process(be->blkif->xenblkd);
+                       blkif_put(be->blkif);
+               }
        }
+       be->blkif->be = NULL;
        kfree(be);
        dev->dev.driver_data = NULL;
        return 0;
@@ -218,7 +233,7 @@ static void tap_update_blkif_status(blkif_t *blkif)
 
 int tap_blkif_connected(blkif_t *blkif)
 {
-       return (blkif->be->dev->state == XenbusStateConnected);
+       return (blkif->be && blkif->be->dev->state == XenbusStateConnected);
 }
 
 /**