aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-05-20 13:32:19 +0000
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-05-20 13:32:19 +0000
commit642d0333322a840e00b76522b26af65db729980a (patch)
treeb9be70cf4bfdf1c7745d7db59c54639dae3ba14b
parentb87d148b3b6fcbfe1d5c093f68a59989b05e9e79 (diff)
downloadxen-642d0333322a840e00b76522b26af65db729980a.tar.gz
xen-642d0333322a840e00b76522b26af65db729980a.tar.bz2
xen-642d0333322a840e00b76522b26af65db729980a.zip
bitkeeper revision 1.1159.258.141 (428de6e3qI6WPj3ZDv-N9guEb9d7uA)
Blkfront cleanups and fix whole-device mapping. Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r--linux-2.6.11-xen-sparse/drivers/xen/blkfront/blkfront.c10
-rw-r--r--linux-2.6.11-xen-sparse/drivers/xen/blkfront/block.h8
-rw-r--r--linux-2.6.11-xen-sparse/drivers/xen/blkfront/vbd.c611
3 files changed, 318 insertions, 311 deletions
diff --git a/linux-2.6.11-xen-sparse/drivers/xen/blkfront/blkfront.c b/linux-2.6.11-xen-sparse/drivers/xen/blkfront/blkfront.c
index c6035b7b4d..9c181affab 100644
--- a/linux-2.6.11-xen-sparse/drivers/xen/blkfront/blkfront.c
+++ b/linux-2.6.11-xen-sparse/drivers/xen/blkfront/blkfront.c
@@ -60,8 +60,6 @@ static void vbd_update(void){};
#define BLKIF_STATE_DISCONNECTED 1
#define BLKIF_STATE_CONNECTED 2
-#define WPRINTK(fmt, args...) printk(KERN_WARNING "xen_blk: " fmt, ##args)
-
static int blkif_handle = 0;
static unsigned int blkif_state = BLKIF_STATE_CLOSED;
static unsigned int blkif_evtchn = 0;
@@ -694,7 +692,7 @@ int blkif_ioctl(struct inode *inode, struct file *filep,
return -ENOSYS;
default:
- printk(KERN_ALERT "ioctl %08x not supported by XL blkif\n", command);
+ WPRINTK("ioctl %08x not supported by XL blkif\n", command);
return -ENOSYS;
}
@@ -1206,7 +1204,7 @@ static void blkif_connect(blkif_fe_interface_status_t *status)
err = request_irq(blkif_irq, blkif_int, SA_SAMPLE_RANDOM, "blkif", NULL);
if ( err )
{
- printk(KERN_ALERT "xen_blk: request_irq failed (err=%d)\n", err);
+ WPRINTK("request_irq failed (err=%d)\n", err);
return;
}
@@ -1353,7 +1351,7 @@ int wait_for_blkif(void)
if ( blkif_state != BLKIF_STATE_CONNECTED )
{
- printk(KERN_INFO "xen_blk: Timeout connecting to device!\n");
+ WPRINTK("Timeout connecting to device!\n");
err = -ENOSYS;
}
return err;
@@ -1367,7 +1365,7 @@ int __init xlblk_init(void)
(xen_start_info.flags & SIF_BLK_BE_DOMAIN) )
return 0;
- printk(KERN_INFO "xen_blk: Initialising virtual block device driver\n");
+ IPRINTK("Initialising virtual block device driver\n");
rec_ring_free = 0;
for ( i = 0; i < BLKIF_RING_SIZE; i++ )
diff --git a/linux-2.6.11-xen-sparse/drivers/xen/blkfront/block.h b/linux-2.6.11-xen-sparse/drivers/xen/blkfront/block.h
index b7fff75956..7f46506285 100644
--- a/linux-2.6.11-xen-sparse/drivers/xen/blkfront/block.h
+++ b/linux-2.6.11-xen-sparse/drivers/xen/blkfront/block.h
@@ -50,6 +50,11 @@
#include <asm/atomic.h>
#include <asm/uaccess.h>
+#define IPRINTK(fmt, args...) \
+ printk(KERN_INFO "xen_blk: " fmt, ##args)
+#define WPRINTK(fmt, args...) \
+ printk(KERN_WARNING "xen_blk: " fmt, ##args)
+
#if 0
#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a )
#else
@@ -64,8 +69,7 @@
struct xlbd_type_info {
int partn_shift;
- int partn_per_major;
- int devs_per_major;
+ int disks_per_major;
char *devname;
char *diskname;
};
diff --git a/linux-2.6.11-xen-sparse/drivers/xen/blkfront/vbd.c b/linux-2.6.11-xen-sparse/drivers/xen/blkfront/vbd.c
index d7b6aa6aa1..0110d11223 100644
--- a/linux-2.6.11-xen-sparse/drivers/xen/blkfront/vbd.c
+++ b/linux-2.6.11-xen-sparse/drivers/xen/blkfront/vbd.c
@@ -31,6 +31,7 @@
#include "block.h"
#include <linux/blkdev.h>
+#include <linux/list.h>
/*
* For convenience we distinguish between ide, scsi and 'other' (i.e.,
@@ -42,23 +43,31 @@
#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 device; /* 8: Device number (opaque 16 bit value). */
+ u16 info;
+ struct list_head list;
+};
+
static struct xlbd_type_info xlbd_ide_type = {
.partn_shift = 6,
- .partn_per_major = 2,
+ .disks_per_major = 2,
.devname = "ide",
.diskname = "hd",
};
static struct xlbd_type_info xlbd_scsi_type = {
.partn_shift = 4,
- .partn_per_major = 16,
+ .disks_per_major = 16,
.devname = "sd",
.diskname = "sd",
};
static struct xlbd_type_info xlbd_vbd_type = {
.partn_shift = 4,
- .partn_per_major = 16,
+ .disks_per_major = 16,
.devname = "xvd",
.diskname = "xvd",
};
@@ -66,10 +75,17 @@ static struct xlbd_type_info xlbd_vbd_type = {
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
+
/* Information about our VBDs. */
#define MAX_VBDS 64
-static int nr_vbds;
-static vdisk_t *vbd_info;
+struct list_head vbds_list;
struct request_queue *xlbd_blk_queue = NULL;
@@ -82,388 +98,381 @@ static struct block_device_operations xlvbd_block_fops =
.open = blkif_open,
.release = blkif_release,
.ioctl = blkif_ioctl,
-#if 0
- check_media_change: blkif_check,
- revalidate: blkif_revalidate,
-#endif
};
spinlock_t blkif_io_lock = SPIN_LOCK_UNLOCKED;
-static int xlvbd_get_vbd_info(vdisk_t *disk_info)
+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 vdisk_t *xlvbd_probe(int *ret)
{
- vdisk_t *buf = (vdisk_t *)__get_free_page(GFP_KERNEL);
- blkif_request_t req;
blkif_response_t rsp;
- int nr;
+ blkif_request_t req;
+ vdisk_t *disk_info = NULL;
+ unsigned long buf;
+ int nr;
+
+ buf = __get_free_page(GFP_KERNEL);
+ if ((void *)buf == NULL)
+ goto out;
memset(&req, 0, sizeof(req));
- req.operation = BLKIF_OP_PROBE;
+ req.operation = BLKIF_OP_PROBE;
req.nr_segments = 1;
+#ifdef CONFIG_XEN_BLKDEV_GRANT
+ blkif_control_probe_send(&req, &rsp,
+ (unsigned long)(virt_to_machine(buf)));
+#else
req.frame_and_sects[0] = virt_to_machine(buf) | 7;
blkif_control_send(&req, &rsp);
-
- if ( rsp.status <= 0 )
- {
- printk(KERN_ALERT "Could not probe disks (%d)\n", rsp.status);
- return -1;
+#endif
+ if ( rsp.status <= 0 ) {
+ WPRINTK("Could not probe disks (%d)\n", rsp.status);
+ goto out;
}
-
- if ( (nr = rsp.status) > MAX_VBDS )
+ nr = rsp.status;
+ if ( nr > MAX_VBDS )
nr = MAX_VBDS;
- memcpy(disk_info, buf, nr * sizeof(vdisk_t));
- free_page((unsigned long)buf);
+ disk_info = kmalloc(nr * sizeof(vdisk_t), GFP_KERNEL);
+ if (disk_info != NULL)
+ memcpy(disk_info, (void *) buf, nr * sizeof(vdisk_t));
- return nr;
+ if (ret != NULL)
+ *ret = nr;
+
+out:
+ free_page(buf);
+ return disk_info;
}
-static struct xlbd_major_info *xlbd_get_major_info(int xd_device, int *minor)
+static struct xlbd_major_info *xlbd_alloc_major_info(
+ int major, int minor, int index)
{
- int mi_idx, new_major;
- int xd_major = MAJOR_XEN(xd_device);
- int xd_minor = MINOR_XEN(xd_device);
-
- *minor = xd_minor;
-
- switch (xd_major) {
- case IDE0_MAJOR: mi_idx = 0; new_major = IDE0_MAJOR; break;
- case IDE1_MAJOR: mi_idx = 1; new_major = IDE1_MAJOR; break;
- case IDE2_MAJOR: mi_idx = 2; new_major = IDE2_MAJOR; break;
- case IDE3_MAJOR: mi_idx = 3; new_major = IDE3_MAJOR; break;
- case IDE4_MAJOR: mi_idx = 4; new_major = IDE4_MAJOR; break;
- case IDE5_MAJOR: mi_idx = 5; new_major = IDE5_MAJOR; break;
- case IDE6_MAJOR: mi_idx = 6; new_major = IDE6_MAJOR; break;
- case IDE7_MAJOR: mi_idx = 7; new_major = IDE7_MAJOR; break;
- case IDE8_MAJOR: mi_idx = 8; new_major = IDE8_MAJOR; break;
- case IDE9_MAJOR: mi_idx = 9; new_major = IDE9_MAJOR; break;
- case SCSI_DISK0_MAJOR: mi_idx = 10; new_major = SCSI_DISK0_MAJOR; break;
- case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
- mi_idx = 11 + xd_major - SCSI_DISK1_MAJOR;
- new_major = SCSI_DISK1_MAJOR + xd_major - SCSI_DISK1_MAJOR;
- break;
- case SCSI_CDROM_MAJOR: mi_idx = 18; new_major = SCSI_CDROM_MAJOR; break;
- default: mi_idx = 19; new_major = 0;/* XXXcl notyet */ break;
- }
-
- if (major_info[mi_idx])
- return major_info[mi_idx];
+ struct xlbd_major_info *ptr;
- major_info[mi_idx] = kmalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
- if (major_info[mi_idx] == NULL)
+ ptr = kmalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
+ if (ptr == NULL)
return NULL;
- memset(major_info[mi_idx], 0, sizeof(struct xlbd_major_info));
+ memset(ptr, 0, sizeof(struct xlbd_major_info));
- switch (mi_idx) {
- case 0 ... (NUM_IDE_MAJORS - 1):
- major_info[mi_idx]->type = &xlbd_ide_type;
- major_info[mi_idx]->index = mi_idx;
+ ptr->major = major;
+
+ switch (index) {
+ case XLBD_MAJOR_IDE_RANGE:
+ ptr->type = &xlbd_ide_type;
+ ptr->index = index - XLBD_MAJOR_IDE_START;
break;
- case NUM_IDE_MAJORS ... (NUM_IDE_MAJORS + NUM_SCSI_MAJORS - 1):
- major_info[mi_idx]->type = &xlbd_scsi_type;
- major_info[mi_idx]->index = mi_idx - NUM_IDE_MAJORS;
+ case XLBD_MAJOR_SCSI_RANGE:
+ ptr->type = &xlbd_scsi_type;
+ ptr->index = index - XLBD_MAJOR_SCSI_START;
break;
- case (NUM_IDE_MAJORS + NUM_SCSI_MAJORS) ...
- (NUM_IDE_MAJORS + NUM_SCSI_MAJORS + NUM_VBD_MAJORS - 1):
- major_info[mi_idx]->type = &xlbd_vbd_type;
- major_info[mi_idx]->index = mi_idx -
- (NUM_IDE_MAJORS + NUM_SCSI_MAJORS);
+ case XLBD_MAJOR_VBD_RANGE:
+ ptr->type = &xlbd_vbd_type;
+ ptr->index = index - XLBD_MAJOR_VBD_START;
break;
}
- major_info[mi_idx]->major = new_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;
+ }
- if (register_blkdev(major_info[mi_idx]->major, major_info[mi_idx]->type->devname)) {
- printk(KERN_ALERT "XL VBD: can't get major %d with name %s\n",
- major_info[mi_idx]->major, major_info[mi_idx]->type->devname);
- goto out;
+ 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;
}
- devfs_mk_dir(major_info[mi_idx]->type->devname);
+ return ((major_info[index] != NULL) ? major_info[index] :
+ xlbd_alloc_major_info(major, minor, index));
+}
- return major_info[mi_idx];
+static int xlvbd_blk_queue_alloc(struct xlbd_type_info *type)
+{
+ xlbd_blk_queue = blk_init_queue(do_blkif_request, &blkif_io_lock);
+ if (xlbd_blk_queue == NULL)
+ return -1;
- out:
- kfree(major_info[mi_idx]);
- major_info[mi_idx] = NULL;
- return NULL;
+ elevator_init(xlbd_blk_queue, "noop");
+
+ /*
+ * Turn off barking 'headactive' mode. We dequeue
+ * buffer heads as soon as we pass them to back-end
+ * driver.
+ */
+ blk_queue_headactive(xlbd_blk_queue, 0);
+
+ /* Hard sector size and max sectors impersonate the equiv. hardware. */
+ blk_queue_hardsect_size(xlbd_blk_queue, 512);
+ blk_queue_max_sectors(xlbd_blk_queue, 512);
+
+ /* Each segment in a request is up to an aligned page in size. */
+ blk_queue_segment_boundary(xlbd_blk_queue, PAGE_SIZE - 1);
+ blk_queue_max_segment_size(xlbd_blk_queue, PAGE_SIZE);
+
+ /* Ensure a merged request will fit in a single I/O ring slot. */
+ blk_queue_max_phys_segments(xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ blk_queue_max_hw_segments(xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+ /* Make sure buffer addresses are sector-aligned. */
+ blk_queue_dma_alignment(xlbd_blk_queue, 511);
+ return 0;
}
-static struct gendisk *xlvbd_get_gendisk(struct xlbd_major_info *mi,
- int xd_minor, vdisk_t *xd)
+struct gendisk *xlvbd_alloc_gendisk(
+ struct xlbd_major_info *mi, int minor, vdisk_t *disk)
{
struct gendisk *gd;
struct xlbd_disk_info *di;
- int device, partno;
-
- device = MKDEV(mi->major, xd_minor);
- gd = get_gendisk(device, &partno);
- if ( gd != NULL )
- return gd;
+ int nr_minors = 1;
di = kmalloc(sizeof(struct xlbd_disk_info), GFP_KERNEL);
- if ( di == NULL )
- return NULL;
+ if (di == NULL)
+ goto out;
di->mi = mi;
- di->xd_device = xd->device;
+ di->xd_device = disk->device;
- /* Construct an appropriate gendisk structure. */
- gd = alloc_disk(1);
- if ( gd == NULL )
+ /* Full disk rather than a single partition? */
+ if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
+ nr_minors = 1 << mi->type->partn_shift;
+
+ gd = alloc_disk(nr_minors);
+ if ( !gd )
goto out;
+ if ( nr_minors > 1 ) /* full disk? */
+ 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 = xd_minor;
+ gd->first_minor = minor;
gd->fops = &xlvbd_block_fops;
gd->private_data = di;
- sprintf(gd->disk_name, "%s%c%d", mi->type->diskname,
- 'a' + mi->index * mi->type->partn_per_major +
- (xd_minor >> mi->type->partn_shift),
- xd_minor & ((1 << mi->type->partn_shift) - 1));
-
- set_capacity(gd, xd->capacity);
-
- if ( xlbd_blk_queue == NULL )
- {
- xlbd_blk_queue = blk_init_queue(do_blkif_request,
- &blkif_io_lock);
- if ( xlbd_blk_queue == NULL )
- goto out;
- elevator_init(xlbd_blk_queue, "noop");
-
- /*
- * Turn off barking 'headactive' mode. We dequeue buffer heads as soon
- * as we pass them to back-end driver.
- */
- blk_queue_headactive(xlbd_blk_queue, 0);
-
- blk_queue_hardsect_size(xlbd_blk_queue, 512);
- blk_queue_max_sectors(xlbd_blk_queue, 512);
-
- /* Each segment in a request is up to an aligned page in size. */
- blk_queue_segment_boundary(xlbd_blk_queue, PAGE_SIZE - 1);
- blk_queue_max_segment_size(xlbd_blk_queue, PAGE_SIZE);
-
- /* Ensure a merged request will fit in a single I/O ring slot. */
- blk_queue_max_phys_segments(
- xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST);
- blk_queue_max_hw_segments(
- xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-
- /* Make sure buffer addresses are sector-aligned. */
- blk_queue_dma_alignment(xlbd_blk_queue, 511);
- }
- gd->queue = xlbd_blk_queue;
+ set_capacity(gd, disk->capacity);
- add_disk(gd);
+ if ((xlbd_blk_queue == NULL) && xlvbd_blk_queue_alloc(mi->type))
+ goto out_gendisk;
+ gd->queue = xlbd_blk_queue;
+ add_disk(gd);
return gd;
- out:
- if ( gd != NULL )
- del_gendisk(gd);
+out_gendisk:
+ del_gendisk(gd);
+out:
kfree(di);
return NULL;
}
-/*
- * xlvbd_init_device - initialise a VBD device
- * @disk: a vdisk_t describing the VBD
- *
- * Takes a vdisk_t * that describes a VBD the domain has access to.
- * Performs appropriate initialisation and registration of the device.
- *
- * Care needs to be taken when making re-entrant calls to ensure that
- * corruption does not occur. Also, devices that are in use should not have
- * their details updated. This is the caller's responsibility.
- */
-static int xlvbd_init_device(vdisk_t *xd)
+static int xlvbd_device_add(struct list_head *list, vdisk_t *disk)
{
+ struct lvdisk *new;
+ int minor;
+ dev_t device;
struct block_device *bd;
struct gendisk *gd;
struct xlbd_major_info *mi;
- int device;
- int minor;
- int err = -ENOMEM;
-
- mi = xlbd_get_major_info(xd->device, &minor);
+ mi = xlbd_get_major_info(disk->device);
if (mi == NULL)
return -EPERM;
+ new = xlvbd_device_alloc();
+ if (new == NULL)
+ return -1;
+ new->capacity = disk->capacity;
+ new->device = disk->device;
+ new->info = disk->info;
+
+ minor = MINOR_XEN(disk->device);
device = MKDEV(mi->major, minor);
-
- if ((bd = bdget(device)) == NULL)
- return -EPERM;
-
- /*
- * Update of partition info, and check of usage count, is protected
- * by the per-block-device semaphore.
- */
- down(&bd->bd_sem);
-
- gd = xlvbd_get_gendisk(mi, minor, xd);
- if (gd == NULL) {
- err = -EPERM;
+
+ bd = bdget(device);
+ if (bd == NULL)
goto out;
- }
+
+ gd = xlvbd_alloc_gendisk(mi, minor, disk);
+ if (gd == NULL)
+ goto out_bd;
- if (VDISK_READONLY(xd->info))
- set_disk_ro(gd, 1);
+ if (VDISK_READONLY(disk->info))
+ set_disk_ro(gd, 1);
- /* Some final fix-ups depending on the device type */
- switch (VDISK_TYPE(xd->info)) {
+ switch (VDISK_TYPE(disk->info)) {
case VDISK_TYPE_CDROM:
- gd->flags |= GENHD_FL_REMOVABLE | GENHD_FL_CD;
- /* FALLTHROUGH */
+ gd->flags |= GENHD_FL_REMOVABLE | GENHD_FL_CD;
+ break;
case VDISK_TYPE_FLOPPY:
case VDISK_TYPE_TAPE:
- gd->flags |= GENHD_FL_REMOVABLE;
- break;
-
+ gd->flags |= GENHD_FL_REMOVABLE;
+ break;
case VDISK_TYPE_DISK:
- break;
-
+ break;
default:
- printk(KERN_ALERT "XenLinux: unknown device type %d\n",
- VDISK_TYPE(xd->info));
- break;
- }
+ WPRINTK("unknown device type %d\n", VDISK_TYPE(disk->info));
+ break;
+ }
- err = 0;
- out:
- up(&bd->bd_sem);
- bdput(bd);
- return err;
+ list_add(&new->list, list);
+out_bd:
+ bdput(bd);
+out:
+ return 0;
}
-/*
- * xlvbd_remove_device - remove a device node if possible
- * @device: numeric device ID
- *
- * Updates the gendisk structure and invalidates devices.
- *
- * This is OK for now but in future, should perhaps consider where this should
- * deallocate gendisks / unregister devices.
- */
-static int xlvbd_remove_device(int dev16)
+static int xlvbd_device_del(struct lvdisk *disk)
{
- int i, rc = 0;
- struct gendisk *gd;
+ dev_t device;
struct block_device *bd;
+ struct gendisk *gd;
struct xlbd_disk_info *di;
- dev_t device = MKDEV(MAJOR_XEN(dev16), MINOR_XEN(dev16));
+ int ret = 0, unused;
+
+ device = MKDEV(MAJOR_XEN(disk->device), MINOR_XEN(disk->device));
bd = bdget(device);
- if (!bd)
+ if (bd == NULL)
return -1;
- /*
- * Update of partition info, and check of usage count, is protected
- * by the per-block-device semaphore.
- */
- down(&bd->bd_sem);
-
- gd = get_gendisk(device, &i);
- BUG_ON(gd == NULL);
- di = (struct xlbd_disk_info *) gd->private_data;
- BUG_ON(di == NULL);
-
- if ( di->mi->usage != 0 )
- {
- printk(KERN_ALERT "VBD removal failed - in use [dev=%x]\n", device);
- rc = -1;
+ gd = get_gendisk(device, &unused);
+ di = gd->private_data;
+
+ if (di->mi->usage != 0) {
+ WPRINTK("disk removal failed: used [dev=%x]\n", device);
+ ret = -1;
goto out;
}
- /* The VBD is mapped to an entire unit. */
-
- invalidate_partition(gd, 0);
- set_capacity(gd, 0);
+ del_gendisk(gd);
+ xlvbd_device_free(disk);
out:
- up(&bd->bd_sem);
bdput(bd);
- return rc;
+ return ret;
}
-/*
- * xlvbd_update_vbds - reprobes the VBD status and performs updates driver
- * state. The VBDs need to be updated in this way when the domain is
- * initialised and also each time we receive an XLBLK_UPDATE event.
- */
-void xlvbd_update_vbds(void)
+static int xlvbd_device_update(struct lvdisk *ldisk, vdisk_t *disk)
{
- int i, j, k, old_nr, new_nr;
- vdisk_t *old_info, *new_info, *merged_info;
+ dev_t device;
+ struct block_device *bd;
+ struct gendisk *gd;
+ int unused;
- old_info = vbd_info;
- old_nr = nr_vbds;
+ if ((ldisk->capacity == disk->capacity) && (ldisk->info == disk->info))
+ return 0;
- new_info = kmalloc(MAX_VBDS * sizeof(vdisk_t), GFP_KERNEL);
- if (!new_info)
- return;
+ device = MKDEV(MAJOR_XEN(ldisk->device), MINOR_XEN(ldisk->device));
- if ( unlikely(new_nr = xlvbd_get_vbd_info(new_info)) < 0 )
- goto out;
+ bd = bdget(device);
+ if (bd == NULL)
+ return -1;
- /*
- * Final list maximum size is old list + new list. This occurs only when
- * old list and new list do not overlap at all, and we cannot yet destroy
- * VBDs in the old list because the usage counts are busy.
- */
- merged_info = kmalloc((old_nr + new_nr) * sizeof(vdisk_t), GFP_KERNEL);
- if (!merged_info)
- goto out;
+ gd = get_gendisk(device, &unused);
+ set_capacity(gd, disk->capacity);
+ ldisk->capacity = disk->capacity;
- /* @i tracks old list; @j tracks new list; @k tracks merged list. */
- i = j = k = 0;
+ bdput(bd);
- while ( (i < old_nr) && (j < new_nr) )
- {
- if ( old_info[i].device < new_info[j].device )
- {
- if ( xlvbd_remove_device(old_info[i].device) != 0 )
- memcpy(&merged_info[k++], &old_info[i], sizeof(vdisk_t));
- i++;
- }
- else if ( old_info[i].device > new_info[j].device )
- {
- if ( xlvbd_init_device(&new_info[j]) == 0 )
- memcpy(&merged_info[k++], &new_info[j], sizeof(vdisk_t));
- j++;
- }
- else
- {
- if ( ((old_info[i].capacity == new_info[j].capacity) &&
- (old_info[i].info == new_info[j].info)) ||
- (xlvbd_remove_device(old_info[i].device) != 0) )
- memcpy(&merged_info[k++], &old_info[i], sizeof(vdisk_t));
- else if ( xlvbd_init_device(&new_info[j]) == 0 )
- memcpy(&merged_info[k++], &new_info[j], sizeof(vdisk_t));
- i++; j++;
- }
- }
+ return 0;
+}
- for ( ; i < old_nr; i++ )
- {
- if ( xlvbd_remove_device(old_info[i].device) != 0 )
- memcpy(&merged_info[k++], &old_info[i], sizeof(vdisk_t));
+void xlvbd_refresh(void)
+{
+ vdisk_t *newdisks;
+ struct list_head *tmp, *tmp2;
+ struct lvdisk *disk;
+ int i, nr;
+
+ newdisks = xlvbd_probe(&nr);
+ if (newdisks == NULL) {
+ WPRINTK("failed to probe\n");
+ return;
}
-
- for ( ; j < new_nr; j++ )
- {
- if ( xlvbd_init_device(&new_info[j]) == 0 )
- memcpy(&merged_info[k++], &new_info[j], sizeof(vdisk_t));
+
+ i = 0;
+ list_for_each_safe(tmp, tmp2, &vbds_list) {
+ disk = list_entry(tmp, struct lvdisk, list);
+
+ for (i = 0; i < nr; i++) {
+ if ( !newdisks[i].device )
+ continue;
+ if ( disk->device == newdisks[i].device ) {
+ xlvbd_device_update(disk, &newdisks[i]);
+ newdisks[i].device = 0;
+ break;
+ }
+ }
+ if (i == nr) {
+ xlvbd_device_del(disk);
+ newdisks[i].device = 0;
+ }
}
+ for (i = 0; i < nr; i++)
+ if ( newdisks[i].device )
+ xlvbd_device_add(&vbds_list, &newdisks[i]);
+ kfree(newdisks);
+}
- vbd_info = merged_info;
- nr_vbds = k;
-
- kfree(old_info);
-out:
- kfree(new_info);
+/*
+ * xlvbd_update_vbds - reprobes the VBD status and performs updates driver
+ * state. The VBDs need to be updated in this way when the domain is
+ * initialised and also each time we receive an XLBLK_UPDATE event.
+ */
+void xlvbd_update_vbds(void)
+{
+ xlvbd_refresh();
}
/*
@@ -477,26 +486,22 @@ out:
*/
int xlvbd_init(void)
{
- int i;
+ int i, nr;
+ vdisk_t *disks;
- memset(major_info, 0, sizeof(major_info));
+ INIT_LIST_HEAD(&vbds_list);
- vbd_info = kmalloc(MAX_VBDS * sizeof(vdisk_t), GFP_KERNEL);
- if (vbd_info == NULL) {
- printk(KERN_ALERT "Failed to allocate memory for disk info.\n");
- nr_vbds = 0;
- return 0;
+ memset(major_info, 0, sizeof(major_info));
+
+ disks = xlvbd_probe(&nr);
+ if (disks == NULL) {
+ WPRINTK("failed to probe\n");
+ return -1;
}
- nr_vbds = xlvbd_get_vbd_info(vbd_info);
- if (nr_vbds < 0) {
- kfree(vbd_info);
- vbd_info = NULL;
- nr_vbds = 0;
- } else {
- for (i = 0; i < nr_vbds; i++)
- xlvbd_init_device(&vbd_info[i]);
- }
+ for (i = 0; i < nr; i++)
+ xlvbd_device_add(&vbds_list, &disks[i]);
+ kfree(disks);
return 0;
}