/**
* @topsrc: virStorageSource representing 'top' of the job
* @basesrc: virStorageSource representing 'base' of the job
- * @blockNamedNodeData: hash table containing data about bitmaps
- * @actions: filled with arguments for a 'transaction' command
- * @disabledBitmapsBase: filled with a list of bitmap names which must be disabled
- *
- * Prepares data for correctly handling bitmaps during the start of a commit
- * job. The bitmaps in the 'base' image must be disabled, so that the writes
- * done by the blockjob don't dirty the enabled bitmaps.
- *
- * @actions and @disabledBitmapsBase are untouched if no bitmaps need
- * to be disabled.
- */
-int
-qemuBlockBitmapsHandleCommitStart(virStorageSourcePtr topsrc,
- virStorageSourcePtr basesrc,
- virHashTablePtr blockNamedNodeData,
- virJSONValuePtr *actions,
- char ***disabledBitmapsBase)
-{
- g_autoptr(virJSONValue) act = virJSONValueNewArray();
- VIR_AUTOSTRINGLIST bitmaplist = NULL;
- size_t curbitmapstr = 0;
- qemuBlockNamedNodeDataPtr entry;
- bool disable_bitmaps = false;
- size_t i;
-
- if (!(entry = virHashLookup(blockNamedNodeData, basesrc->nodeformat)))
- return 0;
-
- bitmaplist = g_new0(char *, entry->nbitmaps + 1);
-
- for (i = 0; i < entry->nbitmaps; i++) {
- qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
-
- if (!bitmap->recording || bitmap->inconsistent ||
- !qemuBlockBitmapChainIsValid(topsrc, bitmap->name, blockNamedNodeData))
- continue;
-
- disable_bitmaps = true;
-
- if (qemuMonitorTransactionBitmapDisable(act, basesrc->nodeformat,
- bitmap->name) < 0)
- return -1;
-
- bitmaplist[curbitmapstr++] = g_strdup(bitmap->name);
- }
-
- if (disable_bitmaps) {
- *actions = g_steal_pointer(&act);
- *disabledBitmapsBase = g_steal_pointer(&bitmaplist);
- }
-
- return 0;
-}
-
-
-struct qemuBlockBitmapsHandleCommitData {
- bool skip;
- bool create;
- bool enable;
- const char *basenode;
- virJSONValuePtr merge;
- unsigned long long granularity;
- bool persistent;
-};
-
-
-static void
-qemuBlockBitmapsHandleCommitDataFree(void *opaque)
-{
- struct qemuBlockBitmapsHandleCommitData *data = opaque;
-
- virJSONValueFree(data->merge);
- g_free(data);
-}
-
-
-static int
-qemuBlockBitmapsHandleCommitFinishIterate(void *payload,
- const void *entryname,
- void *opaque)
-{
- struct qemuBlockBitmapsHandleCommitData *data = payload;
- const char *bitmapname = entryname;
- virJSONValuePtr actions = opaque;
-
- if (data->skip)
- return 0;
-
- if (data->create) {
- if (qemuMonitorTransactionBitmapAdd(actions, data->basenode, bitmapname,
- data->persistent, !data->enable,
- data->granularity) < 0)
- return -1;
- } else {
- if (data->enable &&
- qemuMonitorTransactionBitmapEnable(actions, data->basenode, bitmapname) < 0)
- return -1;
- }
-
- if (data->merge &&
- qemuMonitorTransactionBitmapMerge(actions, data->basenode, bitmapname,
- &data->merge) < 0)
- return -1;
-
- return 0;
-}
-
-
-/**
- * @topsrc: virStorageSource representing 'top' of the job
- * @basesrc: virStorageSource representing 'base' of the job
+ * @active: commit job is an active layer block-commit
* @blockNamedNodeData: hash table containing data about bitmaps
* @actions: filled with arguments for a 'transaction' command
* @disabledBitmapsBase: bitmap names which were disabled
int
qemuBlockBitmapsHandleCommitFinish(virStorageSourcePtr topsrc,
virStorageSourcePtr basesrc,
+ bool active,
virHashTablePtr blockNamedNodeData,
- virJSONValuePtr *actions,
- char **disabledBitmapsBase)
+ virJSONValuePtr *actions)
{
- g_autoptr(virJSONValue) act = virJSONValueNewArray();
- virStorageSourcePtr n;
- qemuBlockNamedNodeDataPtr entry;
- g_autoptr(virHashTable) commitdata = NULL;
- struct qemuBlockBitmapsHandleCommitData *bitmapdata;
- size_t i;
-
- commitdata = virHashNew(qemuBlockBitmapsHandleCommitDataFree);
-
- for (n = topsrc; n != basesrc; n = n->backingStore) {
- if (!(entry = virHashLookup(blockNamedNodeData, n->nodeformat)))
- continue;
-
- for (i = 0; i < entry->nbitmaps; i++) {
- qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
-
- if (!(bitmapdata = virHashLookup(commitdata, bitmap->name))) {
- bitmapdata = g_new0(struct qemuBlockBitmapsHandleCommitData, 1);
+ virStorageSourcePtr writebitmapsrc = NULL;
- /* we must mirror the state of the topmost bitmap and merge
- * everything else */
- bitmapdata->create = true;
- bitmapdata->enable = bitmap->recording;
- bitmapdata->basenode = basesrc->nodeformat;
- bitmapdata->merge = virJSONValueNewArray();
- bitmapdata->granularity = bitmap->granularity;
- bitmapdata->persistent = bitmap->persistent;
+ if (active)
+ writebitmapsrc = basesrc;
- if (virHashAddEntry(commitdata, bitmap->name, bitmapdata) < 0) {
- qemuBlockBitmapsHandleCommitDataFree(bitmapdata);
- return -1;
- }
- }
-
- if (bitmap->inconsistent ||
- !qemuBlockBitmapChainIsValid(topsrc, bitmap->name, blockNamedNodeData))
- bitmapdata->skip = true;
-
- if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(bitmapdata->merge,
- n->nodeformat,
- bitmap->name) < 0)
- return -1;
- }
- }
-
- if ((entry = virHashLookup(blockNamedNodeData, basesrc->nodeformat))) {
- /* note that all bitmaps in 'base' were disabled when commit was started */
- for (i = 0; i < entry->nbitmaps; i++) {
- qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
-
- if ((bitmapdata = virHashLookup(commitdata, bitmap->name))) {
- bitmapdata->create = false;
- } else {
- if (disabledBitmapsBase) {
- char **disabledbitmaps;
-
- for (disabledbitmaps = disabledBitmapsBase; *disabledbitmaps; disabledbitmaps++) {
- if (STREQ(*disabledbitmaps, bitmap->name)) {
- bitmapdata = g_new0(struct qemuBlockBitmapsHandleCommitData, 1);
-
- bitmapdata->create = false;
- bitmapdata->enable = true;
- bitmapdata->basenode = basesrc->nodeformat;
- bitmapdata->granularity = bitmap->granularity;
- bitmapdata->persistent = bitmap->persistent;
-
- if (virHashAddEntry(commitdata, bitmap->name, bitmapdata) < 0) {
- qemuBlockBitmapsHandleCommitDataFree(bitmapdata);
- return -1;
- }
-
- break;
- }
- }
- }
- }
- }
- }
-
- if (virHashForEach(commitdata, qemuBlockBitmapsHandleCommitFinishIterate, act) < 0)
+ if (qemuBlockGetBitmapMergeActions(topsrc, basesrc, basesrc, NULL, NULL,
+ writebitmapsrc, actions,
+ blockNamedNodeData) < 0)
return -1;
- if (virJSONValueArraySize(act) > 0)
- *actions = g_steal_pointer(&act);
-
return 0;
}
bool shallow,
virJSONValuePtr *actions);
-int
-qemuBlockBitmapsHandleCommitStart(virStorageSourcePtr topsrc,
- virStorageSourcePtr basesrc,
- virHashTablePtr blockNamedNodeData,
- virJSONValuePtr *actions,
- char ***disabledBitmapsBase);
-
int
qemuBlockBitmapsHandleCommitFinish(virStorageSourcePtr topsrc,
virStorageSourcePtr basesrc,
+ bool active,
virHashTablePtr blockNamedNodeData,
- virJSONValuePtr *actions,
- char **disabledBitmapsBase);
+ virJSONValuePtr *actions);
int
qemuBlockReopenReadWrite(virDomainObjPtr vm,
qemuDomainObjPrivatePtr priv = vm->privateData;
g_autoptr(virHashTable) blockNamedNodeData = NULL;
g_autoptr(virJSONValue) actions = NULL;
+ bool active = job->type == QEMU_BLOCKJOB_TYPE_ACTIVE_COMMIT;
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN))
return 0;
if (qemuBlockBitmapsHandleCommitFinish(job->data.commit.top,
job->data.commit.base,
+ active,
blockNamedNodeData,
- &actions,
- job->data.commit.disabledBitmapsBase) < 0)
+ &actions) < 0)
return 0;
if (!actions)
return 0;
- if (qemuBlockReopenReadWrite(vm, job->data.commit.base, asyncJob) < 0)
- return -1;
+ if (!active) {
+ if (qemuBlockReopenReadWrite(vm, job->data.commit.base, asyncJob) < 0)
+ return -1;
+ }
if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0)
return -1;
if (qemuDomainObjExitMonitor(priv->driver, vm) < 0)
return -1;
- if (qemuBlockReopenReadOnly(vm, job->data.commit.base, asyncJob) < 0)
- return -1;
+ if (!active) {
+ if (qemuBlockReopenReadOnly(vm, job->data.commit.base, asyncJob) < 0)
+ return -1;
+ }
return 0;
}
job->disk->src = job->data.commit.base;
job->disk->src->readonly = job->data.commit.top->readonly;
+ if (qemuBlockJobProcessEventCompletedCommitBitmaps(vm, job, asyncJob) < 0)
+ return;
+
qemuBlockJobEventProcessConcludedRemoveChain(driver, vm, asyncJob, job->data.commit.top);
if (job->data.commit.deleteCommittedImages)
virDomainObjPtr vm,
qemuBlockJobDataPtr job)
{
+ g_autoptr(virJSONValue) actions = virJSONValueNewArray();
virDomainDiskDefPtr disk = job->disk;
VIR_DEBUG("active commit job '%s' on VM '%s' failed", job->name, vm->def->name);
if (!disk)
return;
+ ignore_value(qemuMonitorTransactionBitmapRemove(actions, disk->mirror->nodeformat,
+ "libvirt-tmp-activewrite"));
+
+
/* Ideally, we would make the backing chain read only again (yes, SELinux
* can do that using different labels). But that is not implemented yet and
* not leaking security driver metadata is more important. */
case QEMU_BLOCKJOB_TYPE_COPY:
if (blockdev && !job->jobflagsmissing) {
- g_autoptr(virHashTable) blockNamedNodeData = NULL;
bool shallow = job->jobflags & VIR_DOMAIN_BLOCK_COPY_SHALLOW;
bool reuse = job->jobflags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT;
+ g_autoptr(virHashTable) blockNamedNodeData = NULL;
if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
return -1;
* the bitmaps if it wasn't present thus must skip this */
if (blockdev &&
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN)) {
- g_autoptr(virHashTable) blockNamedNodeData = NULL;
- if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
- return -1;
+ actions = virJSONValueNewArray();
- if (qemuBlockBitmapsHandleCommitFinish(job->data.commit.top,
- job->data.commit.base,
- blockNamedNodeData,
- &actions,
- job->data.commit.disabledBitmapsBase) < 0)
+ if (qemuMonitorTransactionBitmapAdd(actions,
+ job->data.commit.base->nodeformat,
+ "libvirt-tmp-activewrite",
+ false,
+ false,
+ 0) < 0)
return -1;
}
const char *nodebase = NULL;
bool persistjob = false;
bool blockdev = false;
- g_autoptr(virJSONValue) bitmapDisableActions = NULL;
VIR_AUTOSTRINGLIST bitmapDisableList = NULL;
virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW |
goto endjob;
}
- if (blockdev &&
- virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN)) {
- g_autoptr(virHashTable) blockNamedNodeData = NULL;
- if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
- goto endjob;
-
- if (qemuBlockBitmapsHandleCommitStart(topSource, baseSource,
- blockNamedNodeData,
- &bitmapDisableActions,
- &bitmapDisableList) < 0)
- goto endjob;
-
- /* if we don't have terminator on 'base' we can't reopen it */
- if (bitmapDisableActions && !baseSource->backingStore) {
- virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
- _("can't handle bitmaps on unterminated backing image '%s'"),
- base);
- goto endjob;
- }
- }
-
if (!(job = qemuBlockJobDiskNewCommit(vm, disk, top_parent, topSource,
baseSource, &bitmapDisableList,
flags & VIR_DOMAIN_BLOCK_COMMIT_DELETE,
!(backingPath = qemuBlockGetBackingStoreString(baseSource, false)))
goto endjob;
- if (bitmapDisableActions) {
- int rc;
-
- if (qemuBlockReopenReadWrite(vm, baseSource, QEMU_ASYNC_JOB_NONE) < 0)
- goto endjob;
-
- qemuDomainObjEnterMonitor(driver, vm);
- rc = qemuMonitorTransaction(priv->mon, &bitmapDisableActions);
- if (qemuDomainObjExitMonitor(driver, vm) < 0)
- goto endjob;
-
- if (qemuBlockReopenReadOnly(vm, baseSource, QEMU_ASYNC_JOB_NONE) < 0)
- goto endjob;
-
- if (rc < 0)
- goto endjob;
- }
} else {
device = job->name;
}
g_autofree char *actual = NULL;
g_autofree char *expectpath = NULL;
- g_autoptr(virJSONValue) actionsDisable = NULL;
g_autoptr(virJSONValue) actionsMerge = NULL;
g_autoptr(virJSONValue) nodedatajson = NULL;
g_autoptr(virHashTable) nodedata = NULL;
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
- VIR_AUTOSTRINGLIST bitmapsDisable = NULL;
+ bool active = data->top == data->chain;
expectpath = g_strdup_printf("%s/%s%s", abs_srcdir,
blockcommitPrefix, data->name);
return -1;
}
- if (qemuBlockBitmapsHandleCommitStart(data->top, data->base, nodedata,
- &actionsDisable, &bitmapsDisable) < 0)
- return -1;
-
- virBufferAddLit(&buf, "pre job bitmap disable:\n");
-
- if (actionsDisable &&
- virJSONValueToBuffer(actionsDisable, &buf, true) < 0)
- return -1;
-
virBufferAddLit(&buf, "merge bitmpas:\n");
- if (qemuBlockBitmapsHandleCommitFinish(data->top, data->base, nodedata,
- &actionsMerge, bitmapsDisable) < 0)
+ if (qemuBlockBitmapsHandleCommitFinish(data->top, data->base, active, nodedata,
+ &actionsMerge) < 0)
return -1;
if (actionsMerge &&
#define TEST_BITMAP_BLOCKCOMMIT(testname, topimg, baseimg, ndf) \
do {\
blockbitmapblockcommitdata.name = testname; \
+ blockbitmapblockcommitdata.chain = bitmapSourceChain; \
blockbitmapblockcommitdata.top = testQemuBitmapGetFakeChainEntry(bitmapSourceChain, topimg); \
blockbitmapblockcommitdata.base = testQemuBitmapGetFakeChainEntry(bitmapSourceChain, baseimg); \
blockbitmapblockcommitdata.nodedatafile = ndf; \
-pre job bitmap disable:
merge bitmpas: