refactoring balback
Signed-off-by: Ronghui Duan <ronghui.duan@xxxxxxxxx>
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