[libvirt] [PATCHv2 13/16] storage: use cache to walk backing chain

Laine Stump laine at laine.org
Tue Oct 16 20:51:44 UTC 2012


On 10/13/2012 06:00 PM, Eric Blake wrote:
> We used to walk the backing file chain at least twice per disk,
> once to set up cgroup device whitelisting, and once to set up
> security labeling.  Rather than walk the chain every iteration,
> which possibly includes calls to fork() in order to open root-squashed
> NFS files, we can exploit the cache of the previous patch.

Obviously creating the rule that you can't mess with the backing chain
outside the libvirt API, but I think you've already said that :-)


>
> * src/conf/domain_conf.h (virDomainDiskDefForeachPath): Alter
> signature.
> * src/conf/domain_conf.c (virDomainDiskDefForeachPath): Require caller
> to supply backing chain via disk, if recursion is desired.
> * src/security/security_dac.c
> (virSecurityDACSetSecurityImageLabel): Adjust caller.
> * src/security/security_selinux.c
> (virSecuritySELinuxSetSecurityImageLabel): Likewise.
> * src/security/virt-aa-helper.c (get_files): Likewise.
> * src/qemu/qemu_cgroup.c (qemuSetupDiskCgroup)
> (qemuTeardownDiskCgroup): Likewise.
> (qemuSetupCgroup): Pre-populate chain.
> ---
>  src/conf/domain_conf.c          | 100 +++++++---------------------------------
>  src/conf/domain_conf.h          |   2 -
>  src/qemu/qemu_cgroup.c          |  12 ++---
>  src/security/security_dac.c     |   7 ---
>  src/security/security_selinux.c |  11 -----
>  src/security/virt-aa-helper.c   |  27 +++++++----
>  6 files changed, 40 insertions(+), 119 deletions(-)
>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index f4c05a3..2c0b296 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -14633,110 +14633,42 @@ done:
>  }
>
>
> +/* Call iter(disk, name, depth, opaque) for each element of disk and
> +   its backing chain in the pre-populated disk->chain.
> +   ignoreOpenFailure determines whether to warn about a chain that
> +   mentions a backing file without also having metadata on that
> +   file.  */
>  int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
> -                                bool allowProbing,
>                                  bool ignoreOpenFailure,
> -                                uid_t uid, gid_t gid,
>                                  virDomainDiskDefPathIterator iter,
>                                  void *opaque)
>  {
> -    virHashTablePtr paths = NULL;
> -    int format;
>      int ret = -1;
>      size_t depth = 0;
> -    char *nextpath = NULL;
> -    virStorageFileMetadata *meta = NULL;
> +    virStorageFileMetadata *tmp;
>
>      if (!disk->src || disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
>          return 0;
>
> -    if (disk->format > 0) {
> -        format = disk->format;
> -    } else {
> -        if (allowProbing) {
> -            format = VIR_STORAGE_FILE_AUTO;
> -        } else {
> -            virReportError(VIR_ERR_INTERNAL_ERROR,
> -                           _("no disk format for %s and probing is disabled"),
> -                           disk->src);
> -            goto cleanup;
> -        }
> -    }
> -
> -    paths = virHashCreate(5, NULL);
> -
> -    do {
> -        const char *path = nextpath ? nextpath : disk->src;
> -        int fd;
> -
> -        if (iter(disk, path, depth, opaque) < 0)
> -            goto cleanup;
> +    if (iter(disk, disk->src, 0, opaque) < 0)
> +        goto cleanup;
>
> -        if (virHashLookup(paths, path)) {
> +    tmp = disk->chain;
> +    while (tmp && tmp->backingStoreIsFile) {
> +        if (!ignoreOpenFailure && !tmp->backingMeta) {
>              virReportError(VIR_ERR_INTERNAL_ERROR,
> -                           _("backing store for %s is self-referential"),
> -                           disk->src);
> +                           _("unable to visit backing chain file %s"),
> +                           tmp->backingStore);
>              goto cleanup;
>          }
> -
> -        if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) {
> -            if (ignoreOpenFailure) {
> -                char ebuf[1024];
> -                VIR_WARN("Ignoring open failure on %s: %s", path,
> -                         virStrerror(-fd, ebuf, sizeof(ebuf)));
> -                break;
> -            } else {
> -                virReportSystemError(-fd, _("unable to open disk path %s"),
> -                                     path);
> -                goto cleanup;
> -            }
> -        }
> -
> -        if (!(meta = virStorageFileGetMetadataFromFD(path, fd, format))) {
> -            VIR_FORCE_CLOSE(fd);
> -            goto cleanup;
> -        }
> -
> -        if (VIR_CLOSE(fd) < 0)
> -            virReportSystemError(errno,
> -                                 _("could not close file %s"),
> -                                 path);
> -
> -        if (virHashAddEntry(paths, path, (void*)0x1) < 0)
> +        if (iter(disk, tmp->backingStore, ++depth, opaque) < 0)
>              goto cleanup;
> -
> -        depth++;
> -        VIR_FREE(nextpath);
> -        nextpath = meta->backingStore;
> -        meta->backingStore = NULL;
> -
> -        /* Stop iterating if we reach a non-file backing store */
> -        if (nextpath && !meta->backingStoreIsFile) {
> -            VIR_DEBUG("Stopping iteration on non-file backing store: %s",
> -                      nextpath);
> -            break;
> -        }
> -
> -        format = meta->backingStoreFormat;
> -
> -        if (format == VIR_STORAGE_FILE_AUTO &&
> -            !allowProbing)
> -            format = VIR_STORAGE_FILE_RAW; /* Stops further recursion */
> -
> -        /* Allow probing for image formats that are safe */
> -        if (format == VIR_STORAGE_FILE_AUTO_SAFE)
> -            format = VIR_STORAGE_FILE_AUTO;
> -        virStorageFileFreeMetadata(meta);
> -        meta = NULL;
> -    } while (nextpath);
> +        tmp = tmp->backingMeta;
> +    }
>
>      ret = 0;
>
>  cleanup:
> -    virHashFree(paths);
> -    VIR_FREE(nextpath);
> -    virStorageFileFreeMetadata(meta);
> -
>      return ret;
>  }

Whew! Can't see the code for all the deletions! :-)


>
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 06c1ccd..87faa7e 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -2139,9 +2139,7 @@ typedef int (*virDomainDiskDefPathIterator)(virDomainDiskDefPtr disk,
>                                              void *opaque);
>
>  int virDomainDiskDefForeachPath(virDomainDiskDefPtr disk,
> -                                bool allowProbing,
>                                  bool ignoreOpenFailure,
> -                                uid_t uid, gid_t gid,
>                                  virDomainDiskDefPathIterator iter,
>                                  void *opaque);
>
> diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
> index 166f9b9..10acb26 100644
> --- a/src/qemu/qemu_cgroup.c
> +++ b/src/qemu/qemu_cgroup.c
> @@ -87,16 +87,14 @@ qemuSetupDiskPathAllow(virDomainDiskDefPtr disk,
>  }
>
>
> -int qemuSetupDiskCgroup(struct qemud_driver *driver,
> +int qemuSetupDiskCgroup(struct qemud_driver *driver ATTRIBUTE_UNUSED,
>                          virDomainObjPtr vm,
>                          virCgroupPtr cgroup,
>                          virDomainDiskDefPtr disk)
>  {
>      qemuCgroupData data = { vm, cgroup };
>      return virDomainDiskDefForeachPath(disk,
> -                                       driver->allowDiskFormatProbing,
>                                         true,
> -                                       driver->user, driver->group,
>                                         qemuSetupDiskPathAllow,
>                                         &data);
>  }
> @@ -129,16 +127,14 @@ qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
>  }
>
>
> -int qemuTeardownDiskCgroup(struct qemud_driver *driver,
> +int qemuTeardownDiskCgroup(struct qemud_driver *driver ATTRIBUTE_UNUSED,
>                             virDomainObjPtr vm,
>                             virCgroupPtr cgroup,
>                             virDomainDiskDefPtr disk)
>  {
>      qemuCgroupData data = { vm, cgroup };
>      return virDomainDiskDefForeachPath(disk,
> -                                       driver->allowDiskFormatProbing,
>                                         true,
> -                                       driver->user, driver->group,
>                                         qemuTeardownDiskPathDeny,
>                                         &data);
>  }
> @@ -232,7 +228,9 @@ int qemuSetupCgroup(struct qemud_driver *driver,
>          }
>
>          for (i = 0; i < vm->def->ndisks ; i++) {
> -            if (qemuSetupDiskCgroup(driver, vm, cgroup, vm->def->disks[i]) < 0)
> +            if (qemuDomainDetermineDiskChain(driver, vm->def->disks[i],
> +                                             false) < 0 ||
> +                qemuSetupDiskCgroup(driver, vm, cgroup, vm->def->disks[i]) < 0)
>                  goto cleanup;
>          }
>
> diff --git a/src/security/security_dac.c b/src/security/security_dac.c
> index f126aa5..5f11810 100644
> --- a/src/security/security_dac.c
> +++ b/src/security/security_dac.c
> @@ -358,8 +358,6 @@ virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr,
>                                      virDomainDiskDefPtr disk)
>
>  {
> -    uid_t user;
> -    gid_t group;
>      void *params[2];
>      virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
>
> @@ -369,15 +367,10 @@ virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr,
>      if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
>          return 0;
>
> -    if (virSecurityDACGetImageIds(def, priv, &user, &group))
> -        return -1;
> -
>      params[0] = mgr;
>      params[1] = def;
>      return virDomainDiskDefForeachPath(disk,
> -                                       virSecurityManagerGetAllowDiskFormatProbing(mgr),
>                                         false,
> -                                       user, group,
>                                         virSecurityDACSetSecurityFileLabel,
>                                         params);
>  }
> diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
> index 10135ed..00c34c2 100644
> --- a/src/security/security_selinux.c
> +++ b/src/security/security_selinux.c
> @@ -1022,13 +1022,10 @@ virSecuritySELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
>                                          virDomainDiskDefPtr disk)
>
>  {
> -    bool allowDiskFormatProbing;
>      virSecuritySELinuxCallbackData cbdata;
>      cbdata.manager = mgr;
>      cbdata.secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
>
> -    allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr);
> -
>      if (cbdata.secdef == NULL)
>          return -1;
>
> @@ -1038,16 +1035,8 @@ virSecuritySELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
>      if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
>          return 0;
>
> -    /* XXX On one hand, it would be nice to have the driver's uid:gid
> -     * here so we could retry opens with it. On the other hand, it
> -     * probably doesn't matter because in practice that's only useful
> -     * for files on root-squashed NFS shares, and NFS doesn't properly
> -     * support selinux anyway.
> -     */
>      return virDomainDiskDefForeachPath(disk,
> -                                       allowDiskFormatProbing,
>                                         true,
> -                                       -1, -1, /* current process uid:gid */
>                                         virSecuritySELinuxSetSecurityFileLabel,
>                                         &cbdata);
>  }
> diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
> index 51daa4b..729c0d1 100644
> --- a/src/security/virt-aa-helper.c
> +++ b/src/security/virt-aa-helper.c
> @@ -919,19 +919,30 @@ get_files(vahControl * ctl)
>      }
>
>      for (i = 0; i < ctl->def->ndisks; i++) {
> +        int ret;
> +        int format;
> +        virDomainDiskDefPtr disk = ctl->def->disks[i];
> +
> +        if (disk->format > 0)
> +            format = disk->format;
> +        else if (ctl->allowDiskFormatProbing)
> +            format = VIR_STORAGE_FILE_AUTO;
> +        else
> +            format = VIR_STORAGE_FILE_RAW;

It seems like I've seen this same bit of code a few times now...

> +
> +        /* XXX - if we knew the qemu user:group here we could send it in
> +         *        so that the open could be re-tried as that user:group.
> +         */
> +        disk->chain = virStorageFileGetMetadata(disk->src, format, -1, -1,
> +                                                ctl->allowDiskFormatProbing,
> +                                                NULL);
> +
>          /* XXX passing ignoreOpenFailure = true to get back to the behavior
>           * from before using virDomainDiskDefForeachPath. actually we should
>           * be passing ignoreOpenFailure = false and handle open errors more
>           * careful than just ignoring them.
> -         * XXX2 - if we knew the qemu user:group here we could send it in
> -         *        so that the open could be re-tried as that user:group.
>           */
> -        int ret = virDomainDiskDefForeachPath(ctl->def->disks[i],
> -                                              ctl->allowDiskFormatProbing,
> -                                              true,
> -                                              -1, -1, /* current uid:gid */
> -                                              add_file_path,
> -                                              &buf);
> +        ret = virDomainDiskDefForeachPath(disk, true, add_file_path, &buf);
>          if (ret != 0)
>              goto clean;
>      }

ACK.




More information about the libvir-list mailing list