xref: /qemu/migration/file.c (revision 72a8192e225ceafd8494150eb9375c400da50dd6)
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"
9385f510dSSteve Sistare #include "qemu/cutils.h"
10385f510dSSteve Sistare #include "qapi/error.h"
112a9e2e59SSteve Sistare #include "channel.h"
122a9e2e59SSteve Sistare #include "file.h"
132a9e2e59SSteve Sistare #include "migration.h"
142a9e2e59SSteve Sistare #include "io/channel-file.h"
152a9e2e59SSteve Sistare #include "io/channel-util.h"
162a9e2e59SSteve Sistare #include "trace.h"
172a9e2e59SSteve Sistare 
18385f510dSSteve Sistare #define OFFSET_OPTION ",offset="
19385f510dSSteve Sistare 
20385f510dSSteve Sistare /* Remove the offset option from @filespec and return it in @offsetp. */
21385f510dSSteve Sistare 
22*72a8192eSHet Gala int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp)
23385f510dSSteve Sistare {
24385f510dSSteve Sistare     char *option = strstr(filespec, OFFSET_OPTION);
25385f510dSSteve Sistare     int ret;
26385f510dSSteve Sistare 
27385f510dSSteve Sistare     if (option) {
28385f510dSSteve Sistare         *option = 0;
29385f510dSSteve Sistare         option += sizeof(OFFSET_OPTION) - 1;
30385f510dSSteve Sistare         ret = qemu_strtosz(option, NULL, offsetp);
31385f510dSSteve Sistare         if (ret) {
32385f510dSSteve Sistare             error_setg_errno(errp, -ret, "file URI has bad offset %s", option);
33385f510dSSteve Sistare             return -1;
34385f510dSSteve Sistare         }
35385f510dSSteve Sistare     }
36385f510dSSteve Sistare     return 0;
37385f510dSSteve Sistare }
38385f510dSSteve Sistare 
39385f510dSSteve Sistare void file_start_outgoing_migration(MigrationState *s, const char *filespec,
402a9e2e59SSteve Sistare                                    Error **errp)
412a9e2e59SSteve Sistare {
42385f510dSSteve Sistare     g_autofree char *filename = g_strdup(filespec);
432a9e2e59SSteve Sistare     g_autoptr(QIOChannelFile) fioc = NULL;
44385f510dSSteve Sistare     uint64_t offset = 0;
452a9e2e59SSteve Sistare     QIOChannel *ioc;
462a9e2e59SSteve Sistare 
472a9e2e59SSteve Sistare     trace_migration_file_outgoing(filename);
482a9e2e59SSteve Sistare 
49385f510dSSteve Sistare     if (file_parse_offset(filename, &offset, errp)) {
50385f510dSSteve Sistare         return;
51385f510dSSteve Sistare     }
52385f510dSSteve Sistare 
532a9e2e59SSteve Sistare     fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY | O_TRUNC,
542a9e2e59SSteve Sistare                                      0600, errp);
552a9e2e59SSteve Sistare     if (!fioc) {
562a9e2e59SSteve Sistare         return;
572a9e2e59SSteve Sistare     }
582a9e2e59SSteve Sistare 
592a9e2e59SSteve Sistare     ioc = QIO_CHANNEL(fioc);
60385f510dSSteve Sistare     if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) {
61385f510dSSteve Sistare         return;
62385f510dSSteve Sistare     }
632a9e2e59SSteve Sistare     qio_channel_set_name(ioc, "migration-file-outgoing");
642a9e2e59SSteve Sistare     migration_channel_connect(s, ioc, NULL, NULL);
652a9e2e59SSteve Sistare }
662a9e2e59SSteve Sistare 
672a9e2e59SSteve Sistare static gboolean file_accept_incoming_migration(QIOChannel *ioc,
682a9e2e59SSteve Sistare                                                GIOCondition condition,
692a9e2e59SSteve Sistare                                                gpointer opaque)
702a9e2e59SSteve Sistare {
712a9e2e59SSteve Sistare     migration_channel_process_incoming(ioc);
722a9e2e59SSteve Sistare     object_unref(OBJECT(ioc));
732a9e2e59SSteve Sistare     return G_SOURCE_REMOVE;
742a9e2e59SSteve Sistare }
752a9e2e59SSteve Sistare 
76385f510dSSteve Sistare void file_start_incoming_migration(const char *filespec, Error **errp)
772a9e2e59SSteve Sistare {
78385f510dSSteve Sistare     g_autofree char *filename = g_strdup(filespec);
792a9e2e59SSteve Sistare     QIOChannelFile *fioc = NULL;
80385f510dSSteve Sistare     uint64_t offset = 0;
812a9e2e59SSteve Sistare     QIOChannel *ioc;
822a9e2e59SSteve Sistare 
832a9e2e59SSteve Sistare     trace_migration_file_incoming(filename);
842a9e2e59SSteve Sistare 
85385f510dSSteve Sistare     if (file_parse_offset(filename, &offset, errp)) {
86385f510dSSteve Sistare         return;
87385f510dSSteve Sistare     }
88385f510dSSteve Sistare 
892a9e2e59SSteve Sistare     fioc = qio_channel_file_new_path(filename, O_RDONLY, 0, errp);
902a9e2e59SSteve Sistare     if (!fioc) {
912a9e2e59SSteve Sistare         return;
922a9e2e59SSteve Sistare     }
932a9e2e59SSteve Sistare 
942a9e2e59SSteve Sistare     ioc = QIO_CHANNEL(fioc);
95385f510dSSteve Sistare     if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) {
96385f510dSSteve Sistare         return;
97385f510dSSteve Sistare     }
982a9e2e59SSteve Sistare     qio_channel_set_name(QIO_CHANNEL(ioc), "migration-file-incoming");
992a9e2e59SSteve Sistare     qio_channel_add_watch_full(ioc, G_IO_IN,
1002a9e2e59SSteve Sistare                                file_accept_incoming_migration,
1012a9e2e59SSteve Sistare                                NULL, NULL,
1022a9e2e59SSteve Sistare                                g_main_context_get_thread_default());
1032a9e2e59SSteve Sistare }
104