[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 2 of 3] Check whether a PCI device is assignable before assigning it do a domU



Implement both of Stefanos suggestions this time:

On Wed, 2010-07-28 at 20:40 +0100, Gianni Tedesco wrote:
> tools/libxl/libxl.h          |    3 +-
>  tools/libxl/libxl_internal.h |    3 +
>  tools/libxl/libxl_pci.c      |  186 
> +++++++++++++++++++++++++++++++++++++++---
>  tools/libxl/xl.h             |    1 +
>  tools/libxl/xl_cmdimpl.c     |   36 +++++++-
>  tools/libxl/xl_cmdtable.c    |    5 +
>  6 files changed, 214 insertions(+), 20 deletions(-)
> 
> 
> Implement a new libxl function libxl_device_pci_list_assignable. This is
> used to implement the xl list-assignable-pci-devices command and part of
> the implementation is used to make sure that PCI devices are not multiply
> assigned to one or more domU's before doing the passthrough assignment.
> 
> The function libxl_device_pci_list changes to libxl_device_pci_list_assigned
> due to a parameter change for consistency with pci_list_assignable.
> 
> Signed-off-by: Gianni Tedesco <gianni.tedesco@xxxxxxxxxx>

diff -r 43150fdd0106 tools/libxl/libxl.h
--- a/tools/libxl/libxl.h       Thu Jul 29 16:47:16 2010 +0100
+++ b/tools/libxl/libxl.h       Thu Jul 29 16:48:48 2010 +0100
@@ -521,7 +521,8 @@ int libxl_device_vfb_hard_shutdown(libxl
 int libxl_device_pci_add(libxl_ctx *ctx, uint32_t domid, libxl_device_pci 
*pcidev);
 int libxl_device_pci_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_pci 
*pcidev);
 int libxl_device_pci_shutdown(libxl_ctx *ctx, uint32_t domid);
-libxl_device_pci *libxl_device_pci_list(libxl_ctx *ctx, uint32_t domid, int 
*num);
+int libxl_device_pci_list_assigned(libxl_ctx *ctx, libxl_device_pci **list, 
uint32_t domid, int *num);
+int libxl_device_pci_list_assignable(libxl_ctx *ctx, libxl_device_pci **list, 
int *num);
 int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
                           unsigned int bus, unsigned int dev,
                           unsigned int func, unsigned int vdevfn);
diff -r 43150fdd0106 tools/libxl/libxl_internal.h
--- a/tools/libxl/libxl_internal.h      Thu Jul 29 16:47:16 2010 +0100
+++ b/tools/libxl/libxl_internal.h      Thu Jul 29 16:48:48 2010 +0100
@@ -91,6 +91,8 @@ typedef struct {
 #define XC_PCI_BDF             "0x%x, 0x%x, 0x%x, 0x%x"
 #define AUTO_PHP_SLOT          0x100
 #define SYSFS_PCI_DEV          "/sys/bus/pci/devices"
+#define SYSFS_PCIBACK_DRIVER   "/sys/bus/pci/drivers/pciback"
+
 #define PROC_PCI_NUM_RESOURCES 7
 #define PCI_BAR_IO             0x01
 
diff -r 43150fdd0106 tools/libxl/libxl_pci.c
--- a/tools/libxl/libxl_pci.c   Thu Jul 29 16:47:16 2010 +0100
+++ b/tools/libxl/libxl_pci.c   Thu Jul 29 16:48:48 2010 +0100
@@ -28,6 +28,7 @@
 #include <unistd.h> /* for write, unlink and close */
 #include <stdint.h>
 #include <inttypes.h>
+#include <dirent.h>
 #include <assert.h>
 
 #include "libxl.h"
@@ -258,22 +259,77 @@ retry_transaction2:
     return 0;
 }
 
-int libxl_device_pci_add(libxl_ctx *ctx, uint32_t domid, libxl_device_pci 
*pcidev)
+static int get_all_assigned_devices(libxl_ctx *ctx, libxl_device_pci **list, 
int *num)
+{
+    libxl_device_pci *pcidevs = NULL;
+    char **domlist;
+    unsigned int nd = 0, i;
+
+    *list = NULL;
+    *num = 0;
+
+    domlist = libxl_xs_directory(ctx, XBT_NULL, "/local/domain", &nd);
+    for(i = 0; i < nd; i++) {
+        char *path, *num_devs;
+
+        path = libxl_sprintf(ctx, "/local/domain/0/backend/pci/%s/0/num_devs", 
domlist[i]);
+        num_devs = libxl_xs_read(ctx, XBT_NULL, path);
+        if ( num_devs ) {
+            int ndev = atoi(num_devs), j;
+            char *devpath, *bdf;
+
+            pcidevs = calloc(sizeof(*pcidevs), ndev);
+            for(j = (pcidevs) ? 0 : ndev; j < ndev; j++) {
+                devpath = libxl_sprintf(ctx, 
"/local/domain/0/backend/pci/%s/0/dev-%u",
+                                        domlist[i], j);
+                bdf = libxl_xs_read(ctx, XBT_NULL, devpath);
+                if ( bdf ) {
+                    unsigned dom, bus, dev, func;
+                    if ( sscanf(bdf, PCI_BDF, &dom, &bus, &dev, &func) != 4 )
+                        continue;
+
+                    libxl_device_pci_init(pcidevs + *num, dom, bus, dev, func, 
0);
+                    (*num)++;
+                }
+            }
+        }
+    }
+
+    if ( 0 == *num ) {
+        free(pcidevs);
+        pcidevs = NULL;
+    }else{
+        *list = pcidevs;
+    }
+
+    return 0;
+}
+
+static int is_assigned(libxl_device_pci *assigned, int num_assigned,
+                       int dom, int bus, int dev, int func)
+{
+    int i;
+
+    for(i = 0; i < num_assigned; i++) {
+        if ( assigned[i].domain != dom )
+            continue;
+        if ( assigned[i].bus != bus )
+            continue;
+        if ( assigned[i].dev != dev )
+            continue;
+        if ( assigned[i].func != func )
+            continue;
+        return 1;
+    }
+
+    return 0;
+}
+
+static int do_pci_add(libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
 {
     char *path;
     char *state, *vdevfn;
     int rc, hvm;
-    int stubdomid = 0;
-
-    /* TODO: check if the device can be assigned */
-
-    libxl_device_pci_reset(ctx, pcidev->domain, pcidev->bus, pcidev->dev, 
pcidev->func);
-
-    stubdomid = libxl_get_stubdom_id(ctx, domid);
-    if (stubdomid != 0) {
-        libxl_device_pci pcidev_s = *pcidev;
-        libxl_device_pci_add(ctx, stubdomid, &pcidev_s);
-    }
 
     hvm = is_hvm(ctx, domid);
     if (hvm) {
@@ -370,6 +426,38 @@ out:
     return 0;
 }
 
+int libxl_device_pci_add(libxl_ctx *ctx, uint32_t domid, libxl_device_pci 
*pcidev)
+{
+    libxl_device_pci *assigned;
+    int num_assigned, rc;
+    int stubdomid = 0;
+
+    rc = get_all_assigned_devices(ctx, &assigned, &num_assigned);
+    if ( rc ) {
+        XL_LOG(ctx, XL_LOG_ERROR, "cannot determine if device is assigned, 
refusing to continue");
+        return ERROR_FAIL;
+    }
+    if ( is_assigned(assigned, num_assigned, pcidev->domain,
+                     pcidev->bus, pcidev->dev, pcidev->func) ) {
+        XL_LOG(ctx, XL_LOG_ERROR, "PCI device already attached to a domain");
+        free(assigned);
+        return ERROR_FAIL;
+    }
+    free(assigned);
+
+    libxl_device_pci_reset(ctx, pcidev->domain, pcidev->bus, pcidev->dev, 
pcidev->func);
+
+    stubdomid = libxl_get_stubdom_id(ctx, domid);
+    if (stubdomid != 0) {
+        libxl_device_pci pcidev_s = *pcidev;
+        rc = do_pci_add(ctx, stubdomid, &pcidev_s);
+        if ( rc )
+            return rc;
+    }
+
+    return do_pci_add(ctx, domid, pcidev);
+}
+
 int libxl_device_pci_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_pci 
*pcidev)
 {
     char *path;
@@ -466,7 +554,64 @@ out:
     return 0;
 }
 
-libxl_device_pci *libxl_device_pci_list(libxl_ctx *ctx, uint32_t domid, int 
*num)
+static libxl_device_pci *scan_sys_pcidir(libxl_device_pci *assigned,
+                                         int num_assigned, const char *path, 
int *num)
+{
+    libxl_device_pci *pcidevs = NULL, *new;
+    struct dirent *de;
+    DIR *dir;
+
+    dir = opendir(path);
+    if ( NULL == dir )
+        return pcidevs;
+
+    while( (de = readdir(dir)) ) {
+        unsigned dom, bus, dev, func;
+        if ( sscanf(de->d_name, PCI_BDF, &dom, &bus, &dev, &func) != 4 )
+            continue;
+
+        if ( is_assigned(assigned, num_assigned, dom, bus, dev, func) )
+            continue;
+
+        new = realloc(pcidevs, ((*num) + 1) * sizeof(*new));
+        if ( NULL == new )
+            continue;
+
+        pcidevs = new;
+        new = pcidevs + *num;
+
+        memset(new, 0, sizeof(*new));
+        libxl_device_pci_init(new, dom, bus, dev, func, 0);
+        (*num)++;
+    }
+
+    closedir(dir);
+    return pcidevs;
+}
+
+int libxl_device_pci_list_assignable(libxl_ctx *ctx, libxl_device_pci **list, 
int *num)
+{
+    libxl_device_pci *pcidevs = NULL;
+    libxl_device_pci *assigned;
+    int num_assigned, rc;
+
+    *num = 0;
+    *list = NULL;
+
+    rc = get_all_assigned_devices(ctx, &assigned, &num_assigned);
+    if ( rc )
+        return rc;
+
+    pcidevs = scan_sys_pcidir(assigned, num_assigned,
+                              SYSFS_PCIBACK_DRIVER, num);
+
+    free(assigned);
+    if ( *num )
+        *list = pcidevs;
+    return 0;
+}
+
+int libxl_device_pci_list_assigned(libxl_ctx *ctx, libxl_device_pci **list, 
uint32_t domid, int *num)
 {
     char *be_path, *num_devs, *xsdev, *xsvdevfn, *xsopts;
     int n, i;
@@ -477,7 +622,8 @@ libxl_device_pci *libxl_device_pci_list(
     num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", 
be_path));
     if (!num_devs) {
         *num = 0;
-        return NULL;
+        *list = NULL;
+        return ERROR_FAIL;
     }
     n = atoi(num_devs);
     pcidevs = calloc(n, sizeof(libxl_device_pci));
@@ -507,15 +653,19 @@ libxl_device_pci *libxl_device_pci_list(
             } while ((p = strtok_r(NULL, ",=", &saveptr)) != NULL);
         }
     }
-    return pcidevs;
+    if ( *num )
+        *list = pcidevs;
+    return 0;
 }
 
 int libxl_device_pci_shutdown(libxl_ctx *ctx, uint32_t domid)
 {
     libxl_device_pci *pcidevs;
-    int num, i;
+    int num, i, rc;
 
-    pcidevs = libxl_device_pci_list(ctx, domid, &num);
+    rc = libxl_device_pci_list_assigned(ctx, &pcidevs, domid, &num);
+    if ( rc )
+        return rc;
     for (i = 0; i < num; i++) {
         if (libxl_device_pci_remove(ctx, domid, pcidevs + i) < 0)
             return ERROR_FAIL;
diff -r 43150fdd0106 tools/libxl/xl.h
--- a/tools/libxl/xl.h  Thu Jul 29 16:47:16 2010 +0100
+++ b/tools/libxl/xl.h  Thu Jul 29 16:48:48 2010 +0100
@@ -32,6 +32,7 @@ int main_cd_insert(int argc, char **argv
 int main_console(int argc, char **argv);
 int main_vncviewer(int argc, char **argv);
 int main_pcilist(int argc, char **argv);
+int main_pcilist_assignable(int argc, char **argv);
 int main_pcidetach(int argc, char **argv);
 int main_pciattach(int argc, char **argv);
 int main_restore(int argc, char **argv);
diff -r 43150fdd0106 tools/libxl/xl_cmdimpl.c
--- a/tools/libxl/xl_cmdimpl.c  Thu Jul 29 16:47:16 2010 +0100
+++ b/tools/libxl/xl_cmdimpl.c  Thu Jul 29 16:48:48 2010 +0100
@@ -1920,6 +1920,39 @@ int main_vncviewer(int argc, char **argv
     exit(0);
 }
 
+void pcilist_assignable(void)
+{
+    libxl_device_pci *pcidevs;
+    int num, i;
+
+    if ( libxl_device_pci_list_assignable(&ctx, &pcidevs, &num) )
+        return;
+    for (i = 0; i < num; i++) {
+        printf("%04x:%02x:%02x:%01x\n",
+                pcidevs[i].domain, pcidevs[i].bus, pcidevs[i].dev, 
pcidevs[i].func);
+    }
+    free(pcidevs);
+}
+
+int main_pcilist_assignable(int argc, char **argv)
+{
+    int opt;
+
+    while ((opt = getopt(argc, argv, "h")) != -1) {
+        switch (opt) {
+        case 'h':
+            help("pci-list-assignable-devices");
+            exit(0);
+        default:
+            fprintf(stderr, "option not supported\n");
+            break;
+        }
+    }
+
+    pcilist_assignable();
+    exit(0);
+}
+
 void pcilist(char *dom)
 {
     libxl_device_pci *pcidevs;
@@ -1927,8 +1960,7 @@ void pcilist(char *dom)
 
     find_domain(dom);
 
-    pcidevs = libxl_device_pci_list(&ctx, domid, &num);
-    if (!num)
+    if (libxl_device_pci_list_assigned(&ctx, &pcidevs, domid, &num))
         return;
     printf("VFn  domain bus  slot func\n");
     for (i = 0; i < num; i++) {
diff -r 43150fdd0106 tools/libxl/xl_cmdtable.c
--- a/tools/libxl/xl_cmdtable.c Thu Jul 29 16:47:16 2010 +0100
+++ b/tools/libxl/xl_cmdtable.c Thu Jul 29 16:48:48 2010 +0100
@@ -69,6 +69,11 @@ struct cmd_spec cmd_table[] = {
       "List pass-through pci devices for a domain",
       "<Domain>",
     },
+    { "pci-list-assignable-devices",
+      &main_pcilist_assignable,
+      "List all the assignable pci devices",
+      "",
+    },
     { "pause",
       &main_pause,
       "Pause execution of a domain",



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.