[libvirt] [[RFC] 6/8] Code refactor: Move helper functions of doCoreDump*, syncNicRxFilter*, and qemuOpenFile* to qemu_process.[ch]

Prerna Saxena saxenap.ltc at gmail.com
Tue Oct 24 17:34:59 UTC 2017


Signed-off-by: Prerna Saxena <saxenap.ltc at gmail.com>
---
 src/qemu/qemu_driver.c  | 1161 -----------------------------------------------
 src/qemu/qemu_process.c | 1133 +++++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_process.h |   86 ++++
 3 files changed, 1219 insertions(+), 1161 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b249347..9d495fb 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -151,11 +151,6 @@ static int qemuDomainObjStart(virConnectPtr conn,
 static int qemuDomainManagedSaveLoad(virDomainObjPtr vm,
                                      void *opaque);
 
-static int qemuOpenFileAs(uid_t fallback_uid, gid_t fallback_gid,
-                          bool dynamicOwnership,
-                          const char *path, int oflags,
-                          bool *needUnlink, bool *bypassSecurityDriver);
-
 static int qemuGetDHCPInterfaces(virDomainPtr dom,
                                  virDomainObjPtr vm,
                                  virDomainInterfacePtr **ifaces);
@@ -2819,38 +2814,6 @@ qemuDomainGetControlInfo(virDomainPtr dom,
 
 verify(sizeof(QEMU_SAVE_MAGIC) == sizeof(QEMU_SAVE_PARTIAL));
 
-typedef enum {
-    QEMU_SAVE_FORMAT_RAW = 0,
-    QEMU_SAVE_FORMAT_GZIP = 1,
-    QEMU_SAVE_FORMAT_BZIP2 = 2,
-    /*
-     * Deprecated by xz and never used as part of a release
-     * QEMU_SAVE_FORMAT_LZMA
-     */
-    QEMU_SAVE_FORMAT_XZ = 3,
-    QEMU_SAVE_FORMAT_LZOP = 4,
-    /* Note: add new members only at the end.
-       These values are used in the on-disk format.
-       Do not change or re-use numbers. */
-
-    QEMU_SAVE_FORMAT_LAST
-} virQEMUSaveFormat;
-
-VIR_ENUM_DECL(qemuSaveCompression)
-VIR_ENUM_IMPL(qemuSaveCompression, QEMU_SAVE_FORMAT_LAST,
-              "raw",
-              "gzip",
-              "bzip2",
-              "xz",
-              "lzop")
-
-VIR_ENUM_DECL(qemuDumpFormat)
-VIR_ENUM_IMPL(qemuDumpFormat, VIR_DOMAIN_CORE_DUMP_FORMAT_LAST,
-              "elf",
-              "kdump-zlib",
-              "kdump-lzo",
-              "kdump-snappy")
-
 typedef struct _virQEMUSaveHeader virQEMUSaveHeader;
 typedef virQEMUSaveHeader *virQEMUSaveHeaderPtr;
 struct _virQEMUSaveHeader {
@@ -3062,214 +3025,6 @@ qemuCompressGetCommand(virQEMUSaveFormat compression)
     return ret;
 }
 
-/**
- * qemuOpenFile:
- * @driver: driver object
- * @vm: domain object
- * @path: path to file to open
- * @oflags: flags for opening/creation of the file
- * @needUnlink: set to true if file was created by this function
- * @bypassSecurityDriver: optional pointer to a boolean that will be set to true
- *                        if security driver operations are pointless (due to
- *                        NFS mount)
- *
- * Internal function to properly create or open existing files, with
- * ownership affected by qemu driver setup and domain DAC label.
- *
- * Returns the file descriptor on success and negative errno on failure.
- *
- * This function should not be used on storage sources. Use
- * qemuDomainStorageFileInit and storage driver APIs if possible.
- **/
-static int
-qemuOpenFile(virQEMUDriverPtr driver,
-             virDomainObjPtr vm,
-             const char *path,
-             int oflags,
-             bool *needUnlink,
-             bool *bypassSecurityDriver)
-{
-    int ret = -1;
-    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-    uid_t user = cfg->user;
-    gid_t group = cfg->group;
-    bool dynamicOwnership = cfg->dynamicOwnership;
-    virSecurityLabelDefPtr seclabel;
-
-    virObjectUnref(cfg);
-
-    /* TODO: Take imagelabel into account? */
-    if (vm &&
-        (seclabel = virDomainDefGetSecurityLabelDef(vm->def, "dac")) != NULL &&
-        seclabel->label != NULL &&
-        (virParseOwnershipIds(seclabel->label, &user, &group) < 0))
-        goto cleanup;
-
-    ret = qemuOpenFileAs(user, group, dynamicOwnership,
-                         path, oflags, needUnlink, bypassSecurityDriver);
-
- cleanup:
-    return ret;
-}
-
-static int
-qemuOpenFileAs(uid_t fallback_uid, gid_t fallback_gid,
-               bool dynamicOwnership,
-               const char *path, int oflags,
-               bool *needUnlink, bool *bypassSecurityDriver)
-{
-    struct stat sb;
-    bool is_reg = true;
-    bool need_unlink = false;
-    bool bypass_security = false;
-    unsigned int vfoflags = 0;
-    int fd = -1;
-    int path_shared = virFileIsSharedFS(path);
-    uid_t uid = geteuid();
-    gid_t gid = getegid();
-
-    /* path might be a pre-existing block dev, in which case
-     * we need to skip the create step, and also avoid unlink
-     * in the failure case */
-    if (oflags & O_CREAT) {
-        need_unlink = true;
-
-        /* Don't force chown on network-shared FS
-         * as it is likely to fail. */
-        if (path_shared <= 0 || dynamicOwnership)
-            vfoflags |= VIR_FILE_OPEN_FORCE_OWNER;
-
-        if (stat(path, &sb) == 0) {
-            /* It already exists, we don't want to delete it on error */
-            need_unlink = false;
-
-            is_reg = !!S_ISREG(sb.st_mode);
-            /* If the path is regular file which exists
-             * already and dynamic_ownership is off, we don't
-             * want to change its ownership, just open it as-is */
-            if (is_reg && !dynamicOwnership) {
-                uid = sb.st_uid;
-                gid = sb.st_gid;
-            }
-        }
-    }
-
-    /* First try creating the file as root */
-    if (!is_reg) {
-        if ((fd = open(path, oflags & ~O_CREAT)) < 0) {
-            fd = -errno;
-            goto error;
-        }
-    } else {
-        if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
-                                vfoflags | VIR_FILE_OPEN_NOFORK)) < 0) {
-            /* If we failed as root, and the error was permission-denied
-               (EACCES or EPERM), assume it's on a network-connected share
-               where root access is restricted (eg, root-squashed NFS). If the
-               qemu user is non-root, just set a flag to
-               bypass security driver shenanigans, and retry the operation
-               after doing setuid to qemu user */
-            if ((fd != -EACCES && fd != -EPERM) || fallback_uid == geteuid())
-                goto error;
-
-            /* On Linux we can also verify the FS-type of the directory. */
-            switch (path_shared) {
-                case 1:
-                    /* it was on a network share, so we'll continue
-                     * as outlined above
-                     */
-                    break;
-
-                case -1:
-                    virReportSystemError(-fd, oflags & O_CREAT
-                                         ? _("Failed to create file "
-                                             "'%s': couldn't determine fs type")
-                                         : _("Failed to open file "
-                                             "'%s': couldn't determine fs type"),
-                                         path);
-                    goto cleanup;
-
-                case 0:
-                default:
-                    /* local file - log the error returned by virFileOpenAs */
-                    goto error;
-            }
-
-            /* If we created the file above, then we need to remove it;
-             * otherwise, the next attempt to create will fail. If the
-             * file had already existed before we got here, then we also
-             * don't want to delete it and allow the following to succeed
-             * or fail based on existing protections
-             */
-            if (need_unlink)
-                unlink(path);
-
-            /* Retry creating the file as qemu user */
-
-            /* Since we're passing different modes... */
-            vfoflags |= VIR_FILE_OPEN_FORCE_MODE;
-
-            if ((fd = virFileOpenAs(path, oflags,
-                                    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
-                                    fallback_uid, fallback_gid,
-                                    vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
-                virReportSystemError(-fd, oflags & O_CREAT
-                                     ? _("Error from child process creating '%s'")
-                                     : _("Error from child process opening '%s'"),
-                                     path);
-                goto cleanup;
-            }
-
-            /* Since we had to setuid to create the file, and the fstype
-               is NFS, we assume it's a root-squashing NFS share, and that
-               the security driver stuff would have failed anyway */
-
-            bypass_security = true;
-        }
-    }
- cleanup:
-    if (needUnlink)
-        *needUnlink = need_unlink;
-    if (bypassSecurityDriver)
-        *bypassSecurityDriver = bypass_security;
-    return fd;
-
- error:
-    virReportSystemError(-fd, oflags & O_CREAT
-                         ? _("Failed to create file '%s'")
-                         : _("Failed to open file '%s'"),
-                         path);
-    goto cleanup;
-}
-
-
-static int
-qemuFileWrapperFDClose(virDomainObjPtr vm,
-                       virFileWrapperFdPtr fd)
-{
-    int ret;
-
-    /* virFileWrapperFd uses iohelper to write data onto disk.
-     * However, iohelper calls fdatasync() which may take ages to
-     * finish. Therefore, we shouldn't be waiting with the domain
-     * object locked. */
-
-    /* XXX Currently, this function is intended for *Save() only
-     * as restore needs some reworking before it's ready for
-     * this. */
-
-    virObjectUnlock(vm);
-    ret = virFileWrapperFdClose(fd);
-    virObjectLock(vm);
-    if (!virDomainObjIsActive(vm)) {
-        if (!virGetLastError())
-            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                           _("domain is no longer running"));
-        ret = -1;
-    }
-    return ret;
-}
-
 
 /* Helper function to execute a migration to file with a correct save header
  * the caller needs to make sure that the processors are stopped and do all other
@@ -3481,82 +3236,6 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
     return ret;
 }
 
-
-/* qemuGetCompressionProgram:
- * @imageFormat: String representation from qemu.conf for the compression
- *               image format being used (dump, save, or snapshot).
- * @compresspath: Pointer to a character string to store the fully qualified
- *                path from virFindFileInPath.
- * @styleFormat: String representing the style of format (dump, save, snapshot)
- * @use_raw_on_fail: Boolean indicating how to handle the error path. For
- *                   callers that are OK with invalid data or inability to
- *                   find the compression program, just return a raw format
- *                   and let the path remain as NULL.
- *
- * Returns:
- *    virQEMUSaveFormat    - Integer representation of the compression
- *                           program to be used for particular style
- *                           (e.g. dump, save, or snapshot).
- *    QEMU_SAVE_FORMAT_RAW - If there is no qemu.conf imageFormat value or
- *                           no there was an error, then just return RAW
- *                           indicating none.
- */
-static int ATTRIBUTE_NONNULL(2)
-qemuGetCompressionProgram(const char *imageFormat,
-                          char **compresspath,
-                          const char *styleFormat,
-                          bool use_raw_on_fail)
-{
-    int ret;
-
-    *compresspath = NULL;
-
-    if (!imageFormat)
-        return QEMU_SAVE_FORMAT_RAW;
-
-    if ((ret = qemuSaveCompressionTypeFromString(imageFormat)) < 0)
-        goto error;
-
-    if (ret == QEMU_SAVE_FORMAT_RAW)
-        return QEMU_SAVE_FORMAT_RAW;
-
-    if (!(*compresspath = virFindFileInPath(imageFormat)))
-        goto error;
-
-    return ret;
-
- error:
-    if (ret < 0) {
-        if (use_raw_on_fail)
-            VIR_WARN("Invalid %s image format specified in "
-                     "configuration file, using raw",
-                     styleFormat);
-        else
-            virReportError(VIR_ERR_OPERATION_FAILED,
-                           _("Invalid %s image format specified "
-                             "in configuration file"),
-                           styleFormat);
-    } else {
-        if (use_raw_on_fail)
-            VIR_WARN("Compression program for %s image format in "
-                     "configuration file isn't available, using raw",
-                     styleFormat);
-        else
-            virReportError(VIR_ERR_OPERATION_FAILED,
-                           _("Compression program for %s image format "
-                             "in configuration file isn't available"),
-                           styleFormat);
-    }
-
-    /* Use "raw" as the format if the specified format is not valid,
-     * or the compress program is not available. */
-    if (use_raw_on_fail)
-        return QEMU_SAVE_FORMAT_RAW;
-
-    return -1;
-}
-
-
 static int
 qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
                     unsigned int flags)
@@ -3761,147 +3440,6 @@ qemuDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
     return ret;
 }
 
-static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm,
-                        int fd, qemuDomainAsyncJob asyncJob,
-                        const char *dumpformat)
-{
-    qemuDomainObjPrivatePtr priv = vm->privateData;
-    int ret = -1;
-
-    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) {
-        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
-                       _("dump-guest-memory is not supported"));
-        return -1;
-    }
-
-    if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, fd) < 0)
-        return -1;
-
-    VIR_FREE(priv->job.current);
-    priv->job.dump_memory_only = true;
-
-    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
-        return -1;
-
-    if (dumpformat) {
-        ret = qemuMonitorGetDumpGuestMemoryCapability(priv->mon, dumpformat);
-
-        if (ret <= 0) {
-            virReportError(VIR_ERR_INVALID_ARG,
-                           _("unsupported dumpformat '%s' "
-                             "for this QEMU binary"),
-                           dumpformat);
-            ret = -1;
-            goto cleanup;
-        }
-    }
-
-    ret = qemuMonitorDumpToFd(priv->mon, fd, dumpformat);
-
- cleanup:
-    ignore_value(qemuDomainObjExitMonitor(driver, vm));
-
-    return ret;
-}
-
-static int
-doCoreDump(virQEMUDriverPtr driver,
-           virDomainObjPtr vm,
-           const char *path,
-           unsigned int dump_flags,
-           unsigned int dumpformat)
-{
-    int fd = -1;
-    int ret = -1;
-    virFileWrapperFdPtr wrapperFd = NULL;
-    int directFlag = 0;
-    unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
-    const char *memory_dump_format = NULL;
-    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-    char *compressedpath = NULL;
-
-    /* We reuse "save" flag for "dump" here. Then, we can support the same
-     * format in "save" and "dump". This path doesn't need the compression
-     * program to exist and can ignore the return value - it only cares to
-     * get the compressedpath */
-    ignore_value(qemuGetCompressionProgram(cfg->dumpImageFormat,
-                                           &compressedpath,
-                                           "dump", true));
-
-    /* Create an empty file with appropriate ownership.  */
-    if (dump_flags & VIR_DUMP_BYPASS_CACHE) {
-        flags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
-        directFlag = virFileDirectFdFlag();
-        if (directFlag < 0) {
-            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                           _("bypass cache unsupported by this system"));
-            goto cleanup;
-        }
-    }
-    /* Core dumps usually imply last-ditch analysis efforts are
-     * desired, so we intentionally do not unlink even if a file was
-     * created.  */
-    if ((fd = qemuOpenFile(driver, vm, path,
-                           O_CREAT | O_TRUNC | O_WRONLY | directFlag,
-                           NULL, NULL)) < 0)
-        goto cleanup;
-
-    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags)))
-        goto cleanup;
-
-    if (dump_flags & VIR_DUMP_MEMORY_ONLY) {
-        if (!(memory_dump_format = qemuDumpFormatTypeToString(dumpformat))) {
-            virReportError(VIR_ERR_INVALID_ARG,
-                           _("unknown dumpformat '%d'"), dumpformat);
-            goto cleanup;
-        }
-
-        /* qemu dumps in "elf" without dumpformat set */
-        if (STREQ(memory_dump_format, "elf"))
-            memory_dump_format = NULL;
-
-        ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP,
-                           memory_dump_format);
-    } else {
-        if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
-            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
-                           _("kdump-compressed format is only supported with "
-                             "memory-only dump"));
-            goto cleanup;
-        }
-
-        if (!qemuMigrationIsAllowed(driver, vm, false, 0))
-            goto cleanup;
-
-        ret = qemuMigrationToFile(driver, vm, fd, compressedpath,
-                                  QEMU_ASYNC_JOB_DUMP);
-    }
-
-    if (ret < 0)
-        goto cleanup;
-
-    if (VIR_CLOSE(fd) < 0) {
-        virReportSystemError(errno,
-                             _("unable to close file %s"),
-                             path);
-        goto cleanup;
-    }
-    if (qemuFileWrapperFDClose(vm, wrapperFd) < 0)
-        goto cleanup;
-
-    ret = 0;
-
- cleanup:
-    VIR_FORCE_CLOSE(fd);
-    if (ret != 0)
-        unlink(path);
-    virFileWrapperFdFree(wrapperFd);
-    VIR_FREE(compressedpath);
-    virObjectUnref(cfg);
-    return ret;
-}
-
-
 static int
 qemuDomainCoreDumpWithFormat(virDomainPtr dom,
                              const char *path,
@@ -4106,712 +3644,13 @@ qemuDomainScreenshot(virDomainPtr dom,
     return ret;
 }
 
-static char *
-getAutoDumpPath(virQEMUDriverPtr driver,
-                virDomainObjPtr vm)
-{
-    char *dumpfile = NULL;
-    char *domname = virDomainObjGetShortName(vm->def);
-    char timestr[100];
-    struct tm time_info;
-    time_t curtime = time(NULL);
-    virQEMUDriverConfigPtr cfg = NULL;
-
-    if (!domname)
-        return NULL;
-
-    cfg = virQEMUDriverGetConfig(driver);
-
-    localtime_r(&curtime, &time_info);
-    strftime(timestr, sizeof(timestr), "%Y-%m-%d-%H:%M:%S", &time_info);
-
-    ignore_value(virAsprintf(&dumpfile, "%s/%s-%s",
-                             cfg->autoDumpPath,
-                             domname,
-                             timestr));
-
-    virObjectUnref(cfg);
-    VIR_FREE(domname);
-    return dumpfile;
-}
-
-static void
-processWatchdogEvent(virQEMUDriverPtr driver,
-                     virDomainObjPtr vm,
-                     int action)
-{
-    int ret;
-    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-    char *dumpfile = getAutoDumpPath(driver, vm);
-    unsigned int flags = VIR_DUMP_MEMORY_ONLY;
-
-    if (!dumpfile)
-        goto cleanup;
-
-    switch (action) {
-    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
-        if (qemuDomainObjBeginAsyncJob(driver, vm,
-                                       QEMU_ASYNC_JOB_DUMP,
-                                       VIR_DOMAIN_JOB_OPERATION_DUMP) < 0) {
-            goto cleanup;
-        }
-
-        if (!virDomainObjIsActive(vm)) {
-            virReportError(VIR_ERR_OPERATION_INVALID,
-                           "%s", _("domain is not running"));
-            goto endjob;
-        }
-
-        flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
-        if ((ret = doCoreDump(driver, vm, dumpfile, flags,
-                              VIR_DOMAIN_CORE_DUMP_FORMAT_RAW)) < 0)
-            virReportError(VIR_ERR_OPERATION_FAILED,
-                           "%s", _("Dump failed"));
-
-        ret = qemuProcessStartCPUs(driver, vm, NULL,
-                                   VIR_DOMAIN_RUNNING_UNPAUSED,
-                                   QEMU_ASYNC_JOB_DUMP);
-
-        if (ret < 0)
-            virReportError(VIR_ERR_OPERATION_FAILED,
-                           "%s", _("Resuming after dump failed"));
-        break;
-    default:
-        goto cleanup;
-    }
-
- endjob:
-    qemuDomainObjEndAsyncJob(driver, vm);
-
- cleanup:
-    VIR_FREE(dumpfile);
-    virObjectUnref(cfg);
-}
 
-static int
-doCoreDumpToAutoDumpPath(virQEMUDriverPtr driver,
-                         virDomainObjPtr vm,
-                         unsigned int flags)
-{
-    int ret = -1;
-    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-    char *dumpfile = getAutoDumpPath(driver, vm);
 
-    if (!dumpfile)
-        goto cleanup;
 
-    flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
-    if ((ret = doCoreDump(driver, vm, dumpfile, flags,
-                          VIR_DOMAIN_CORE_DUMP_FORMAT_RAW)) < 0)
-        virReportError(VIR_ERR_OPERATION_FAILED,
-                       "%s", _("Dump failed"));
- cleanup:
-    VIR_FREE(dumpfile);
-    virObjectUnref(cfg);
-    return ret;
-}
 
 
-static void
-qemuProcessGuestPanicEventInfo(virQEMUDriverPtr driver,
-                               virDomainObjPtr vm,
-                               qemuMonitorEventPanicInfoPtr info)
-{
-    char *msg = qemuMonitorGuestPanicEventInfoFormatMsg(info);
-    char *timestamp = virTimeStringNow();
 
-    if (msg && timestamp)
-        qemuDomainLogAppendMessage(driver, vm, "%s: panic %s\n", timestamp, msg);
 
-    VIR_FREE(timestamp);
-    VIR_FREE(msg);
-}
-
-
-static void
-processGuestPanicEvent(virQEMUDriverPtr driver,
-                       virDomainObjPtr vm,
-                       int action,
-                       qemuMonitorEventPanicInfoPtr info)
-{
-    qemuDomainObjPrivatePtr priv = vm->privateData;
-    virObjectEventPtr event = NULL;
-    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-    bool removeInactive = false;
-
-    if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_DUMP,
-                                   VIR_DOMAIN_JOB_OPERATION_DUMP) < 0)
-        goto cleanup;
-
-    if (!virDomainObjIsActive(vm)) {
-        VIR_DEBUG("Ignoring GUEST_PANICKED event from inactive domain %s",
-                  vm->def->name);
-        goto endjob;
-    }
-
-    if (info)
-        qemuProcessGuestPanicEventInfo(driver, vm, info);
-
-    virDomainObjSetState(vm, VIR_DOMAIN_CRASHED, VIR_DOMAIN_CRASHED_PANICKED);
-
-    event = virDomainEventLifecycleNewFromObj(vm,
-                                              VIR_DOMAIN_EVENT_CRASHED,
-                                              VIR_DOMAIN_EVENT_CRASHED_PANICKED);
-
-    qemuDomainEventQueue(driver, event);
-
-    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) {
-        VIR_WARN("Unable to save status on vm %s after state change",
-                 vm->def->name);
-    }
-
-    if (virDomainLockProcessPause(driver->lockManager, vm, &priv->lockState) < 0)
-        VIR_WARN("Unable to release lease on %s", vm->def->name);
-    VIR_DEBUG("Preserving lock state '%s'", NULLSTR(priv->lockState));
-
-    switch (action) {
-    case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_DESTROY:
-        if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0)
-            goto endjob;
-        ATTRIBUTE_FALLTHROUGH;
-
-    case VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY:
-        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED,
-                        QEMU_ASYNC_JOB_DUMP, 0);
-        event = virDomainEventLifecycleNewFromObj(vm,
-                                                  VIR_DOMAIN_EVENT_STOPPED,
-                                                  VIR_DOMAIN_EVENT_STOPPED_CRASHED);
-
-        qemuDomainEventQueue(driver, event);
-        virDomainAuditStop(vm, "destroyed");
-        removeInactive = true;
-        break;
-
-    case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_RESTART:
-        if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0)
-            goto endjob;
-        ATTRIBUTE_FALLTHROUGH;
-
-    case VIR_DOMAIN_LIFECYCLE_CRASH_RESTART:
-        qemuDomainSetFakeReboot(driver, vm, true);
-        qemuProcessShutdownOrReboot(driver, vm);
-        break;
-
-    case VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE:
-        break;
-
-    default:
-        break;
-    }
-
- endjob:
-    qemuDomainObjEndAsyncJob(driver, vm);
-    if (removeInactive)
-        qemuDomainRemoveInactiveJob(driver, vm);
-
- cleanup:
-    virObjectUnref(cfg);
-}
-
-
-static void
-processDeviceDeletedEvent(virQEMUDriverPtr driver,
-                          virDomainObjPtr vm,
-                          char *devAlias)
-{
-    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-    virDomainDeviceDef dev;
-
-    VIR_DEBUG("Removing device %s from domain %p %s",
-              devAlias, vm, vm->def->name);
-
-    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
-        goto cleanup;
-
-    if (!virDomainObjIsActive(vm)) {
-        VIR_DEBUG("Domain is not running");
-        goto endjob;
-    }
-
-    if (STRPREFIX(devAlias, "vcpu")) {
-        qemuDomainRemoveVcpuAlias(driver, vm, devAlias);
-    } else {
-        if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
-            goto endjob;
-
-        if (qemuDomainRemoveDevice(driver, vm, &dev) < 0)
-            goto endjob;
-    }
-
-    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
-        VIR_WARN("unable to save domain status after removing device %s",
-                 devAlias);
-
- endjob:
-    qemuDomainObjEndJob(driver, vm);
-
- cleanup:
-    VIR_FREE(devAlias);
-    virObjectUnref(cfg);
-}
-
-
-static void
-syncNicRxFilterMacAddr(char *ifname, virNetDevRxFilterPtr guestFilter,
-                       virNetDevRxFilterPtr hostFilter)
-{
-    char newMacStr[VIR_MAC_STRING_BUFLEN];
-
-    if (virMacAddrCmp(&hostFilter->mac, &guestFilter->mac)) {
-        virMacAddrFormat(&guestFilter->mac, newMacStr);
-
-        /* set new MAC address from guest to associated macvtap device */
-        if (virNetDevSetMAC(ifname, &guestFilter->mac) < 0) {
-            VIR_WARN("Couldn't set new MAC address %s to device %s "
-                     "while responding to NIC_RX_FILTER_CHANGED",
-                     newMacStr, ifname);
-        } else {
-            VIR_DEBUG("device %s MAC address set to %s", ifname, newMacStr);
-        }
-    }
-}
-
-
-static void
-syncNicRxFilterGuestMulticast(char *ifname, virNetDevRxFilterPtr guestFilter,
-                              virNetDevRxFilterPtr hostFilter)
-{
-    size_t i, j;
-    bool found;
-    char macstr[VIR_MAC_STRING_BUFLEN];
-
-    for (i = 0; i < guestFilter->multicast.nTable; i++) {
-        found = false;
-
-        for (j = 0; j < hostFilter->multicast.nTable; j++) {
-            if (virMacAddrCmp(&guestFilter->multicast.table[i],
-                              &hostFilter->multicast.table[j]) == 0) {
-                found = true;
-                break;
-            }
-        }
-
-        if (!found) {
-            virMacAddrFormat(&guestFilter->multicast.table[i], macstr);
-
-            if (virNetDevAddMulti(ifname, &guestFilter->multicast.table[i]) < 0) {
-                VIR_WARN("Couldn't add new multicast MAC address %s to "
-                         "device %s while responding to NIC_RX_FILTER_CHANGED",
-                         macstr, ifname);
-            } else {
-                VIR_DEBUG("Added multicast MAC %s to %s interface",
-                          macstr, ifname);
-            }
-        }
-    }
-}
-
-
-static void
-syncNicRxFilterHostMulticast(char *ifname, virNetDevRxFilterPtr guestFilter,
-                             virNetDevRxFilterPtr hostFilter)
-{
-    size_t i, j;
-    bool found;
-    char macstr[VIR_MAC_STRING_BUFLEN];
-
-    for (i = 0; i < hostFilter->multicast.nTable; i++) {
-        found = false;
-
-        for (j = 0; j < guestFilter->multicast.nTable; j++) {
-            if (virMacAddrCmp(&hostFilter->multicast.table[i],
-                              &guestFilter->multicast.table[j]) == 0) {
-                found = true;
-                break;
-            }
-        }
-
-        if (!found) {
-            virMacAddrFormat(&hostFilter->multicast.table[i], macstr);
-
-            if (virNetDevDelMulti(ifname, &hostFilter->multicast.table[i]) < 0) {
-                VIR_WARN("Couldn't delete multicast MAC address %s from "
-                         "device %s while responding to NIC_RX_FILTER_CHANGED",
-                         macstr, ifname);
-            } else {
-                VIR_DEBUG("Deleted multicast MAC %s from %s interface",
-                          macstr, ifname);
-            }
-        }
-    }
-}
-
-
-static void
-syncNicRxFilterPromiscMode(char *ifname,
-                           virNetDevRxFilterPtr guestFilter,
-                           virNetDevRxFilterPtr hostFilter)
-{
-    bool promisc;
-    bool setpromisc = false;
-
-    /* Set macvtap promisc mode to true if the guest has vlans defined */
-    /* or synchronize the macvtap promisc mode if different from guest */
-    if (guestFilter->vlan.nTable > 0) {
-        if (!hostFilter->promiscuous) {
-            setpromisc = true;
-            promisc = true;
-        }
-    } else if (hostFilter->promiscuous != guestFilter->promiscuous) {
-        setpromisc = true;
-        promisc = guestFilter->promiscuous;
-    }
-
-    if (setpromisc) {
-        if (virNetDevSetPromiscuous(ifname, promisc) < 0) {
-            VIR_WARN("Couldn't set PROMISC flag to %s for device %s "
-                     "while responding to NIC_RX_FILTER_CHANGED",
-                     promisc ? "true" : "false", ifname);
-        }
-    }
-}
-
-
-static void
-syncNicRxFilterMultiMode(char *ifname, virNetDevRxFilterPtr guestFilter,
-                         virNetDevRxFilterPtr hostFilter)
-{
-    if (hostFilter->multicast.mode != guestFilter->multicast.mode) {
-        switch (guestFilter->multicast.mode) {
-            case VIR_NETDEV_RX_FILTER_MODE_ALL:
-                if (virNetDevSetRcvAllMulti(ifname, true)) {
-
-                    VIR_WARN("Couldn't set allmulticast flag to 'on' for "
-                             "device %s while responding to "
-                             "NIC_RX_FILTER_CHANGED", ifname);
-                }
-                break;
-
-            case VIR_NETDEV_RX_FILTER_MODE_NORMAL:
-                if (virNetDevSetRcvMulti(ifname, true)) {
-
-                    VIR_WARN("Couldn't set multicast flag to 'on' for "
-                             "device %s while responding to "
-                             "NIC_RX_FILTER_CHANGED", ifname);
-                }
-
-                if (virNetDevSetRcvAllMulti(ifname, false)) {
-                    VIR_WARN("Couldn't set allmulticast flag to 'off' for "
-                             "device %s while responding to "
-                             "NIC_RX_FILTER_CHANGED", ifname);
-                }
-                break;
-
-            case VIR_NETDEV_RX_FILTER_MODE_NONE:
-                if (virNetDevSetRcvAllMulti(ifname, false)) {
-                    VIR_WARN("Couldn't set allmulticast flag to 'off' for "
-                             "device %s while responding to "
-                             "NIC_RX_FILTER_CHANGED", ifname);
-                }
-
-                if (virNetDevSetRcvMulti(ifname, false)) {
-                    VIR_WARN("Couldn't set multicast flag to 'off' for "
-                             "device %s while responding to "
-                             "NIC_RX_FILTER_CHANGED",
-                             ifname);
-                }
-                break;
-        }
-    }
-}
-
-
-static void
-syncNicRxFilterDeviceOptions(char *ifname, virNetDevRxFilterPtr guestFilter,
-                           virNetDevRxFilterPtr hostFilter)
-{
-    syncNicRxFilterPromiscMode(ifname, guestFilter, hostFilter);
-    syncNicRxFilterMultiMode(ifname, guestFilter, hostFilter);
-}
-
-
-static void
-syncNicRxFilterMulticast(char *ifname,
-                         virNetDevRxFilterPtr guestFilter,
-                         virNetDevRxFilterPtr hostFilter)
-{
-    syncNicRxFilterGuestMulticast(ifname, guestFilter, hostFilter);
-    syncNicRxFilterHostMulticast(ifname, guestFilter, hostFilter);
-}
-
-static void
-processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
-                               virDomainObjPtr vm,
-                               char *devAlias)
-{
-    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-    qemuDomainObjPrivatePtr priv = vm->privateData;
-    virDomainDeviceDef dev;
-    virDomainNetDefPtr def;
-    virNetDevRxFilterPtr guestFilter = NULL;
-    virNetDevRxFilterPtr hostFilter = NULL;
-    int ret;
-
-    VIR_DEBUG("Received NIC_RX_FILTER_CHANGED event for device %s "
-              "from domain %p %s",
-              devAlias, vm, vm->def->name);
-
-    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
-        goto cleanup;
-
-    if (!virDomainObjIsActive(vm)) {
-        VIR_DEBUG("Domain is not running");
-        goto endjob;
-    }
-
-    if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0) {
-        VIR_WARN("NIC_RX_FILTER_CHANGED event received for "
-                 "non-existent device %s in domain %s",
-                 devAlias, vm->def->name);
-        goto endjob;
-    }
-    if (dev.type != VIR_DOMAIN_DEVICE_NET) {
-        VIR_WARN("NIC_RX_FILTER_CHANGED event received for "
-                 "non-network device %s in domain %s",
-                 devAlias, vm->def->name);
-        goto endjob;
-    }
-    def = dev.data.net;
-
-    if (!virDomainNetGetActualTrustGuestRxFilters(def)) {
-        VIR_DEBUG("ignore NIC_RX_FILTER_CHANGED event for network "
-                  "device %s in domain %s",
-                  def->info.alias, vm->def->name);
-        /* not sending "query-rx-filter" will also suppress any
-         * further NIC_RX_FILTER_CHANGED events for this device
-         */
-        goto endjob;
-    }
-
-    /* handle the event - send query-rx-filter and respond to it. */
-
-    VIR_DEBUG("process NIC_RX_FILTER_CHANGED event for network "
-              "device %s in domain %s", def->info.alias, vm->def->name);
-
-    qemuDomainObjEnterMonitor(driver, vm);
-    ret = qemuMonitorQueryRxFilter(priv->mon, devAlias, &guestFilter);
-    if (qemuDomainObjExitMonitor(driver, vm) < 0)
-        ret = -1;
-    if (ret < 0)
-        goto endjob;
-
-    if (virDomainNetGetActualType(def) == VIR_DOMAIN_NET_TYPE_DIRECT) {
-
-        if (virNetDevGetRxFilter(def->ifname, &hostFilter)) {
-            VIR_WARN("Couldn't get current RX filter for device %s "
-                     "while responding to NIC_RX_FILTER_CHANGED",
-                     def->ifname);
-            goto endjob;
-        }
-
-        /* For macvtap connections, set the following macvtap network device
-         * attributes to match those of the guest network device:
-         * - MAC address
-         * - Multicast MAC address table
-         * - Device options:
-         *   - PROMISC
-         *   - MULTICAST
-         *   - ALLMULTI
-         */
-        syncNicRxFilterMacAddr(def->ifname, guestFilter, hostFilter);
-        syncNicRxFilterMulticast(def->ifname, guestFilter, hostFilter);
-        syncNicRxFilterDeviceOptions(def->ifname, guestFilter, hostFilter);
-    }
-
-    if (virDomainNetGetActualType(def) == VIR_DOMAIN_NET_TYPE_NETWORK) {
-        const char *brname = virDomainNetGetActualBridgeName(def);
-
-        /* For libivrt network connections, set the following TUN/TAP network
-         * device attributes to match those of the guest network device:
-         * - QoS filters (which are based on MAC address)
-         */
-        if (virDomainNetGetActualBandwidth(def) &&
-            def->data.network.actual &&
-            virNetDevBandwidthUpdateFilter(brname, &guestFilter->mac,
-                                           def->data.network.actual->class_id) < 0)
-            goto endjob;
-    }
-
- endjob:
-    qemuDomainObjEndJob(driver, vm);
-
- cleanup:
-    virNetDevRxFilterFree(hostFilter);
-    virNetDevRxFilterFree(guestFilter);
-    VIR_FREE(devAlias);
-    virObjectUnref(cfg);
-}
-
-
-static void
-processSerialChangedEvent(virQEMUDriverPtr driver,
-                          virDomainObjPtr vm,
-                          char *devAlias,
-                          bool connected)
-{
-    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-    virDomainChrDeviceState newstate;
-    virObjectEventPtr event = NULL;
-    virDomainDeviceDef dev;
-    qemuDomainObjPrivatePtr priv = vm->privateData;
-
-    if (connected)
-        newstate = VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED;
-    else
-        newstate = VIR_DOMAIN_CHR_DEVICE_STATE_DISCONNECTED;
-
-    VIR_DEBUG("Changing serial port state %s in domain %p %s",
-              devAlias, vm, vm->def->name);
-
-    if (newstate == VIR_DOMAIN_CHR_DEVICE_STATE_DISCONNECTED &&
-        virDomainObjIsActive(vm) && priv->agent) {
-        /* peek into the domain definition to find the channel */
-        if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) == 0 &&
-            dev.type == VIR_DOMAIN_DEVICE_CHR &&
-            dev.data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
-            dev.data.chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO &&
-            STREQ_NULLABLE(dev.data.chr->target.name, "org.qemu.guest_agent.0"))
-            /* Close agent monitor early, so that other threads
-             * waiting for the agent to reply can finish and our
-             * job we acquire below can succeed. */
-            qemuAgentNotifyClose(priv->agent);
-
-        /* now discard the data, since it may possibly change once we unlock
-         * while entering the job */
-        memset(&dev, 0, sizeof(dev));
-    }
-
-    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
-        goto cleanup;
-
-    if (!virDomainObjIsActive(vm)) {
-        VIR_DEBUG("Domain is not running");
-        goto endjob;
-    }
-
-    if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
-        goto endjob;
-
-    /* we care only about certain devices */
-    if (dev.type != VIR_DOMAIN_DEVICE_CHR ||
-        dev.data.chr->deviceType != VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL ||
-        dev.data.chr->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO)
-        goto endjob;
-
-    dev.data.chr->state = newstate;
-
-    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
-        VIR_WARN("unable to save status of domain %s after updating state of "
-                 "channel %s", vm->def->name, devAlias);
-
-    if (STREQ_NULLABLE(dev.data.chr->target.name, "org.qemu.guest_agent.0")) {
-        if (newstate == VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED) {
-            if (qemuConnectAgent(driver, vm) < 0)
-                goto endjob;
-        } else {
-            if (priv->agent) {
-                qemuAgentClose(priv->agent);
-                priv->agent = NULL;
-            }
-            priv->agentError = false;
-        }
-
-        event = virDomainEventAgentLifecycleNewFromObj(vm, newstate,
-                                                       VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_CHANNEL);
-        qemuDomainEventQueue(driver, event);
-    }
-
- endjob:
-    qemuDomainObjEndJob(driver, vm);
-
- cleanup:
-    VIR_FREE(devAlias);
-    virObjectUnref(cfg);
-
-}
-
-
-static void
-processBlockJobEvent(virQEMUDriverPtr driver,
-                     virDomainObjPtr vm,
-                     char *diskAlias,
-                     int type,
-                     int status)
-{
-    virDomainDiskDefPtr disk;
-
-    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
-        goto cleanup;
-
-    if (!virDomainObjIsActive(vm)) {
-        VIR_DEBUG("Domain is not running");
-        goto endjob;
-    }
-
-    if ((disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias)))
-        qemuBlockJobEventProcess(driver, vm, disk, QEMU_ASYNC_JOB_NONE, type, status);
-
- endjob:
-    qemuDomainObjEndJob(driver, vm);
- cleanup:
-    VIR_FREE(diskAlias);
-}
-
-
-static void
-processMonitorEOFEvent(virQEMUDriverPtr driver,
-                       virDomainObjPtr vm)
-{
-    qemuDomainObjPrivatePtr priv = vm->privateData;
-    int eventReason = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
-    int stopReason = VIR_DOMAIN_SHUTOFF_SHUTDOWN;
-    const char *auditReason = "shutdown";
-    unsigned int stopFlags = 0;
-    virObjectEventPtr event = NULL;
-
-    if (qemuProcessBeginStopJob(driver, vm, QEMU_JOB_DESTROY, true) < 0)
-        return;
-
-    if (!virDomainObjIsActive(vm)) {
-        VIR_DEBUG("Domain %p '%s' is not active, ignoring EOF",
-                  vm, vm->def->name);
-        goto endjob;
-    }
-
-    if (priv->monJSON && !priv->gotShutdown) {
-        VIR_DEBUG("Monitor connection to '%s' closed without SHUTDOWN event; "
-                  "assuming the domain crashed", vm->def->name);
-        eventReason = VIR_DOMAIN_EVENT_STOPPED_FAILED;
-        stopReason = VIR_DOMAIN_SHUTOFF_CRASHED;
-        auditReason = "failed";
-    }
-
-    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
-        stopFlags |= VIR_QEMU_PROCESS_STOP_MIGRATED;
-        qemuMigrationErrorSave(driver, vm->def->name,
-                               qemuMonitorLastError(priv->mon));
-    }
-
-    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
-                                              eventReason);
-    qemuProcessStop(driver, vm, stopReason, QEMU_ASYNC_JOB_NONE, stopFlags);
-    virDomainAuditStop(vm, auditReason);
-    qemuDomainEventQueue(driver, event);
-
- endjob:
-    qemuDomainRemoveInactive(driver, vm);
-    qemuDomainObjEndJob(driver, vm);
-}
 
 
 static void qemuProcessEventHandler(void *data, void *opaque)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index ee8bae5..d2b5fe8 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -36,6 +36,7 @@
 #include "qemu_processpriv.h"
 #include "qemu_alias.h"
 #include "qemu_block.h"
+#include "qemu_blockjob.h"
 #include "qemu_domain.h"
 #include "qemu_domain_address.h"
 #include "qemu_cgroup.h"
@@ -87,6 +88,18 @@ typedef struct {
     void (*handler_func)(qemuEventPtr ev, void *opaque);
 } qemuEventFuncTable;
 
+VIR_ENUM_IMPL(qemuSaveCompression, QEMU_SAVE_FORMAT_LAST,
+              "raw",
+              "gzip",
+              "bzip2",
+              "xz",
+              "lzop")
+
+VIR_ENUM_IMPL(qemuDumpFormat, VIR_DOMAIN_CORE_DUMP_FORMAT_LAST,
+              "elf",
+              "kdump-zlib",
+              "kdump-lzo",
+              "kdump-snappy")
 
 /**
  * qemuProcessRemoveDomainStatus
@@ -7458,3 +7471,1123 @@ qemuProcessReconnectAll(virConnectPtr conn, virQEMUDriverPtr driver)
     struct qemuProcessReconnectData data = {.conn = conn, .driver = driver};
     virDomainObjListForEach(driver->domains, qemuProcessReconnectHelper, &data);
 }
+
+static int
+qemuOpenFileAs(uid_t fallback_uid, gid_t fallback_gid,
+               bool dynamicOwnership,
+               const char *path, int oflags,
+               bool *needUnlink, bool *bypassSecurityDriver)
+{
+    struct stat sb;
+    bool is_reg = true;
+    bool need_unlink = false;
+    bool bypass_security = false;
+    unsigned int vfoflags = 0;
+    int fd = -1;
+    int path_shared = virFileIsSharedFS(path);
+    uid_t uid = geteuid();
+    gid_t gid = getegid();
+
+    /* path might be a pre-existing block dev, in which case
+     * we need to skip the create step, and also avoid unlink
+     * in the failure case */
+    if (oflags & O_CREAT) {
+        need_unlink = true;
+
+        /* Don't force chown on network-shared FS
+         * as it is likely to fail. */
+        if (path_shared <= 0 || dynamicOwnership)
+            vfoflags |= VIR_FILE_OPEN_FORCE_OWNER;
+
+        if (stat(path, &sb) == 0) {
+            /* It already exists, we don't want to delete it on error */
+            need_unlink = false;
+
+            is_reg = !!S_ISREG(sb.st_mode);
+            /* If the path is regular file which exists
+             * already and dynamic_ownership is off, we don't
+             * want to change its ownership, just open it as-is */
+            if (is_reg && !dynamicOwnership) {
+                uid = sb.st_uid;
+                gid = sb.st_gid;
+            }
+        }
+    }
+
+    /* First try creating the file as root */
+    if (!is_reg) {
+        if ((fd = open(path, oflags & ~O_CREAT)) < 0) {
+            fd = -errno;
+            goto error;
+        }
+    } else {
+        if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
+                                vfoflags | VIR_FILE_OPEN_NOFORK)) < 0) {
+            /* If we failed as root, and the error was permission-denied
+               (EACCES or EPERM), assume it's on a network-connected share
+               where root access is restricted (eg, root-squashed NFS). If the
+               qemu user is non-root, just set a flag to
+               bypass security driver shenanigans, and retry the operation
+               after doing setuid to qemu user */
+            if ((fd != -EACCES && fd != -EPERM) || fallback_uid == geteuid())
+                goto error;
+
+            /* On Linux we can also verify the FS-type of the directory. */
+            switch (path_shared) {
+                case 1:
+                    /* it was on a network share, so we'll continue
+                     * as outlined above
+                     */
+                    break;
+
+                case -1:
+                    virReportSystemError(-fd, oflags & O_CREAT
+                                         ? _("Failed to create file "
+                                             "'%s': couldn't determine fs type")
+                                         : _("Failed to open file "
+                                             "'%s': couldn't determine fs type"),
+                                         path);
+                    goto cleanup;
+
+                case 0:
+                default:
+                    /* local file - log the error returned by virFileOpenAs */
+                    goto error;
+            }
+
+            /* If we created the file above, then we need to remove it;
+             * otherwise, the next attempt to create will fail. If the
+             * file had already existed before we got here, then we also
+             * don't want to delete it and allow the following to succeed
+             * or fail based on existing protections
+             */
+            if (need_unlink)
+                unlink(path);
+
+            /* Retry creating the file as qemu user */
+
+            /* Since we're passing different modes... */
+            vfoflags |= VIR_FILE_OPEN_FORCE_MODE;
+
+            if ((fd = virFileOpenAs(path, oflags,
+                                    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
+                                    fallback_uid, fallback_gid,
+                                    vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
+                virReportSystemError(-fd, oflags & O_CREAT
+                                     ? _("Error from child process creating '%s'")
+                                     : _("Error from child process opening '%s'"),
+                                     path);
+                goto cleanup;
+            }
+
+            /* Since we had to setuid to create the file, and the fstype
+               is NFS, we assume it's a root-squashing NFS share, and that
+               the security driver stuff would have failed anyway */
+
+            bypass_security = true;
+        }
+    }
+ cleanup:
+    if (needUnlink)
+        *needUnlink = need_unlink;
+    if (bypassSecurityDriver)
+        *bypassSecurityDriver = bypass_security;
+    return fd;
+
+ error:
+    virReportSystemError(-fd, oflags & O_CREAT
+                         ? _("Failed to create file '%s'")
+                         : _("Failed to open file '%s'"),
+                         path);
+    goto cleanup;
+}
+
+/**
+ * qemuOpenFile:
+ * @driver: driver object
+ * @vm: domain object
+ * @path: path to file to open
+ * @oflags: flags for opening/creation of the file
+ * @needUnlink: set to true if file was created by this function
+ * @bypassSecurityDriver: optional pointer to a boolean that will be set to true
+ *                        if security driver operations are pointless (due to
+ *                        NFS mount)
+ *
+ * Internal function to properly create or open existing files, with
+ * ownership affected by qemu driver setup and domain DAC label.
+ *
+ * Returns the file descriptor on success and negative errno on failure.
+ *
+ * This function should not be used on storage sources. Use
+ * qemuDomainStorageFileInit and storage driver APIs if possible.
+ **/
+int
+qemuOpenFile(virQEMUDriverPtr driver,
+             virDomainObjPtr vm,
+             const char *path,
+             int oflags,
+             bool *needUnlink,
+             bool *bypassSecurityDriver)
+{
+    int ret = -1;
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    uid_t user = cfg->user;
+    gid_t group = cfg->group;
+    bool dynamicOwnership = cfg->dynamicOwnership;
+    virSecurityLabelDefPtr seclabel;
+
+    virObjectUnref(cfg);
+
+    /* TODO: Take imagelabel into account? */
+    if (vm &&
+        (seclabel = virDomainDefGetSecurityLabelDef(vm->def, "dac")) != NULL &&
+        seclabel->label != NULL &&
+        (virParseOwnershipIds(seclabel->label, &user, &group) < 0))
+        goto cleanup;
+
+    ret = qemuOpenFileAs(user, group, dynamicOwnership,
+                         path, oflags, needUnlink, bypassSecurityDriver);
+
+ cleanup:
+    return ret;
+}
+
+/* qemuGetCompressionProgram:
+ * @imageFormat: String representation from qemu.conf for the compression
+ *               image format being used (dump, save, or snapshot).
+ * @compresspath: Pointer to a character string to store the fully qualified
+ *                path from virFindFileInPath.
+ * @styleFormat: String representing the style of format (dump, save, snapshot)
+ * @use_raw_on_fail: Boolean indicating how to handle the error path. For
+ *                   callers that are OK with invalid data or inability to
+ *                   find the compression program, just return a raw format
+ *                   and let the path remain as NULL.
+ *
+ * Returns:
+ *    virQEMUSaveFormat    - Integer representation of the compression
+ *                           program to be used for particular style
+ *                           (e.g. dump, save, or snapshot).
+ *    QEMU_SAVE_FORMAT_RAW - If there is no qemu.conf imageFormat value or
+ *                           no there was an error, then just return RAW
+ *                           indicating none.
+ **/
+int ATTRIBUTE_NONNULL(2)
+qemuGetCompressionProgram(const char *imageFormat,
+                          char **compresspath,
+                          const char *styleFormat,
+                          bool use_raw_on_fail)
+{
+    int ret;
+
+    *compresspath = NULL;
+
+    if (!imageFormat)
+        return QEMU_SAVE_FORMAT_RAW;
+
+    if ((ret = qemuSaveCompressionTypeFromString(imageFormat)) < 0)
+        goto error;
+
+    if (ret == QEMU_SAVE_FORMAT_RAW)
+        return QEMU_SAVE_FORMAT_RAW;
+
+    if (!(*compresspath = virFindFileInPath(imageFormat)))
+        goto error;
+
+    return ret;
+
+ error:
+    if (ret < 0) {
+        if (use_raw_on_fail)
+            VIR_WARN("Invalid %s image format specified in "
+                     "configuration file, using raw",
+                     styleFormat);
+        else
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("Invalid %s image format specified "
+                             "in configuration file"),
+                           styleFormat);
+    } else {
+        if (use_raw_on_fail)
+            VIR_WARN("Compression program for %s image format in "
+                     "configuration file isn't available, using raw",
+                     styleFormat);
+        else
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("Compression program for %s image format "
+                             "in configuration file isn't available"),
+                           styleFormat);
+    }
+
+    /* Use "raw" as the format if the specified format is not valid,
+     * or the compress program is not available. */
+    if (use_raw_on_fail)
+        return QEMU_SAVE_FORMAT_RAW;
+
+    return -1;
+}
+
+
+static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm,
+                        int fd, qemuDomainAsyncJob asyncJob,
+                        const char *dumpformat)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    int ret = -1;
+
+    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("dump-guest-memory is not supported"));
+        return -1;
+    }
+
+    if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, fd) < 0)
+        return -1;
+
+    VIR_FREE(priv->job.current);
+    priv->job.dump_memory_only = true;
+
+    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+        return -1;
+
+    if (dumpformat) {
+        ret = qemuMonitorGetDumpGuestMemoryCapability(priv->mon, dumpformat);
+
+        if (ret <= 0) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("unsupported dumpformat '%s' "
+                             "for this QEMU binary"),
+                           dumpformat);
+            ret = -1;
+            goto cleanup;
+        }
+    }
+
+    ret = qemuMonitorDumpToFd(priv->mon, fd, dumpformat);
+
+ cleanup:
+    ignore_value(qemuDomainObjExitMonitor(driver, vm));
+
+    return ret;
+}
+
+int
+doCoreDump(virQEMUDriverPtr driver,
+           virDomainObjPtr vm,
+           const char *path,
+           unsigned int dump_flags,
+           unsigned int dumpformat)
+{
+    int fd = -1;
+    int ret = -1;
+    virFileWrapperFdPtr wrapperFd = NULL;
+    int directFlag = 0;
+    unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
+    const char *memory_dump_format = NULL;
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    char *compressedpath = NULL;
+
+    /* We reuse "save" flag for "dump" here. Then, we can support the same
+     * format in "save" and "dump". This path doesn't need the compression
+     * program to exist and can ignore the return value - it only cares to
+     * get the compressedpath */
+    ignore_value(qemuGetCompressionProgram(cfg->dumpImageFormat,
+                                           &compressedpath,
+                                           "dump", true));
+
+    /* Create an empty file with appropriate ownership.  */
+    if (dump_flags & VIR_DUMP_BYPASS_CACHE) {
+        flags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
+        directFlag = virFileDirectFdFlag();
+        if (directFlag < 0) {
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("bypass cache unsupported by this system"));
+            goto cleanup;
+        }
+    }
+    /* Core dumps usually imply last-ditch analysis efforts are
+     * desired, so we intentionally do not unlink even if a file was
+     * created.  */
+    if ((fd = qemuOpenFile(driver, vm, path,
+                           O_CREAT | O_TRUNC | O_WRONLY | directFlag,
+                           NULL, NULL)) < 0)
+        goto cleanup;
+
+    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags)))
+        goto cleanup;
+
+    if (dump_flags & VIR_DUMP_MEMORY_ONLY) {
+        if (!(memory_dump_format = qemuDumpFormatTypeToString(dumpformat))) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("unknown dumpformat '%d'"), dumpformat);
+            goto cleanup;
+        }
+
+        /* qemu dumps in "elf" without dumpformat set */
+        if (STREQ(memory_dump_format, "elf"))
+            memory_dump_format = NULL;
+
+        ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP,
+                           memory_dump_format);
+    } else {
+        if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
+            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                           _("kdump-compressed format is only supported with "
+                             "memory-only dump"));
+            goto cleanup;
+        }
+
+        if (!qemuMigrationIsAllowed(driver, vm, false, 0))
+            goto cleanup;
+
+        ret = qemuMigrationToFile(driver, vm, fd, compressedpath,
+                                  QEMU_ASYNC_JOB_DUMP);
+    }
+
+    if (ret < 0)
+        goto cleanup;
+
+    if (VIR_CLOSE(fd) < 0) {
+        virReportSystemError(errno,
+                             _("unable to close file %s"),
+                             path);
+        goto cleanup;
+    }
+    if (qemuFileWrapperFDClose(vm, wrapperFd) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    VIR_FORCE_CLOSE(fd);
+    if (ret != 0)
+        unlink(path);
+    virFileWrapperFdFree(wrapperFd);
+    VIR_FREE(compressedpath);
+    virObjectUnref(cfg);
+    return ret;
+}
+
+int
+qemuFileWrapperFDClose(virDomainObjPtr vm,
+                       virFileWrapperFdPtr fd)
+{
+    int ret;
+
+    /* virFileWrapperFd uses iohelper to write data onto disk.
+     * However, iohelper calls fdatasync() which may take ages to
+     * finish. Therefore, we shouldn't be waiting with the domain
+     * object locked. */
+
+    /* XXX Currently, this function is intended for *Save() only
+     * as restore needs some reworking before it's ready for
+     * this. */
+
+    virObjectUnlock(vm);
+    ret = virFileWrapperFdClose(fd);
+    virObjectLock(vm);
+    if (!virDomainObjIsActive(vm)) {
+        if (!virGetLastError())
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("domain is no longer running"));
+        ret = -1;
+    }
+    return ret;
+}
+
+static char *
+getAutoDumpPath(virQEMUDriverPtr driver,
+                virDomainObjPtr vm)
+{
+    char *dumpfile = NULL;
+    char *domname = virDomainObjGetShortName(vm->def);
+    char timestr[100];
+    struct tm time_info;
+    time_t curtime = time(NULL);
+    virQEMUDriverConfigPtr cfg = NULL;
+
+    if (!domname)
+        return NULL;
+
+    cfg = virQEMUDriverGetConfig(driver);
+
+    localtime_r(&curtime, &time_info);
+    strftime(timestr, sizeof(timestr), "%Y-%m-%d-%H:%M:%S", &time_info);
+
+    ignore_value(virAsprintf(&dumpfile, "%s/%s-%s",
+                             cfg->autoDumpPath,
+                             domname,
+                             timestr));
+
+    virObjectUnref(cfg);
+    VIR_FREE(domname);
+    return dumpfile;
+}
+void
+processWatchdogEvent(virQEMUDriverPtr driver,
+                     virDomainObjPtr vm,
+                     int action)
+{
+    int ret;
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    char *dumpfile = getAutoDumpPath(driver, vm);
+    unsigned int flags = VIR_DUMP_MEMORY_ONLY;
+
+    if (!dumpfile)
+        goto cleanup;
+
+    switch (action) {
+    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
+        if (qemuDomainObjBeginAsyncJob(driver, vm,
+                                       QEMU_ASYNC_JOB_DUMP,
+                                       VIR_DOMAIN_JOB_OPERATION_DUMP) < 0) {
+            goto cleanup;
+        }
+
+        if (!virDomainObjIsActive(vm)) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           "%s", _("domain is not running"));
+            goto endjob;
+        }
+
+        flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
+        if ((ret = doCoreDump(driver, vm, dumpfile, flags,
+                              VIR_DOMAIN_CORE_DUMP_FORMAT_RAW)) < 0)
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           "%s", _("Dump failed"));
+
+        ret = qemuProcessStartCPUs(driver, vm, NULL,
+                                   VIR_DOMAIN_RUNNING_UNPAUSED,
+                                   QEMU_ASYNC_JOB_DUMP);
+
+        if (ret < 0)
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           "%s", _("Resuming after dump failed"));
+        break;
+    default:
+        goto cleanup;
+    }
+
+ endjob:
+    qemuDomainObjEndAsyncJob(driver, vm);
+
+ cleanup:
+    VIR_FREE(dumpfile);
+    virObjectUnref(cfg);
+}
+
+static int
+doCoreDumpToAutoDumpPath(virQEMUDriverPtr driver,
+                         virDomainObjPtr vm,
+                         unsigned int flags)
+{
+    int ret = -1;
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    char *dumpfile = getAutoDumpPath(driver, vm);
+
+    if (!dumpfile)
+        goto cleanup;
+
+    flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
+    if ((ret = doCoreDump(driver, vm, dumpfile, flags,
+                          VIR_DOMAIN_CORE_DUMP_FORMAT_RAW)) < 0)
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       "%s", _("Dump failed"));
+ cleanup:
+    VIR_FREE(dumpfile);
+    virObjectUnref(cfg);
+    return ret;
+}
+
+static void
+qemuProcessGuestPanicEventInfo(virQEMUDriverPtr driver,
+                               virDomainObjPtr vm,
+                               qemuMonitorEventPanicInfoPtr info)
+{
+    char *msg = qemuMonitorGuestPanicEventInfoFormatMsg(info);
+    char *timestamp = virTimeStringNow();
+
+    if (msg && timestamp)
+        qemuDomainLogAppendMessage(driver, vm, "%s: panic %s\n", timestamp, msg);
+
+    VIR_FREE(timestamp);
+    VIR_FREE(msg);
+}
+
+void
+processGuestPanicEvent(virQEMUDriverPtr driver,
+                       virDomainObjPtr vm,
+                       int action,
+                       qemuMonitorEventPanicInfoPtr info)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virObjectEventPtr event = NULL;
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    bool removeInactive = false;
+
+    if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_DUMP,
+                                   VIR_DOMAIN_JOB_OPERATION_DUMP) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        VIR_DEBUG("Ignoring GUEST_PANICKED event from inactive domain %s",
+                  vm->def->name);
+        goto endjob;
+    }
+
+    if (info)
+        qemuProcessGuestPanicEventInfo(driver, vm, info);
+
+    virDomainObjSetState(vm, VIR_DOMAIN_CRASHED, VIR_DOMAIN_CRASHED_PANICKED);
+
+    event = virDomainEventLifecycleNewFromObj(vm,
+                                              VIR_DOMAIN_EVENT_CRASHED,
+                                              VIR_DOMAIN_EVENT_CRASHED_PANICKED);
+
+    qemuDomainEventQueue(driver, event);
+
+    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) {
+        VIR_WARN("Unable to save status on vm %s after state change",
+                 vm->def->name);
+    }
+
+    if (virDomainLockProcessPause(driver->lockManager, vm, &priv->lockState) < 0)
+        VIR_WARN("Unable to release lease on %s", vm->def->name);
+    VIR_DEBUG("Preserving lock state '%s'", NULLSTR(priv->lockState));
+
+    switch (action) {
+    case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_DESTROY:
+        if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0)
+            goto endjob;
+        ATTRIBUTE_FALLTHROUGH;
+
+    case VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY:
+        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED,
+                        QEMU_ASYNC_JOB_DUMP, 0);
+        event = virDomainEventLifecycleNewFromObj(vm,
+                                                  VIR_DOMAIN_EVENT_STOPPED,
+                                                  VIR_DOMAIN_EVENT_STOPPED_CRASHED);
+
+        qemuDomainEventQueue(driver, event);
+        virDomainAuditStop(vm, "destroyed");
+        removeInactive = true;
+        break;
+
+    case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_RESTART:
+        if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0)
+            goto endjob;
+        ATTRIBUTE_FALLTHROUGH;
+
+    case VIR_DOMAIN_LIFECYCLE_CRASH_RESTART:
+        qemuDomainSetFakeReboot(driver, vm, true);
+        qemuProcessShutdownOrReboot(driver, vm);
+        break;
+
+    case VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE:
+        break;
+
+    default:
+        break;
+    }
+
+ endjob:
+    qemuDomainObjEndAsyncJob(driver, vm);
+    if (removeInactive)
+        qemuDomainRemoveInactiveJob(driver, vm);
+
+ cleanup:
+    virObjectUnref(cfg);
+}
+
+void
+processDeviceDeletedEvent(virQEMUDriverPtr driver,
+                          virDomainObjPtr vm,
+                          char *devAlias)
+{
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainDeviceDef dev;
+
+    VIR_DEBUG("Removing device %s from domain %p %s",
+              devAlias, vm, vm->def->name);
+
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        VIR_DEBUG("Domain is not running");
+        goto endjob;
+    }
+
+    if (STRPREFIX(devAlias, "vcpu")) {
+        qemuDomainRemoveVcpuAlias(driver, vm, devAlias);
+    } else {
+        if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
+            goto endjob;
+
+        if (qemuDomainRemoveDevice(driver, vm, &dev) < 0)
+            goto endjob;
+    }
+
+    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
+        VIR_WARN("unable to save domain status after removing device %s",
+                 devAlias);
+
+ endjob:
+    qemuDomainObjEndJob(driver, vm);
+
+ cleanup:
+    VIR_FREE(devAlias);
+    virObjectUnref(cfg);
+}
+
+
+
+
+void
+syncNicRxFilterMacAddr(char *ifname, virNetDevRxFilterPtr guestFilter,
+                       virNetDevRxFilterPtr hostFilter)
+{
+    char newMacStr[VIR_MAC_STRING_BUFLEN];
+
+    if (virMacAddrCmp(&hostFilter->mac, &guestFilter->mac)) {
+        virMacAddrFormat(&guestFilter->mac, newMacStr);
+
+        /* set new MAC address from guest to associated macvtap device */
+        if (virNetDevSetMAC(ifname, &guestFilter->mac) < 0) {
+            VIR_WARN("Couldn't set new MAC address %s to device %s "
+                     "while responding to NIC_RX_FILTER_CHANGED",
+                     newMacStr, ifname);
+        } else {
+            VIR_DEBUG("device %s MAC address set to %s", ifname, newMacStr);
+        }
+    }
+}
+
+static void
+syncNicRxFilterGuestMulticast(char *ifname, virNetDevRxFilterPtr guestFilter,
+                              virNetDevRxFilterPtr hostFilter)
+{
+    size_t i, j;
+    bool found;
+    char macstr[VIR_MAC_STRING_BUFLEN];
+
+    for (i = 0; i < guestFilter->multicast.nTable; i++) {
+        found = false;
+
+        for (j = 0; j < hostFilter->multicast.nTable; j++) {
+            if (virMacAddrCmp(&guestFilter->multicast.table[i],
+                              &hostFilter->multicast.table[j]) == 0) {
+                found = true;
+                break;
+            }
+        }
+
+        if (!found) {
+            virMacAddrFormat(&guestFilter->multicast.table[i], macstr);
+
+            if (virNetDevAddMulti(ifname, &guestFilter->multicast.table[i]) < 0) {
+                VIR_WARN("Couldn't add new multicast MAC address %s to "
+                         "device %s while responding to NIC_RX_FILTER_CHANGED",
+                         macstr, ifname);
+            } else {
+                VIR_DEBUG("Added multicast MAC %s to %s interface",
+                          macstr, ifname);
+            }
+        }
+    }
+}
+
+static void
+syncNicRxFilterHostMulticast(char *ifname, virNetDevRxFilterPtr guestFilter,
+                             virNetDevRxFilterPtr hostFilter)
+{
+    size_t i, j;
+    bool found;
+    char macstr[VIR_MAC_STRING_BUFLEN];
+
+    for (i = 0; i < hostFilter->multicast.nTable; i++) {
+        found = false;
+
+        for (j = 0; j < guestFilter->multicast.nTable; j++) {
+            if (virMacAddrCmp(&hostFilter->multicast.table[i],
+                              &guestFilter->multicast.table[j]) == 0) {
+                found = true;
+                break;
+            }
+        }
+
+        if (!found) {
+            virMacAddrFormat(&hostFilter->multicast.table[i], macstr);
+
+            if (virNetDevDelMulti(ifname, &hostFilter->multicast.table[i]) < 0) {
+                VIR_WARN("Couldn't delete multicast MAC address %s from "
+                         "device %s while responding to NIC_RX_FILTER_CHANGED",
+                         macstr, ifname);
+            } else {
+                VIR_DEBUG("Deleted multicast MAC %s from %s interface",
+                          macstr, ifname);
+            }
+        }
+    }
+}
+
+
+static void
+syncNicRxFilterPromiscMode(char *ifname,
+                           virNetDevRxFilterPtr guestFilter,
+                           virNetDevRxFilterPtr hostFilter)
+{
+    bool promisc;
+    bool setpromisc = false;
+
+    /* Set macvtap promisc mode to true if the guest has vlans defined */
+    /* or synchronize the macvtap promisc mode if different from guest */
+    if (guestFilter->vlan.nTable > 0) {
+        if (!hostFilter->promiscuous) {
+            setpromisc = true;
+            promisc = true;
+        }
+    } else if (hostFilter->promiscuous != guestFilter->promiscuous) {
+        setpromisc = true;
+        promisc = guestFilter->promiscuous;
+    }
+
+    if (setpromisc) {
+        if (virNetDevSetPromiscuous(ifname, promisc) < 0) {
+            VIR_WARN("Couldn't set PROMISC flag to %s for device %s "
+                     "while responding to NIC_RX_FILTER_CHANGED",
+                     promisc ? "true" : "false", ifname);
+        }
+    }
+}
+
+static void
+syncNicRxFilterMultiMode(char *ifname, virNetDevRxFilterPtr guestFilter,
+                         virNetDevRxFilterPtr hostFilter)
+{
+    if (hostFilter->multicast.mode != guestFilter->multicast.mode) {
+        switch (guestFilter->multicast.mode) {
+            case VIR_NETDEV_RX_FILTER_MODE_ALL:
+                if (virNetDevSetRcvAllMulti(ifname, true)) {
+
+                    VIR_WARN("Couldn't set allmulticast flag to 'on' for "
+                             "device %s while responding to "
+                             "NIC_RX_FILTER_CHANGED", ifname);
+                }
+                break;
+
+            case VIR_NETDEV_RX_FILTER_MODE_NORMAL:
+                if (virNetDevSetRcvMulti(ifname, true)) {
+
+                    VIR_WARN("Couldn't set multicast flag to 'on' for "
+                             "device %s while responding to "
+                             "NIC_RX_FILTER_CHANGED", ifname);
+                }
+
+                if (virNetDevSetRcvAllMulti(ifname, false)) {
+                    VIR_WARN("Couldn't set allmulticast flag to 'off' for "
+                             "device %s while responding to "
+                             "NIC_RX_FILTER_CHANGED", ifname);
+                }
+                break;
+
+            case VIR_NETDEV_RX_FILTER_MODE_NONE:
+                if (virNetDevSetRcvAllMulti(ifname, false)) {
+                    VIR_WARN("Couldn't set allmulticast flag to 'off' for "
+                             "device %s while responding to "
+                             "NIC_RX_FILTER_CHANGED", ifname);
+                }
+
+                if (virNetDevSetRcvMulti(ifname, false)) {
+                    VIR_WARN("Couldn't set multicast flag to 'off' for "
+                             "device %s while responding to "
+                             "NIC_RX_FILTER_CHANGED",
+                             ifname);
+                }
+                break;
+        }
+    }
+}
+
+void
+syncNicRxFilterDeviceOptions(char *ifname, virNetDevRxFilterPtr guestFilter,
+                           virNetDevRxFilterPtr hostFilter)
+{
+    syncNicRxFilterPromiscMode(ifname, guestFilter, hostFilter);
+    syncNicRxFilterMultiMode(ifname, guestFilter, hostFilter);
+}
+
+
+void
+syncNicRxFilterMulticast(char *ifname,
+                         virNetDevRxFilterPtr guestFilter,
+                         virNetDevRxFilterPtr hostFilter)
+{
+    syncNicRxFilterGuestMulticast(ifname, guestFilter, hostFilter);
+    syncNicRxFilterHostMulticast(ifname, guestFilter, hostFilter);
+}
+
+void
+processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
+                               virDomainObjPtr vm,
+                               char *devAlias)
+{
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virDomainDeviceDef dev;
+    virDomainNetDefPtr def;
+    virNetDevRxFilterPtr guestFilter = NULL;
+    virNetDevRxFilterPtr hostFilter = NULL;
+    int ret;
+
+    VIR_DEBUG("Received NIC_RX_FILTER_CHANGED event for device %s "
+              "from domain %p %s",
+              devAlias, vm, vm->def->name);
+
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        VIR_DEBUG("Domain is not running");
+        goto endjob;
+    }
+
+    if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0) {
+        VIR_WARN("NIC_RX_FILTER_CHANGED event received for "
+                 "non-existent device %s in domain %s",
+                 devAlias, vm->def->name);
+        goto endjob;
+    }
+    if (dev.type != VIR_DOMAIN_DEVICE_NET) {
+        VIR_WARN("NIC_RX_FILTER_CHANGED event received for "
+                 "non-network device %s in domain %s",
+                 devAlias, vm->def->name);
+        goto endjob;
+    }
+    def = dev.data.net;
+
+    if (!virDomainNetGetActualTrustGuestRxFilters(def)) {
+        VIR_DEBUG("ignore NIC_RX_FILTER_CHANGED event for network "
+                  "device %s in domain %s",
+                  def->info.alias, vm->def->name);
+        /* not sending "query-rx-filter" will also suppress any
+         * further NIC_RX_FILTER_CHANGED events for this device
+         */
+        goto endjob;
+    }
+
+    /* handle the event - send query-rx-filter and respond to it. */
+
+    VIR_DEBUG("process NIC_RX_FILTER_CHANGED event for network "
+              "device %s in domain %s", def->info.alias, vm->def->name);
+
+    qemuDomainObjEnterMonitor(driver, vm);
+    ret = qemuMonitorQueryRxFilter(priv->mon, devAlias, &guestFilter);
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)
+        ret = -1;
+    if (ret < 0)
+        goto endjob;
+
+    if (virDomainNetGetActualType(def) == VIR_DOMAIN_NET_TYPE_DIRECT) {
+
+        if (virNetDevGetRxFilter(def->ifname, &hostFilter)) {
+            VIR_WARN("Couldn't get current RX filter for device %s "
+                     "while responding to NIC_RX_FILTER_CHANGED",
+                     def->ifname);
+            goto endjob;
+        }
+
+        /* For macvtap connections, set the following macvtap network device
+         * attributes to match those of the guest network device:
+         * - MAC address
+         * - Multicast MAC address table
+         * - Device options:
+         *   - PROMISC
+         *   - MULTICAST
+         *   - ALLMULTI
+         */
+        syncNicRxFilterMacAddr(def->ifname, guestFilter, hostFilter);
+        syncNicRxFilterMulticast(def->ifname, guestFilter, hostFilter);
+        syncNicRxFilterDeviceOptions(def->ifname, guestFilter, hostFilter);
+    }
+
+    if (virDomainNetGetActualType(def) == VIR_DOMAIN_NET_TYPE_NETWORK) {
+        const char *brname = virDomainNetGetActualBridgeName(def);
+
+        /* For libivrt network connections, set the following TUN/TAP network
+         * device attributes to match those of the guest network device:
+         * - QoS filters (which are based on MAC address)
+         */
+        if (virDomainNetGetActualBandwidth(def) &&
+            def->data.network.actual &&
+            virNetDevBandwidthUpdateFilter(brname, &guestFilter->mac,
+                                           def->data.network.actual->class_id) < 0)
+            goto endjob;
+    }
+
+ endjob:
+    qemuDomainObjEndJob(driver, vm);
+
+ cleanup:
+    virNetDevRxFilterFree(hostFilter);
+    virNetDevRxFilterFree(guestFilter);
+    VIR_FREE(devAlias);
+    virObjectUnref(cfg);
+}
+
+void
+processSerialChangedEvent(virQEMUDriverPtr driver,
+                          virDomainObjPtr vm,
+                          char *devAlias,
+                          bool connected)
+{
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainChrDeviceState newstate;
+    virObjectEventPtr event = NULL;
+    virDomainDeviceDef dev;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+
+    if (connected)
+        newstate = VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED;
+    else
+        newstate = VIR_DOMAIN_CHR_DEVICE_STATE_DISCONNECTED;
+
+    VIR_DEBUG("Changing serial port state %s in domain %p %s",
+              devAlias, vm, vm->def->name);
+
+    if (newstate == VIR_DOMAIN_CHR_DEVICE_STATE_DISCONNECTED &&
+        virDomainObjIsActive(vm) && priv->agent) {
+        /* peek into the domain definition to find the channel */
+        if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) == 0 &&
+            dev.type == VIR_DOMAIN_DEVICE_CHR &&
+            dev.data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
+            dev.data.chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO &&
+            STREQ_NULLABLE(dev.data.chr->target.name, "org.qemu.guest_agent.0"))
+            /* Close agent monitor early, so that other threads
+             * waiting for the agent to reply can finish and our
+             * job we acquire below can succeed. */
+            qemuAgentNotifyClose(priv->agent);
+
+        /* now discard the data, since it may possibly change once we unlock
+         * while entering the job */
+        memset(&dev, 0, sizeof(dev));
+    }
+
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        VIR_DEBUG("Domain is not running");
+        goto endjob;
+    }
+
+    if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
+        goto endjob;
+
+    /* we care only about certain devices */
+    if (dev.type != VIR_DOMAIN_DEVICE_CHR ||
+        dev.data.chr->deviceType != VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL ||
+        dev.data.chr->targetType != VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO)
+        goto endjob;
+
+    dev.data.chr->state = newstate;
+
+    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
+        VIR_WARN("unable to save status of domain %s after updating state of "
+                 "channel %s", vm->def->name, devAlias);
+
+    if (STREQ_NULLABLE(dev.data.chr->target.name, "org.qemu.guest_agent.0")) {
+        if (newstate == VIR_DOMAIN_CHR_DEVICE_STATE_CONNECTED) {
+            if (qemuConnectAgent(driver, vm) < 0)
+                goto endjob;
+        } else {
+            if (priv->agent) {
+                qemuAgentClose(priv->agent);
+                priv->agent = NULL;
+            }
+            priv->agentError = false;
+        }
+
+        event = virDomainEventAgentLifecycleNewFromObj(vm, newstate,
+                                                       VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_CHANNEL);
+        qemuDomainEventQueue(driver, event);
+    }
+
+ endjob:
+    qemuDomainObjEndJob(driver, vm);
+
+ cleanup:
+    VIR_FREE(devAlias);
+    virObjectUnref(cfg);
+
+}
+
+void
+processBlockJobEvent(virQEMUDriverPtr driver,
+                     virDomainObjPtr vm,
+                     char *diskAlias,
+                     int type,
+                     int status)
+{
+    virDomainDiskDefPtr disk;
+
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        VIR_DEBUG("Domain is not running");
+        goto endjob;
+    }
+
+    if ((disk = qemuProcessFindDomainDiskByAlias(vm, diskAlias)))
+        qemuBlockJobEventProcess(driver, vm, disk, QEMU_ASYNC_JOB_NONE, type, status);
+
+ endjob:
+    qemuDomainObjEndJob(driver, vm);
+ cleanup:
+    VIR_FREE(diskAlias);
+}
+
+void
+processMonitorEOFEvent(virQEMUDriverPtr driver,
+                       virDomainObjPtr vm)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    int eventReason = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
+    int stopReason = VIR_DOMAIN_SHUTOFF_SHUTDOWN;
+    const char *auditReason = "shutdown";
+    unsigned int stopFlags = 0;
+    virObjectEventPtr event = NULL;
+
+    if (qemuProcessBeginStopJob(driver, vm, QEMU_JOB_DESTROY, true) < 0)
+        return;
+
+    if (!virDomainObjIsActive(vm)) {
+        VIR_DEBUG("Domain %p '%s' is not active, ignoring EOF",
+                  vm, vm->def->name);
+        goto endjob;
+    }
+
+    if (priv->monJSON && !priv->gotShutdown) {
+        VIR_DEBUG("Monitor connection to '%s' closed without SHUTDOWN event; "
+                  "assuming the domain crashed", vm->def->name);
+        eventReason = VIR_DOMAIN_EVENT_STOPPED_FAILED;
+        stopReason = VIR_DOMAIN_SHUTOFF_CRASHED;
+        auditReason = "failed";
+    }
+
+    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
+        stopFlags |= VIR_QEMU_PROCESS_STOP_MIGRATED;
+        qemuMigrationErrorSave(driver, vm->def->name,
+                               qemuMonitorLastError(priv->mon));
+    }
+
+    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
+                                              eventReason);
+    qemuProcessStop(driver, vm, stopReason, QEMU_ASYNC_JOB_NONE, stopFlags);
+    virDomainAuditStop(vm, auditReason);
+    qemuDomainEventQueue(driver, event);
+
+ endjob:
+    qemuDomainRemoveInactive(driver, vm);
+    qemuDomainObjEndJob(driver, vm);
+}
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
index a2bbc4f..95007b5 100644
--- a/src/qemu/qemu_process.h
+++ b/src/qemu/qemu_process.h
@@ -25,6 +25,92 @@
 # include "qemu_conf.h"
 # include "qemu_domain.h"
 
+typedef enum {
+    QEMU_SAVE_FORMAT_RAW = 0,
+    QEMU_SAVE_FORMAT_GZIP = 1,
+    QEMU_SAVE_FORMAT_BZIP2 = 2,
+    /*
+     * Deprecated by xz and never used as part of a release
+     * QEMU_SAVE_FORMAT_LZMA
+     */
+    QEMU_SAVE_FORMAT_XZ = 3,
+    QEMU_SAVE_FORMAT_LZOP = 4,
+    /* Note: add new members only at the end.
+       These values are used in the on-disk format.
+       Do not change or re-use numbers. */
+
+    QEMU_SAVE_FORMAT_LAST
+} virQEMUSaveFormat;
+
+VIR_ENUM_DECL(qemuSaveCompression)
+VIR_ENUM_DECL(qemuDumpFormat)
+
+int
+qemuFileWrapperFDClose(virDomainObjPtr vm,
+                       virFileWrapperFdPtr fd);
+
+int
+qemuGetCompressionProgram(const char *imageFormat,
+                          char **compresspath,
+                          const char *styleFormat,
+                          bool use_raw_on_fail);
+int
+qemuOpenFile(virQEMUDriverPtr driver,
+             virDomainObjPtr vm,
+             const char *path,
+             int oflags,
+             bool *needUnlink,
+             bool *bypassSecurityDriver);
+int
+doCoreDump(virQEMUDriverPtr driver,
+           virDomainObjPtr vm,
+           const char *path,
+           unsigned int dump_flags,
+           unsigned int dumpformat);
+
+void
+syncNicRxFilterMacAddr(char *ifname, virNetDevRxFilterPtr guestFilter,
+                       virNetDevRxFilterPtr hostFilter);
+
+void
+syncNicRxFilterDeviceOptions(char *ifname, virNetDevRxFilterPtr guestFilter,
+                           virNetDevRxFilterPtr hostFilter);
+
+void
+syncNicRxFilterMulticast(char *ifname,
+                         virNetDevRxFilterPtr guestFilter,
+                         virNetDevRxFilterPtr hostFilter);
+
+void
+processWatchdogEvent(virQEMUDriverPtr driver,
+                     virDomainObjPtr vm,
+                     int action);
+void
+processGuestPanicEvent(virQEMUDriverPtr driver,
+                       virDomainObjPtr vm,
+                       int action,
+                       qemuMonitorEventPanicInfoPtr info);
+void
+processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
+                               virDomainObjPtr vm,
+                               char *devAlias);
+void
+processSerialChangedEvent(virQEMUDriverPtr driver,
+                          virDomainObjPtr vm,
+                          char *devAlias,
+                          bool connected);
+
+void
+processBlockJobEvent(virQEMUDriverPtr driver,
+                     virDomainObjPtr vm,
+                     char *diskAlias,
+                     int type,
+                     int status);
+void processMonitorEOFEvent(virQEMUDriverPtr driver,
+                       virDomainObjPtr vm);
+void processDeviceDeletedEvent(virQEMUDriverPtr driver,
+                          virDomainObjPtr vm,
+                          char *devAlias);
 int qemuProcessPrepareMonitorChr(virDomainChrSourceDefPtr monConfig,
                                  const char *domainDir);
 
-- 
2.9.5




More information about the libvir-list mailing list