/* * libvirt-domain-checkpoint.c: entry points for virDomainCheckpointPtr APIs * * Copyright (C) 2006-2019 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #include #include "datatypes.h" #include "virlog.h" VIR_LOG_INIT("libvirt.domain-checkpoint"); #define VIR_FROM_THIS VIR_FROM_DOMAIN_CHECKPOINT /** * virDomainCheckpointGetName: * @checkpoint: a checkpoint object * * Get the public name for that checkpoint * * Returns a pointer to the name or NULL, the string need not be deallocated * as its lifetime will be the same as the checkpoint object. */ const char * virDomainCheckpointGetName(virDomainCheckpointPtr checkpoint) { VIR_DEBUG("checkpoint=%p", checkpoint); virResetLastError(); virCheckDomainCheckpointReturn(checkpoint, NULL); return checkpoint->name; } /** * virDomainCheckpointGetDomain: * @checkpoint: a checkpoint object * * Provides the domain pointer associated with a checkpoint. The * reference counter on the domain is not increased by this * call. * * Returns the domain or NULL. */ virDomainPtr virDomainCheckpointGetDomain(virDomainCheckpointPtr checkpoint) { VIR_DEBUG("checkpoint=%p", checkpoint); virResetLastError(); virCheckDomainCheckpointReturn(checkpoint, NULL); return checkpoint->domain; } /** * virDomainCheckpointGetConnect: * @checkpoint: a checkpoint object * * Provides the connection pointer associated with a checkpoint. The * reference counter on the connection is not increased by this * call. * * Returns the connection or NULL. */ virConnectPtr virDomainCheckpointGetConnect(virDomainCheckpointPtr checkpoint) { VIR_DEBUG("checkpoint=%p", checkpoint); virResetLastError(); virCheckDomainCheckpointReturn(checkpoint, NULL); return checkpoint->domain->conn; } /** * virDomainCheckpointCreateXML: * @domain: a domain object * @xmlDesc: description of the checkpoint to create * @flags: bitwise-OR of supported virDomainCheckpointCreateFlags * * Create a new checkpoint using @xmlDesc, with a top-level * element, on a running @domain. Note that @xmlDesc * must validate against the XML schema. * * See Checkpoint XML * for more details on @xmlDesc. In particular, some hypervisors may require * particular disk formats, such as qcow2, in order to support this * command; where @xmlDesc can be used to limit the checkpoint to a working * subset of the domain's disks. * * If @flags includes VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE, then this * is a request to reinstate checkpoint metadata that was previously * captured from virDomainCheckpointGetXMLDesc() before removing that * metadata, rather than creating a new checkpoint. Note that while * original creation can omit a number of elements from @xmlDesc (and * libvirt will supply sane defaults based on the domain state at that * point in time), a redefinition must supply more elements (as the * domain may have changed in the meantime, so that libvirt no longer * has a way to resupply correct defaults). Not all hypervisors support * this flag. * * If @flags includes VIR_DOMAIN_CHECKPOINT_CREATE_QUIESCE, then the * libvirt will attempt to use guest agent to freeze and thaw all file * systems in use within domain OS. However, if the guest agent is not * present, an error is thrown. This flag is incompatible with * VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE. * * Returns an (opaque) new virDomainCheckpointPtr on success or NULL * on failure. */ virDomainCheckpointPtr virDomainCheckpointCreateXML(virDomainPtr domain, const char *xmlDesc, unsigned int flags) { virConnectPtr conn; VIR_DOMAIN_DEBUG(domain, "xmlDesc=%s, flags=0x%x", xmlDesc, flags); virResetLastError(); virCheckDomainReturn(domain, NULL); conn = domain->conn; virCheckNonNullArgGoto(xmlDesc, error); virCheckReadOnlyGoto(conn->flags, error); VIR_EXCLUSIVE_FLAGS_GOTO(VIR_DOMAIN_CHECKPOINT_CREATE_REDEFINE, VIR_DOMAIN_CHECKPOINT_CREATE_QUIESCE, error); if (conn->driver->domainCheckpointCreateXML) { virDomainCheckpointPtr ret; ret = conn->driver->domainCheckpointCreateXML(domain, xmlDesc, flags); if (!ret) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return NULL; } /** * virDomainCheckpointGetXMLDesc: * @checkpoint: a domain checkpoint object * @flags: bitwise-OR of supported virDomainCheckpointXMLFlags * * Provide an XML description of the domain checkpoint. * * No security-sensitive data will be included unless @flags contains * VIR_DOMAIN_CHECKPOINT_XML_SECURE; this flag is rejected on read-only * connections. * * Normally, the XML description includes an element giving a full * description of the domain at the time the checkpoint was created; to * reduce parsing time, it will be suppressed when @flags contains * VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN. * * By default, the XML description contains only static information that * does not change over time. However, when @flags contains * VIR_DOMAIN_CHECKPOINT_XML_SIZE, each listing adds an additional * attribute that shows an estimate of the current size in bytes that * have been dirtied between the time the checkpoint was created and the * current point in time. * * Returns a 0 terminated UTF-8 encoded XML instance or NULL in case * of error. The caller must free() the returned value. */ char * virDomainCheckpointGetXMLDesc(virDomainCheckpointPtr checkpoint, unsigned int flags) { virConnectPtr conn; VIR_DEBUG("checkpoint=%p, flags=0x%x", checkpoint, flags); virResetLastError(); virCheckDomainCheckpointReturn(checkpoint, NULL); conn = checkpoint->domain->conn; if ((conn->flags & VIR_CONNECT_RO) && (flags & VIR_DOMAIN_CHECKPOINT_XML_SECURE)) { virReportError(VIR_ERR_OPERATION_DENIED, "%s", _("virDomainCheckpointGetXMLDesc with secure flag")); goto error; } if (conn->driver->domainCheckpointGetXMLDesc) { char *ret; ret = conn->driver->domainCheckpointGetXMLDesc(checkpoint, flags); if (!ret) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return NULL; } /** * virDomainListAllCheckpoints: * @domain: a domain object * @checkpoints: pointer to variable to store the array containing checkpoint * object, or NULL if the list is not required (just returns * number of checkpoints) * @flags: bitwise-OR of supported virDomainCheckpoinListFlags * * Collect the list of domain checkpoints for the given domain and allocate * an array to store those objects. * * If @flags contains VIR_DOMAIN_CHECKPOINT_LIST_TOPOLOGICAL, * @checkpoints is non-NULL, and no other connection is modifying * checkpoints, then it is guaranteed that for any checkpoint in the * resulting list, no checkpoints later in the list can be reached by * a sequence of virDomainCheckpointGetParent() starting from that * earlier checkpoint; otherwise, the order of checkpoints in the * resulting list is unspecified. * * By default, this command covers all checkpoints. It is also * possible to limit things to just checkpoints with no parents, when * @flags includes VIR_DOMAIN_CHECKPOINT_LIST_ROOTS. Additional * filters are provided in groups listed below. Within a group, bits * are mutually exclusive, where all possible checkpoints are * described by exactly one bit from the group. Some hypervisors might * reject particular flags where it cannot make a distinction for * filtering. If the set of filter flags selected forms an impossible * combination, the hypervisor may return either 0 or an error. * * The first group of @flags is VIR_DOMAIN_CHECKPOINT_LIST_LEAVES and * VIR_DOMAIN_CHECKPOINT_LIST_NO_LEAVES, to filter based on checkpoints that * have no further children (a leaf checkpoint). * * Returns the number of domain checkpoints found or -1 and sets @checkpoints * to NULL in case of error. On success, the array stored into @checkpoints * is guaranteed to have an extra allocated element set to NULL but not * included in the return count, to make iteration easier. The caller is * responsible for calling virDomainCheckpointFree() on each array element, * then calling free() on @checkpoints. */ int virDomainListAllCheckpoints(virDomainPtr domain, virDomainCheckpointPtr **checkpoints, unsigned int flags) { virConnectPtr conn; VIR_DOMAIN_DEBUG(domain, "checkpoints=%p, flags=0x%x", checkpoints, flags); virResetLastError(); if (checkpoints) *checkpoints = NULL; virCheckDomainReturn(domain, -1); conn = domain->conn; if (conn->driver->domainListAllCheckpoints) { int ret = conn->driver->domainListAllCheckpoints(domain, checkpoints, flags); if (ret < 0) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return -1; } /** * virDomainCheckpointListAllChildren: * @checkpoint: a domain checkpoint object * @children: pointer to variable to store the array containing checkpoint * objects or NULL if the list is not required (just returns * number of checkpoints) * @flags: bitwise-OR of supported virDomainCheckpointListFlags * * Collect the list of domain checkpoints that are children of the given * checkpoint, and allocate an array to store those objects. * * If @flags contains VIR_DOMAIN_CHECKPOINT_LIST_TOPOLOGICAL, * @checkpoints is non-NULL, and no other connection is modifying * checkpoints, then it is guaranteed that for any checkpoint in the * resulting list, no checkpoints later in the list can be reached by * a sequence of virDomainCheckpointGetParent() starting from that * earlier checkpoint; otherwise, the order of checkpoints in the * resulting list is unspecified. * * By default, this command covers only direct children. It is also * possible to expand things to cover all descendants, when @flags * includes VIR_DOMAIN_CHECKPOINT_LIST_DESCENDANTS. Additional * are provided via the remaining @flags values as documented in * virDomainListAllCheckpoints(), with the exception that * VIR_DOMAIN_CHECKPOINT_LIST_ROOTS is not supported (in fact, * VIR_DOMAIN_CHECKPOINT_LIST_DESCENDANTS has the same bit value but * opposite semantics of widening rather than narrowing the listing). * * Returns the number of domain checkpoints found or -1 and sets @children to * NULL in case of error. On success, the array stored into @children is * guaranteed to have an extra allocated element set to NULL but not included * in the return count, to make iteration easier. The caller is responsible * for calling virDomainCheckpointFree() on each array element, then calling * free() on @children. */ int virDomainCheckpointListAllChildren(virDomainCheckpointPtr checkpoint, virDomainCheckpointPtr **children, unsigned int flags) { virConnectPtr conn; VIR_DEBUG("checkpoint=%p, children=%p, flags=0x%x", checkpoint, children, flags); virResetLastError(); if (children) *children = NULL; virCheckDomainCheckpointReturn(checkpoint, -1); conn = checkpoint->domain->conn; if (conn->driver->domainCheckpointListAllChildren) { int ret = conn->driver->domainCheckpointListAllChildren(checkpoint, children, flags); if (ret < 0) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return -1; } /** * virDomainCheckpointLookupByName: * @domain: a domain object * @name: name for the domain checkpoint * @flags: extra flags; not used yet, so callers should always pass 0 * * Try to lookup a domain checkpoint based on its name. * * Returns a domain checkpoint object or NULL in case of failure. If the * domain checkpoint cannot be found, then the VIR_ERR_NO_DOMAIN_CHECKPOINT * error is raised. */ virDomainCheckpointPtr virDomainCheckpointLookupByName(virDomainPtr domain, const char *name, unsigned int flags) { virConnectPtr conn; VIR_DOMAIN_DEBUG(domain, "name=%s, flags=0x%x", name, flags); virResetLastError(); virCheckDomainReturn(domain, NULL); conn = domain->conn; virCheckNonNullArgGoto(name, error); if (conn->driver->domainCheckpointLookupByName) { virDomainCheckpointPtr checkpoint; checkpoint = conn->driver->domainCheckpointLookupByName(domain, name, flags); if (!checkpoint) goto error; return checkpoint; } virReportUnsupportedError(); error: virDispatchError(conn); return NULL; } /** * virDomainCheckpointGetParent: * @checkpoint: a checkpoint object * @flags: extra flags; not used yet, so callers should always pass 0 * * Get the parent checkpoint for @checkpoint, if any. * * virDomainCheckpointFree should be used to free the resources after the * checkpoint object is no longer needed. * * Returns a domain checkpoint object or NULL in case of failure. If the * given checkpoint is a root (no parent), then the VIR_ERR_NO_DOMAIN_CHECKPOINT * error is raised. */ virDomainCheckpointPtr virDomainCheckpointGetParent(virDomainCheckpointPtr checkpoint, unsigned int flags) { virConnectPtr conn; VIR_DEBUG("checkpoint=%p, flags=0x%x", checkpoint, flags); virResetLastError(); virCheckDomainCheckpointReturn(checkpoint, NULL); conn = checkpoint->domain->conn; if (conn->driver->domainCheckpointGetParent) { virDomainCheckpointPtr parent; parent = conn->driver->domainCheckpointGetParent(checkpoint, flags); if (!parent) goto error; return parent; } virReportUnsupportedError(); error: virDispatchError(conn); return NULL; } /** * virDomainCheckpointDelete: * @checkpoint: the checkpoint to remove * @flags: bitwise-OR of supported virDomainCheckpointDeleteFlags * * Removes a checkpoint from the domain. * * When removing a checkpoint, the record of which portions of the * disk were dirtied after the checkpoint will be merged into the * record tracked by the parent checkpoint, if any. * * If @flags includes VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN, then any * descendant checkpoints are also deleted. If @flags includes * VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY, then any descendant * checkepoints are deleted, but this checkpoint remains. These two * flags are mutually exclusive. * * If @flags includes VIR_DOMAIN_CHECKPOINT_DELETE_METADATA_ONLY, then * any checkpoint metadata tracked by libvirt is removed while keeping * the checkpoint contents intact; if a hypervisor does not require * any libvirt metadata to track checkpoints, then this flag is * silently ignored. * * Returns 0 on success, -1 on error. */ int virDomainCheckpointDelete(virDomainCheckpointPtr checkpoint, unsigned int flags) { virConnectPtr conn; VIR_DEBUG("checkpoint=%p, flags=0x%x", checkpoint, flags); virResetLastError(); virCheckDomainCheckpointReturn(checkpoint, -1); conn = checkpoint->domain->conn; virCheckReadOnlyGoto(conn->flags, error); VIR_EXCLUSIVE_FLAGS_GOTO(VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN, VIR_DOMAIN_CHECKPOINT_DELETE_CHILDREN_ONLY, error); if (conn->driver->domainCheckpointDelete) { int ret = conn->driver->domainCheckpointDelete(checkpoint, flags); if (ret < 0) goto error; return ret; } virReportUnsupportedError(); error: virDispatchError(conn); return -1; } /** * virDomainCheckpointRef: * @checkpoint: the checkpoint to hold a reference on * * Increment the reference count on the checkpoint. For each * additional call to this method, there shall be a corresponding * call to virDomainCheckpointFree to release the reference count, once * the caller no longer needs the reference to this object. * * This method is typically useful for applications where multiple * threads are using a connection, and it is required that the * connection and domain remain open until all threads have finished * using the checkpoint. ie, each new thread using a checkpoint would * increment the reference count. * * Returns 0 in case of success and -1 in case of failure. */ int virDomainCheckpointRef(virDomainCheckpointPtr checkpoint) { VIR_DEBUG("checkpoint=%p, refs=%d", checkpoint, checkpoint ? checkpoint->parent.u.s.refs : 0); virResetLastError(); virCheckDomainCheckpointReturn(checkpoint, -1); virObjectRef(checkpoint); return 0; } /** * virDomainCheckpointFree: * @checkpoint: a domain checkpoint object * * Free the domain checkpoint object. The checkpoint itself is not modified. * The data structure is freed and should not be used thereafter. * * Returns 0 in case of success and -1 in case of failure. */ int virDomainCheckpointFree(virDomainCheckpointPtr checkpoint) { VIR_DEBUG("checkpoint=%p", checkpoint); virResetLastError(); virCheckDomainCheckpointReturn(checkpoint, -1); virObjectUnref(checkpoint); return 0; }