On 10/16/2012 06:03 PM, Eric Blake wrote: > Previously, snapshot code did its own permission granting (lock > manager, cgroup device controller, and security manager labeling) > inline. But now that we are adding block-commit and block-copy > which also have to change permissions, it's better to reuse > common code for the task. While snapshot should fall back to > no access if read-write access failed, block-commit will want to > fall back to read-only access. The common code doesn't know > whether failure to grant read-write access should revert to no > access (snapshot, block-copy) or read-only access (block-commit). > This code can also be used to revoke access to unused files after > block-pull. > > * src/qemu/qemu_driver.c (qemuDomainPrepareDiskChainElement): New > function. > (qemuDomainSnapshotCreateSingleDiskActive) > (qemuDomainSnapshotUndoSingleDiskActive): Use it. > --- > src/qemu/qemu_driver.c | 101 ++++++++++++++++++++++++++++++++----------------- > 1 file changed, 66 insertions(+), 35 deletions(-) > > diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c > index 04b28a1..59c475e 100644 > --- a/src/qemu/qemu_driver.c > +++ b/src/qemu/qemu_driver.c > @@ -10452,6 +10452,65 @@ cleanup: > return ret; > } > > +typedef enum { > + VIR_DISK_CHAIN_NO_ACCESS, > + VIR_DISK_CHAIN_READ_ONLY, > + VIR_DISK_CHAIN_READ_WRITE, > +} qemuDomainDiskChainMode; > + > +/* Several operations end up adding or removing a single element of a > + * disk backing file chain; this helper function ensures that the lock > + * manager, cgroup device controller, and security manager labelling > + * are all aware of each new file before it is added to a chain. */ > +static int > +qemuDomainPrepareDiskChainElement(struct qemud_driver *driver, > + virDomainObjPtr vm, > + virCgroupPtr cgroup, > + virDomainDiskDefPtr disk, > + char *file, > + qemuDomainDiskChainMode mode) > +{ > + /* The easiest way to label a single file with the same > + * permissions it would have as if part of the disk chain is to > + * temporarily modify the disk in place. */ > + char *origsrc = disk->src; > + int origformat = disk->format; > + virStorageFileMetadataPtr origchain = disk->chain; > + bool origreadonly = disk->readonly; > + int ret = -1; > + > + disk->src = file; > + disk->format = VIR_STORAGE_FILE_RAW; > + disk->chain = NULL; > + disk->readonly = mode == VIR_DISK_CHAIN_READ_ONLY; > + > + if (mode == VIR_DISK_CHAIN_NO_ACCESS) { > + if (virSecurityManagerRestoreImageLabel(driver->securityManager, > + vm->def, disk) < 0) > + VIR_WARN("Unable to restore security label on %s", disk->src); > + if (cgroup && qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0) > + VIR_WARN("Failed to teardown cgroup for disk path %s", disk->src); > + if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0) > + VIR_WARN("Unable to release lock on %s", disk->src); This feels like a bit of a hackish way to get around an inadequate security driver (and lock and cgroup?) API by hijacking what's available. But then I haven't looked at just how deep the changes would need to be to make it work properly, so I won't dismiss it out of hand. It seems like something that should require a promise of later cleanup though :-) > + } else if (virDomainLockDiskAttach(driver->lockManager, driver->uri, > + vm, disk) < 0 || > + (cgroup && qemuSetupDiskCgroup(driver, vm, cgroup, disk) < 0) || > + virSecurityManagerSetImageLabel(driver->securityManager, > + vm->def, disk) < 0) { > + goto cleanup; > + } > + > + ret = 0; > + > +cleanup: > + disk->src = origsrc; > + disk->format = origformat; > + disk->chain = origchain; > + disk->readonly = origreadonly; > + return ret; > +} > + > + > static bool > qemuDomainSnapshotIsAllowed(virDomainObjPtr vm) > { > @@ -10742,6 +10801,7 @@ cleanup: > return ret; > } > > + > /* The domain is expected to hold monitor lock. */ > static int > qemuDomainSnapshotCreateSingleDiskActive(struct qemud_driver *driver, > @@ -10761,8 +10821,6 @@ qemuDomainSnapshotCreateSingleDiskActive(struct qemud_driver *driver, > char *persistSource = NULL; > int ret = -1; > int fd = -1; > - char *origsrc = NULL; > - int origdriver; > bool need_unlink = false; > > if (snap->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) { > @@ -10789,10 +10847,6 @@ qemuDomainSnapshotCreateSingleDiskActive(struct qemud_driver *driver, > VIR_FORCE_CLOSE(fd); > } > > - origsrc = disk->src; > - disk->src = source; > - origdriver = disk->format; > - disk->format = VIR_STORAGE_FILE_RAW; /* Don't want to probe backing files */ > /* XXX Here, we know we are about to alter disk->chain if > * successful, so we nuke the existing chain so that future > * commands will recompute it. Better would be storing the chain > @@ -10802,27 +10856,13 @@ qemuDomainSnapshotCreateSingleDiskActive(struct qemud_driver *driver, > virStorageFileFreeMetadata(disk->chain); > disk->chain = NULL; > > - if (virDomainLockDiskAttach(driver->lockManager, driver->uri, > - vm, disk) < 0) > - goto cleanup; > - if (cgroup && qemuSetupDiskCgroup(driver, vm, cgroup, disk) < 0) { > - if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0) > - VIR_WARN("Unable to release lock on %s", source); > - goto cleanup; > - } > - if (virSecurityManagerSetImageLabel(driver->securityManager, vm->def, > - disk) < 0) { > - if (cgroup && qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0) > - VIR_WARN("Failed to teardown cgroup for disk path %s", source); > - if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0) > - VIR_WARN("Unable to release lock on %s", source); > + if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, source, > + VIR_DISK_CHAIN_READ_WRITE) < 0) { > + qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, source, > + VIR_DISK_CHAIN_NO_ACCESS); > goto cleanup; > } > > - disk->src = origsrc; > - origsrc = NULL; > - disk->format = origdriver; > - > /* create the actual snapshot */ > if (snap->format) > formatStr = virStorageFileFormatTypeToString(snap->format); > @@ -10846,10 +10886,6 @@ qemuDomainSnapshotCreateSingleDiskActive(struct qemud_driver *driver, > } > > cleanup: > - if (origsrc) { > - disk->src = origsrc; > - disk->format = origdriver; > - } > if (need_unlink && unlink(source)) > VIR_WARN("unable to unlink just-created %s", source); > VIR_FREE(device); > @@ -10881,13 +10917,8 @@ qemuDomainSnapshotUndoSingleDiskActive(struct qemud_driver *driver, > goto cleanup; > } > > - if (virSecurityManagerRestoreImageLabel(driver->securityManager, > - vm->def, disk) < 0) > - VIR_WARN("Unable to restore security label on %s", disk->src); > - if (cgroup && qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0) > - VIR_WARN("Failed to teardown cgroup for disk path %s", disk->src); > - if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0) > - VIR_WARN("Unable to release lock on %s", disk->src); > + qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, origdisk->src, > + VIR_DISK_CHAIN_NO_ACCESS); > if (need_unlink && stat(disk->src, &st) == 0 && > S_ISREG(st.st_mode) && unlink(disk->src) < 0) > VIR_WARN("Unable to remove just-created %s", disk->src); -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list