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

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



On Wed, 28 Jul 2010, Gianni Tedesco (3P) 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 e2520c8b96b7 -r 099e4eb3803a tools/libxl/libxl.h
> --- a/tools/libxl/libxl.h     Wed Jul 28 20:29:08 2010 +0100
> +++ b/tools/libxl/libxl.h     Wed Jul 28 20:31:59 2010 +0100
> @@ -521,7 +521,8 @@ int libxl_device_vfb_hard_shutdown(struc
>  int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, 
> libxl_device_pci *pcidev);
>  int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, 
> libxl_device_pci *pcidev);
>  int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid);
> -libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t 
> domid, int *num);
> +int libxl_device_pci_list_assigned(struct libxl_ctx *ctx, libxl_device_pci 
> **list, uint32_t domid, int *num);
> +int libxl_device_pci_list_assignable(struct 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 e2520c8b96b7 -r 099e4eb3803a tools/libxl/libxl_internal.h
> --- a/tools/libxl/libxl_internal.h    Wed Jul 28 20:29:08 2010 +0100
> +++ b/tools/libxl/libxl_internal.h    Wed Jul 28 20:31:59 2010 +0100
> @@ -91,6 +91,9 @@ 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 SYSFS_PCISTUB_DRIVER   "/sys/bus/pci/drivers/pcistub"
> +
>  #define PROC_PCI_NUM_RESOURCES 7
>  #define PCI_BAR_IO             0x01
>  
> diff -r e2520c8b96b7 -r 099e4eb3803a tools/libxl/libxl_pci.c
> --- a/tools/libxl/libxl_pci.c Wed Jul 28 20:29:08 2010 +0100
> +++ b/tools/libxl/libxl_pci.c Wed Jul 28 20:31:59 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(struct libxl_ctx *ctx, uint32_t domid, 
> libxl_device_pci *pcidev)
> +int get_all_assigned_devices(struct libxl_ctx *ctx, libxl_device_pci **list, 
> int *num)

shouldn't this be static?

> +{
> +    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(struct 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(struct 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(struct libxl_ctx *ctx, uint32_t domid, 
> libxl_device_pci *pcidev)
>  {
>      char *path;
> @@ -466,7 +554,66 @@ out:
>      return 0;
>  }
>  
> -libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t 
> domid, int *num)
> +static libxl_device_pci *scan_sys_pcidir(libxl_device_pci *pcidevs, 
> libxl_device_pci *assigned,
> +                                         int num_assigned, const char *path, 
> int *num)
> +{
> +    libxl_device_pci *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(struct 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(pcidevs, assigned, num_assigned,
> +                              SYSFS_PCIBACK_DRIVER, num);
> +    pcidevs = scan_sys_pcidir(pcidevs, assigned, num_assigned,
> +                              SYSFS_PCISTUB_DRIVER, num);
> +

I still think we should remove pcistub scanning from here: when running
on xen people should use pciback anyway.


> +    free(assigned);
> +    if ( *num )
> +        *list = pcidevs;
> +    return 0;
> +}
> +
> +int libxl_device_pci_list_assigned(struct 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 +624,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 +655,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(struct 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 e2520c8b96b7 -r 099e4eb3803a tools/libxl/xl.h
> --- a/tools/libxl/xl.h        Wed Jul 28 20:29:08 2010 +0100
> +++ b/tools/libxl/xl.h        Wed Jul 28 20:31:59 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 e2520c8b96b7 -r 099e4eb3803a tools/libxl/xl_cmdimpl.c
> --- a/tools/libxl/xl_cmdimpl.c        Wed Jul 28 20:29:08 2010 +0100
> +++ b/tools/libxl/xl_cmdimpl.c        Wed Jul 28 20:31:59 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 e2520c8b96b7 -r 099e4eb3803a tools/libxl/xl_cmdtable.c
> --- a/tools/libxl/xl_cmdtable.c       Wed Jul 28 20:29:08 2010 +0100
> +++ b/tools/libxl/xl_cmdtable.c       Wed Jul 28 20:31:59 2010 +0100
> @@ -68,6 +68,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®.