mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-11-09 23:10:08 +00:00
717f1cc4d1
'virDomainSnapshotRedefinePrep' does everything needed for a redefine when the snapshot exists but not when we are defining metadata for a new snapshot. This gives us weird semantics. Extract the code for replacing the definition of an existing snapshot into a new helper 'virDomainSnapshotReplaceDef' and refactor all callers. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
318 lines
9.4 KiB
C
318 lines
9.4 KiB
C
/*
|
|
* virdomainsnapshotobjlist.c: handle a tree of snapshot objects
|
|
* (derived from snapshot_conf.c)
|
|
*
|
|
* Copyright (C) 2006-2019 Red Hat, Inc.
|
|
* Copyright (C) 2006-2008 Daniel P. Berrange
|
|
*
|
|
* 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
|
|
* <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include "internal.h"
|
|
#include "virdomainsnapshotobjlist.h"
|
|
#include "snapshot_conf.h"
|
|
#include "virlog.h"
|
|
#include "virerror.h"
|
|
#include "datatypes.h"
|
|
#include "virstring.h"
|
|
#include "viralloc.h"
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_DOMAIN_SNAPSHOT
|
|
|
|
VIR_LOG_INIT("conf.virdomainsnapshotobjlist");
|
|
|
|
struct _virDomainSnapshotObjList {
|
|
virDomainMomentObjList *base;
|
|
};
|
|
|
|
|
|
virDomainMomentObj *
|
|
virDomainSnapshotAssignDef(virDomainSnapshotObjList *snapshots,
|
|
virDomainSnapshotDef **snapdefptr)
|
|
{
|
|
virDomainSnapshotDef *snapdef = *snapdefptr;
|
|
virDomainMomentObj *ret = virDomainMomentAssignDef(snapshots->base, &snapdef->parent);
|
|
|
|
if (ret)
|
|
*snapdefptr = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void
|
|
virDomainSnapshotReplaceDef(virDomainMomentObj *snap,
|
|
virDomainSnapshotDef **snapdefptr)
|
|
{
|
|
virDomainSnapshotDef *snapdef = *snapdefptr;
|
|
g_autoptr(virDomainSnapshotDef) origsnapdef = virDomainSnapshotObjGetDef(snap);
|
|
|
|
/* steal the domain definition if redefining an existing snapshot which
|
|
* with a snapshot definition lacking the domain definition */
|
|
if (!snapdef->parent.dom)
|
|
snapdef->parent.dom = g_steal_pointer(&origsnapdef->parent.dom);
|
|
|
|
/* Drop and rebuild the parent relationship, but keep all child relations by reusing snap. */
|
|
virDomainMomentDropParent(snap);
|
|
snap->def = &snapdef->parent;
|
|
*snapdefptr = NULL;
|
|
}
|
|
|
|
|
|
static bool
|
|
virDomainSnapshotFilter(virDomainMomentObj *obj,
|
|
unsigned int flags)
|
|
{
|
|
virDomainSnapshotDef *def = virDomainSnapshotObjGetDef(obj);
|
|
|
|
/* Caller has already sanitized flags and performed filtering on
|
|
* DESCENDANTS and LEAVES. */
|
|
if (flags & VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS) {
|
|
if (!(flags & VIR_DOMAIN_SNAPSHOT_LIST_INACTIVE) &&
|
|
def->state == VIR_DOMAIN_SNAPSHOT_SHUTOFF)
|
|
return false;
|
|
if (!(flags & VIR_DOMAIN_SNAPSHOT_LIST_DISK_ONLY) &&
|
|
def->state == VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT)
|
|
return false;
|
|
if (!(flags & VIR_DOMAIN_SNAPSHOT_LIST_ACTIVE) &&
|
|
def->state != VIR_DOMAIN_SNAPSHOT_SHUTOFF &&
|
|
def->state != VIR_DOMAIN_SNAPSHOT_DISK_SNAPSHOT)
|
|
return false;
|
|
}
|
|
|
|
if ((flags & VIR_DOMAIN_SNAPSHOT_LIST_INTERNAL) &&
|
|
virDomainSnapshotIsExternal(obj))
|
|
return false;
|
|
if ((flags & VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL) &&
|
|
!virDomainSnapshotIsExternal(obj))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
virDomainSnapshotObjList *
|
|
virDomainSnapshotObjListNew(void)
|
|
{
|
|
virDomainSnapshotObjList *snapshots;
|
|
|
|
snapshots = g_new0(virDomainSnapshotObjList, 1);
|
|
snapshots->base = virDomainMomentObjListNew();
|
|
if (!snapshots->base) {
|
|
VIR_FREE(snapshots);
|
|
return NULL;
|
|
}
|
|
return snapshots;
|
|
}
|
|
|
|
|
|
void
|
|
virDomainSnapshotObjListFree(virDomainSnapshotObjList *snapshots)
|
|
{
|
|
if (!snapshots)
|
|
return;
|
|
virDomainMomentObjListFree(snapshots->base);
|
|
g_free(snapshots);
|
|
}
|
|
|
|
|
|
int
|
|
virDomainSnapshotObjListGetNames(virDomainSnapshotObjList *snapshots,
|
|
virDomainMomentObj *from,
|
|
char **const names,
|
|
int maxnames,
|
|
unsigned int flags)
|
|
{
|
|
/* Convert public flags into common flags */
|
|
unsigned int moment_flags = 0;
|
|
struct { int snap_flag; int moment_flag; } map[] = {
|
|
{ VIR_DOMAIN_SNAPSHOT_LIST_ROOTS,
|
|
VIR_DOMAIN_MOMENT_LIST_ROOTS, },
|
|
{ VIR_DOMAIN_SNAPSHOT_LIST_TOPOLOGICAL,
|
|
VIR_DOMAIN_MOMENT_LIST_TOPOLOGICAL, },
|
|
{ VIR_DOMAIN_SNAPSHOT_LIST_LEAVES,
|
|
VIR_DOMAIN_MOMENT_LIST_LEAVES, },
|
|
{ VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES,
|
|
VIR_DOMAIN_MOMENT_LIST_NO_LEAVES, },
|
|
{ VIR_DOMAIN_SNAPSHOT_LIST_METADATA,
|
|
VIR_DOMAIN_MOMENT_LIST_METADATA, },
|
|
{ VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA,
|
|
VIR_DOMAIN_MOMENT_LIST_NO_METADATA, },
|
|
};
|
|
size_t i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS(map); i++) {
|
|
if (flags & map[i].snap_flag) {
|
|
flags &= ~map[i].snap_flag;
|
|
moment_flags |= map[i].moment_flag;
|
|
}
|
|
}
|
|
|
|
/* For ease of coding the visitor, it is easier to zero each group
|
|
* where all of the bits are set. */
|
|
if ((flags & VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES) ==
|
|
VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES)
|
|
flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_LEAVES;
|
|
if ((flags & VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS) ==
|
|
VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS)
|
|
flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_STATUS;
|
|
if ((flags & VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION) ==
|
|
VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION)
|
|
flags &= ~VIR_DOMAIN_SNAPSHOT_FILTERS_LOCATION;
|
|
return virDomainMomentObjListGetNames(snapshots->base, from, names,
|
|
maxnames, moment_flags,
|
|
virDomainSnapshotFilter, flags);
|
|
}
|
|
|
|
|
|
int
|
|
virDomainSnapshotObjListNum(virDomainSnapshotObjList *snapshots,
|
|
virDomainMomentObj *from,
|
|
unsigned int flags)
|
|
{
|
|
return virDomainSnapshotObjListGetNames(snapshots, from, NULL, 0, flags);
|
|
}
|
|
|
|
|
|
virDomainMomentObj *
|
|
virDomainSnapshotFindByName(virDomainSnapshotObjList *snapshots,
|
|
const char *name)
|
|
{
|
|
return virDomainMomentFindByName(snapshots->base, name);
|
|
}
|
|
|
|
|
|
/* Return the current snapshot, or NULL */
|
|
virDomainMomentObj *
|
|
virDomainSnapshotGetCurrent(virDomainSnapshotObjList *snapshots)
|
|
{
|
|
return virDomainMomentGetCurrent(snapshots->base);
|
|
}
|
|
|
|
|
|
/* Return the current snapshot's name, or NULL */
|
|
const char *
|
|
virDomainSnapshotGetCurrentName(virDomainSnapshotObjList *snapshots)
|
|
{
|
|
return virDomainMomentGetCurrentName(snapshots->base);
|
|
}
|
|
|
|
|
|
/* Update the current snapshot, using NULL if no current remains */
|
|
void
|
|
virDomainSnapshotSetCurrent(virDomainSnapshotObjList *snapshots,
|
|
virDomainMomentObj *snapshot)
|
|
{
|
|
virDomainMomentSetCurrent(snapshots->base, snapshot);
|
|
}
|
|
|
|
|
|
/* Remove snapshot from the list; return true if it was current */
|
|
bool
|
|
virDomainSnapshotObjListRemove(virDomainSnapshotObjList *snapshots,
|
|
virDomainMomentObj *snapshot)
|
|
{
|
|
return virDomainMomentObjListRemove(snapshots->base, snapshot);
|
|
}
|
|
|
|
|
|
/* Remove all snapshots tracked in the list */
|
|
void
|
|
virDomainSnapshotObjListRemoveAll(virDomainSnapshotObjList *snapshots)
|
|
{
|
|
return virDomainMomentObjListRemoveAll(snapshots->base);
|
|
}
|
|
|
|
|
|
int
|
|
virDomainSnapshotForEach(virDomainSnapshotObjList *snapshots,
|
|
virHashIterator iter,
|
|
void *data)
|
|
{
|
|
return virDomainMomentForEach(snapshots->base, iter, data);
|
|
}
|
|
|
|
|
|
/* Populate parent link of a given snapshot. */
|
|
void
|
|
virDomainSnapshotLinkParent(virDomainSnapshotObjList *snapshots,
|
|
virDomainMomentObj *snap)
|
|
{
|
|
return virDomainMomentLinkParent(snapshots->base, snap);
|
|
}
|
|
|
|
|
|
/* Populate parent link and child count of all snapshots, with all
|
|
* assigned defs having relations starting as 0/NULL. Return 0 on
|
|
* success, -1 if a parent is missing or if a circular relationship
|
|
* was requested. */
|
|
int
|
|
virDomainSnapshotUpdateRelations(virDomainSnapshotObjList *snapshots)
|
|
{
|
|
return virDomainMomentUpdateRelations(snapshots->base);
|
|
}
|
|
|
|
|
|
int
|
|
virDomainSnapshotCheckCycles(virDomainSnapshotObjList *snapshots,
|
|
virDomainSnapshotDef *def,
|
|
const char *domname)
|
|
{
|
|
return virDomainMomentCheckCycles(snapshots->base, &def->parent, domname);
|
|
}
|
|
|
|
|
|
int
|
|
virDomainListSnapshots(virDomainSnapshotObjList *snapshots,
|
|
virDomainMomentObj *from,
|
|
virDomainPtr dom,
|
|
virDomainSnapshotPtr **snaps,
|
|
unsigned int flags)
|
|
{
|
|
int count = virDomainSnapshotObjListNum(snapshots, from, flags);
|
|
virDomainSnapshotPtr *list = NULL;
|
|
char **names;
|
|
int ret = -1;
|
|
size_t i;
|
|
|
|
if (!snaps || count < 0)
|
|
return count;
|
|
names = g_new0(char *, count);
|
|
list = g_new0(virDomainSnapshotPtr, count + 1);
|
|
|
|
if (virDomainSnapshotObjListGetNames(snapshots, from, names, count,
|
|
flags) < 0)
|
|
goto cleanup;
|
|
for (i = 0; i < count; i++)
|
|
if ((list[i] = virGetDomainSnapshot(dom, names[i])) == NULL)
|
|
goto cleanup;
|
|
|
|
ret = count;
|
|
*snaps = list;
|
|
|
|
cleanup:
|
|
for (i = 0; i < count; i++)
|
|
VIR_FREE(names[i]);
|
|
VIR_FREE(names);
|
|
if (ret < 0 && list) {
|
|
for (i = 0; i < count; i++)
|
|
virObjectUnref(list[i]);
|
|
VIR_FREE(list);
|
|
}
|
|
return ret;
|
|
}
|