1 /* 2 * Copyright (c) 2021-2023 Oracle and/or its affiliates. 3 * 4 * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 * See the COPYING file in the top-level directory. 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qemu/cutils.h" 10 #include "qapi/error.h" 11 #include "channel.h" 12 #include "file.h" 13 #include "migration.h" 14 #include "io/channel-file.h" 15 #include "io/channel-util.h" 16 #include "trace.h" 17 18 #define OFFSET_OPTION ",offset=" 19 20 /* Remove the offset option from @filespec and return it in @offsetp. */ 21 22 static int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp) 23 { 24 char *option = strstr(filespec, OFFSET_OPTION); 25 int ret; 26 27 if (option) { 28 *option = 0; 29 option += sizeof(OFFSET_OPTION) - 1; 30 ret = qemu_strtosz(option, NULL, offsetp); 31 if (ret) { 32 error_setg_errno(errp, -ret, "file URI has bad offset %s", option); 33 return -1; 34 } 35 } 36 return 0; 37 } 38 39 void file_start_outgoing_migration(MigrationState *s, const char *filespec, 40 Error **errp) 41 { 42 g_autofree char *filename = g_strdup(filespec); 43 g_autoptr(QIOChannelFile) fioc = NULL; 44 uint64_t offset = 0; 45 QIOChannel *ioc; 46 47 trace_migration_file_outgoing(filename); 48 49 if (file_parse_offset(filename, &offset, errp)) { 50 return; 51 } 52 53 fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY | O_TRUNC, 54 0600, errp); 55 if (!fioc) { 56 return; 57 } 58 59 ioc = QIO_CHANNEL(fioc); 60 if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) { 61 return; 62 } 63 qio_channel_set_name(ioc, "migration-file-outgoing"); 64 migration_channel_connect(s, ioc, NULL, NULL); 65 } 66 67 static gboolean file_accept_incoming_migration(QIOChannel *ioc, 68 GIOCondition condition, 69 gpointer opaque) 70 { 71 migration_channel_process_incoming(ioc); 72 object_unref(OBJECT(ioc)); 73 return G_SOURCE_REMOVE; 74 } 75 76 void file_start_incoming_migration(const char *filespec, Error **errp) 77 { 78 g_autofree char *filename = g_strdup(filespec); 79 QIOChannelFile *fioc = NULL; 80 uint64_t offset = 0; 81 QIOChannel *ioc; 82 83 trace_migration_file_incoming(filename); 84 85 if (file_parse_offset(filename, &offset, errp)) { 86 return; 87 } 88 89 fioc = qio_channel_file_new_path(filename, O_RDONLY, 0, errp); 90 if (!fioc) { 91 return; 92 } 93 94 ioc = QIO_CHANNEL(fioc); 95 if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) { 96 return; 97 } 98 qio_channel_set_name(QIO_CHANNEL(ioc), "migration-file-incoming"); 99 qio_channel_add_watch_full(ioc, G_IO_IN, 100 file_accept_incoming_migration, 101 NULL, NULL, 102 g_main_context_get_thread_default()); 103 } 104