}
disk->bus = busType;
- disk->dst = virIndexToDiskName(ctrlr_idx * diskNameOffset + addr, diskNamePrefix);
+ disk->dst = virIndexToDiskName(0, ctrlr_idx * diskNameOffset + addr, diskNamePrefix);
if (busType == VIR_DOMAIN_DISK_BUS_IDE) {
disk->info.addr.drive.controller = 0;
disk->info.addr.drive.bus = ctrlr_idx;
}
}
disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
- disk->dst = virIndexToDiskName(ctrlr_idx * 64 + addr, "sd");
+ disk->dst = virIndexToDiskName(0, ctrlr_idx * 64 + addr, "sd");
disk->info.addr.drive.unit = addr;
disk->info.addr.drive.controller = ctrlr_idx;
disk->info.addr.drive.bus = 0;
}
}
disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
- disk->dst = virIndexToDiskName(ctrlr_idx * 4 + addr, "hd");
+ disk->dst = virIndexToDiskName(0, ctrlr_idx * 4 + addr, "hd");
disk->info.addr.drive.unit = addr;
disk->info.addr.drive.controller = 0;
disk->info.addr.drive.bus = ctrlr_idx;
/* Find any disk prefixes we know about */
for (i = 0; i < G_N_ELEMENTS(drive_prefix); i++) {
if (STRPREFIX(virtpath, drive_prefix[i]) &&
- !virDiskNameParse(virtpath, &disk, &partition)) {
+ !virDiskNameParse(virtpath, NULL, &disk, &partition)) {
fmt = i;
break;
}
return -1;
}
- if (virDiskNameParse(disk->dst, &idx, &partition) < 0) {
+ if (virDiskNameParse(disk->dst, NULL, &idx, &partition) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("invalid disk target '%1$s'"), disk->dst);
return -1;
}
+static int
+virDiskNameParseNvme(const char *name, int *controller, int *disk, int *partition)
+{
+ int ctrl = 0;
+ int ns = 0;
+ int part = 0;
+ char *end_ptr = NULL;
+ const char *tmp = STRSKIP(name, "nvme");
+
+ if (!controller)
+ return -1;
+
+ if (!tmp)
+ return -1;
+
+ if (virStrToLong_i(tmp, &end_ptr, 10, &ctrl) < 0)
+ return -1;
+
+ if (*end_ptr != 'n')
+ return -1;
+
+ if (ctrl < 0)
+ return -1;
+
+ tmp = end_ptr + 1;
+
+ if (virStrToLong_i(tmp, &end_ptr, 10, &ns) < 0)
+ return -1;
+
+ if (*end_ptr != '\0' && *end_ptr != 'p')
+ return -1;
+
+ /* NSIDs start from 1, but we need to map them to [0..] for the controller
+ * address. */
+ if (ns < 1)
+ return -1;
+ ns--;
+
+ if (partition) {
+ *partition = 0;
+
+ if (*end_ptr != '\0') {
+ tmp = end_ptr + 1;
+
+ if (virStrToLong_i(tmp, NULL, 10, &part) < 0)
+ return -1;
+
+ /* Partitions on NVMe disks also from 1 */
+ if (part < 1)
+ return -1;
+
+ *partition = part - 1;
+ }
+ }
+
+ *controller = ctrl;
+ *disk = ns;
+
+ return 0;
+}
+
+
/* Translates a device name of the form (regex) /^[fhv]d[a-z]+[0-9]*$/
- * into the corresponding index and partition number
- * (e.g. sda0 => (0,0), hdz2 => (25,2), vdaa12 => (26,12))
+ * or nvme[0-9]+n[0-9]+(p[0-9]+) for NVMe devices
+ * into the corresponding nvme controller (see below), index and partition number
+ * (e.g. sda0 => (0,0,0), hdz2 => (0,25,2), vdaa12 => (0,26,12)) as these do not
+ * support namespaces and controller is calculated from the disk index
+ * for nvme disks disks: (nvme1n2p3 => (1, 1, 2) as nvme namespaces and
+ * partitions are numbered from 1 and not 0).
* @param name The name of the device
+ * @param nvme_ctrl The disk namespace to be returned
* @param disk The disk index to be returned
* @param partition The partition index to be returned
* @return 0 on success, or -1 on failure
*/
-int virDiskNameParse(const char *name, int *disk, int *partition)
+int virDiskNameParse(const char *name, int *nvme_ctrl, int *disk, int *partition)
{
const char *ptr = NULL;
char *rem;
size_t i;
size_t n_digits;
+ if (STRPREFIX(name, "nvme"))
+ return virDiskNameParseNvme(name, nvme_ctrl, disk, partition);
+
+ if (nvme_ctrl)
+ *nvme_ctrl = 0;
+
for (i = 0; i < G_N_ELEMENTS(drive_prefix); i++) {
if (STRPREFIX(name, drive_prefix[i])) {
ptr = name + strlen(drive_prefix[i]);
/* Translates a device name of the form (regex) /^[fhv]d[a-z]+[0-9]*$/
* into the corresponding index (e.g. sda => 0, hdz => 25, vdaa => 26)
* Note that any trailing string of digits is simply ignored.
+ * Since NVMe disks require controller devices, this function should not be used
+ * for nvme* names unless the caller does not need to know then controller index
* @param name The name of the device
* @return name's index, or -1 on failure
*/
{
int idx;
- if (virDiskNameParse(name, &idx, NULL) < 0)
+ if (virDiskNameParse(name, NULL, &idx, NULL) < 0)
idx = -1;
return idx;
}
-char *virIndexToDiskName(unsigned int idx, const char *prefix)
+char *virIndexToDiskName(unsigned int nvme_ctrl,
+ unsigned int idx,
+ const char *prefix)
{
- GString *str = g_string_new(NULL);
+ GString *str = NULL;
long long ctr;
+ if (STREQ_NULLABLE(prefix, "nvme"))
+ return g_strdup_printf("nvme%dn%d", nvme_ctrl, idx + 1);
+
+ str = g_string_new(NULL);
+
for (ctr = idx; ctr >= 0; ctr = ctr / 26 - 1)
g_string_prepend_c(str, 'a' + (ctr % 26));
virFormatIntPretty(unsigned long long val,
const char **unit);
-int virDiskNameParse(const char *name, int *disk, int *partition);
+int virDiskNameParse(const char *name, int *nvme_ctrl,
+ int *disk, int *partition);
int virDiskNameToIndex(const char* str);
-char *virIndexToDiskName(unsigned int idx, const char *prefix);
+char *virIndexToDiskName(unsigned int nvme_ctrl,
+ unsigned int idx,
+ const char *prefix);
/* No-op workarounds for functionality missing in mingw. */
#ifndef WITH_GETUID
return NULL;
}
- name = virIndexToDiskName(total, prefix);
+ name = virIndexToDiskName(0, total, prefix);
return name;
}
return -1;
}
- def->dst = virIndexToDiskName(idx, prefix);
+ def->dst = virIndexToDiskName(0, idx, prefix);
return 0;
}
switch (ifType) {
case PMS_IDE_DEVICE:
*bus = VIR_DOMAIN_DISK_BUS_IDE;
- *dst = virIndexToDiskName(pos, "hd");
+ *dst = virIndexToDiskName(0, pos, "hd");
break;
case PMS_SCSI_DEVICE:
case PMS_UNKNOWN_DEVICE:
*bus = VIR_DOMAIN_DISK_BUS_SCSI;
- *dst = virIndexToDiskName(pos, "sd");
+ *dst = virIndexToDiskName(0, pos, "sd");
break;
case PMS_SATA_DEVICE:
*bus = VIR_DOMAIN_DISK_BUS_SATA;
- *dst = virIndexToDiskName(pos, "sd");
+ *dst = virIndexToDiskName(0, pos, "sd");
break;
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
struct testDiskName
{
const char *name;
+ int ctrl;
int idx;
int partition;
};
static struct testDiskName diskNamesPart[] = {
- {"sda0", 0, 0},
- {"sdb10", 1, 10},
- {"sdc2147483647", 2, 2147483647},
+ {"sda", 0, 0, 0},
+ {"sda0", 0, 0, 0},
+ {"sdb10", 0, 1, 10},
+ {"sdc2147483647", 0, 2, 2147483647},
+ {"nvme0n1", 0, 0, 0},
+ {"nvme0n1p1", 0, 0, 0},
+ {"nvme1n2p3", 1, 1, 2},
};
static const char* diskNamesInvalid[] = {
"sda00", "sda01", "sdb-1",
- "vd2"
+ "vd2",
+ "nvme0n0", "nvme0n1p0",
};
static int
for (i = 0; i < G_N_ELEMENTS(diskNames); ++i) {
g_autofree char *diskName = NULL;
- diskName = virIndexToDiskName(i, "sd");
+ diskName = virIndexToDiskName(0, i, "sd");
if (virTestCompareToString(diskNames[i], diskName) < 0) {
return -1;
for (i = 0; i < 100000; ++i) {
g_autofree char *diskName = NULL;
- diskName = virIndexToDiskName(i, "sd");
+ diskName = virIndexToDiskName(0, i, "sd");
idx = virDiskNameToIndex(diskName);
if (idx < 0 || idx != i) {
testDiskNameParse(const void *data G_GNUC_UNUSED)
{
size_t i;
+ int nvme_ctrl;
int idx;
int partition;
struct testDiskName *disk = NULL;
for (i = 0; i < G_N_ELEMENTS(diskNamesPart); ++i) {
disk = &diskNamesPart[i];
- if (virDiskNameParse(disk->name, &idx, &partition))
+ partition = 0;
+ if (virDiskNameParse(disk->name, &nvme_ctrl, &idx, &partition))
return -1;
+ if (disk->ctrl != nvme_ctrl) {
+ VIR_TEST_DEBUG("\nExpect NVMe controller [%d]", disk->ctrl);
+ VIR_TEST_DEBUG("Actual NVMe controller [%d]", nvme_ctrl);
+ return -1;
+ }
+
if (disk->idx != idx) {
- VIR_TEST_DEBUG("\nExpect [%d]", disk->idx);
- VIR_TEST_DEBUG("Actual [%d]", idx);
+ VIR_TEST_DEBUG("\nExpect index [%d]", disk->idx);
+ VIR_TEST_DEBUG("Actual index [%d]", idx);
return -1;
}
if (disk->partition != partition) {
- VIR_TEST_DEBUG("\nExpect [%d]", disk->partition);
- VIR_TEST_DEBUG("Actual [%d]", partition);
+ VIR_TEST_DEBUG("\nExpect partition [%d]", disk->partition);
+ VIR_TEST_DEBUG("Actual partition [%d]", partition);
return -1;
}
}
for (i = 0; i < G_N_ELEMENTS(diskNamesInvalid); ++i) {
- if (!virDiskNameParse(diskNamesInvalid[i], &idx, &partition)) {
+ if (!virDiskNameParse(diskNamesInvalid[i], &nvme_ctrl, &idx, &partition)) {
VIR_TEST_DEBUG("Should Fail [%s]", diskNamesInvalid[i]);
return -1;
}