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:
kaf24@scramble.cl.cam.ac.uk committed 2004-12-30 14:20:11 +00:00
1 parent 3d866e0585
commit 0b788798d8
8 files changed
+388 -137

No files matched your search

+1
View File
@@ -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>
+5 -19
View File
@@ -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:
+254
View File
@@ -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__ */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.