xref: /openbmc/qemu/migration/file.c (revision a9bc470ec208bd27a82100abc9dccf1b69f41b45)
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  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,
40                                     FileMigrationArgs *file_args, Error **errp)
41  {
42      g_autoptr(QIOChannelFile) fioc = NULL;
43      g_autofree char *filename = g_strdup(file_args->filename);
44      uint64_t offset = file_args->offset;
45      QIOChannel *ioc;
46  
47      trace_migration_file_outgoing(filename);
48  
49      fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY | O_TRUNC,
50                                       0600, errp);
51      if (!fioc) {
52          return;
53      }
54  
55      ioc = QIO_CHANNEL(fioc);
56      if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) {
57          return;
58      }
59      qio_channel_set_name(ioc, "migration-file-outgoing");
60      migration_channel_connect(s, ioc, NULL, NULL);
61  }
62  
63  static gboolean file_accept_incoming_migration(QIOChannel *ioc,
64                                                 GIOCondition condition,
65                                                 gpointer opaque)
66  {
67      migration_channel_process_incoming(ioc);
68      object_unref(OBJECT(ioc));
69      return G_SOURCE_REMOVE;
70  }
71  
72  void file_start_incoming_migration(FileMigrationArgs *file_args, Error **errp)
73  {
74      g_autofree char *filename = g_strdup(file_args->filename);
75      QIOChannelFile *fioc = NULL;
76      uint64_t offset = file_args->offset;
77      QIOChannel *ioc;
78  
79      trace_migration_file_incoming(filename);
80  
81      fioc = qio_channel_file_new_path(filename, O_RDONLY, 0, errp);
82      if (!fioc) {
83          return;
84      }
85  
86      ioc = QIO_CHANNEL(fioc);
87      if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) {
88          return;
89      }
90      qio_channel_set_name(QIO_CHANNEL(ioc), "migration-file-incoming");
91      qio_channel_add_watch_full(ioc, G_IO_IN,
92                                 file_accept_incoming_migration,
93                                 NULL, NULL,
94                                 g_main_context_get_thread_default());
95  }
96