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>
This commit is contained in:
Chris Lalancette 2008-09-17 14:30:32 -07:00 committed by Jens Axboe
parent 9c02f2b02e
commit 9246b5f06d
1 changed files with 55 additions and 21 deletions

View File

@ -105,15 +105,17 @@ static DEFINE_SPINLOCK(blkif_io_lock);
#define GRANT_INVALID_REF 0 #define GRANT_INVALID_REF 0
#define PARTS_PER_DISK 16 #define PARTS_PER_DISK 16
#define PARTS_PER_EXT_DISK 256
#define BLKIF_MAJOR(dev) ((dev)>>8) #define BLKIF_MAJOR(dev) ((dev)>>8)
#define BLKIF_MINOR(dev) ((dev) & 0xff) #define BLKIF_MINOR(dev) ((dev) & 0xff)
#define DEV_NAME "xvd" /* name in /dev */ #define EXT_SHIFT 28
#define EXTENDED (1<<EXT_SHIFT)
#define VDEV_IS_EXTENDED(dev) ((dev)&(EXTENDED))
#define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
/* Information about our VBDs. */ #define DEV_NAME "xvd" /* name in /dev */
#define MAX_VBDS 64
static LIST_HEAD(vbds_list);
static int get_id_from_freelist(struct blkfront_info *info) static int get_id_from_freelist(struct blkfront_info *info)
{ {
@ -386,31 +388,60 @@ static int xlvbd_barrier(struct blkfront_info *info)
} }
static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
int vdevice, u16 vdisk_info, u16 sector_size, struct blkfront_info *info,
struct blkfront_info *info) u16 vdisk_info, u16 sector_size)
{ {
struct gendisk *gd; struct gendisk *gd;
int nr_minors = 1; int nr_minors = 1;
int err = -ENODEV; int err = -ENODEV;
unsigned int offset;
int minor;
int nr_parts;
BUG_ON(info->gd != NULL); BUG_ON(info->gd != NULL);
BUG_ON(info->rq != NULL); BUG_ON(info->rq != NULL);
if ((minor % PARTS_PER_DISK) == 0) if ((info->vdevice>>EXT_SHIFT) > 1) {
nr_minors = PARTS_PER_DISK; /* this is above the extended range; something is wrong */
printk(KERN_WARNING "blkfront: vdevice 0x%x is above the extended range; ignoring\n", info->vdevice);
return -ENODEV;
}
if (!VDEV_IS_EXTENDED(info->vdevice)) {
minor = BLKIF_MINOR(info->vdevice);
nr_parts = PARTS_PER_DISK;
} else {
minor = BLKIF_MINOR_EXT(info->vdevice);
nr_parts = PARTS_PER_EXT_DISK;
}
if ((minor % nr_parts) == 0)
nr_minors = nr_parts;
gd = alloc_disk(nr_minors); gd = alloc_disk(nr_minors);
if (gd == NULL) if (gd == NULL)
goto out; goto out;
if (nr_minors > 1) offset = minor / nr_parts;
sprintf(gd->disk_name, "%s%c", DEV_NAME,
'a' + minor / PARTS_PER_DISK); if (nr_minors > 1) {
else if (offset < 26)
sprintf(gd->disk_name, "%s%c%d", DEV_NAME, sprintf(gd->disk_name, "%s%c", DEV_NAME, 'a' + offset);
'a' + minor / PARTS_PER_DISK, else
minor % PARTS_PER_DISK); sprintf(gd->disk_name, "%s%c%c", DEV_NAME,
'a' + ((offset / 26)-1), 'a' + (offset % 26));
} else {
if (offset < 26)
sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
'a' + offset,
minor & (nr_parts - 1));
else
sprintf(gd->disk_name, "%s%c%c%d", DEV_NAME,
'a' + ((offset / 26) - 1),
'a' + (offset % 26),
minor & (nr_parts - 1));
}
gd->major = XENVBD_MAJOR; gd->major = XENVBD_MAJOR;
gd->first_minor = minor; gd->first_minor = minor;
@ -699,8 +730,13 @@ static int blkfront_probe(struct xenbus_device *dev,
err = xenbus_scanf(XBT_NIL, dev->nodename, err = xenbus_scanf(XBT_NIL, dev->nodename,
"virtual-device", "%i", &vdevice); "virtual-device", "%i", &vdevice);
if (err != 1) { if (err != 1) {
xenbus_dev_fatal(dev, err, "reading virtual-device"); /* go looking in the extended area instead */
return err; err = xenbus_scanf(XBT_NIL, dev->nodename, "virtual-device-ext",
"%i", &vdevice);
if (err != 1) {
xenbus_dev_fatal(dev, err, "reading virtual-device");
return err;
}
} }
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
@ -861,9 +897,7 @@ static void blkfront_connect(struct blkfront_info *info)
if (err) if (err)
info->feature_barrier = 0; info->feature_barrier = 0;
err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice), err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
sectors, info->vdevice,
binfo, sector_size, info);
if (err) { if (err) {
xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s", xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
info->xbdev->otherend); info->xbdev->otherend);