Duan, Ronghui
2012-Aug-16 10:27 UTC
[RFC v1 3/5] VBD: enlarge max segment per request in blkfront
refactoring balback Signed-off-by: Ronghui Duan <ronghui.duan@intel.com<mailto:ronghui.duan@intel.com>> diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 73f196c..b4767f5 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -64,6 +64,11 @@ MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate"); static unsigned int log_stats; module_param(log_stats, int, 0644); +struct seg_buf { + unsigned long buf; + unsigned int nsec; +}; + /* * Each outstanding request that we''ve passed to the lower device layers has a * ''pending_req'' allocated to it. Each buffer_head that completes decrements @@ -78,6 +83,11 @@ struct pending_req { unsigned short operation; int status; struct list_head free_list; + struct gnttab_map_grant_ref *map; + struct gnttab_unmap_grant_ref *unmap; + struct seg_buf *seg; + struct bio **biolist; + struct page **pages; }; #define BLKBACK_INVALID_HANDLE (~0) @@ -123,28 +133,9 @@ static inline unsigned long vaddr(struct pending_req *req, int seg) static int do_block_io_op(struct xen_blkif *blkif); static int dispatch_rw_block_io(struct xen_blkif *blkif, - struct blkif_request *req, struct pending_req *pending_req); static void make_response(struct xen_blkif *blkif, u64 id, - unsigned short op, int st); - -/* - * Retrieve from the ''pending_reqs'' a free pending_req structure to be used. - */ -static struct pending_req *alloc_req(void) -{ - struct pending_req *req = NULL; - unsigned long flags; - - spin_lock_irqsave(&blkbk->pending_free_lock, flags); - if (!list_empty(&blkbk->pending_free)) { - req = list_entry(blkbk->pending_free.next, struct pending_req, - free_list); - list_del(&req->free_list); - } - spin_unlock_irqrestore(&blkbk->pending_free_lock, flags); - return req; -} + unsigned short op, int nr_page, int st); /* * Return the ''pending_req'' structure back to the freepool. We also @@ -155,6 +146,12 @@ static void free_req(struct pending_req *req) unsigned long flags; int was_empty; + kfree(req->map); + kfree(req->unmap); + kfree(req->biolist); + kfree(req->seg); + kfree(req->pages); + spin_lock_irqsave(&blkbk->pending_free_lock, flags); was_empty = list_empty(&blkbk->pending_free); list_add(&req->free_list, &blkbk->pending_free); @@ -162,7 +159,42 @@ static void free_req(struct pending_req *req) if (was_empty) wake_up(&blkbk->pending_free_wq); } - +/* + * Retrieve from the ''pending_reqs'' a free pending_req structure to be used. + */ +static struct pending_req *alloc_req(void) +{ + struct pending_req *req = NULL; + unsigned long flags; + unsigned int max_seg = BLKIF_MAX_SEGMENTS_PER_REQUEST; + + spin_lock_irqsave(&blkbk->pending_free_lock, flags); + if (!list_empty(&blkbk->pending_free)) { + req = list_entry(blkbk->pending_free.next, struct pending_req, + free_list); + list_del(&req->free_list); + } + spin_unlock_irqrestore(&blkbk->pending_free_lock, flags); + + if (req != NULL) { + req->map = kzalloc(sizeof(struct gnttab_map_grant_ref) * + max_seg, GFP_KERNEL); + req->unmap = kzalloc(sizeof(struct gnttab_unmap_grant_ref) * + max_seg, GFP_KERNEL); + req->biolist = kzalloc(sizeof(struct bio *) * max_seg, + GFP_KERNEL); + req->seg = kzalloc(sizeof(struct seg_buf) * max_seg, + GFP_KERNEL); + req->pages = kzalloc(sizeof(struct page *) * max_seg, + GFP_KERNEL); + if (!req->map || !req->unmap || !req->biolist || + !req->seg || !req->pages) { + free_req(req); + req = NULL; + } + } + return req; +} /* * Routines for managing virtual block devices (vbds). */ @@ -308,11 +340,6 @@ int xen_blkif_schedule(void *arg) xen_blkif_put(blkif); return 0; -} - -struct seg_buf { - unsigned long buf; - unsigned int nsec; }; /* * Unmap the grant references, and also remove the M2P over-rides @@ -320,8 +347,8 @@ struct seg_buf { */ static void xen_blkbk_unmap(struct pending_req *req) { - struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + struct gnttab_unmap_grant_ref *unmap = req->unmap; + struct page **pages = req->pages; unsigned int i, invcount = 0; grant_handle_t handle; int ret; @@ -341,11 +368,13 @@ static void xen_blkbk_unmap(struct pending_req *req) BUG_ON(ret); } + static int xen_blkbk_map(struct blkif_request *req, + struct blkif_request_segment *seg_req, struct pending_req *pending_req, struct seg_buf seg[]) { - struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + struct gnttab_map_grant_ref *map = pending_req->map; int i; int nseg = req->u.rw.nr_segments; int ret = 0; @@ -362,7 +391,7 @@ static int xen_blkbk_map(struct blkif_request *req, if (pending_req->operation != BLKIF_OP_READ) flags |= GNTMAP_readonly; gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags, - req->u.rw.seg[i].gref, + seg_req[i].gref, pending_req->blkif->domid); } @@ -387,14 +416,15 @@ static int xen_blkbk_map(struct blkif_request *req, continue; seg[i].buf = map[i].dev_bus_addr | - (req->u.rw.seg[i].first_sect << 9); + (seg_req[i].first_sect << 9); } return ret; } -static int dispatch_discard_io(struct xen_blkif *blkif, - struct blkif_request *req) +static int dispatch_discard_io(struct xen_blkif *blkif) { + struct blkif_request *blkif_req = (struct blkif_request *)blkif->req; + struct blkif_request_discard *req = &blkif_req->u.discard; int err = 0; int status = BLKIF_RSP_OKAY; struct block_device *bdev = blkif->vbd.bdev; @@ -404,11 +434,11 @@ static int dispatch_discard_io(struct xen_blkif *blkif, xen_blkif_get(blkif); secure = (blkif->vbd.discard_secure && - (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ? + (req->flag & BLKIF_DISCARD_SECURE)) ? BLKDEV_DISCARD_SECURE : 0; - err = blkdev_issue_discard(bdev, req->u.discard.sector_number, - req->u.discard.nr_sectors, + err = blkdev_issue_discard(bdev, req->sector_number, + req->nr_sectors, GFP_KERNEL, secure); if (err == -EOPNOTSUPP) { @@ -417,7 +447,7 @@ static int dispatch_discard_io(struct xen_blkif *blkif, } else if (err) status = BLKIF_RSP_ERROR; - make_response(blkif, req->u.discard.id, req->operation, status); + make_response(blkif, req->id, BLKIF_OP_DISCARD, 0, status); xen_blkif_put(blkif); return err; } @@ -470,7 +500,8 @@ static void __end_block_io_op(struct pending_req *pending_req, int error) if (atomic_dec_and_test(&pending_req->pendcnt)) { xen_blkbk_unmap(pending_req); make_response(pending_req->blkif, pending_req->id, - pending_req->operation, pending_req->status); + pending_req->operation, pending_req->nr_pages, + pending_req->status); xen_blkif_put(pending_req->blkif); if (atomic_read(&pending_req->blkif->refcnt) <= 2) { if (atomic_read(&pending_req->blkif->drain)) @@ -489,8 +520,37 @@ static void end_block_io_op(struct bio *bio, int error) bio_put(bio); } +void *get_back_ring(struct xen_blkif *blkif) +{ + return (void *)&blkif->blk_rings; +} +void copy_blkif_req(struct xen_blkif *blkif, RING_IDX rc) +{ + struct blkif_request *req = (struct blkif_request *)blkif->req; + union blkif_back_rings *blk_rings = &blkif->blk_rings; + switch (blkif->blk_protocol) { + case BLKIF_PROTOCOL_NATIVE: + memcpy(req, RING_GET_REQUEST(&blk_rings->native, rc), + sizeof(struct blkif_request)); + break; + case BLKIF_PROTOCOL_X86_32: + blkif_get_x86_32_req(req, RING_GET_REQUEST(&blk_rings->x86_32, rc)); + break; + case BLKIF_PROTOCOL_X86_64: + blkif_get_x86_64_req(req, RING_GET_REQUEST(&blk_rings->x86_64, rc)); + break; + default: + BUG(); + } +} + +void copy_blkif_seg_req(struct xen_blkif *blkif) +{ + struct blkif_request *req = (struct blkif_request *)blkif->req; + blkif->seg_req = req->u.rw.seg; +} /* * Function to copy the from the ring buffer the ''struct blkif_request'' * (which has the sectors we want, number of them, grant references, etc), @@ -499,8 +559,9 @@ static void end_block_io_op(struct bio *bio, int error) static int __do_block_io_op(struct xen_blkif *blkif) { - union blkif_back_rings *blk_rings = &blkif->blk_rings; - struct blkif_request req; + union blkif_back_rings *blk_rings + (union blkif_back_rings *)blkif->ops->get_back_ring(blkif); + struct blkif_request *req = (struct blkif_request *)blkif->req; struct pending_req *pending_req; RING_IDX rc, rp; int more_to_do = 0; @@ -526,28 +587,19 @@ __do_block_io_op(struct xen_blkif *blkif) break; } - switch (blkif->blk_protocol) { - case BLKIF_PROTOCOL_NATIVE: - memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc), sizeof(req)); - break; - case BLKIF_PROTOCOL_X86_32: - blkif_get_x86_32_req(&req, RING_GET_REQUEST(&blk_rings->x86_32, rc)); - break; - case BLKIF_PROTOCOL_X86_64: - blkif_get_x86_64_req(&req, RING_GET_REQUEST(&blk_rings->x86_64, rc)); - break; - default: - BUG(); - } + blkif->ops->copy_blkif_req(blkif, rc); + + blkif->ops->copy_blkif_seg_req(blkif); + blk_rings->common.req_cons = ++rc; /* before make_response() */ /* Apply all sanity checks to /private copy/ of request. */ barrier(); - if (unlikely(req.operation == BLKIF_OP_DISCARD)) { + if (unlikely(req->operation == BLKIF_OP_DISCARD)) { free_req(pending_req); - if (dispatch_discard_io(blkif, &req)) + if (dispatch_discard_io(blkif)) break; - } else if (dispatch_rw_block_io(blkif, &req, pending_req)) + } else if (dispatch_rw_block_io(blkif, pending_req)) break; /* Yield point for this unbounded loop. */ @@ -560,7 +612,8 @@ __do_block_io_op(struct xen_blkif *blkif) static int do_block_io_op(struct xen_blkif *blkif) { - union blkif_back_rings *blk_rings = &blkif->blk_rings; + union blkif_back_rings *blk_rings + (union blkif_back_rings *)blkif->ops->get_back_ring(blkif); int more_to_do; do { @@ -578,14 +631,15 @@ do_block_io_op(struct xen_blkif *blkif) * and call the ''submit_bio'' to pass it to the underlying storage. */ static int dispatch_rw_block_io(struct xen_blkif *blkif, - struct blkif_request *req, struct pending_req *pending_req) { + struct blkif_request *req = (struct blkif_request *)blkif->req; + struct blkif_request_segment *seg_req = blkif->seg_req; struct phys_req preq; - struct seg_buf seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + struct seg_buf *seg = pending_req->seg; unsigned int nseg; struct bio *bio = NULL; - struct bio *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + struct bio **biolist = pending_req->biolist; int i, nbio = 0; int operation; struct blk_plug plug; @@ -616,7 +670,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, nseg = req->u.rw.nr_segments; if (unlikely(nseg == 0 && operation != WRITE_FLUSH) || - unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) { + unlikely(nseg > blkif->ops->max_seg)) { pr_debug(DRV_PFX "Bad number of segments in request (%d)\n", nseg); /* Haven''t submitted any bio''s yet. */ @@ -634,10 +688,10 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, pending_req->nr_pages = nseg; for (i = 0; i < nseg; i++) { - seg[i].nsec = req->u.rw.seg[i].last_sect - - req->u.rw.seg[i].first_sect + 1; - if ((req->u.rw.seg[i].last_sect >= (PAGE_SIZE >> 9)) || - (req->u.rw.seg[i].last_sect < req->u.rw.seg[i].first_sect)) + seg[i].nsec = seg_req[i].last_sect - + seg_req[i].first_sect + 1; + if ((seg_req[i].last_sect >= (PAGE_SIZE >> 9)) || + (seg_req[i].last_sect < seg_req[i].first_sect)) goto fail_response; preq.nr_sects += seg[i].nsec; @@ -676,7 +730,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, * the hypercall to unmap the grants - that is all done in * xen_blkbk_unmap. */ - if (xen_blkbk_map(req, pending_req, seg)) + if (xen_blkbk_map(req, seg_req, pending_req, seg)) goto fail_flush; /* @@ -746,7 +800,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, xen_blkbk_unmap(pending_req); fail_response: /* Haven''t submitted any bio''s yet. */ - make_response(blkif, req->u.rw.id, req->operation, BLKIF_RSP_ERROR); + make_response(blkif, req->u.rw.id, req->operation, 0, BLKIF_RSP_ERROR); free_req(pending_req); msleep(1); /* back off a bit */ return -EIO; @@ -759,17 +813,28 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, return -EIO; } +struct blkif_segment_back_ring * + get_seg_back_ring(struct xen_blkif *blkif) +{ + return NULL; +} +void push_back_ring_rsp(union blkif_back_rings *blk_rings, int nr_page, int *notify) +{ + blk_rings->common.rsp_prod_pvt++; + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, *notify); +} /* * Put a response on the ring on how the operation fared. */ static void make_response(struct xen_blkif *blkif, u64 id, - unsigned short op, int st) + unsigned short op, int nr_page, int st) { struct blkif_response resp; unsigned long flags; - union blkif_back_rings *blk_rings = &blkif->blk_rings; + union blkif_back_rings *blk_rings + (union blkif_back_rings *)blkif->ops->get_back_ring(blkif); int notify; resp.id = id; @@ -794,8 +859,9 @@ static void make_response(struct xen_blkif *blkif, u64 id, default: BUG(); } - blk_rings->common.rsp_prod_pvt++; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify); + + blkif->ops->push_back_ring_rsp(blk_rings, nr_page, ¬ify); + spin_unlock_irqrestore(&blkif->blk_ring_lock, flags); if (notify) notify_remote_via_irq(blkif->irq); @@ -873,6 +939,14 @@ static int __init xen_blkif_init(void) return rc; } +struct blkback_ring_operation blkback_ring_ops = { + .get_back_ring = get_back_ring, + .copy_blkif_req = copy_blkif_req, + .copy_blkif_seg_req = copy_blkif_seg_req, + .push_back_ring_rsp = push_back_ring_rsp, + .max_seg = BLKIF_MAX_SEGMENTS_PER_REQUEST, +}; + module_init(xen_blkif_init); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 9ad3b5e..ce5556a 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -146,6 +146,11 @@ enum blkif_protocol { BLKIF_PROTOCOL_X86_64 = 3, }; +enum blkif_backring_type { + BACKRING_TYPE_1 = 1, + BACKRING_TYPE_2 = 2, +}; + struct xen_vbd { /* What the domain refers to this vbd as. */ blkif_vdev_t handle; @@ -163,6 +168,15 @@ struct xen_vbd { }; struct backend_info; +struct xen_blkif; + +struct blkback_ring_operation { + void *(*get_back_ring) (struct xen_blkif *blkif); + void (*copy_blkif_req) (struct xen_blkif *blkif, RING_IDX rc); + void (*copy_blkif_seg_req) (struct xen_blkif *blkif); + void (*push_back_ring_rsp) (union blkif_back_rings *blk_rings, int nr_page, int *notify); + unsigned int max_seg; +}; struct xen_blkif { /* Unique identifier for this interface. */ @@ -171,7 +185,9 @@ struct xen_blkif { /* Physical parameters of the comms window. */ unsigned int irq; /* Comms information. */ + struct blkback_ring_operation *ops; enum blkif_protocol blk_protocol; + enum blkif_backring_type blk_backring_type; union blkif_back_rings blk_rings; void *blk_ring; /* The VBD attached to this interface. */ @@ -179,6 +195,8 @@ struct xen_blkif { /* Back pointer to the backend_info. */ struct backend_info *be; /* Private fields. */ + void * req; + struct blkif_request_segment *seg_req; spinlock_t blk_ring_lock; atomic_t refcnt; diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 4f66171..850ecad 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -36,6 +36,8 @@ static int connect_ring(struct backend_info *); static void backend_changed(struct xenbus_watch *, const char **, unsigned int); +extern struct blkback_ring_operation blkback_ring_ops; + struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be) { return be->dev; @@ -725,6 +727,12 @@ static int connect_ring(struct backend_info *be) int err; DPRINTK("%s", dev->otherend); + be->blkif->ops = &blkback_ring_ops; + be->blkif->req = kmalloc(sizeof(struct blkif_request), + GFP_KERNEL); + be->blkif->seg_req = kmalloc(sizeof(struct blkif_request_segment)* + be->blkif->ops->max_seg, GFP_KERNEL); + be->blkif->blk_backring_type = BACKRING_TYPE_1; err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", &ring_ref, "event-channel", "%u", &evtchn, NULL); -ronghui _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel