![Fabiano Rosas](/assets/img/avatar_default.png)
When the "file:" migration support was added we missed the special case in the qemu_open_old implementation that allows for a particular file name format to be used to refer to a set of file descriptors that have been previously provided to QEMU via the add-fd QMP command. When using this fdset feature, we should not truncate the migration file because being given an fd means that the management layer is in control of the file and will likely already have some data written to it. This is further indicated by the presence of the 'offset' argument, which indicates the start of the region where QEMU is allowed to write. Fix the issue by replacing the O_TRUNC flag on open by an ftruncate call, which will take the offset into consideration. Fixes: 385f510df5 ("migration: file URI offset") Suggested-by: Daniel P. Berrangé <berrange@redhat.com> Reviewed-by: Prasad Pandit <pjp@fedoraproject.org> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Fabiano Rosas <farosas@suse.de> (cherry picked from commit 6d3279655ac49b806265f08415165f471d33e032) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> (Mjt: context fixup in migration/file.c due to missing v8.2.0-1958-gb7b03eb614d0 "migration/multifd: Add outgoing QIOChannelFile support")
103 lines
3.0 KiB
C
103 lines
3.0 KiB
C
/*
|
|
* Copyright (c) 2021-2023 Oracle and/or its affiliates.
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
* See the COPYING file in the top-level directory.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/cutils.h"
|
|
#include "qapi/error.h"
|
|
#include "channel.h"
|
|
#include "file.h"
|
|
#include "migration.h"
|
|
#include "io/channel-file.h"
|
|
#include "io/channel-util.h"
|
|
#include "trace.h"
|
|
|
|
#define OFFSET_OPTION ",offset="
|
|
|
|
/* Remove the offset option from @filespec and return it in @offsetp. */
|
|
|
|
int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp)
|
|
{
|
|
char *option = strstr(filespec, OFFSET_OPTION);
|
|
int ret;
|
|
|
|
if (option) {
|
|
*option = 0;
|
|
option += sizeof(OFFSET_OPTION) - 1;
|
|
ret = qemu_strtosz(option, NULL, offsetp);
|
|
if (ret) {
|
|
error_setg_errno(errp, -ret, "file URI has bad offset %s", option);
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void file_start_outgoing_migration(MigrationState *s,
|
|
FileMigrationArgs *file_args, Error **errp)
|
|
{
|
|
g_autoptr(QIOChannelFile) fioc = NULL;
|
|
g_autofree char *filename = g_strdup(file_args->filename);
|
|
uint64_t offset = file_args->offset;
|
|
QIOChannel *ioc;
|
|
|
|
trace_migration_file_outgoing(filename);
|
|
|
|
fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY, 0600, errp);
|
|
if (!fioc) {
|
|
return;
|
|
}
|
|
|
|
if (ftruncate(fioc->fd, offset)) {
|
|
error_setg_errno(errp, errno,
|
|
"failed to truncate migration file to offset %" PRIx64,
|
|
offset);
|
|
object_unref(OBJECT(fioc));
|
|
return;
|
|
}
|
|
|
|
ioc = QIO_CHANNEL(fioc);
|
|
if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) {
|
|
return;
|
|
}
|
|
qio_channel_set_name(ioc, "migration-file-outgoing");
|
|
migration_channel_connect(s, ioc, NULL, NULL);
|
|
}
|
|
|
|
static gboolean file_accept_incoming_migration(QIOChannel *ioc,
|
|
GIOCondition condition,
|
|
gpointer opaque)
|
|
{
|
|
migration_channel_process_incoming(ioc);
|
|
object_unref(OBJECT(ioc));
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
void file_start_incoming_migration(FileMigrationArgs *file_args, Error **errp)
|
|
{
|
|
g_autofree char *filename = g_strdup(file_args->filename);
|
|
QIOChannelFile *fioc = NULL;
|
|
uint64_t offset = file_args->offset;
|
|
QIOChannel *ioc;
|
|
|
|
trace_migration_file_incoming(filename);
|
|
|
|
fioc = qio_channel_file_new_path(filename, O_RDONLY, 0, errp);
|
|
if (!fioc) {
|
|
return;
|
|
}
|
|
|
|
ioc = QIO_CHANNEL(fioc);
|
|
if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) {
|
|
return;
|
|
}
|
|
qio_channel_set_name(QIO_CHANNEL(ioc), "migration-file-incoming");
|
|
qio_channel_add_watch_full(ioc, G_IO_IN,
|
|
file_accept_incoming_migration,
|
|
NULL, NULL,
|
|
g_main_context_get_thread_default());
|
|
}
|