aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorChris Lalancette <clalance@redhat.com>2008-09-17 17:30:32 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 02:56:18 -0400
commit9246b5f06deeea541e7c62437c2ad19a0b1172c0 (patch)
treeb7af564d1e32ce4eceba6f6a438256d6c3ca77fd /drivers/block
parent9c02f2b02e29a2244e36c6e1f246080d8afc6cff (diff)
block: Expand Xen blkfront for > 16 xvd
Until recently, the maximum number of xvd block devices you could attach to a Xen domU was 16. This limitation turned out to be problematic for some users, so it was expanded to handle a much larger number of disks. However, this requires a couple of changes in the way that blkfront scans for disks. This functionality is already present in the Xen linux-2.6.18-xen.hg tree; the attached patch adds this functionality to the mainline xen-blkfront implementation. I successfully tested it on a 2.6.25 tree, and build tested it on 2.6.27-rc3. Signed-off-by: Chris Lalancette <clalance@redhat.com> Acked-by: Jeremy Fitzhardinge <jeremy@goop.org> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/xen-blkfront.c76
1 files changed, 55 insertions, 21 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 3ca643cafccd..bff602ccccf3 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -105,15 +105,17 @@ static DEFINE_SPINLOCK(blkif_io_lock);
105#define GRANT_INVALID_REF 0 105#define GRANT_INVALID_REF 0
106 106
107#define PARTS_PER_DISK 16 107#define PARTS_PER_DISK 16
108#define PARTS_PER_EXT_DISK 256
108 109
109#define BLKIF_MAJOR(dev) ((dev)>>8) 110#define BLKIF_MAJOR(dev) ((dev)>>8)
110#define BLKIF_MINOR(dev) ((dev) & 0xff) 111#define BLKIF_MINOR(dev) ((dev) & 0xff)
111 112
112#define DEV_NAME "xvd" /* name in /dev */ 113#define EXT_SHIFT 28
114#define EXTENDED (1<<EXT_SHIFT)
115#define VDEV_IS_EXTENDED(dev) ((dev)&(EXTENDED))
116#define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
113 117
114/* Information about our VBDs. */ 118#define DEV_NAME "xvd" /* name in /dev */
115#define MAX_VBDS 64
116static LIST_HEAD(vbds_list);
117 119
118static int get_id_from_freelist(struct blkfront_info *info) 120static int get_id_from_freelist(struct blkfront_info *info)
119{ 121{
@@ -386,31 +388,60 @@ static int xlvbd_barrier(struct blkfront_info *info)
386} 388}
387 389
388 390
389static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, 391static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
390 int vdevice, u16 vdisk_info, u16 sector_size, 392 struct blkfront_info *info,
391 struct blkfront_info *info) 393 u16 vdisk_info, u16 sector_size)
392{ 394{
393 struct gendisk *gd; 395 struct gendisk *gd;
394 int nr_minors = 1; 396 int nr_minors = 1;
395 int err = -ENODEV; 397 int err = -ENODEV;
398 unsigned int offset;
399 int minor;
400 int nr_parts;
396 401
397 BUG_ON(info->gd != NULL); 402 BUG_ON(info->gd != NULL);
398 BUG_ON(info->rq != NULL); 403 BUG_ON(info->rq != NULL);
399 404
400 if ((minor % PARTS_PER_DISK) == 0) 405 if ((info->vdevice>>EXT_SHIFT) > 1) {
401 nr_minors = PARTS_PER_DISK; 406 /* this is above the extended range; something is wrong */
407 printk(KERN_WARNING "blkfront: vdevice 0x%x is above the extended range; ignoring\n", info->vdevice);
408 return -ENODEV;
409 }
410
411 if (!VDEV_IS_EXTENDED(info->vdevice)) {
412 minor = BLKIF_MINOR(info->vdevice);
413 nr_parts = PARTS_PER_DISK;
414 } else {
415 minor = BLKIF_MINOR_EXT(info->vdevice);
416 nr_parts = PARTS_PER_EXT_DISK;
417 }
418
419 if ((minor % nr_parts) == 0)
420 nr_minors = nr_parts;
402 421
403 gd = alloc_disk(nr_minors); 422 gd = alloc_disk(nr_minors);
404 if (gd == NULL) 423 if (gd == NULL)
405 goto out; 424 goto out;
406 425
407 if (nr_minors > 1) 426 offset = minor / nr_parts;
408 sprintf(gd->disk_name, "%s%c", DEV_NAME, 427
409 'a' + minor / PARTS_PER_DISK); 428 if (nr_minors > 1) {
410 else 429 if (offset < 26)
411 sprintf(gd->disk_name, "%s%c%d", DEV_NAME, 430 sprintf(gd->disk_name, "%s%c", DEV_NAME, 'a' + offset);
412 'a' + minor / PARTS_PER_DISK, 431 else
413 minor % PARTS_PER_DISK); 432 sprintf(gd->disk_name, "%s%c%c", DEV_NAME,
433 'a' + ((offset / 26)-1), 'a' + (offset % 26));
434 } else {
435 if (offset < 26)
436 sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
437 'a' + offset,
438 minor & (nr_parts - 1));
439 else
440 sprintf(gd->disk_name, "%s%c%c%d", DEV_NAME,
441 'a' + ((offset / 26) - 1),
442 'a' + (offset % 26),
443 minor & (nr_parts - 1));
444 }
414 445
415 gd->major = XENVBD_MAJOR; 446 gd->major = XENVBD_MAJOR;
416 gd->first_minor = minor; 447 gd->first_minor = minor;
@@ -699,8 +730,13 @@ static int blkfront_probe(struct xenbus_device *dev,
699 err = xenbus_scanf(XBT_NIL, dev->nodename, 730 err = xenbus_scanf(XBT_NIL, dev->nodename,
700 "virtual-device", "%i", &vdevice); 731 "virtual-device", "%i", &vdevice);
701 if (err != 1) { 732 if (err != 1) {
702 xenbus_dev_fatal(dev, err, "reading virtual-device"); 733 /* go looking in the extended area instead */
703 return err; 734 err = xenbus_scanf(XBT_NIL, dev->nodename, "virtual-device-ext",
735 "%i", &vdevice);
736 if (err != 1) {
737 xenbus_dev_fatal(dev, err, "reading virtual-device");
738 return err;
739 }
704 } 740 }
705 741
706 info = kzalloc(sizeof(*info), GFP_KERNEL); 742 info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -861,9 +897,7 @@ static void blkfront_connect(struct blkfront_info *info)
861 if (err) 897 if (err)
862 info->feature_barrier = 0; 898 info->feature_barrier = 0;
863 899
864 err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice), 900 err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
865 sectors, info->vdevice,
866 binfo, sector_size, info);
867 if (err) { 901 if (err) {
868 xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s", 902 xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
869 info->xbdev->otherend); 903 info->xbdev->otherend);