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