#include <fcntl.h>
#include <string.h>
#include <unistd.h>
+#include <regex.h>
#include "c-ctype.h"
#ifdef WITH_XEN
#include "util.h"
#include "xen_unified.h"
#include "stats_linux.h"
+#include "memory.h"
/**
* statsErrorFunc:
return 0;
}
+static int
+disk_re_match(const char *regex, const char *path, int *part)
+{
+ regex_t myreg;
+ int err;
+ int retval;
+ regmatch_t pmatch[3];
+
+ retval = 0;
+
+ err = regcomp(&myreg, regex, REG_EXTENDED);
+ if (err != 0)
+ return 0;
+
+ err = regexec(&myreg, path, 3, pmatch, 0);
+
+ if (err == 0) {
+ /* OK, we have a match; see if we have a partition */
+ *part = 0;
+ retval = 1;
+ if (pmatch[1].rm_so != -1) {
+ if (virStrToLong_i(path + pmatch[1].rm_so, NULL, 10, part) < 0)
+ retval = 0;
+ }
+ }
+
+ regfree(&myreg);
+
+ return retval;
+}
+
int
xenLinuxDomainDeviceID(virConnectPtr conn, int domid, const char *path)
{
- int disk, part = 0;
-
- /* Strip leading path if any */
- if (strlen(path) > 5 &&
- STRPREFIX(path, "/dev/"))
- path += 5;
+ int major, minor;
+ int part;
+ int retval;
+ char *mod_path;
+
+ int const scsi_majors[] = { SCSI_DISK0_MAJOR, SCSI_DISK1_MAJOR,
+ SCSI_DISK2_MAJOR, SCSI_DISK3_MAJOR,
+ SCSI_DISK4_MAJOR, SCSI_DISK5_MAJOR,
+ SCSI_DISK6_MAJOR, SCSI_DISK7_MAJOR,
+ SCSI_DISK8_MAJOR, SCSI_DISK9_MAJOR,
+ SCSI_DISK10_MAJOR, SCSI_DISK11_MAJOR,
+ SCSI_DISK12_MAJOR, SCSI_DISK13_MAJOR,
+ SCSI_DISK14_MAJOR, SCSI_DISK15_MAJOR };
+ int const ide_majors[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
+ IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR,
+ IDE8_MAJOR, IDE9_MAJOR };
/*
* Possible block device majors & partition ranges. This
* matches the ranges supported in Xend xen/util/blkif.py
*
- * hdNM: N=a-t, M=1-63, major={IDE0_MAJOR -> IDE9_MAJOR}
- * sdNM: N=a-z,aa-iv, M=1-15, major={SCSI_DISK0_MAJOR -> SCSI_DISK15_MAJOR}
- * xvdNM: N=a-p, M=1-15, major=XENVBD_MAJOR
- *
- * NB, the SCSI major isn't technically correct, as XenD only knows
- * about major=8. We cope with all SCSI majors in anticipation of
- * XenD perhaps being fixed one day....
+ * hdNM: N=a-t, M=1-63, major={IDE0_MAJOR -> IDE9_MAJOR}
+ * sdNM: N=a-z,aa-iv, M=1-15, major={SCSI_DISK0_MAJOR -> SCSI_DISK15_MAJOR}
+ * xvdNM: N=a-p M=1-15, major=XENVBD_MAJOR
+ * xvdNM: N=q-z,aa-iz M=1-15, major=(1<<28)
*
* The path for statistics will be
*
* /sys/devices/xen-backend/(vbd|tap)-{domid}-{devid}/statistics/{...}
*/
- if (strlen (path) >= 4 &&
- STRPREFIX (path, "xvd")) {
- /* Xen paravirt device handling */
- disk = (path[3] - 'a');
- if (disk < 0 || disk > 15) {
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, device names must be in range xvda - xvdp",
- domid);
- return -1;
- }
+ if (strlen(path) >= 5 && STRPREFIX(path, "/dev/"))
+ retval = asprintf(&mod_path, "%s", path);
+ else
+ retval = asprintf(&mod_path, "/dev/%s", path);
- if (path[4] != '\0') {
- if (!c_isdigit(path[4]) || path[4] == '0' ||
- virStrToLong_i(path+4, NULL, 10, &part) < 0 ||
- part < 1 || part > 15) {
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, partition numbers for xvdN must be in range 1 - 15",
- domid);
- return -1;
- }
- }
-
- return (XENVBD_MAJOR * 256) + (disk * 16) + part;
- } else if (strlen (path) >= 3 &&
- STRPREFIX (path, "sd")) {
- /* SCSI device handling */
- int majors[] = { SCSI_DISK0_MAJOR, SCSI_DISK1_MAJOR, SCSI_DISK2_MAJOR,
- SCSI_DISK3_MAJOR, SCSI_DISK4_MAJOR, SCSI_DISK5_MAJOR,
- SCSI_DISK6_MAJOR, SCSI_DISK7_MAJOR, SCSI_DISK8_MAJOR,
- SCSI_DISK9_MAJOR, SCSI_DISK10_MAJOR, SCSI_DISK11_MAJOR,
- SCSI_DISK12_MAJOR, SCSI_DISK13_MAJOR, SCSI_DISK14_MAJOR,
- SCSI_DISK15_MAJOR };
-
- disk = (path[2] - 'a');
- if (disk < 0 || disk > 25) {
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, device names must be in range sda - sdiv",
- domid);
- return -1;
- }
- if (path[3] != '\0') {
- const char *p = NULL;
- if (path[3] >= 'a' && path[3] <= 'z') {
- disk = ((disk + 1) * 26) + (path[3] - 'a');
- if (disk < 0 || disk > 255) {
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, device names must be in range sda - sdiv",
- domid);
- return -1;
- }
-
- if (path[4] != '\0')
- p = path + 4;
- } else {
- p = path + 3;
- }
- if (p && (!c_isdigit(*p) || *p == '0' ||
- virStrToLong_i(p, NULL, 10, &part) < 0 ||
- part < 1 || part > 15)) {
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, partition numbers for sdN must be in range 1 - 15",
- domid);
- return -1;
- }
- }
-
- return (majors[disk/16] * 256) + ((disk%16) * 16) + part;
- } else if (strlen (path) >= 3 &&
- STRPREFIX (path, "hd")) {
- /* IDE device handling */
- int majors[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
- IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR,
- IDE8_MAJOR, IDE9_MAJOR };
- disk = (path[2] - 'a');
- if (disk < 0 || disk > 19) {
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, device names must be in range hda - hdt",
- domid);
- return -1;
- }
+ if (retval < 0) {
+ statsErrorFunc (conn, VIR_ERR_NO_MEMORY, __FUNCTION__,
+ "allocating mod_path", domid);
+ return -1;
+ }
- if (path[3] != '\0') {
- if (!c_isdigit(path[3]) || path[3] == '0' ||
- virStrToLong_i(path+3, NULL, 10, &part) < 0 ||
- part < 1 || part > 63) {
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, partition numbers for hdN must be in range 1 - 63",
- domid);
- return -1;
- }
- }
+ retval = -1;
- return (majors[disk/2] * 256) + ((disk % 2) * 63) + part;
+ if (disk_re_match("/dev/sd[a-z]([1-9]|1[0-5])?$", mod_path, &part)) {
+ major = scsi_majors[(mod_path[7] - 'a') / 16];
+ minor = ((mod_path[7] - 'a') % 16) * 16 + part;
+ retval = major * 256 + minor;
}
-
- /* Otherwise, unsupported device name. */
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "unsupported path, use xvdN, hdN, or sdN", domid);
- return -1;
+ else if (disk_re_match("/dev/sd[a-h][a-z]([1-9]|1[0-5])?$",
+ mod_path, &part) ||
+ disk_re_match("/dev/sdi[a-v]([1-9]|1[0-5])?$",
+ mod_path, &part)) {
+ major = scsi_majors[((mod_path[7] - 'a' + 1) * 26 + (mod_path[8] - 'a')) / 16];
+ minor = (((mod_path[7] - 'a' + 1) * 26 + (mod_path[8] - 'a')) % 16)
+ * 16 + part;
+ retval = major * 256 + minor;
+ }
+ else if (disk_re_match("/dev/hd[a-t]([1-9]|[1-5][0-9]|6[0-3])?$",
+ mod_path, &part)) {
+ major = ide_majors[(mod_path[7] - 'a') / 2];
+ minor = ((mod_path[7] - 'a') % 2) * 64 + part;
+ retval = major * 256 + minor;
+ }
+ else if (disk_re_match("/dev/xvd[a-p]([1-9]|1[0-5])?$", mod_path, &part))
+ retval = (202 << 8) + ((mod_path[8] - 'a') << 4) + part;
+ else if (disk_re_match("/dev/xvd[q-z]([1-9]|1[0-5])?$", mod_path, &part))
+ retval = (1 << 28) + ((mod_path[8] - 'a') << 8) + part;
+ else if (disk_re_match("/dev/xvd[a-i][a-z]([1-9]|1[0-5])?$",
+ mod_path, &part))
+ retval = (1 << 28) + (((mod_path[8] - 'a' + 1) * 26 + (mod_path[9] - 'a')) << 8) + part;
+ /*
+ * OK, we've now checked the common case (things that work); check the
+ * beginning of the strings for better error messages
+ */
+ else if (strlen(mod_path) >= 7 && STRPREFIX(mod_path, "/dev/sd"))
+ statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "invalid path, device names must be in the range sda[1-15] - sdiv[1-15]",
+ domid);
+ else if (strlen(mod_path) >= 7 && STRPREFIX(mod_path, "/dev/hd"))
+ statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "invalid path, device names must be in the range hda[1-63] - hdt[1-63]",
+ domid);
+ else if (strlen(mod_path) >= 8 && STRPREFIX(mod_path, "/dev/xvd"))
+ statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "invalid path, device names must be in the range xvda[1-15] - xvdiz[1-15]",
+ domid);
+ else
+ statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "unsupported path, use xvdN, hdN, or sdN", domid);
+
+ VIR_FREE(mod_path);
+
+ return retval;
}
int
* Xen paravirt disks
********************************/
+ DO_TEST("xvd", -1);
+
/* first valid disk */
DO_TEST("xvda", 51712);
DO_TEST("xvda1", 51713);
DO_TEST("xvda15", 51727);
- /* Last valid disk */
+ /* Last non-extended disk */
DO_TEST("xvdp", 51952);
DO_TEST("xvdp1", 51953);
DO_TEST("xvdp15", 51967);
- /* Disk letter to large */
- DO_TEST("xvdq", -1);
+ /* First extended disk */
+ DO_TEST("xvdq", 268439552);
+ DO_TEST("xvdq1", 268439553);
+ DO_TEST("xvdq15", 268439567);
+ /* Last extended disk */
+ DO_TEST("xvdiz", 268501760);
+ DO_TEST("xvdiz1", 268501761);
+ DO_TEST("xvdiz15", 268501775);
+
+ /* Disk letter too large */
+ DO_TEST("xvdja", -1);
+
/* missing disk letter */
DO_TEST("xvd1", -1);
- /* partition to large */
+ /* partition too large */
DO_TEST("xvda16", -1);
- /* partition to small */
+ /* partition too small */
DO_TEST("xvda0", -1);
/* leading zeros */
DO_TEST("xvda01", -1);
* IDE disks
********************************/
- /* odd numbered disk */
+ DO_TEST("hd", -1);
+
+ /* first numbered disk */
DO_TEST("hda", 768);
DO_TEST("hda1", 769);
DO_TEST("hda63", 831);
- /* even number disk */
- DO_TEST("hdd", 5695);
- DO_TEST("hdd1", 5696);
- DO_TEST("hdd63", 5758);
+ /* second numbered disk */
+ DO_TEST("hdb", 832);
+ DO_TEST("hdb1", 833);
+ DO_TEST("hdb63", 895);
+ /* third numbered disk */
+ DO_TEST("hdc", 5632);
+ DO_TEST("hdc1", 5633);
+ DO_TEST("hdc63", 5695);
+ /* fourth numbered disk */
+ DO_TEST("hdd", 5696);
+ DO_TEST("hdd1", 5697);
+ DO_TEST("hdd63", 5759);
/* last valid disk */
- DO_TEST("hdt", 23359);
- DO_TEST("hdt1", 23360);
- DO_TEST("hdt63", 23422);
+ DO_TEST("hdt", 23360);
+ DO_TEST("hdt1", 23361);
+ DO_TEST("hdt63", 23423);
/* Disk letter to large */
DO_TEST("hdu", -1);
/* missing disk letter */
DO_TEST("hd1", -1);
- /* partition to large */
+ /* partition too large */
DO_TEST("hda64", -1);
- /* partition to small */
+ /* partition too small */
DO_TEST("hda0", -1);
* SCSI disks
********************************/
+ DO_TEST("sd", -1);
+
/* first valid disk */
DO_TEST("sda", 2048);
DO_TEST("sda1", 2049);
DO_TEST("sdiv1", 34801);
DO_TEST("sdiv15", 34815);
- /* Disk letter to large */
+ /* Disk letter too large */
DO_TEST("sdix", -1);
/* missing disk letter */
DO_TEST("sd1", -1);
- /* partition to large */
+ /* partition too large */
DO_TEST("sda16", -1);
- /* partition to small */
+ /* partition too small */
DO_TEST("sda0", -1);