xref: /qemu/migration/file.c (revision b7b03eb6)
12a9e2e59SSteve Sistare /*
22a9e2e59SSteve Sistare  * Copyright (c) 2021-2023 Oracle and/or its affiliates.
32a9e2e59SSteve Sistare  *
42a9e2e59SSteve Sistare  * This work is licensed under the terms of the GNU GPL, version 2 or later.
52a9e2e59SSteve Sistare  * See the COPYING file in the top-level directory.
62a9e2e59SSteve Sistare  */
72a9e2e59SSteve Sistare 
82a9e2e59SSteve Sistare #include "qemu/osdep.h"
9d117ed06SFabiano Rosas #include "exec/ramblock.h"
10385f510dSSteve Sistare #include "qemu/cutils.h"
11385f510dSSteve Sistare #include "qapi/error.h"
122a9e2e59SSteve Sistare #include "channel.h"
132a9e2e59SSteve Sistare #include "file.h"
142a9e2e59SSteve Sistare #include "migration.h"
15b7b03eb6SFabiano Rosas #include "multifd.h"
162a9e2e59SSteve Sistare #include "io/channel-file.h"
172a9e2e59SSteve Sistare #include "io/channel-util.h"
182a9e2e59SSteve Sistare #include "trace.h"
192a9e2e59SSteve Sistare 
20385f510dSSteve Sistare #define OFFSET_OPTION ",offset="
21385f510dSSteve Sistare 
22b7b03eb6SFabiano Rosas static struct FileOutgoingArgs {
23b7b03eb6SFabiano Rosas     char *fname;
24b7b03eb6SFabiano Rosas } outgoing_args;
25b7b03eb6SFabiano Rosas 
26385f510dSSteve Sistare /* Remove the offset option from @filespec and return it in @offsetp. */
27385f510dSSteve Sistare 
2872a8192eSHet Gala int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp)
29385f510dSSteve Sistare {
30385f510dSSteve Sistare     char *option = strstr(filespec, OFFSET_OPTION);
31385f510dSSteve Sistare     int ret;
32385f510dSSteve Sistare 
33385f510dSSteve Sistare     if (option) {
34385f510dSSteve Sistare         *option = 0;
35385f510dSSteve Sistare         option += sizeof(OFFSET_OPTION) - 1;
36385f510dSSteve Sistare         ret = qemu_strtosz(option, NULL, offsetp);
37385f510dSSteve Sistare         if (ret) {
38385f510dSSteve Sistare             error_setg_errno(errp, -ret, "file URI has bad offset %s", option);
39385f510dSSteve Sistare             return -1;
40385f510dSSteve Sistare         }
41385f510dSSteve Sistare     }
42385f510dSSteve Sistare     return 0;
43385f510dSSteve Sistare }
44385f510dSSteve Sistare 
45b7b03eb6SFabiano Rosas void file_cleanup_outgoing_migration(void)
46b7b03eb6SFabiano Rosas {
47b7b03eb6SFabiano Rosas     g_free(outgoing_args.fname);
48b7b03eb6SFabiano Rosas     outgoing_args.fname = NULL;
49b7b03eb6SFabiano Rosas }
50b7b03eb6SFabiano Rosas 
51b7b03eb6SFabiano Rosas bool file_send_channel_create(gpointer opaque, Error **errp)
52b7b03eb6SFabiano Rosas {
53b7b03eb6SFabiano Rosas     QIOChannelFile *ioc;
54b7b03eb6SFabiano Rosas     int flags = O_WRONLY;
55b7b03eb6SFabiano Rosas     bool ret = true;
56b7b03eb6SFabiano Rosas 
57b7b03eb6SFabiano Rosas     ioc = qio_channel_file_new_path(outgoing_args.fname, flags, 0, errp);
58b7b03eb6SFabiano Rosas     if (!ioc) {
59b7b03eb6SFabiano Rosas         ret = false;
60b7b03eb6SFabiano Rosas         goto out;
61b7b03eb6SFabiano Rosas     }
62b7b03eb6SFabiano Rosas 
63b7b03eb6SFabiano Rosas     multifd_channel_connect(opaque, QIO_CHANNEL(ioc));
64b7b03eb6SFabiano Rosas 
65b7b03eb6SFabiano Rosas out:
66b7b03eb6SFabiano Rosas     /*
67b7b03eb6SFabiano Rosas      * File channel creation is synchronous. However posting this
68b7b03eb6SFabiano Rosas      * semaphore here is simpler than adding a special case.
69b7b03eb6SFabiano Rosas      */
70b7b03eb6SFabiano Rosas     multifd_send_channel_created();
71b7b03eb6SFabiano Rosas 
72b7b03eb6SFabiano Rosas     return ret;
73b7b03eb6SFabiano Rosas }
74b7b03eb6SFabiano Rosas 
7502afba63SFabiano Rosas void file_start_outgoing_migration(MigrationState *s,
7602afba63SFabiano Rosas                                    FileMigrationArgs *file_args, Error **errp)
772a9e2e59SSteve Sistare {
782a9e2e59SSteve Sistare     g_autoptr(QIOChannelFile) fioc = NULL;
7902afba63SFabiano Rosas     g_autofree char *filename = g_strdup(file_args->filename);
8002afba63SFabiano Rosas     uint64_t offset = file_args->offset;
812a9e2e59SSteve Sistare     QIOChannel *ioc;
822a9e2e59SSteve Sistare 
832a9e2e59SSteve Sistare     trace_migration_file_outgoing(filename);
842a9e2e59SSteve Sistare 
852a9e2e59SSteve Sistare     fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY | O_TRUNC,
862a9e2e59SSteve Sistare                                      0600, errp);
872a9e2e59SSteve Sistare     if (!fioc) {
882a9e2e59SSteve Sistare         return;
892a9e2e59SSteve Sistare     }
902a9e2e59SSteve Sistare 
91b7b03eb6SFabiano Rosas     outgoing_args.fname = g_strdup(filename);
92b7b03eb6SFabiano Rosas 
932a9e2e59SSteve Sistare     ioc = QIO_CHANNEL(fioc);
94385f510dSSteve Sistare     if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) {
95385f510dSSteve Sistare         return;
96385f510dSSteve Sistare     }
972a9e2e59SSteve Sistare     qio_channel_set_name(ioc, "migration-file-outgoing");
982a9e2e59SSteve Sistare     migration_channel_connect(s, ioc, NULL, NULL);
992a9e2e59SSteve Sistare }
1002a9e2e59SSteve Sistare 
1012a9e2e59SSteve Sistare static gboolean file_accept_incoming_migration(QIOChannel *ioc,
1022a9e2e59SSteve Sistare                                                GIOCondition condition,
1032a9e2e59SSteve Sistare                                                gpointer opaque)
1042a9e2e59SSteve Sistare {
1052a9e2e59SSteve Sistare     migration_channel_process_incoming(ioc);
1062a9e2e59SSteve Sistare     object_unref(OBJECT(ioc));
1072a9e2e59SSteve Sistare     return G_SOURCE_REMOVE;
1082a9e2e59SSteve Sistare }
1092a9e2e59SSteve Sistare 
11002afba63SFabiano Rosas void file_start_incoming_migration(FileMigrationArgs *file_args, Error **errp)
1112a9e2e59SSteve Sistare {
11202afba63SFabiano Rosas     g_autofree char *filename = g_strdup(file_args->filename);
1132a9e2e59SSteve Sistare     QIOChannelFile *fioc = NULL;
11402afba63SFabiano Rosas     uint64_t offset = file_args->offset;
1152a9e2e59SSteve Sistare     QIOChannel *ioc;
1162a9e2e59SSteve Sistare 
1172a9e2e59SSteve Sistare     trace_migration_file_incoming(filename);
1182a9e2e59SSteve Sistare 
1192a9e2e59SSteve Sistare     fioc = qio_channel_file_new_path(filename, O_RDONLY, 0, errp);
1202a9e2e59SSteve Sistare     if (!fioc) {
1212a9e2e59SSteve Sistare         return;
1222a9e2e59SSteve Sistare     }
1232a9e2e59SSteve Sistare 
1242a9e2e59SSteve Sistare     ioc = QIO_CHANNEL(fioc);
125385f510dSSteve Sistare     if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) {
126385f510dSSteve Sistare         return;
127385f510dSSteve Sistare     }
1282a9e2e59SSteve Sistare     qio_channel_set_name(QIO_CHANNEL(ioc), "migration-file-incoming");
1292a9e2e59SSteve Sistare     qio_channel_add_watch_full(ioc, G_IO_IN,
1302a9e2e59SSteve Sistare                                file_accept_incoming_migration,
1312a9e2e59SSteve Sistare                                NULL, NULL,
1322a9e2e59SSteve Sistare                                g_main_context_get_thread_default());
1332a9e2e59SSteve Sistare }
134