blkfront: properly name all devices - devices beyond xvdzz didn't get proper names assigned at all - devices using SCSI_CDROM_MAJOR got named sdXX rather than srNN - devices with unknown majors got mistakenly converted to use major 202 - extended devices with minors not representable within the kernel's major/minor bit split spilled into foreign majors Signed-off-by: Jan Beulich --- a/drivers/xen/blkfront/block.h +++ b/drivers/xen/blkfront/block.h @@ -64,20 +64,12 @@ #define DPRINTK_IOCTL(_f, _a...) ((void)0) #endif -struct xlbd_type_info -{ - int partn_shift; - int disks_per_major; - char *devname; - char *diskname; -}; - struct xlbd_major_info { int major; int index; int usage; - struct xlbd_type_info *type; + const struct xlbd_type_info *type; struct xlbd_minor_state *minors; }; --- a/drivers/xen/blkfront/vbd.c +++ b/drivers/xen/blkfront/vbd.c @@ -65,46 +65,63 @@ struct xlbd_minor_state { */ #define NUM_IDE_MAJORS 10 -#define NUM_SCSI_MAJORS 17 +#define NUM_SD_MAJORS 16 #define NUM_VBD_MAJORS 2 -static struct xlbd_type_info xlbd_ide_type = { +struct xlbd_type_info +{ + int partn_shift; + int disks_per_major; + char *devname; + char *diskname; +}; + +static const struct xlbd_type_info xlbd_ide_type = { .partn_shift = 6, .disks_per_major = 2, .devname = "ide", .diskname = "hd", }; -static struct xlbd_type_info xlbd_scsi_type = { +static const struct xlbd_type_info xlbd_sd_type = { .partn_shift = 4, .disks_per_major = 16, .devname = "sd", .diskname = "sd", }; -static struct xlbd_type_info xlbd_vbd_type = { +static const struct xlbd_type_info xlbd_sr_type = { + .partn_shift = 0, + .disks_per_major = 256, + .devname = "sr", + .diskname = "sr", +}; + +static const struct xlbd_type_info xlbd_vbd_type = { .partn_shift = 4, .disks_per_major = 16, .devname = "xvd", .diskname = "xvd", }; -static struct xlbd_type_info xlbd_vbd_type_ext = { +static const struct xlbd_type_info xlbd_vbd_type_ext = { .partn_shift = 8, .disks_per_major = 256, .devname = "xvd", .diskname = "xvd", }; -static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS + +static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SD_MAJORS + 1 + 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_SD_START (NUM_IDE_MAJORS) +#define XLBD_MAJOR_SR_START (NUM_IDE_MAJORS + NUM_SD_MAJORS) +#define XLBD_MAJOR_VBD_START (NUM_IDE_MAJORS + NUM_SD_MAJORS + 1) + +#define XLBD_MAJOR_IDE_RANGE XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SD_START - 1 +#define XLBD_MAJOR_SD_RANGE XLBD_MAJOR_SD_START ... XLBD_MAJOR_SR_START - 1 +#define XLBD_MAJOR_SR_RANGE XLBD_MAJOR_SR_START #define XLBD_MAJOR_VBD_RANGE XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1 #define XLBD_MAJOR_VBD_ALT(idx) ((idx) ^ XLBD_MAJOR_VBD_START ^ (XLBD_MAJOR_VBD_START + 1)) @@ -155,9 +172,13 @@ xlbd_alloc_major_info(int major, int min ptr->type = &xlbd_ide_type; ptr->index = index - XLBD_MAJOR_IDE_START; break; - case XLBD_MAJOR_SCSI_RANGE: - ptr->type = &xlbd_scsi_type; - ptr->index = index - XLBD_MAJOR_SCSI_START; + case XLBD_MAJOR_SD_RANGE: + ptr->type = &xlbd_sd_type; + ptr->index = index - XLBD_MAJOR_SD_START; + break; + case XLBD_MAJOR_SR_RANGE: + ptr->type = &xlbd_sr_type; + ptr->index = index - XLBD_MAJOR_SR_START; break; case XLBD_MAJOR_VBD_RANGE: ptr->index = 0; @@ -213,20 +234,21 @@ xlbd_get_major_info(int major, int minor 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_DISK0_MAJOR: index = XLBD_MAJOR_SD_START; break; case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR: - index = 11 + major - SCSI_DISK1_MAJOR; + index = XLBD_MAJOR_SD_START + 1 + major - SCSI_DISK1_MAJOR; break; - case SCSI_DISK8_MAJOR ... SCSI_DISK15_MAJOR: - index = 18 + major - SCSI_DISK8_MAJOR; - break; - case SCSI_CDROM_MAJOR: index = 26; break; - default: - if (!VDEV_IS_EXTENDED(vdevice)) - index = 27; - else - index = 28; + case SCSI_DISK8_MAJOR ... SCSI_DISK15_MAJOR: + index = XLBD_MAJOR_SD_START + 8 + major - SCSI_DISK8_MAJOR; + break; + case SCSI_CDROM_MAJOR: + index = XLBD_MAJOR_SR_START; break; + case XENVBD_MAJOR: + index = XLBD_MAJOR_VBD_START + !!VDEV_IS_EXTENDED(vdevice); + break; + default: + return NULL; } mi = ((major_info[index] != NULL) ? major_info[index] : @@ -324,6 +346,14 @@ xlbd_release_minors(struct xlbd_major_in spin_unlock(&ms->lock); } +static char *encode_disk_name(char *ptr, unsigned int n) +{ + if (n >= 26) + ptr = encode_disk_name(ptr, n / 26 - 1); + *ptr = 'a' + n % 26; + return ptr + 1; +} + static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size, struct blkfront_info *info) @@ -369,6 +399,7 @@ xlvbd_alloc_gendisk(int major, int minor struct xlbd_major_info *mi; int nr_minors = 1; int err = -ENODEV; + char *ptr; unsigned int offset; BUG_ON(info->gd != NULL); @@ -392,33 +423,21 @@ xlvbd_alloc_gendisk(int major, int minor if (gd == NULL) goto release; - offset = mi->index * mi->type->disks_per_major + - (minor >> mi->type->partn_shift); - if (nr_minors > 1) { - if (offset < 26) { - sprintf(gd->disk_name, "%s%c", - mi->type->diskname, 'a' + offset ); - } - else { - sprintf(gd->disk_name, "%s%c%c", - mi->type->diskname, - 'a' + ((offset/26)-1), 'a' + (offset%26) ); - } - } - else { - if (offset < 26) { - sprintf(gd->disk_name, "%s%c%d", - mi->type->diskname, - 'a' + offset, - minor & ((1 << mi->type->partn_shift) - 1)); - } - else { - sprintf(gd->disk_name, "%s%c%c%d", - mi->type->diskname, - 'a' + ((offset/26)-1), 'a' + (offset%26), - minor & ((1 << mi->type->partn_shift) - 1)); - } - } + strcpy(gd->disk_name, mi->type->diskname); + ptr = gd->disk_name + strlen(mi->type->diskname); + offset = mi->index * mi->type->disks_per_major + + (minor >> mi->type->partn_shift); + if (mi->type->partn_shift) { + ptr = encode_disk_name(ptr, offset); + offset = minor & ((1 << mi->type->partn_shift) - 1); + } else + gd->flags |= GENHD_FL_CD; + BUG_ON(ptr >= gd->disk_name + ARRAY_SIZE(gd->disk_name)); + if (nr_minors > 1) + *ptr = 0; + else + snprintf(ptr, gd->disk_name + ARRAY_SIZE(gd->disk_name) - ptr, + "%u", offset); gd->major = mi->major; gd->first_minor = minor; @@ -478,6 +497,11 @@ xlvbd_add(blkif_sector_t capacity, int v else { major = XENVBD_MAJOR; minor = BLKIF_MINOR_EXT(vdevice); + if (minor >> MINORBITS) { + printk(KERN_WARNING "blkfront: %#x's minor (%#x)" + " out of range; ignoring\n", vdevice, minor); + return -ENODEV; + } } info->dev = MKDEV(major, minor);