diff options
Diffstat (limited to 'drivers/block/xen-blkfront.c')
-rw-r--r-- | drivers/block/xen-blkfront.c | 76 |
1 files changed, 55 insertions, 21 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index d5e753255153..1a50ae70f716 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 | ||
116 | static LIST_HEAD(vbds_list); | ||
117 | 119 | ||
118 | static int get_id_from_freelist(struct blkfront_info *info) | 120 | static 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 | ||
389 | static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, | 391 | static 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); |