mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
bitkeeper revision 1.1159.207.3 (41d40e9b3_4vSbRgi7pJ9tnNxCToeQ)
New generic I/O ring macros from Andrew Warfield and Tim Deegan. Currently only used for block-device channels.
This commit is contained in:
1 parent
3d866e0585
commit
0b788798d8
8 files changed
+388
-137
No files matched your search
@@ -860,6 +860,7 @@
|
||||
40dc4076pVeE1kEEWzcUaNZin65kCA xen/include/public/io/domain_controller.h
|
||||
41c0c412FLc0gunlJl91qMYscFtXVA xen/include/public/io/ioreq.h
|
||||
40f5623cTZ80EwjWUBlh44A9F9i_Lg xen/include/public/io/netif.h
|
||||
41d40e9b8zCk5VDqhVbuQyhc7G3lqA xen/include/public/io/ring.h
|
||||
4051db79512nOCGweabrFWO2M2h5ng xen/include/public/physdev.h
|
||||
40589968wmhPmV5-ENbBYmMjnedgKw xen/include/public/sched_ctl.h
|
||||
404f3d2eR2Owk-ZcGOx9ULGHg3nrww xen/include/public/trace.h
|
||||
|
||||
@@ -74,12 +74,11 @@ static kmem_cache_t *buffer_head_cachep;
|
||||
* If the tap driver is used, we may get pages belonging to either the tap
|
||||
* or (more likely) the real frontend. The backend must specify which domain
|
||||
* a given page belongs to in update_va_mapping though. For the moment,
|
||||
* we pass in the domid of the real frontend in PROBE messages and store
|
||||
* this value in alt_dom. Then on mapping, we try both. This is a Guiness
|
||||
* book of records-calibre grim hack, and represents a bit of a security risk.
|
||||
* Grant tables will soon solve the problem though!
|
||||
* the tap rewrites the ID field of the request to contain the request index
|
||||
* and the id of the real front end domain.
|
||||
*/
|
||||
static domid_t alt_dom = 0;
|
||||
#define BLKTAP_COOKIE 0xbeadfeed
|
||||
static inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); }
|
||||
#endif
|
||||
|
||||
static int do_block_io_op(blkif_t *blkif, int max_to_do);
|
||||
@@ -279,17 +278,16 @@ irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
|
||||
|
||||
static int do_block_io_op(blkif_t *blkif, int max_to_do)
|
||||
{
|
||||
blkif_ring_t *blk_ring = blkif->blk_ring_base;
|
||||
blkif_back_ring_t *blk_ring = &blkif->blk_ring;
|
||||
blkif_request_t *req;
|
||||
BLKIF_RING_IDX i, rp;
|
||||
RING_IDX i, rp;
|
||||
int more_to_do = 0;
|
||||
|
||||
rp = blk_ring->req_prod;
|
||||
rp = blk_ring->sring->req_prod;
|
||||
rmb(); /* Ensure we see queued requests up to 'rp'. */
|
||||
|
||||
/* Take items off the comms ring, taking care not to overflow. */
|
||||
for ( i = blkif->blk_req_cons;
|
||||
(i != rp) && ((i-blkif->blk_resp_prod) != BLKIF_RING_SIZE);
|
||||
for ( i = blk_ring->req_cons;
|
||||
(i != rp) && !RING_REQUEST_CONS_OVERFLOW(BLKIF_RING, blk_ring, i);
|
||||
i++ )
|
||||
{
|
||||
if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) )
|
||||
@@ -298,7 +296,7 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
|
||||
break;
|
||||
}
|
||||
|
||||
req = &blk_ring->ring[MASK_BLKIF_IDX(i)].req;
|
||||
req = RING_GET_REQUEST(BLKIF_RING, blk_ring, i);
|
||||
switch ( req->operation )
|
||||
{
|
||||
case BLKIF_OP_READ:
|
||||
@@ -312,14 +310,13 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
|
||||
|
||||
default:
|
||||
DPRINTK("error: unknown block io operation [%d]\n",
|
||||
blk_ring->ring[i].req.operation);
|
||||
make_response(blkif, blk_ring->ring[i].req.id,
|
||||
blk_ring->ring[i].req.operation, BLKIF_RSP_ERROR);
|
||||
req->operation);
|
||||
make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
blkif->blk_req_cons = i;
|
||||
blk_ring->req_cons = i;
|
||||
return more_to_do;
|
||||
}
|
||||
|
||||
@@ -339,24 +336,26 @@ static void dispatch_probe(blkif_t *blkif, blkif_request_t *req)
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
/* Grab the real frontend out of the probe message. */
|
||||
alt_dom = (domid_t)req->frame_and_sects[1];
|
||||
if (req->frame_and_sects[1] == BLKTAP_COOKIE)
|
||||
blkif->is_blktap = 1;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
if ( HYPERVISOR_update_va_mapping_otherdomain(
|
||||
MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
|
||||
(pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
|
||||
0, blkif->domid) ) {
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
/* That didn't work. Try alt_dom. */
|
||||
if ( HYPERVISOR_update_va_mapping_otherdomain(
|
||||
MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
|
||||
(pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
|
||||
0, alt_dom) )
|
||||
goto out;
|
||||
#else
|
||||
0, (blkif->is_blktap ? ID_TO_DOM(req->id) : blkif->domid) ) )
|
||||
|
||||
goto out;
|
||||
#else
|
||||
if ( HYPERVISOR_update_va_mapping_otherdomain(
|
||||
MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
|
||||
(pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
|
||||
0, blkif->domid) )
|
||||
|
||||
goto out;
|
||||
#endif
|
||||
}
|
||||
|
||||
rsp = vbd_probe(blkif, (vdisk_t *)MMAP_VADDR(pending_idx, 0),
|
||||
PAGE_SIZE / sizeof(vdisk_t));
|
||||
@@ -441,7 +440,7 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
|
||||
mcl[i].args[1] = (phys_seg[i].buffer & PAGE_MASK) | remap_prot;
|
||||
mcl[i].args[2] = 0;
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
mcl[i].args[3] = (alt_dom != 0) ? alt_dom : blkif->domid;
|
||||
mcl[i].args[3] = (blkif->is_blktap) ? ID_TO_DOM(req->id) : blkif->domid;
|
||||
#else
|
||||
mcl[i].args[3] = blkif->domid;
|
||||
#endif
|
||||
@@ -558,16 +557,17 @@ static void make_response(blkif_t *blkif, unsigned long id,
|
||||
{
|
||||
blkif_response_t *resp;
|
||||
unsigned long flags;
|
||||
blkif_back_ring_t *blk_ring = &blkif->blk_ring;
|
||||
|
||||
/* Place on the response ring for the relevant domain. */
|
||||
spin_lock_irqsave(&blkif->blk_ring_lock, flags);
|
||||
resp = &blkif->blk_ring_base->
|
||||
ring[MASK_BLKIF_IDX(blkif->blk_resp_prod)].resp;
|
||||
resp = RING_GET_RESPONSE(BLKIF_RING, blk_ring, blk_ring->rsp_prod_pvt);
|
||||
resp->id = id;
|
||||
resp->operation = op;
|
||||
resp->status = st;
|
||||
wmb(); /* Ensure other side can see the response fields. */
|
||||
blkif->blk_ring_base->resp_prod = ++blkif->blk_resp_prod;
|
||||
blk_ring->rsp_prod_pvt++;
|
||||
RING_PUSH_RESPONSES(BLKIF_RING, blk_ring);
|
||||
spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
|
||||
|
||||
/* Kick the relevant domain. */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <asm-xen/ctrl_if.h>
|
||||
#include <asm-xen/hypervisor.h>
|
||||
#include <asm-xen/xen-public/io/blkif.h>
|
||||
#include <asm-xen/xen-public/io/ring.h>
|
||||
|
||||
#if 0
|
||||
#define ASSERT(_p) \
|
||||
@@ -36,19 +37,17 @@ struct block_device;
|
||||
|
||||
typedef struct blkif_st {
|
||||
/* Unique identifier for this interface. */
|
||||
domid_t domid;
|
||||
unsigned int handle;
|
||||
domid_t domid;
|
||||
unsigned int handle;
|
||||
/* Physical parameters of the comms window. */
|
||||
unsigned long shmem_frame;
|
||||
unsigned int evtchn;
|
||||
int irq;
|
||||
unsigned long shmem_frame;
|
||||
unsigned int evtchn;
|
||||
int irq;
|
||||
/* Comms information. */
|
||||
blkif_ring_t *blk_ring_base; /* ioremap()'ed ptr to shmem_frame. */
|
||||
BLKIF_RING_IDX blk_req_cons; /* Request consumer. */
|
||||
BLKIF_RING_IDX blk_resp_prod; /* Private version of resp. producer. */
|
||||
blkif_back_ring_t blk_ring;
|
||||
/* VBDs attached to this interface. */
|
||||
rb_root_t vbd_rb; /* Mapping from 16-bit vdevices to VBDs. */
|
||||
spinlock_t vbd_lock; /* Protects VBD mapping. */
|
||||
rb_root_t vbd_rb; /* Mapping from 16-bit vdevices to VBDs.*/
|
||||
spinlock_t vbd_lock; /* Protects VBD mapping. */
|
||||
/* Private fields. */
|
||||
enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
|
||||
/*
|
||||
@@ -56,6 +55,10 @@ typedef struct blkif_st {
|
||||
* We therefore need to store the id from the original request.
|
||||
*/
|
||||
u8 disconnect_rspid;
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
/* Is this a blktap frontend */
|
||||
unsigned int is_blktap;
|
||||
#endif
|
||||
struct blkif_st *hash_next;
|
||||
struct list_head blkdev_list;
|
||||
spinlock_t blk_ring_lock;
|
||||
|
||||
@@ -39,7 +39,7 @@ static void __blkif_disconnect_complete(void *arg)
|
||||
* must still be notified to the remote driver.
|
||||
*/
|
||||
unbind_evtchn_from_irq(blkif->evtchn);
|
||||
vfree(blkif->blk_ring_base);
|
||||
vfree(blkif->blk_ring.sring);
|
||||
|
||||
/* Construct the deferred response message. */
|
||||
cmsg.type = CMSG_BLKIF_BE;
|
||||
@@ -149,14 +149,15 @@ void blkif_destroy(blkif_be_destroy_t *destroy)
|
||||
|
||||
void blkif_connect(blkif_be_connect_t *connect)
|
||||
{
|
||||
domid_t domid = connect->domid;
|
||||
unsigned int handle = connect->blkif_handle;
|
||||
unsigned int evtchn = connect->evtchn;
|
||||
unsigned long shmem_frame = connect->shmem_frame;
|
||||
domid_t domid = connect->domid;
|
||||
unsigned int handle = connect->blkif_handle;
|
||||
unsigned int evtchn = connect->evtchn;
|
||||
unsigned long shmem_frame = connect->shmem_frame;
|
||||
struct vm_struct *vma;
|
||||
pgprot_t prot;
|
||||
int error;
|
||||
blkif_t *blkif;
|
||||
pgprot_t prot;
|
||||
int error;
|
||||
blkif_t *blkif;
|
||||
blkif_sring_t *sring;
|
||||
|
||||
blkif = blkif_find_by_handle(domid, handle);
|
||||
if ( unlikely(blkif == NULL) )
|
||||
@@ -195,11 +196,13 @@ void blkif_connect(blkif_be_connect_t *connect)
|
||||
vfree(vma->addr);
|
||||
return;
|
||||
}
|
||||
|
||||
sring = (blkif_sring_t *)vma->addr;
|
||||
SHARED_RING_INIT(BLKIF_RING, sring);
|
||||
BACK_RING_INIT(BLKIF_RING, &blkif->blk_ring, sring);
|
||||
|
||||
blkif->evtchn = evtchn;
|
||||
blkif->irq = bind_evtchn_to_irq(evtchn);
|
||||
blkif->shmem_frame = shmem_frame;
|
||||
blkif->blk_ring_base = (blkif_ring_t *)vma->addr;
|
||||
blkif->status = CONNECTED;
|
||||
blkif_get(blkif);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* Copyright (c) 2003-2004, Keir Fraser & Steve Hand
|
||||
* Modifications by Mark A. Williamson are (c) Intel Research Cambridge
|
||||
* Copyright (c) 2004, Christian Limpach
|
||||
* Copyright (c) 2004, Andrew Warfield
|
||||
*
|
||||
* This file may be distributed separately from the Linux kernel, or
|
||||
* incorporated into other software packages, subject to the following license:
|
||||
@@ -84,20 +85,14 @@ static unsigned int blkif_irq = 0;
|
||||
static int blkif_control_rsp_valid;
|
||||
static blkif_response_t blkif_control_rsp;
|
||||
|
||||
static blkif_ring_t *blk_ring = NULL;
|
||||
static BLKIF_RING_IDX resp_cons; /* Response consumer for comms ring. */
|
||||
static BLKIF_RING_IDX req_prod; /* Private request producer. */
|
||||
static blkif_front_ring_t blk_ring;
|
||||
|
||||
unsigned long rec_ring_free;
|
||||
blkif_request_t rec_ring[BLKIF_RING_SIZE];
|
||||
blkif_request_t rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)];
|
||||
|
||||
static int recovery = 0; /* "Recovery in progress" flag. Protected
|
||||
* by the blkif_io_lock */
|
||||
|
||||
/* We plug the I/O ring if the driver is suspended or if the ring is full. */
|
||||
#define BLKIF_RING_FULL (((req_prod - resp_cons) == BLKIF_RING_SIZE) || \
|
||||
(blkif_state != BLKIF_STATE_CONNECTED))
|
||||
|
||||
static void kick_pending_request_queues(void);
|
||||
|
||||
int __init xlblk_init(void);
|
||||
@@ -108,7 +103,7 @@ static inline int GET_ID_FROM_FREELIST( void )
|
||||
{
|
||||
unsigned long free = rec_ring_free;
|
||||
|
||||
if ( free > BLKIF_RING_SIZE )
|
||||
if ( free > RING_SIZE(BLKIF_RING, &blk_ring) )
|
||||
BUG();
|
||||
|
||||
rec_ring_free = rec_ring[free].id;
|
||||
@@ -169,8 +164,7 @@ static inline void translate_req_to_mfn(blkif_request_t *xreq,
|
||||
static inline void flush_requests(void)
|
||||
{
|
||||
DISABLE_SCATTERGATHER();
|
||||
wmb(); /* Ensure that the frontend can see the requests. */
|
||||
blk_ring->req_prod = req_prod;
|
||||
RING_PUSH_REQUESTS(BLKIF_RING, &blk_ring);
|
||||
notify_via_evtchn(blkif_evtchn);
|
||||
}
|
||||
|
||||
@@ -343,7 +337,7 @@ static int blkif_queue_request(struct request *req)
|
||||
return 1;
|
||||
|
||||
/* Fill out a communications ring structure. */
|
||||
ring_req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req;
|
||||
ring_req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
|
||||
id = GET_ID_FROM_FREELIST();
|
||||
rec_ring[id].id = (unsigned long) req;
|
||||
|
||||
@@ -372,8 +366,8 @@ static int blkif_queue_request(struct request *req)
|
||||
}
|
||||
}
|
||||
|
||||
req_prod++;
|
||||
|
||||
blk_ring.req_prod_pvt++;
|
||||
|
||||
/* Keep a private copy so we can reissue requests when recovering. */
|
||||
translate_req_to_pfn( &rec_ring[id], ring_req);
|
||||
|
||||
@@ -400,7 +394,7 @@ void do_blkif_request(request_queue_t *rq)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( BLKIF_RING_FULL )
|
||||
if ( RING_FULL(BLKIF_RING, &blk_ring) )
|
||||
{
|
||||
blk_stop_queue(rq);
|
||||
break;
|
||||
@@ -426,9 +420,9 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
{
|
||||
struct request *req;
|
||||
blkif_response_t *bret;
|
||||
BLKIF_RING_IDX i, rp;
|
||||
RING_IDX i, rp;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
spin_lock_irqsave(&blkif_io_lock, flags);
|
||||
|
||||
if ( unlikely(blkif_state == BLKIF_STATE_CLOSED) ||
|
||||
@@ -437,18 +431,17 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
spin_unlock_irqrestore(&blkif_io_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
rp = blk_ring->resp_prod;
|
||||
|
||||
rp = blk_ring.sring->rsp_prod;
|
||||
rmb(); /* Ensure we see queued responses up to 'rp'. */
|
||||
|
||||
for ( i = resp_cons; i != rp; i++ )
|
||||
for ( i = blk_ring.rsp_cons; i != rp; i++ )
|
||||
{
|
||||
unsigned long id;
|
||||
bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp;
|
||||
|
||||
bret = RING_GET_RESPONSE(BLKIF_RING, &blk_ring, i);
|
||||
id = bret->id;
|
||||
req = (struct request *)rec_ring[id].id;
|
||||
|
||||
blkif_completion( &rec_ring[id] );
|
||||
|
||||
ADD_ID_TO_FREELIST(id); /* overwrites req */
|
||||
@@ -477,9 +470,9 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
resp_cons = i;
|
||||
|
||||
blk_ring.rsp_cons = i;
|
||||
|
||||
kick_pending_request_queues();
|
||||
|
||||
spin_unlock_irqrestore(&blkif_io_lock, flags);
|
||||
@@ -533,10 +526,11 @@ static void kick_pending_request_queues(void)
|
||||
{
|
||||
/* We kick pending request queues if the ring is reasonably empty. */
|
||||
if ( (nr_pending != 0) &&
|
||||
((req_prod - resp_cons) < (BLKIF_RING_SIZE >> 1)) )
|
||||
(RING_PENDING_REQUESTS(BLKIF_RING, &blk_ring) <
|
||||
(RING_SIZE(&blk_ring) >> 1)) )
|
||||
{
|
||||
/* Attempt to drain the queue, but bail if the ring becomes full. */
|
||||
while ( (nr_pending != 0) && !BLKIF_RING_FULL )
|
||||
while ( (nr_pending != 0) && !RING_FULL(BLKIF_RING, &blk_ring) )
|
||||
do_blkif_request(pending_queues[--nr_pending]);
|
||||
}
|
||||
}
|
||||
@@ -830,8 +824,8 @@ static int blkif_queue_request(unsigned long id,
|
||||
(sg_dev == device) &&
|
||||
(sg_next_sect == sector_number) )
|
||||
{
|
||||
|
||||
req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod-1)].req;
|
||||
req = RING_GET_REQUEST(BLKIF_RING, &blk_ring,
|
||||
blk_ring.rsp_prod_pvt - 1);
|
||||
bh = (struct buffer_head *)id;
|
||||
|
||||
bh->b_reqnext = (struct buffer_head *)rec_ring[req->id].id;
|
||||
@@ -851,7 +845,7 @@ static int blkif_queue_request(unsigned long id,
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if ( BLKIF_RING_FULL )
|
||||
else if ( RING_FULL(BLKIF_RING, &blk_ring) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
@@ -868,7 +862,7 @@ static int blkif_queue_request(unsigned long id,
|
||||
}
|
||||
|
||||
/* Fill out a communications ring structure. */
|
||||
req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req;
|
||||
req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
|
||||
|
||||
xid = GET_ID_FROM_FREELIST();
|
||||
rec_ring[xid].id = id;
|
||||
@@ -880,11 +874,11 @@ static int blkif_queue_request(unsigned long id,
|
||||
req->nr_segments = 1;
|
||||
req->frame_and_sects[0] = buffer_ma | (fsect<<3) | lsect;
|
||||
|
||||
req_prod++;
|
||||
|
||||
/* Keep a private copy so we can reissue requests when recovering. */
|
||||
translate_req_to_pfn(&rec_ring[xid], req );
|
||||
|
||||
blk_ring.req_prod_pvt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -973,7 +967,7 @@ void do_blkif_request(request_queue_t *rq)
|
||||
|
||||
static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
{
|
||||
BLKIF_RING_IDX i, rp;
|
||||
RING_IDX i, rp;
|
||||
unsigned long flags;
|
||||
struct buffer_head *bh, *next_bh;
|
||||
|
||||
@@ -985,14 +979,15 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
return;
|
||||
}
|
||||
|
||||
rp = blk_ring->resp_prod;
|
||||
rp = blk_ring.rsp_prod;
|
||||
rmb(); /* Ensure we see queued responses up to 'rp'. */
|
||||
|
||||
for ( i = resp_cons; i != rp; i++ )
|
||||
for ( i = blk_ring.rsp_cons; i != rp; i++ )
|
||||
{
|
||||
unsigned long id;
|
||||
blkif_response_t *bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp;
|
||||
|
||||
blkif_response_t *bret;
|
||||
|
||||
bret = RING_GET_RESPONSE(BLKIF_RING, &blkif_ring, i);
|
||||
id = bret->id;
|
||||
bh = (struct buffer_head *)rec_ring[id].id;
|
||||
|
||||
@@ -1022,10 +1017,9 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
resp_cons = i;
|
||||
|
||||
blk_ring.rsp_cons = i;
|
||||
|
||||
kick_pending_request_queues();
|
||||
|
||||
spin_unlock_irqrestore(&io_request_lock, flags);
|
||||
@@ -1039,31 +1033,33 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
|
||||
void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp)
|
||||
{
|
||||
unsigned long flags, id;
|
||||
blkif_request_t *req_d;
|
||||
|
||||
retry:
|
||||
while ( (req_prod - resp_cons) == BLKIF_RING_SIZE )
|
||||
while ( RING_FULL(BLKIF_RING, &blk_ring) )
|
||||
{
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(1);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&blkif_io_lock, flags);
|
||||
if ( (req_prod - resp_cons) == BLKIF_RING_SIZE )
|
||||
if ( RING_FULL(BLKIF_RING, &blk_ring) )
|
||||
{
|
||||
spin_unlock_irqrestore(&blkif_io_lock, flags);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
DISABLE_SCATTERGATHER();
|
||||
blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req = *req;
|
||||
req_d = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
|
||||
*req_d = *req;
|
||||
|
||||
id = GET_ID_FROM_FREELIST();
|
||||
blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req.id = id;
|
||||
req_d->id = id;
|
||||
rec_ring[id].id = (unsigned long) req;
|
||||
|
||||
translate_req_to_pfn( &rec_ring[id], req );
|
||||
|
||||
req_prod++;
|
||||
blk_ring.req_prod_pvt++;
|
||||
flush_requests();
|
||||
|
||||
spin_unlock_irqrestore(&blkif_io_lock, flags);
|
||||
@@ -1105,7 +1101,7 @@ static void blkif_send_interface_connect(void)
|
||||
blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
|
||||
|
||||
msg->handle = 0;
|
||||
msg->shmem_frame = (virt_to_machine(blk_ring) >> PAGE_SHIFT);
|
||||
msg->shmem_frame = (virt_to_machine(blk_ring.sring) >> PAGE_SHIFT);
|
||||
|
||||
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
@@ -1119,10 +1115,10 @@ static void blkif_free(void)
|
||||
spin_unlock_irq(&blkif_io_lock);
|
||||
|
||||
/* Free resources associated with old device channel. */
|
||||
if ( blk_ring != NULL )
|
||||
if ( blk_ring.sring != NULL )
|
||||
{
|
||||
free_page((unsigned long)blk_ring);
|
||||
blk_ring = NULL;
|
||||
free_page((unsigned long)blk_ring.sring);
|
||||
blk_ring.sring = NULL;
|
||||
}
|
||||
free_irq(blkif_irq, NULL);
|
||||
blkif_irq = 0;
|
||||
@@ -1138,10 +1134,14 @@ static void blkif_close(void)
|
||||
/* Move from CLOSED to DISCONNECTED state. */
|
||||
static void blkif_disconnect(void)
|
||||
{
|
||||
if ( blk_ring != NULL )
|
||||
free_page((unsigned long)blk_ring);
|
||||
blk_ring = (blkif_ring_t *)__get_free_page(GFP_KERNEL);
|
||||
blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod = 0;
|
||||
blkif_sring_t *sring;
|
||||
|
||||
if ( blk_ring.sring != NULL )
|
||||
free_page((unsigned long)blk_ring.sring);
|
||||
|
||||
sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
|
||||
SHARED_RING_INIT(BLKIF_RING, sring);
|
||||
FRONT_RING_INIT(BLKIF_RING, &blk_ring, sring);
|
||||
blkif_state = BLKIF_STATE_DISCONNECTED;
|
||||
blkif_send_interface_connect();
|
||||
}
|
||||
@@ -1155,34 +1155,37 @@ static void blkif_reset(void)
|
||||
static void blkif_recover(void)
|
||||
{
|
||||
int i;
|
||||
blkif_request_t *req;
|
||||
|
||||
/* Hmm, requests might be re-ordered when we re-issue them.
|
||||
* This will need to be fixed once we have barriers */
|
||||
|
||||
/* Stage 1 : Find active and move to safety. */
|
||||
for ( i = 0; i < BLKIF_RING_SIZE; i++ )
|
||||
for ( i = 0; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
|
||||
{
|
||||
if ( rec_ring[i].id >= PAGE_OFFSET )
|
||||
{
|
||||
translate_req_to_mfn(
|
||||
&blk_ring->ring[req_prod].req, &rec_ring[i]);
|
||||
req_prod++;
|
||||
req = RING_GET_REQUEST(BLKIF_RING, &blk_ring,
|
||||
blk_ring.req_prod_pvt);
|
||||
translate_req_to_mfn(req, &rec_ring[i]);
|
||||
blk_ring.req_prod_pvt++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Stage 2 : Set up shadow list. */
|
||||
for ( i = 0; i < req_prod; i++ )
|
||||
for ( i = 0; i < blk_ring.req_prod_pvt; i++ )
|
||||
{
|
||||
rec_ring[i].id = blk_ring->ring[i].req.id;
|
||||
blk_ring->ring[i].req.id = i;
|
||||
translate_req_to_pfn(&rec_ring[i], &blk_ring->ring[i].req);
|
||||
req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, i);
|
||||
rec_ring[i].id = req->id;
|
||||
req->id = i;
|
||||
translate_req_to_pfn(&rec_ring[i], req);
|
||||
}
|
||||
|
||||
/* Stage 3 : Set up free list. */
|
||||
for ( ; i < BLKIF_RING_SIZE; i++ )
|
||||
for ( ; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
|
||||
rec_ring[i].id = i+1;
|
||||
rec_ring_free = req_prod;
|
||||
rec_ring[BLKIF_RING_SIZE-1].id = 0x0fffffff;
|
||||
rec_ring_free = blk_ring.req_prod_pvt;
|
||||
rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)-1].id = 0x0fffffff;
|
||||
|
||||
/* blk_ring->req_prod will be set when we flush_requests().*/
|
||||
wmb();
|
||||
@@ -1376,9 +1379,9 @@ int __init xlblk_init(void)
|
||||
printk(KERN_INFO "xen_blk: Initialising virtual block device driver\n");
|
||||
|
||||
rec_ring_free = 0;
|
||||
for ( i = 0; i < BLKIF_RING_SIZE; i++ )
|
||||
for ( i = 0; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
|
||||
rec_ring[i].id = i+1;
|
||||
rec_ring[BLKIF_RING_SIZE-1].id = 0x0fffffff;
|
||||
rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)-1].id = 0x0fffffff;
|
||||
|
||||
(void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx,
|
||||
CALLBACK_IN_BLOCKING_CONTEXT);
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
#include <asm-xen/xen-public/xen.h>
|
||||
#include <asm-xen/xen-public/io/blkif.h>
|
||||
#include <asm-xen/xen-public/io/ring.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#ifndef __XEN_PUBLIC_IO_BLKIF_H__
|
||||
#define __XEN_PUBLIC_IO_BLKIF_H__
|
||||
|
||||
#include <asm-xen/xen-public/io/ring.h>
|
||||
|
||||
#define blkif_vdev_t u16
|
||||
#define blkif_sector_t u64
|
||||
|
||||
@@ -52,27 +54,11 @@ typedef struct {
|
||||
#define BLKIF_RSP_OKAY 0 /* non-specific 'okay' */
|
||||
|
||||
/*
|
||||
* We use a special capitalised type name because it is _essential_ that all
|
||||
* arithmetic on indexes is done on an integer type of the correct size.
|
||||
* Generate blkif ring structures and types.
|
||||
*/
|
||||
typedef u32 BLKIF_RING_IDX;
|
||||
|
||||
/*
|
||||
* Ring indexes are 'free running'. That is, they are not stored modulo the
|
||||
* size of the ring buffer. The following macro converts a free-running counter
|
||||
* into a value that can directly index a ring-buffer array.
|
||||
*/
|
||||
#define MASK_BLKIF_IDX(_i) ((_i)&(BLKIF_RING_SIZE-1))
|
||||
|
||||
typedef struct {
|
||||
BLKIF_RING_IDX req_prod; /* 0: Request producer. Updated by front-end. */
|
||||
BLKIF_RING_IDX resp_prod; /* 4: Response producer. Updated by back-end. */
|
||||
union { /* 8 */
|
||||
blkif_request_t req;
|
||||
blkif_response_t resp;
|
||||
} PACKED ring[BLKIF_RING_SIZE];
|
||||
} PACKED blkif_ring_t;
|
||||
|
||||
#define BLKIF_RING RING_PARAMS(blkif_request_t, blkif_response_t, PAGE_SIZE)
|
||||
DEFINE_RING_TYPES(blkif, BLKIF_RING);
|
||||
|
||||
/*
|
||||
* BLKIF_OP_PROBE:
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Shared producer-consumer ring macros.
|
||||
* Tim Deegan and Andrew Warfield November 2004.
|
||||
*/
|
||||
|
||||
#ifndef __XEN_PUBLIC_IO_RING_H__
|
||||
#define __XEN_PUBLIC_IO_RING_H__
|
||||
|
||||
typedef unsigned int RING_IDX;
|
||||
|
||||
/* This is horrible: it rounds a 32-bit unsigned constant down to the
|
||||
* nearest power of two, by finding the highest set bit. */
|
||||
#define __RD2PO2(_x) (((_x) & 0x80000000) ? 0x80000000 : \
|
||||
((_x) & 0x40000000) ? 0x40000000 : \
|
||||
((_x) & 0x20000000) ? 0x20000000 : \
|
||||
((_x) & 0x10000000) ? 0x10000000 : \
|
||||
((_x) & 0x08000000) ? 0x08000000 : \
|
||||
((_x) & 0x04000000) ? 0x04000000 : \
|
||||
((_x) & 0x02000000) ? 0x02000000 : \
|
||||
((_x) & 0x01000000) ? 0x01000000 : \
|
||||
((_x) & 0x00800000) ? 0x00800000 : \
|
||||
((_x) & 0x00400000) ? 0x00400000 : \
|
||||
((_x) & 0x00200000) ? 0x00200000 : \
|
||||
((_x) & 0x00100000) ? 0x00100000 : \
|
||||
((_x) & 0x00080000) ? 0x00080000 : \
|
||||
((_x) & 0x00040000) ? 0x00040000 : \
|
||||
((_x) & 0x00020000) ? 0x00020000 : \
|
||||
((_x) & 0x00010000) ? 0x00010000 : \
|
||||
((_x) & 0x00008000) ? 0x00008000 : \
|
||||
((_x) & 0x00004000) ? 0x00004000 : \
|
||||
((_x) & 0x00002000) ? 0x00002000 : \
|
||||
((_x) & 0x00001000) ? 0x00001000 : \
|
||||
((_x) & 0x00000800) ? 0x00000800 : \
|
||||
((_x) & 0x00000400) ? 0x00000400 : \
|
||||
((_x) & 0x00000200) ? 0x00000200 : \
|
||||
((_x) & 0x00000100) ? 0x00000100 : \
|
||||
((_x) & 0x00000080) ? 0x00000080 : \
|
||||
((_x) & 0x00000040) ? 0x00000040 : \
|
||||
((_x) & 0x00000020) ? 0x00000020 : \
|
||||
((_x) & 0x00000010) ? 0x00000010 : \
|
||||
((_x) & 0x00000008) ? 0x00000008 : \
|
||||
((_x) & 0x00000004) ? 0x00000004 : \
|
||||
((_x) & 0x00000002) ? 0x00000002 : \
|
||||
((_x) & 0x00000001) ? 0x00000001 : 0x00000000)
|
||||
|
||||
/* Given a shared ring, tell me how many entries there are in it. The
|
||||
* rule is: a ring contains as many entries as will fit, rounded down to
|
||||
* the nearest power of two (so we can mask with (size-1) to loop
|
||||
* around) */
|
||||
#define __SRING_SIZE(__params, __esize) \
|
||||
__RD2PO2((sizeof((__params)->size) - (2 * sizeof(RING_IDX))) / (__esize))
|
||||
#define SRING_SIZE(__params, __sringp) \
|
||||
__SRING_SIZE(__params, sizeof (__sringp)->ring[0])
|
||||
|
||||
/*
|
||||
* Macros to make the correct C datatypes for a new kind of ring.
|
||||
*
|
||||
* To make a new ring datatype, you need to have two message structures,
|
||||
* let's say request_t, and response_t already defined. You also need to
|
||||
* know how big the shared memory region you want the ring to occupy is
|
||||
* (PAGE_SIZE, of instance).
|
||||
*
|
||||
* In a header where you want the ring datatype declared, you then do:
|
||||
*
|
||||
* #define MY_RING RING_PARAMS(request_t, response_t, PAGE_SIZE)
|
||||
* DEFINE_RING_TYPES(mytag, MY_RING);
|
||||
*
|
||||
* These expand out to give you a set of types, as you can see below.
|
||||
* The most important of these are:
|
||||
*
|
||||
* mytag_sring_t - The shared ring.
|
||||
* mytag_front_ring_t - The 'front' half of the ring.
|
||||
* mytag_back_ring_t - The 'back' half of the ring.
|
||||
*
|
||||
* Use the RING_PARAMS define (MY_RING above) as a first parameter on all
|
||||
* the ring functions. To initialize a ring in your code, on the front
|
||||
* half, you do a:
|
||||
*
|
||||
* mytag_front_ring_t front_ring;
|
||||
*
|
||||
* SHARED_RING_INIT(MY_RING, (mytag_sring_t *)shared_page)
|
||||
* FRONT_RING_INIT(MY_RING, &front_ring, (mytag_sring_t *)shared_page)
|
||||
*
|
||||
* Initializing the back follows similarly...
|
||||
*/
|
||||
|
||||
/* NB: RING SIZING. (a note to ease future debugging...)
|
||||
*
|
||||
* Passing size information into the ring macros is made difficult by
|
||||
* the lack of a reasonable constant declaration in C. To get around this,
|
||||
* the RING_PARAMS define places the requested size of the ring as the
|
||||
* static size of the 'size' array in the anonymous RING_PARAMS struct.
|
||||
* While this struct is never actually instantiated, __SRING_SIZE is
|
||||
* able to use sizeof() to get at the constant size.
|
||||
*/
|
||||
|
||||
#define RING_PARAMS(__req_t, __rsp_t, __size) \
|
||||
((struct { \
|
||||
char size[__size]; \
|
||||
__req_t req; \
|
||||
__rsp_t rsp; \
|
||||
\
|
||||
} *) 0)
|
||||
|
||||
|
||||
#define DEFINE_RING_TYPES(__name, __params) \
|
||||
\
|
||||
/* Shared ring entry */ \
|
||||
union __name##_sring_entry { \
|
||||
typeof ((__params)->req) req; \
|
||||
typeof ((__params)->rsp) rsp; \
|
||||
} PACKED; \
|
||||
\
|
||||
/* Shared ring page */ \
|
||||
struct __name##_sring { \
|
||||
RING_IDX req_prod; \
|
||||
RING_IDX rsp_prod; \
|
||||
union __name##_sring_entry \
|
||||
ring[__SRING_SIZE(__params, sizeof (union __name##_sring_entry))]; \
|
||||
} PACKED; \
|
||||
\
|
||||
/* "Front" end's private variables */ \
|
||||
struct __name##_front_ring { \
|
||||
RING_IDX req_prod_pvt; \
|
||||
RING_IDX rsp_cons; \
|
||||
struct __name##_sring *sring; \
|
||||
}; \
|
||||
\
|
||||
/* "Back" end's private variables */ \
|
||||
struct __name##_back_ring { \
|
||||
RING_IDX rsp_prod_pvt; \
|
||||
RING_IDX req_cons; \
|
||||
struct __name##_sring *sring; \
|
||||
}; \
|
||||
\
|
||||
/* Syntactic sugar */ \
|
||||
typedef struct __name##_sring __name##_sring_t; \
|
||||
typedef struct __name##_front_ring __name##_front_ring_t; \
|
||||
typedef struct __name##_back_ring __name##_back_ring_t;
|
||||
|
||||
/*
|
||||
* Macros for manipulating rings.
|
||||
*
|
||||
* FRONT_RING_whatever works on the "front end" of a ring: here
|
||||
* requests are pushed on to the ring and responses taken off it.
|
||||
*
|
||||
* BACK_RING_whatever works on the "back end" of a ring: here
|
||||
* requests are taken off the ring and responses put on.
|
||||
*
|
||||
* N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.
|
||||
* This is OK in 1-for-1 request-response situations where the
|
||||
* requestor (front end) never has more than SRING_SIZE()-1
|
||||
* outstanding requests.
|
||||
*/
|
||||
|
||||
|
||||
/* Initialising empty rings */
|
||||
#define SHARED_RING_INIT(_p, _s) do { \
|
||||
(_s)->req_prod = 0; \
|
||||
(_s)->rsp_prod = 0; \
|
||||
} while(0)
|
||||
|
||||
#define FRONT_RING_INIT(_p, _r, _s) do { \
|
||||
(_r)->req_prod_pvt = 0; \
|
||||
(_r)->rsp_cons = 0; \
|
||||
(_r)->sring = (_s); \
|
||||
} while (0)
|
||||
|
||||
#define BACK_RING_INIT(_p, _r, _s) do { \
|
||||
(_r)->rsp_prod_pvt = 0; \
|
||||
(_r)->req_cons = 0; \
|
||||
(_r)->sring = (_s); \
|
||||
} while (0)
|
||||
|
||||
/* Initialize to existing shared indexes -- for recovery */
|
||||
#define FRONT_RING_ATTACH(_p, _r, _s) do { \
|
||||
(_r)->sring = (_s); \
|
||||
(_r)->req_prod_pvt = (_s)->req_prod; \
|
||||
(_r)->rsp_cons = (_s)->rsp_prod; \
|
||||
} while (0)
|
||||
|
||||
#define BACK_RING_ATTACH(_p, _r, _s) do { \
|
||||
(_r)->sring = (_s); \
|
||||
(_r)->rsp_prod_pvt = (_s)->rsp_prod; \
|
||||
(_r)->req_cons = (_s)->req_prod; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* How to mask off a number for use as an offset into a ring
|
||||
* N.B. This evalutes its second argument once but its first often */
|
||||
#define __SHARED_RING_MASK(_p, _s, _i) \
|
||||
((_i) & (SRING_SIZE((_p), (_s)) - 1))
|
||||
|
||||
/* How big is this ring? */
|
||||
#define RING_SIZE(_p, _r) SRING_SIZE((_p), (_r)->sring)
|
||||
|
||||
/* How many empty slots are on a ring? */
|
||||
#define RING_PENDING_REQUESTS(_p, _r) \
|
||||
( ((_r)->req_prod_pvt - (_r)->rsp_cons) )
|
||||
|
||||
/* Test if there is an empty slot available on the front ring.
|
||||
* (This is only meaningful from the front. )
|
||||
*/
|
||||
#define RING_FULL(_p, _r) \
|
||||
(((_r)->req_prod_pvt - (_r)->rsp_cons) == SRING_SIZE((_p), (_r)->sring))
|
||||
|
||||
/* Test if there are outstanding messages to be processed on a ring. */
|
||||
#define RING_HAS_UNCONSUMED_RESPONSES(_p, _r) \
|
||||
( (_r)->rsp_cons != (_r)->sring->rsp_prod )
|
||||
|
||||
#define RING_HAS_UNCONSUMED_REQUESTS(_p, _r) \
|
||||
( ((_r)->req_cons != (_r)->sring->req_prod ) && \
|
||||
(((_r)->req_cons - (_r)->rsp_prod_pvt) != \
|
||||
SRING_SIZE((_p), (_r)->sring)) )
|
||||
|
||||
/* Test if there are messages waiting to be pushed. */
|
||||
#define RING_HAS_UNPUSHED_REQUESTS(_p, _r) \
|
||||
( (_r)->req_prod_pvt != (_r)->sring->req_prod )
|
||||
|
||||
#define RING_HAS_UNPUSHED_RESPONSES(_p, _r) \
|
||||
( (_r)->rsp_prod_pvt != (_r)->sring->rsp_prod )
|
||||
|
||||
|
||||
/* Copy the private producer pointer into the shared ring so the other end
|
||||
* can see the updates we've made. */
|
||||
#define RING_PUSH_REQUESTS(_p, _r) do { \
|
||||
wmb(); \
|
||||
(_r)->sring->req_prod = (_r)->req_prod_pvt; \
|
||||
} while (0)
|
||||
|
||||
#define RING_PUSH_RESPONSES(_p, _r) do { \
|
||||
wmb(); \
|
||||
(_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \
|
||||
} while (0)
|
||||
|
||||
/* Direct access to individual ring elements, by index.
|
||||
*/
|
||||
#define RING_GET_REQUEST(_p, _r, _idx) \
|
||||
(&((_r)->sring->ring[ \
|
||||
__SHARED_RING_MASK((_p), (_r)->sring, (_idx)) \
|
||||
].req))
|
||||
|
||||
#define RING_GET_RESPONSE(_p, _r, _idx) \
|
||||
(&((_r)->sring->ring[ \
|
||||
__SHARED_RING_MASK((_p), (_r)->sring, (_idx)) \
|
||||
].rsp))
|
||||
|
||||
/* Loop termination condition: Would the specified index overflow the
|
||||
* ring?
|
||||
*/
|
||||
#define RING_REQUEST_CONS_OVERFLOW(_p, _r, _cons) \
|
||||
(((_cons) - (_r)->rsp_prod_pvt) >= SRING_SIZE((_p), (_r)->sring))
|
||||
|
||||
#endif /* __XEN_PUBLIC_IO_RING_H__ */
|
||||