# HG changeset patch
# User cl349@xxxxxxxxxxxxxxxxxxxx
# Node ID 827a3c3524b334406b863acbf03405cec451d1f4
# Parent 6078dc5f7ea1809367b720f120b73a5b38bc8f9d
Use a block interface for each device.
Lots of code cleanups, incl. a couple of bug fixes.
Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxx>
diff -r 6078dc5f7ea1 -r 827a3c3524b3
linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c Mon Aug 22
20:57:26 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c Mon Aug 22
20:59:00 2005
@@ -58,39 +58,21 @@
#include <asm-xen/xen-public/grant_table.h>
#include <asm-xen/gnttab.h>
-struct blkfront_info
-{
- /* We watch the backend */
- struct xenbus_watch watch;
- int vdevice;
- u16 handle;
- int connected;
- struct xenbus_device *dev;
- char *backend;
- int backend_id;
- int grant_id;
- blkif_front_ring_t ring;
- unsigned int evtchn;
-};
-
typedef unsigned char byte; /* from linux/ide.h */
/* Control whether runtime update of vbds is enabled. */
#define ENABLE_VBD_UPDATE 1
-#define BLKIF_STATE_CLOSED 0
-#define BLKIF_STATE_DISCONNECTED 1
-#define BLKIF_STATE_CONNECTED 2
-
-static unsigned int blkif_state = BLKIF_STATE_CLOSED;
-static unsigned int blkif_vbds_connected = 0;
+#define BLKIF_STATE_DISCONNECTED 0
+#define BLKIF_STATE_CONNECTED 1
+
+static unsigned int blkif_state = BLKIF_STATE_DISCONNECTED;
#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
(BLKIF_MAX_SEGMENTS_PER_REQUEST * BLKIF_RING_SIZE)
#define GRANTREF_INVALID (1<<15)
-static grant_ref_t gref_head, gref_terminal;
static struct blk_shadow {
blkif_request_t req;
@@ -101,7 +83,7 @@
static int recovery = 0; /* Recovery in progress: protected by blkif_io_lock */
-static void kick_pending_request_queues(void);
+static void kick_pending_request_queues(struct blkfront_info *info);
static int __init xlblk_init(void);
@@ -128,7 +110,7 @@
/* Kernel-specific definitions used in the common code */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-#define DISABLE_SCATTERGATHER()
+#define DISABLE_SCATTERGATHER()
#else
static int sg_operation = -1;
#define DISABLE_SCATTERGATHER() (sg_operation = -1)
@@ -161,30 +143,34 @@
module_init(xlblk_init);
-static struct xlbd_disk_info *head_waiting = NULL;
-static void kick_pending_request_queues(void)
-{
- struct xlbd_disk_info *di;
- while ( ((di = head_waiting) != NULL) && !RING_FULL(&di->info->ring) )
- {
- head_waiting = di->next_waiting;
- di->next_waiting = NULL;
- /* Re-enable calldowns. */
- blk_start_queue(di->rq);
- /* Kick things off immediately. */
- do_blkif_request(di->rq);
- }
+static void kick_pending_request_queues(struct blkfront_info *info)
+{
+ if (!RING_FULL(&info->ring)) {
+ /* Re-enable calldowns. */
+ blk_start_queue(info->rq);
+ /* Kick things off immediately. */
+ do_blkif_request(info->rq);
+ }
+}
+
+static void blkif_restart_queue(void *arg)
+{
+ struct blkfront_info *info = (struct blkfront_info *)arg;
+ spin_lock_irq(&blkif_io_lock);
+ info->callback.work = NULL;
+ kick_pending_request_queues(info);
+ spin_unlock_irq(&blkif_io_lock);
}
int blkif_open(struct inode *inode, struct file *filep)
{
- struct gendisk *gd = inode->i_bdev->bd_disk;
- struct xlbd_disk_info *di = (struct xlbd_disk_info *)gd->private_data;
-
- /* Update of usage count is protected by per-device semaphore. */
- di->mi->usage++;
-
- return 0;
+ // struct gendisk *gd = inode->i_bdev->bd_disk;
+ // struct xlbd_disk_info *di = (struct xlbd_disk_info
*)gd->private_data;
+
+ /* Update of usage count is protected by per-device semaphore. */
+ // di->mi->usage++;
+
+ return 0;
}
@@ -201,8 +187,8 @@
int i;
DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
- command, (long)argument, inode->i_rdev);
-
+ command, (long)argument, inode->i_rdev);
+
switch ( command )
{
case HDIO_GETGEO:
@@ -228,7 +214,7 @@
/*
* blkif_queue_request
*
- * request block io
+ * request block io
*
* id: for guest use only.
* operation: BLKIF_OP_{READ,WRITE,PROBE}
@@ -237,7 +223,7 @@
*/
static int blkif_queue_request(struct request *req)
{
- struct xlbd_disk_info *di = req->rq_disk->private_data;
+ struct blkfront_info *info = req->rq_disk->private_data;
unsigned long buffer_ma;
blkif_request_t *ring_req;
struct bio *bio;
@@ -246,20 +232,29 @@
unsigned long id;
unsigned int fsect, lsect;
int ref;
-
- if ( unlikely(blkif_state != BLKIF_STATE_CONNECTED) )
+ grant_ref_t gref_head, gref_terminal;
+
+ if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
return 1;
+ if (gnttab_alloc_grant_references(BLKIF_MAX_SEGMENTS_PER_REQUEST,
+ &gref_head, &gref_terminal) < 0) {
+ if (info->callback.work)
+ return 1;
+ INIT_WORK(&info->work, blkif_restart_queue, (void *)info);
+ gnttab_request_free_callback(&info->callback, &info->work);
+ return 1;
+ }
+
/* Fill out a communications ring structure. */
- ring_req = RING_GET_REQUEST(&di->info->ring, di->info->ring.req_prod_pvt);
+ ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
id = GET_ID_FROM_FREELIST();
blk_shadow[id].request = (unsigned long)req;
ring_req->id = id;
- ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE :
- BLKIF_OP_READ;
+ ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE : BLKIF_OP_READ;
ring_req->sector_number = (blkif_sector_t)req->sector;
- ring_req->handle = di->handle;
+ ring_req->handle = info->handle;
ring_req->nr_segments = 0;
rq_for_each_bio(bio, req)
@@ -277,26 +272,29 @@
gnttab_grant_foreign_access_ref(
ref,
- di->info->backend_id,
+ info->backend_id,
buffer_ma >> PAGE_SHIFT,
rq_data_dir(req) );
blk_shadow[id].frame[ring_req->nr_segments] =
buffer_ma >> PAGE_SHIFT;
- ring_req->frame_and_sects[ring_req->nr_segments++] =
+ ring_req->frame_and_sects[ring_req->nr_segments] =
blkif_fas_from_gref(ref, fsect, lsect);
+
+ ring_req->nr_segments++;
}
}
- di->info->ring.req_prod_pvt++;
-
+ info->ring.req_prod_pvt++;
+
/* Keep a private copy so we can reissue requests when recovering. */
pickle_request(&blk_shadow[id], ring_req);
+ gnttab_free_grant_references(&gref_head, gref_terminal);
+
return 0;
}
-
/*
* do_blkif_request
@@ -304,17 +302,17 @@
*/
void do_blkif_request(request_queue_t *rq)
{
- struct xlbd_disk_info *di = NULL;
+ struct blkfront_info *info = NULL;
struct request *req;
int queued;
- DPRINTK("Entered do_blkif_request\n");
+ DPRINTK("Entered do_blkif_request\n");
queued = 0;
while ( (req = elv_next_request(rq)) != NULL )
{
- di = req->rq_disk->private_data;
+ info = req->rq_disk->private_data;
if ( !blk_fs_request(req) )
{
@@ -322,8 +320,8 @@
continue;
}
- if ( RING_FULL(&di->info->ring) )
- goto wait;
+ if (RING_FULL(&info->ring))
+ goto wait;
DPRINTK("do_blk_req %p: cmd %p, sec %lx, (%u/%li) buffer:%p [%s]\n",
req, req->cmd, req->sector, req->current_nr_sectors,
@@ -331,24 +329,19 @@
rq_data_dir(req) ? "write" : "read");
blkdev_dequeue_request(req);
- if ( blkif_queue_request(req) )
- {
+ if (blkif_queue_request(req)) {
+ blk_requeue_request(rq, req);
wait:
- if ( di->next_waiting == NULL )
- {
- di->next_waiting = head_waiting;
- head_waiting = di;
- /* Avoid pointless unplugs. */
- blk_stop_queue(rq);
- }
- break;
+ /* Avoid pointless unplugs. */
+ blk_stop_queue(rq);
+ break;
}
queued++;
}
if ( queued != 0 )
- flush_requests(di->info);
+ flush_requests(info);
}
@@ -359,16 +352,14 @@
RING_IDX i, rp;
unsigned long flags;
struct blkfront_info *info = (struct blkfront_info *)dev_id;
-
- spin_lock_irqsave(&blkif_io_lock, flags);
-
- if ( unlikely(blkif_state == BLKIF_STATE_CLOSED) ||
- unlikely(recovery) )
- {
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ if (unlikely(info->connected != BLKIF_STATE_CONNECTED || recovery)) {
spin_unlock_irqrestore(&blkif_io_lock, flags);
return IRQ_HANDLED;
}
-
+
rp = info->ring.sring->rsp_prod;
rmb(); /* Ensure we see queued responses up to 'rp'. */
@@ -393,7 +384,7 @@
bret->status);
if ( unlikely(end_that_request_first
- (req,
+ (req,
(bret->status == BLKIF_RSP_OKAY),
req->hard_nr_sectors)) )
BUG();
@@ -407,7 +398,7 @@
info->ring.rsp_cons = i;
- kick_pending_request_queues();
+ kick_pending_request_queues(info);
spin_unlock_irqrestore(&blkif_io_lock, flags);
@@ -436,7 +427,7 @@
static void kick_pending_request_queues(void)
{
/* We kick pending request queues if the ring is reasonably empty. */
- if ( (nr_pending != 0) &&
+ if ( (nr_pending != 0) &&
(RING_PENDING_REQUESTS(&info->ring) < (BLK_RING_SIZE >> 1)) )
{
/* Attempt to drain the queue, but bail if the ring becomes full. */
@@ -447,20 +438,20 @@
int blkif_open(struct inode *inode, struct file *filep)
{
- short xldev = inode->i_rdev;
+ short xldev = inode->i_rdev;
struct gendisk *gd = get_gendisk(xldev);
xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
- short minor = MINOR(xldev);
+ short minor = MINOR(xldev);
if ( gd->part[minor].nr_sects == 0 )
- {
+ {
/*
* Device either doesn't exist, or has zero capacity; we use a few
* cheesy heuristics to return the relevant error code
*/
if ( (gd->sizes[minor >> gd->minor_shift] != 0) ||
((minor & (gd->max_p - 1)) != 0) )
- {
+ {
/*
* We have a real device, but no such partition, or we just have a
* partition number so guess this is the problem.
@@ -469,16 +460,16 @@
}
else if ( gd->flags[minor >> gd->minor_shift] & GENHD_FL_REMOVABLE )
{
- /* This is a removable device => assume that media is missing. */
+ /* This is a removable device => assume that media is missing. */
return -ENOMEDIUM; /* media not present (this is a guess) */
- }
+ }
else
- {
+ {
/* Just go for the general 'no such device' error. */
return -ENODEV; /* no such device */
}
}
-
+
/* Update of usage count is protected by per-device semaphore. */
disk->usage++;
@@ -507,24 +498,24 @@
{
kdev_t dev = inode->i_rdev;
struct hd_geometry *geo = (struct hd_geometry *)argument;
- struct gendisk *gd;
- struct hd_struct *part;
+ struct gendisk *gd;
+ struct hd_struct *part;
int i;
unsigned short cylinders;
byte heads, sectors;
/* NB. No need to check permissions. That is done for us. */
-
+
DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
- command, (long) argument, dev);
-
+ command, (long) argument, dev);
+
gd = get_gendisk(dev);
- part = &gd->part[MINOR(dev)];
+ part = &gd->part[MINOR(dev)];
switch ( command )
{
case BLKGETSIZE:
- DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects);
+ DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects);
return put_user(part->nr_sects, (unsigned long *) argument);
case BLKGETSIZE64:
@@ -537,7 +528,7 @@
return blkif_revalidate(dev);
case BLKSSZGET:
- return hardsect_size[MAJOR(dev)][MINOR(dev)];
+ return hardsect_size[MAJOR(dev)][MINOR(dev)];
case BLKBSZGET: /* get block size */
DPRINTK_IOCTL(" BLKBSZGET: %x\n", BLKBSZGET);
@@ -563,7 +554,7 @@
values consistent with the size of the device */
heads = 0xff;
- sectors = 0x3f;
+ sectors = 0x3f;
cylinders = part->nr_sects / (heads * sectors);
if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
@@ -573,7 +564,7 @@
return 0;
- case HDIO_GETGEO_BIG:
+ case HDIO_GETGEO_BIG:
DPRINTK_IOCTL(" HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG);
if (!argument) return -EINVAL;
@@ -581,7 +572,7 @@
values consistent with the size of the device */
heads = 0xff;
- sectors = 0x3f;
+ sectors = 0x3f;
cylinders = part->nr_sects / (heads * sectors);
if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT;
@@ -605,7 +596,7 @@
WPRINTK("ioctl %08x not supported by XL blkif\n", command);
return -ENOSYS;
}
-
+
return 0;
}
@@ -625,7 +616,7 @@
xl_disk_t *disk;
unsigned long capacity;
int i, rc = 0;
-
+
if ( (bd = bdget(dev)) == NULL )
return -EINVAL;
@@ -673,7 +664,7 @@
/*
* blkif_queue_request
*
- * request block io
+ * request block io
*
* id: for guest use only.
* operation: BLKIF_OP_{READ,WRITE,PROBE}
@@ -707,7 +698,7 @@
buffer_ma &= PAGE_MASK;
- if ( unlikely(blkif_state != BLKIF_STATE_CONNECTED) )
+ if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
return 1;
switch ( operation )
@@ -715,7 +706,7 @@
case BLKIF_OP_READ:
case BLKIF_OP_WRITE:
- gd = get_gendisk(device);
+ gd = get_gendisk(device);
/*
* Update the sector_number we'll pass down as appropriate; note that
@@ -725,10 +716,10 @@
sector_number += gd->part[MINOR(device)].start_sect;
/*
- * If this unit doesn't consist of virtual partitions then we clear
+ * If this unit doesn't consist of virtual partitions then we clear
* the partn bits from the device number.
*/
- if ( !(gd->flags[MINOR(device)>>gd->minor_shift] &
+ if ( !(gd->flags[MINOR(device)>>gd->minor_shift] &
GENHD_FL_VIRT_PARTNS) )
device &= ~(gd->max_p - 1);
@@ -736,10 +727,10 @@
(sg_dev == device) &&
(sg_next_sect == sector_number) )
{
- req = RING_GET_REQUEST(&info->ring,
+ req = RING_GET_REQUEST(&info->ring,
info->ring.req_prod_pvt - 1);
bh = (struct buffer_head *)id;
-
+
bh->b_reqnext = (struct buffer_head *)blk_shadow[req->id].request;
blk_shadow[req->id].request = (unsigned long)id;
@@ -793,7 +784,7 @@
req->id = xid;
req->operation = operation;
req->sector_number = (blkif_sector_t)sector_number;
- req->handle = handle;
+ req->handle = handle;
req->nr_segments = 1;
/* install a grant reference. */
ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
@@ -809,11 +800,11 @@
req->frame_and_sects[0] = blkif_fas_from_gref(ref, fsect, lsect);
- /* Keep a private copy so we can reissue requests when recovering. */
+ /* Keep a private copy so we can reissue requests when recovering. */
pickle_request(&blk_shadow[xid], req);
info->ring.req_prod_pvt++;
-
+
return 0;
}
@@ -828,13 +819,13 @@
struct buffer_head *bh, *next_bh;
int rw, nsect, full, queued = 0;
- DPRINTK("Entered do_blkif_request\n");
+ DPRINTK("Entered do_blkif_request\n");
while ( !rq->plugged && !list_empty(&rq->queue_head))
{
- if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL )
+ if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL )
goto out;
-
+
DPRINTK("do_blkif_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n",
req, req->cmd, req->sector,
req->current_nr_sectors, req->nr_sectors, req->bh);
@@ -855,16 +846,16 @@
full = blkif_queue_request(
(unsigned long)bh,
- (rw == READ) ? BLKIF_OP_READ : BLKIF_OP_WRITE,
+ (rw == READ) ? BLKIF_OP_READ : BLKIF_OP_WRITE,
bh->b_data, bh->b_rsector, bh->b_size>>9, bh->b_rdev);
if ( full )
- {
+ {
bh->b_reqnext = next_bh;
pending_queues[nr_pending++] = rq;
if ( unlikely(nr_pending >= MAX_PENDING) )
BUG();
- goto out;
+ goto out;
}
queued++;
@@ -872,7 +863,7 @@
/* Dequeue the buffer head from the request. */
nsect = bh->b_size >> 9;
bh = req->bh = next_bh;
-
+
if ( bh != NULL )
{
/* There's another buffer head to do. Update the request. */
@@ -902,13 +893,13 @@
static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
{
- RING_IDX i, rp;
- unsigned long flags;
+ RING_IDX i, rp;
+ unsigned long flags;
struct buffer_head *bh, *next_bh;
-
- spin_lock_irqsave(&io_request_lock, flags);
-
- if ( unlikely(blkif_state == BLKIF_STATE_CLOSED || recovery) )
+
+ spin_lock_irqsave(&io_request_lock, flags);
+
+ if ( unlikely(info->connected != BLKIF_STATE_CONNECTED || recovery) )
{
spin_unlock_irqrestore(&io_request_lock, flags);
return;
@@ -921,7 +912,7 @@
{
unsigned long id;
blkif_response_t *bret;
-
+
bret = RING_GET_RESPONSE(&info->ring, i);
id = bret->id;
bh = (struct buffer_head *)blk_shadow[id].request;
@@ -955,7 +946,7 @@
}
info->ring.rsp_cons = i;
-
+
kick_pending_request_queues();
spin_unlock_irqrestore(&io_request_lock, flags);
@@ -969,7 +960,7 @@
{
/* Prevent new requests being issued until we fix things up. */
spin_lock_irq(&blkif_io_lock);
- blkif_state = BLKIF_STATE_DISCONNECTED;
+ info->connected = BLKIF_STATE_DISCONNECTED;
spin_unlock_irq(&blkif_io_lock);
/* Free resources associated with old device channel. */
@@ -1045,7 +1036,7 @@
flush_requests(info);
/* Now safe to left other people use the interface. */
- blkif_state = BLKIF_STATE_CONNECTED;
+ info->connected = BLKIF_STATE_CONNECTED;
}
static void blkif_connect(struct blkfront_info *info, u16 evtchn)
@@ -1080,31 +1071,29 @@
node += strlen(watch->node);
/* FIXME: clean up when error on the other end. */
- if (info->connected)
+ if (info->connected == BLKIF_STATE_CONNECTED)
return;
- err = xenbus_gather(watch->node,
+ err = xenbus_gather(watch->node,
"sectors", "%lu", §ors,
"info", "%u", &binfo,
"sector-size", "%lu", §or_size,
NULL);
if (err) {
- xenbus_dev_error(info->dev, err, "reading backend fields");
+ xenbus_dev_error(info->xbdev, err, "reading backend fields");
return;
}
- xlvbd_add(sectors, info->vdevice, info->handle, binfo, sector_size,
info);
- info->connected = 1;
-
- /* First to connect? blkif is now connected. */
- if (blkif_vbds_connected++ == 0)
- blkif_state = BLKIF_STATE_CONNECTED;
-
- xenbus_dev_ok(info->dev);
+ xlvbd_add(sectors, info->vdevice, binfo, sector_size, info);
+ info->connected = BLKIF_STATE_CONNECTED;
+
+ blkif_state = BLKIF_STATE_CONNECTED;
+
+ xenbus_dev_ok(info->xbdev);
/* Kick pending requests. */
spin_lock_irq(&blkif_io_lock);
- kick_pending_request_queues();
+ kick_pending_request_queues(info);
spin_unlock_irq(&blkif_io_lock);
}
@@ -1122,17 +1111,20 @@
SHARED_RING_INIT(sring);
FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
- info->grant_id = gnttab_claim_grant_reference(&gref_head,
- gref_terminal);
- ASSERT(info->grant_id != -ENOSPC);
- gnttab_grant_foreign_access_ref(info->grant_id,
- info->backend_id,
- virt_to_mfn(info->ring.sring),
- 0);
+ err = gnttab_grant_foreign_access(info->backend_id,
+ virt_to_mfn(info->ring.sring), 0);
+ if (err == -ENOSPC) {
+ free_page((unsigned long)info->ring.sring);
+ info->ring.sring = 0;
+ xenbus_dev_error(dev, err, "granting access to ring page");
+ return err;
+ }
+ info->grant_id = err;
op.u.alloc_unbound.dom = info->backend_id;
err = HYPERVISOR_event_channel_op(&op);
if (err) {
+ gnttab_end_foreign_access(info->grant_id, 0);
free_page((unsigned long)info->ring.sring);
info->ring.sring = 0;
xenbus_dev_error(dev, err, "allocating event channel");
@@ -1246,9 +1238,10 @@
xenbus_dev_error(dev, err, "allocating info structure");
return err;
}
- info->dev = dev;
+ info->xbdev = dev;
info->vdevice = vdevice;
- info->connected = 0;
+ info->connected = BLKIF_STATE_DISCONNECTED;
+ info->mi = NULL;
/* Front end dir is a number, which is used as the id. */
info->handle = simple_strtoul(strrchr(dev->nodename,'/')+1, NULL, 0);
@@ -1272,10 +1265,8 @@
if (info->backend)
unregister_xenbus_watch(&info->watch);
- if (info->connected) {
- xlvbd_del(info->handle);
- blkif_vbds_connected--;
- }
+ if (info->mi)
+ xlvbd_del(info);
blkif_free(info);
@@ -1359,11 +1350,6 @@
(xen_start_info.flags & SIF_BLK_BE_DOMAIN) )
return 0;
- /* A grant for every ring slot, plus one for the ring itself. */
- if (gnttab_alloc_grant_references(MAXIMUM_OUTSTANDING_BLOCK_REQS + 1,
- &gref_head, &gref_terminal) < 0)
- return 1;
-
IPRINTK("Initialising virtual block device driver\n");
blk_shadow_free = 0;
@@ -1383,6 +1369,6 @@
{
int i;
for ( i = 0; i < s->req.nr_segments; i++ )
- gnttab_release_grant_reference(
- &gref_head, blkif_gref_from_fas(s->req.frame_and_sects[i]));
-}
+ gnttab_free_grant_reference(
+ blkif_gref_from_fas(s->req.frame_and_sects[i]));
+}
diff -r 6078dc5f7ea1 -r 827a3c3524b3
linux-2.6-xen-sparse/drivers/xen/blkfront/block.h
--- a/linux-2.6-xen-sparse/drivers/xen/blkfront/block.h Mon Aug 22 20:57:26 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/block.h Mon Aug 22 20:59:00 2005
@@ -46,6 +46,7 @@
#include <linux/major.h>
#include <linux/devfs_fs_kernel.h>
#include <asm-xen/hypervisor.h>
+#include <asm-xen/xenbus.h>
#include <asm-xen/xen-public/xen.h>
#include <asm-xen/xen-public/io/blkif.h>
#include <asm-xen/xen-public/io/ring.h>
@@ -79,13 +80,20 @@
#define DPRINTK_IOCTL(_f, _a...) ((void)0)
#endif
-struct blkfront_info;
+struct xlbd_type_info
+{
+ int partn_shift;
+ int disks_per_major;
+ char *devname;
+ char *diskname;
+};
-struct xlbd_type_info {
- int partn_shift;
- int disks_per_major;
- char *devname;
- char *diskname;
+struct xlbd_major_info
+{
+ int major;
+ int index;
+ int usage;
+ struct xlbd_type_info *type;
};
/*
@@ -93,27 +101,27 @@
* hang in private_data off the gendisk structure. We may end up
* putting all kinds of interesting stuff here :-)
*/
-struct xlbd_major_info {
- int major;
- int index;
- int usage;
- struct xlbd_type_info *type;
+struct blkfront_info
+{
+ struct xenbus_device *xbdev;
+ /* We watch the backend */
+ struct xenbus_watch watch;
+ dev_t dev;
+ int vdevice;
+ blkif_vdev_t handle;
+ int connected;
+ char *backend;
+ int backend_id;
+ int grant_id;
+ blkif_front_ring_t ring;
+ unsigned int evtchn;
+ struct xlbd_major_info *mi;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ request_queue_t *rq;
+#endif
+ struct work_struct work;
+ struct gnttab_free_callback callback;
};
-
-struct xlbd_disk_info {
- int xd_device;
- blkif_vdev_t handle;
- struct xlbd_major_info *mi;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- struct xlbd_disk_info *next_waiting;
- request_queue_t *rq;
-#endif
- struct blkfront_info *info;
-};
-
-typedef struct xen_block {
- int usage;
-} xen_block_t;
extern spinlock_t blkif_io_lock;
@@ -126,7 +134,7 @@
extern void do_blkif_request (request_queue_t *rq);
/* Virtual block-device subsystem. */
-int xlvbd_add(blkif_sector_t capacity, int device, blkif_vdev_t handle,
+int xlvbd_add(blkif_sector_t capacity, int device,
u16 vdisk_info, u16 sector_size, struct blkfront_info *info);
-void xlvbd_del(blkif_vdev_t handle);
+void xlvbd_del(struct blkfront_info *info);
#endif /* __XEN_DRIVERS_BLOCK_H__ */
diff -r 6078dc5f7ea1 -r 827a3c3524b3
linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c Mon Aug 22 20:57:26 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c Mon Aug 22 20:59:00 2005
@@ -43,46 +43,37 @@
#define NUM_SCSI_MAJORS 9
#define NUM_VBD_MAJORS 1
-struct lvdisk
-{
- blkif_sector_t capacity; /* 0: Size in terms of 512-byte sectors. */
- blkif_vdev_t handle; /* 8: Device number (opaque 16 bit value). */
- u16 info;
- dev_t dev;
- struct list_head list;
+static struct xlbd_type_info xlbd_ide_type = {
+ .partn_shift = 6,
+ .disks_per_major = 2,
+ .devname = "ide",
+ .diskname = "hd",
};
-static struct xlbd_type_info xlbd_ide_type = {
- .partn_shift = 6,
- .disks_per_major = 2,
- .devname = "ide",
- .diskname = "hd",
+static struct xlbd_type_info xlbd_scsi_type = {
+ .partn_shift = 4,
+ .disks_per_major = 16,
+ .devname = "sd",
+ .diskname = "sd",
};
-static struct xlbd_type_info xlbd_scsi_type = {
- .partn_shift = 4,
- .disks_per_major = 16,
- .devname = "sd",
- .diskname = "sd",
+static struct xlbd_type_info xlbd_vbd_type = {
+ .partn_shift = 4,
+ .disks_per_major = 16,
+ .devname = "xvd",
+ .diskname = "xvd",
};
-static struct xlbd_type_info xlbd_vbd_type = {
- .partn_shift = 4,
- .disks_per_major = 16,
- .devname = "xvd",
- .diskname = "xvd",
-};
-
static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS +
- NUM_VBD_MAJORS];
-
-#define XLBD_MAJOR_IDE_START 0
-#define XLBD_MAJOR_SCSI_START (NUM_IDE_MAJORS)
-#define XLBD_MAJOR_VBD_START (NUM_IDE_MAJORS + NUM_SCSI_MAJORS)
-
-#define XLBD_MAJOR_IDE_RANGE XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START
- 1
-#define XLBD_MAJOR_SCSI_RANGE XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START
- 1
-#define XLBD_MAJOR_VBD_RANGE XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START
+ NUM_VBD_MAJORS - 1
+ NUM_VBD_MAJORS];
+
+#define XLBD_MAJOR_IDE_START 0
+#define XLBD_MAJOR_SCSI_START (NUM_IDE_MAJORS)
+#define XLBD_MAJOR_VBD_START (NUM_IDE_MAJORS + NUM_SCSI_MAJORS)
+
+#define XLBD_MAJOR_IDE_RANGE XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START
- 1
+#define XLBD_MAJOR_SCSI_RANGE XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START
- 1
+#define XLBD_MAJOR_VBD_RANGE XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START +
NUM_VBD_MAJORS - 1
/* Information about our VBDs. */
#define MAX_VBDS 64
@@ -91,279 +82,233 @@
#define MAJOR_XEN(dev) ((dev)>>8)
#define MINOR_XEN(dev) ((dev) & 0xff)
-static struct block_device_operations xlvbd_block_fops =
-{
- .owner = THIS_MODULE,
- .open = blkif_open,
- .release = blkif_release,
- .ioctl = blkif_ioctl,
+static struct block_device_operations xlvbd_block_fops =
+{
+ .owner = THIS_MODULE,
+ .open = blkif_open,
+ .release = blkif_release,
+ .ioctl = blkif_ioctl,
};
spinlock_t blkif_io_lock = SPIN_LOCK_UNLOCKED;
-static struct lvdisk *xlvbd_device_alloc(void)
-{
- struct lvdisk *disk;
-
- disk = kmalloc(sizeof(*disk), GFP_KERNEL);
- if (disk != NULL) {
- memset(disk, 0, sizeof(*disk));
- INIT_LIST_HEAD(&disk->list);
- }
- return disk;
-}
-
-static void xlvbd_device_free(struct lvdisk *disk)
-{
- list_del(&disk->list);
- kfree(disk);
-}
-
-static struct xlbd_major_info *xlbd_alloc_major_info(
- int major, int minor, int index)
-{
- struct xlbd_major_info *ptr;
-
- ptr = kmalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
- if (ptr == NULL)
- return NULL;
-
- memset(ptr, 0, sizeof(struct xlbd_major_info));
-
- ptr->major = major;
-
- switch (index) {
- case XLBD_MAJOR_IDE_RANGE:
- ptr->type = &xlbd_ide_type;
- ptr->index = index - XLBD_MAJOR_IDE_START;
- break;
- case XLBD_MAJOR_SCSI_RANGE:
- ptr->type = &xlbd_scsi_type;
- ptr->index = index - XLBD_MAJOR_SCSI_START;
- break;
- case XLBD_MAJOR_VBD_RANGE:
- ptr->type = &xlbd_vbd_type;
- ptr->index = index - XLBD_MAJOR_VBD_START;
- break;
- }
-
- printk("Registering block device major %i\n", ptr->major);
- if (register_blkdev(ptr->major, ptr->type->devname)) {
- WPRINTK("can't get major %d with name %s\n",
- ptr->major, ptr->type->devname);
- kfree(ptr);
- return NULL;
- }
-
- devfs_mk_dir(ptr->type->devname);
- major_info[index] = ptr;
- return ptr;
-}
-
-static struct xlbd_major_info *xlbd_get_major_info(int device)
-{
- int major, minor, index;
-
- major = MAJOR_XEN(device);
- minor = MINOR_XEN(device);
-
- switch (major) {
- case IDE0_MAJOR: index = 0; break;
- case IDE1_MAJOR: index = 1; break;
- case IDE2_MAJOR: index = 2; break;
- case IDE3_MAJOR: index = 3; break;
- case IDE4_MAJOR: index = 4; break;
- case IDE5_MAJOR: index = 5; break;
- case IDE6_MAJOR: index = 6; break;
- case IDE7_MAJOR: index = 7; break;
- case IDE8_MAJOR: index = 8; break;
- case IDE9_MAJOR: index = 9; break;
- case SCSI_DISK0_MAJOR: index = 10; break;
- case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
- index = 11 + major - SCSI_DISK1_MAJOR;
- break;
- case SCSI_CDROM_MAJOR: index = 18; break;
- default: index = 19; break;
- }
-
- return ((major_info[index] != NULL) ? major_info[index] :
- xlbd_alloc_major_info(major, minor, index));
-}
-
-static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
-{
- request_queue_t *rq;
-
- rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
- if (rq == NULL)
- return -1;
-
- elevator_init(rq, "noop");
-
- /* Hard sector size and max sectors impersonate the equiv. hardware. */
- blk_queue_hardsect_size(rq, sector_size);
- blk_queue_max_sectors(rq, 512);
-
- /* Each segment in a request is up to an aligned page in size. */
- blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
- blk_queue_max_segment_size(rq, PAGE_SIZE);
-
- /* Ensure a merged request will fit in a single I/O ring slot. */
- blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
- blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-
- /* Make sure buffer addresses are sector-aligned. */
- blk_queue_dma_alignment(rq, 511);
-
- gd->queue = rq;
-
- return 0;
-}
-
-static struct gendisk *xlvbd_alloc_gendisk(
- struct xlbd_major_info *mi, int minor, blkif_sector_t capacity,
- int device, blkif_vdev_t handle, u16 vdisk_info, u16 sector_size,
- struct blkfront_info *info)
-{
- struct gendisk *gd;
- struct xlbd_disk_info *di;
- int nr_minors = 1;
-
- di = kmalloc(sizeof(struct xlbd_disk_info), GFP_KERNEL);
- if (di == NULL)
- return NULL;
- memset(di, 0, sizeof(*di));
- di->mi = mi;
- di->xd_device = device;
- di->handle = handle;
- di->info = info;
-
- if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
- nr_minors = 1 << mi->type->partn_shift;
-
- gd = alloc_disk(nr_minors);
- if (gd == NULL)
- goto out;
-
- if (nr_minors > 1)
- sprintf(gd->disk_name, "%s%c", mi->type->diskname,
- 'a' + mi->index * mi->type->disks_per_major +
- (minor >> mi->type->partn_shift));
- else
- sprintf(gd->disk_name, "%s%c%d", mi->type->diskname,
- 'a' + mi->index * mi->type->disks_per_major +
- (minor >> mi->type->partn_shift),
- minor & ((1 << mi->type->partn_shift) - 1));
-
- gd->major = mi->major;
- gd->first_minor = minor;
- gd->fops = &xlvbd_block_fops;
- gd->private_data = di;
- set_capacity(gd, capacity);
-
- if (xlvbd_init_blk_queue(gd, sector_size)) {
- del_gendisk(gd);
- goto out;
- }
-
- di->rq = gd->queue;
-
- if (vdisk_info & VDISK_READONLY)
- set_disk_ro(gd, 1);
-
- if (vdisk_info & VDISK_REMOVABLE)
- gd->flags |= GENHD_FL_REMOVABLE;
-
- if (vdisk_info & VDISK_CDROM)
- gd->flags |= GENHD_FL_CD;
-
- add_disk(gd);
-
- return gd;
-
-out:
- kfree(di);
- return NULL;
-}
-
-int xlvbd_add(blkif_sector_t capacity, int device, blkif_vdev_t handle,
- u16 vdisk_info, u16 sector_size, struct blkfront_info *info)
-{
- struct lvdisk *new;
- struct block_device *bd;
- struct gendisk *gd;
- struct xlbd_major_info *mi;
-
- mi = xlbd_get_major_info(device);
- if (mi == NULL)
- return -EPERM;
-
- new = xlvbd_device_alloc();
- if (new == NULL)
- return -ENOMEM;
- new->capacity = capacity;
- new->info = vdisk_info;
- new->handle = handle;
- new->dev = MKDEV(MAJOR_XEN(device), MINOR_XEN(device));
-
- bd = bdget(new->dev);
- if (bd == NULL)
- goto out;
-
- gd = xlvbd_alloc_gendisk(mi, MINOR_XEN(device), capacity, device, handle,
- vdisk_info, sector_size, info);
- if (gd == NULL)
- goto out_bd;
-
- list_add(&new->list, &vbds_list);
-out_bd:
- bdput(bd);
-out:
- return 0;
-}
-
-static int xlvbd_device_del(struct lvdisk *disk)
-{
- struct block_device *bd;
- struct gendisk *gd;
- struct xlbd_disk_info *di;
- int ret = 0, unused;
- request_queue_t *rq;
-
- bd = bdget(disk->dev);
- if (bd == NULL)
- return -1;
-
- gd = get_gendisk(disk->dev, &unused);
- di = gd->private_data;
-
-#if 0 /* This is wrong: hda and hdb share same major, for example. */
- if (di->mi->usage != 0) {
- WPRINTK("disk removal failed: used [dev=%x]\n", disk->dev);
- ret = -1;
- goto out;
- }
-#endif
-
- rq = gd->queue;
- del_gendisk(gd);
- put_disk(gd);
- blk_cleanup_queue(rq);
-
- xlvbd_device_free(disk);
- bdput(bd);
- return ret;
-}
-
-void xlvbd_del(blkif_vdev_t handle)
-{
- struct lvdisk *i;
-
- list_for_each_entry(i, &vbds_list, list) {
- if (i->handle == handle) {
- xlvbd_device_del(i);
- return;
- }
+static struct xlbd_major_info *
+xlbd_alloc_major_info(int major, int minor, int index)
+{
+ struct xlbd_major_info *ptr;
+
+ ptr = kmalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
+ if (ptr == NULL)
+ return NULL;
+
+ memset(ptr, 0, sizeof(struct xlbd_major_info));
+
+ ptr->major = major;
+
+ switch (index) {
+ case XLBD_MAJOR_IDE_RANGE:
+ ptr->type = &xlbd_ide_type;
+ ptr->index = index - XLBD_MAJOR_IDE_START;
+ break;
+ case XLBD_MAJOR_SCSI_RANGE:
+ ptr->type = &xlbd_scsi_type;
+ ptr->index = index - XLBD_MAJOR_SCSI_START;
+ break;
+ case XLBD_MAJOR_VBD_RANGE:
+ ptr->type = &xlbd_vbd_type;
+ ptr->index = index - XLBD_MAJOR_VBD_START;
+ break;
}
- BUG();
-}
+
+ printk("Registering block device major %i\n", ptr->major);
+ if (register_blkdev(ptr->major, ptr->type->devname)) {
+ WPRINTK("can't get major %d with name %s\n",
+ ptr->major, ptr->type->devname);
+ kfree(ptr);
+ return NULL;
+ }
+
+ devfs_mk_dir(ptr->type->devname);
+ major_info[index] = ptr;
+ return ptr;
+}
+
+static struct xlbd_major_info *
+xlbd_get_major_info(int vdevice)
+{
+ struct xlbd_major_info *mi;
+ int major, minor, index;
+
+ major = MAJOR_XEN(vdevice);
+ minor = MINOR_XEN(vdevice);
+
+ switch (major) {
+ case IDE0_MAJOR: index = 0; break;
+ case IDE1_MAJOR: index = 1; break;
+ case IDE2_MAJOR: index = 2; break;
+ case IDE3_MAJOR: index = 3; break;
+ case IDE4_MAJOR: index = 4; break;
+ case IDE5_MAJOR: index = 5; break;
+ case IDE6_MAJOR: index = 6; break;
+ case IDE7_MAJOR: index = 7; break;
+ case IDE8_MAJOR: index = 8; break;
+ case IDE9_MAJOR: index = 9; break;
+ case SCSI_DISK0_MAJOR: index = 10; break;
+ case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
+ index = 11 + major - SCSI_DISK1_MAJOR;
+ break;
+ case SCSI_CDROM_MAJOR: index = 18; break;
+ default: index = 19; break;
+ }
+
+ mi = ((major_info[index] != NULL) ? major_info[index] :
+ xlbd_alloc_major_info(major, minor, index));
+ mi->usage++;
+ return mi;
+}
+
+static void
+xlbd_put_major_info(struct xlbd_major_info *mi)
+{
+ mi->usage--;
+ /* XXX: release major if 0 */
+}
+
+static int
+xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
+{
+ request_queue_t *rq;
+
+ rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
+ if (rq == NULL)
+ return -1;
+
+ elevator_init(rq, "noop");
+
+ /* Hard sector size and max sectors impersonate the equiv. hardware. */
+ blk_queue_hardsect_size(rq, sector_size);
+ blk_queue_max_sectors(rq, 512);
+
+ /* Each segment in a request is up to an aligned page in size. */
+ blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
+ blk_queue_max_segment_size(rq, PAGE_SIZE);
+
+ /* Ensure a merged request will fit in a single I/O ring slot. */
+ blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+ /* Make sure buffer addresses are sector-aligned. */
+ blk_queue_dma_alignment(rq, 511);
+
+ gd->queue = rq;
+
+ return 0;
+}
+
+static int
+xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
+ u16 vdisk_info, u16 sector_size,
+ struct blkfront_info *info)
+{
+ struct gendisk *gd;
+ struct xlbd_major_info *mi;
+ int nr_minors = 1;
+ int err = -ENODEV;
+
+ mi = xlbd_get_major_info(vdevice);
+ if (mi == NULL)
+ goto out;
+ info->mi = mi;
+
+ if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
+ nr_minors = 1 << mi->type->partn_shift;
+
+ gd = alloc_disk(nr_minors);
+ if (gd == NULL)
+ goto out;
+
+ if (nr_minors > 1)
+ sprintf(gd->disk_name, "%s%c", mi->type->diskname,
+ 'a' + mi->index * mi->type->disks_per_major +
+ (minor >> mi->type->partn_shift));
+ else
+ sprintf(gd->disk_name, "%s%c%d", mi->type->diskname,
+ 'a' + mi->index * mi->type->disks_per_major +
+ (minor >> mi->type->partn_shift),
+ minor & ((1 << mi->type->partn_shift) - 1));
+
+ gd->major = mi->major;
+ gd->first_minor = minor;
+ gd->fops = &xlvbd_block_fops;
+ gd->private_data = info;
+ set_capacity(gd, capacity);
+
+ if (xlvbd_init_blk_queue(gd, sector_size)) {
+ del_gendisk(gd);
+ goto out;
+ }
+
+ info->rq = gd->queue;
+
+ if (vdisk_info & VDISK_READONLY)
+ set_disk_ro(gd, 1);
+
+ if (vdisk_info & VDISK_REMOVABLE)
+ gd->flags |= GENHD_FL_REMOVABLE;
+
+ if (vdisk_info & VDISK_CDROM)
+ gd->flags |= GENHD_FL_CD;
+
+ add_disk(gd);
+
+ return 0;
+
+ out:
+ if (mi)
+ xlbd_put_major_info(mi);
+ return err;
+}
+
+int
+xlvbd_add(blkif_sector_t capacity, int vdevice, u16 vdisk_info,
+ u16 sector_size, struct blkfront_info *info)
+{
+ struct block_device *bd;
+ int err = 0;
+
+ info->dev = MKDEV(MAJOR_XEN(vdevice), MINOR_XEN(vdevice));
+
+ bd = bdget(info->dev);
+ if (bd == NULL)
+ return -ENODEV;
+
+ err = xlvbd_alloc_gendisk(MINOR_XEN(vdevice), capacity, vdevice,
+ vdisk_info, sector_size, info);
+
+ bdput(bd);
+ return err;
+}
+
+void
+xlvbd_del(struct blkfront_info *info)
+{
+ struct block_device *bd;
+ struct gendisk *gd;
+ int unused;
+ request_queue_t *rq;
+
+ bd = bdget(info->dev);
+ if (bd == NULL)
+ return;
+
+ gd = get_gendisk(info->dev, &unused);
+ rq = gd->queue;
+
+ del_gendisk(gd);
+ put_disk(gd);
+ xlbd_put_major_info(info->mi);
+ info->mi = NULL;
+ blk_cleanup_queue(rq);
+
+ bdput(bd);
+}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|