diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index df04ea11cfccbc7c2dac30c967a78cb404bb530d..c7923bc6947cf5e85dcf7fdcfb7f4ff1477f1ffe 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5001,13 +5001,6 @@ static int qemudDomainSaveFlag(virDomainPtr dom, const char *path, * we need to ensure there's a 512 byte boundary. Unfortunately * we don't have an explicit offset in the header, so we fake * it by padding the XML string with NULLs. - * - * XXX: This means there will be (QEMU_MONITOR_MIGRATE_TO_FILE_BS - * - strlen(xml)) bytes of wastage in each file. - * Unfortunately, a large BS is needed for reasonable - * performance. It would be nice to find a replacement for dd - * that could specify the start offset in bytes rather than - * blocks, to eliminate this waste. */ if (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS) { unsigned long long pad = diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index e03b4dff19f4d94863384caac6d570fc7c35072e..6c104f1bc9d69c4ed51737f245bc9e1a0bb9e3e9 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1,7 +1,7 @@ /* * qemu_monitor.h: interaction with QEMU monitor console * - * Copyright (C) 2006-2009 Red Hat, Inc. + * Copyright (C) 2006-2010 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -261,10 +261,16 @@ int qemuMonitorMigrateToCommand(qemuMonitorPtr mon, unsigned int background, const char * const *argv); -/* In general, a larger BS means better domain save performance, - * at the expense of a larger resulting file - see qemu_driver.c +/* In general, BS is the smallest fundamental block size we can use to + * access a block device; everything must be aligned to a multiple of + * this. Linux generally supports a BS as small as 512, but with + * newer disks with 4k sectors, performance is better if we guarantee + * alignment to the sector size. However, operating on BS-sized + * blocks is painfully slow, so we also have a transfer size that is + * larger but only aligned to the smaller block size. */ -# define QEMU_MONITOR_MIGRATE_TO_FILE_BS (1024llu * 1024) +# define QEMU_MONITOR_MIGRATE_TO_FILE_BS (1024llu * 4) +# define QEMU_MONITOR_MIGRATE_TO_FILE_TRANSFER_SIZE (1024llu * 1024) int qemuMonitorMigrateToFile(qemuMonitorPtr mon, unsigned int background, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index e89ad43000549df0c1dd6d8b73066494361bcc9a..40218aaf4ee6607aa9ff96e6558526a72db6d3a8 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1695,10 +1695,16 @@ int qemuMonitorJSONMigrateToFile(qemuMonitorPtr mon, goto cleanup; } - if (virAsprintf(&dest, "exec:%s | dd of=%s bs=%llu seek=%llu", - argstr, safe_target, - QEMU_MONITOR_MIGRATE_TO_FILE_BS, - offset / QEMU_MONITOR_MIGRATE_TO_FILE_BS) < 0) { + /* Two dd processes, sharing the same stdout, are necessary to + * allow starting at an alignment of 512, but without wasting + * padding to get to the larger alignment useful for speed. Use + * <> redirection to avoid truncating a regular file. */ + if (virAsprintf(&dest, "exec:%s | { dd bs=%llu seek=%llu if=/dev/null && " + "dd bs=%llu; } 1<>%s", + argstr, QEMU_MONITOR_MIGRATE_TO_FILE_BS, + offset / QEMU_MONITOR_MIGRATE_TO_FILE_BS, + QEMU_MONITOR_MIGRATE_TO_FILE_TRANSFER_SIZE, + safe_target) < 0) { virReportOOMError(); goto cleanup; } diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index c0ebe5f369ccd8c11b30c8bc962934b1760970ac..c08696244f951be88108c346d74d50555e00f81e 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1273,10 +1273,16 @@ int qemuMonitorTextMigrateToFile(qemuMonitorPtr mon, goto cleanup; } - if (virAsprintf(&dest, "exec:%s | dd of=%s bs=%llu seek=%llu", - argstr, safe_target, - QEMU_MONITOR_MIGRATE_TO_FILE_BS, - offset / QEMU_MONITOR_MIGRATE_TO_FILE_BS) < 0) { + /* Two dd processes, sharing the same stdout, are necessary to + * allow starting at an alignment of 512, but without wasting + * padding to get to the larger alignment useful for speed. Use + * <> redirection to avoid truncating a regular file. */ + if (virAsprintf(&dest, "exec:%s | { dd bs=%llu seek=%llu if=/dev/null && " + "dd bs=%llu; } 1<>%s", + argstr, QEMU_MONITOR_MIGRATE_TO_FILE_BS, + offset / QEMU_MONITOR_MIGRATE_TO_FILE_BS, + QEMU_MONITOR_MIGRATE_TO_FILE_TRANSFER_SIZE, + safe_target) < 0) { virReportOOMError(); goto cleanup; }