]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Recently upstream Xen added support for having xvd devices > 16. For the most
authorChris Lalancette <clalance@redhat.com>
Tue, 5 Aug 2008 16:38:49 +0000 (16:38 +0000)
committerChris Lalancette <clalance@redhat.com>
Tue, 5 Aug 2008 16:38:49 +0000 (16:38 +0000)
part, this doesn't really concern libvirt, since for things like attach and
detach we just pass it through and let xend worry about whether it is supported
or not.  The one place this breaks down is in the stats collecting code, where
we need to figure out the device number so we can go digging in /sys for the
statistics.

To remedy this, I've re-written xenLinuxDomainDeviceID() to use regular
expressions to figure out the device number from the name.  The major advantage
is that now xenLinuxDomainDeviceID() looks fairly identical to
tools/python/xen/util/blkif.py (in the Xen sources), so that adding additional
devices in the future should be much easier.  It also reduces the size of the
code, and, in my opinion, the code complexity.

With this patch in place, I was able to get block statistics both on older style
devices (/dev/xvda) and on the new, expanded devices (/dev/xvdaa).

Signed-off-by: Chris Lalancette <clalance@redhat.com>
ChangeLog
src/stats_linux.c
tests/statstest.c

index 318a9f09e82c0018846bfbb27454b6bc3c6ea8da..37453b666c90d6417ac1ea9a32d3665cbf24ea5c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Tue Aug  5 18:36:00 CEST 2008 Chris Lalancette <clalance@redhat.com>
+       * src/stats_linux.c tests/statstest.c: Update the parsing of disks for
+         xen block statistics.  In particular, add support for > 16 xvd devices
+         recently put into upstream Xen, and fix up the test suite to fix some
+         wrong tests and add a couple more.
+       
 Tue Aug  5 12:51:11 CEST 2008 Daniel Veillard <veillard@redhat.com>
 
        * src/openvz_conf.c src/openvz_conf.h src/openvz_driver.c: patch
index e587807ad6bf6ae3e5425f575b18b02a7a5ef680..897251babd9aed3e0b1f71b36b81bc1e041dc07e 100644 (file)
@@ -18,6 +18,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
+#include <regex.h>
 #include "c-ctype.h"
 
 #ifdef WITH_XEN
@@ -28,6 +29,7 @@
 #include "util.h"
 #include "xen_unified.h"
 #include "stats_linux.h"
+#include "memory.h"
 
 /**
  * statsErrorFunc:
@@ -224,132 +226,134 @@ read_bd_stats (virConnectPtr conn, xenUnifiedPrivatePtr priv,
     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
index c2c3f288b63c748f104a4472a66feb140cd29d0a..5b7d35a58c0cd1b6885feb5c9996ddbbea76542b 100644 (file)
@@ -70,22 +70,34 @@ mymain(int argc ATTRIBUTE_UNUSED,
      * 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);
@@ -98,26 +110,36 @@ mymain(int argc ATTRIBUTE_UNUSED,
      * 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);
 
 
@@ -126,6 +148,8 @@ mymain(int argc ATTRIBUTE_UNUSED,
      * SCSI disks
      ********************************/
 
+    DO_TEST("sd", -1);
+
     /* first valid disk */
     DO_TEST("sda", 2048);
     DO_TEST("sda1", 2049);
@@ -159,13 +183,13 @@ mymain(int argc ATTRIBUTE_UNUSED,
     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);