From 7ac62f047e36594198e5846bd1a45cf16149f6aa Mon Sep 17 00:00:00 2001 From: t_jeang Date: Tue, 6 Jan 2009 12:06:01 +0000 Subject: [PATCH] imported patch blktap-shutdown-cleanup2 --- drivers/xen/blktap/backdev.c | 69 +++++++++++++++++++++++++++++++----- drivers/xen/blktap/backdev.h | 3 +- drivers/xen/blktap/blktap.c | 49 ++++++++++++++++--------- drivers/xen/blktap/blktap.h | 5 +-- drivers/xen/blktap/xenbus.c | 27 ++++++++++---- 5 files changed, 117 insertions(+), 36 deletions(-) diff --git a/drivers/xen/blktap/backdev.c b/drivers/xen/blktap/backdev.c index 1b9bd1be..9281dcf6 100644 --- a/drivers/xen/blktap/backdev.c +++ b/drivers/xen/blktap/backdev.c @@ -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 diff --git a/drivers/xen/blktap/backdev.h b/drivers/xen/blktap/backdev.h index 78f27330..c25086cf 100644 --- a/drivers/xen/blktap/backdev.h +++ b/drivers/xen/blktap/backdev.h @@ -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 *); diff --git a/drivers/xen/blktap/blktap.c b/drivers/xen/blktap/blktap.c index 4205ecb7..512c4563 100644 --- a/drivers/xen/blktap/blktap.c +++ b/drivers/xen/blktap/blktap.c @@ -54,6 +54,7 @@ #include #include #include +#include #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); } @@ -363,7 +363,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; } } @@ -512,6 +511,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; @@ -559,11 +561,7 @@ static int blktap_ioctl(struct inode *inode, struct file *filp, return 0; case BLKTAP_IOCTL_SENDPID: - if (info) { - info->pid = (pid_t)arg; - DPRINTK("blktap: pid received %d\n", - info->pid); - } + /* deprecated */ return 0; case BLKTAP_IOCTL_NEWINTF: @@ -880,13 +878,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 +899,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 +915,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 +964,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]); @@ -1302,6 +1316,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; diff --git a/drivers/xen/blktap/blktap.h b/drivers/xen/blktap/blktap.h index e5805ffe..a7411fd2 100644 --- a/drivers/xen/blktap/blktap.h +++ b/drivers/xen/blktap/blktap.h @@ -49,19 +49,16 @@ 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 */ - 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; /* diff --git a/drivers/xen/blktap/xenbus.c b/drivers/xen/blktap/xenbus.c index 3f93a645..e2761383 100644 --- a/drivers/xen/blktap/xenbus.c +++ b/drivers/xen/blktap/xenbus.c @@ -39,6 +39,7 @@ #include #include #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); } /** -- 2.39.5