diff options
author | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2005-05-20 13:32:19 +0000 |
---|---|---|
committer | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2005-05-20 13:32:19 +0000 |
commit | 642d0333322a840e00b76522b26af65db729980a (patch) | |
tree | b9be70cf4bfdf1c7745d7db59c54639dae3ba14b | |
parent | b87d148b3b6fcbfe1d5c093f68a59989b05e9e79 (diff) | |
download | xen-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.c | 10 | ||||
-rw-r--r-- | linux-2.6.11-xen-sparse/drivers/xen/blkfront/block.h | 8 | ||||
-rw-r--r-- | linux-2.6.11-xen-sparse/drivers/xen/blkfront/vbd.c | 611 |
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; } |