file.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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. #include "qemu/osdep.h"
  8. #include "exec/ramblock.h"
  9. #include "qemu/cutils.h"
  10. #include "qemu/error-report.h"
  11. #include "qapi/error.h"
  12. #include "channel.h"
  13. #include "file.h"
  14. #include "migration.h"
  15. #include "io/channel-file.h"
  16. #include "io/channel-socket.h"
  17. #include "io/channel-util.h"
  18. #include "options.h"
  19. #include "trace.h"
  20. #define OFFSET_OPTION ",offset="
  21. static struct FileOutgoingArgs {
  22. char *fname;
  23. } outgoing_args;
  24. /* Remove the offset option from @filespec and return it in @offsetp. */
  25. int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp)
  26. {
  27. char *option = strstr(filespec, OFFSET_OPTION);
  28. int ret;
  29. if (option) {
  30. *option = 0;
  31. option += sizeof(OFFSET_OPTION) - 1;
  32. ret = qemu_strtosz(option, NULL, offsetp);
  33. if (ret) {
  34. error_setg_errno(errp, -ret, "file URI has bad offset %s", option);
  35. return -1;
  36. }
  37. }
  38. return 0;
  39. }
  40. void file_cleanup_outgoing_migration(void)
  41. {
  42. g_free(outgoing_args.fname);
  43. outgoing_args.fname = NULL;
  44. }
  45. static void file_enable_direct_io(int *flags)
  46. {
  47. #ifdef O_DIRECT
  48. *flags |= O_DIRECT;
  49. #else
  50. /* it should have been rejected when setting the parameter */
  51. g_assert_not_reached();
  52. #endif
  53. }
  54. bool file_send_channel_create(gpointer opaque, Error **errp)
  55. {
  56. QIOChannelFile *ioc;
  57. int flags = O_WRONLY;
  58. bool ret = true;
  59. if (migrate_direct_io()) {
  60. /*
  61. * Enable O_DIRECT for the secondary channels. These are used
  62. * for sending ram pages and writes should be guaranteed to be
  63. * aligned to at least page size.
  64. */
  65. file_enable_direct_io(&flags);
  66. }
  67. ioc = qio_channel_file_new_path(outgoing_args.fname, flags, 0, errp);
  68. if (!ioc) {
  69. ret = false;
  70. goto out;
  71. }
  72. multifd_channel_connect(opaque, QIO_CHANNEL(ioc));
  73. out:
  74. /*
  75. * File channel creation is synchronous. However posting this
  76. * semaphore here is simpler than adding a special case.
  77. */
  78. multifd_send_channel_created();
  79. return ret;
  80. }
  81. void file_start_outgoing_migration(MigrationState *s,
  82. FileMigrationArgs *file_args, Error **errp)
  83. {
  84. g_autoptr(QIOChannelFile) fioc = NULL;
  85. g_autofree char *filename = g_strdup(file_args->filename);
  86. uint64_t offset = file_args->offset;
  87. QIOChannel *ioc;
  88. trace_migration_file_outgoing(filename);
  89. fioc = qio_channel_file_new_path(filename, O_CREAT | O_WRONLY, 0600, errp);
  90. if (!fioc) {
  91. return;
  92. }
  93. if (ftruncate(fioc->fd, offset)) {
  94. error_setg_errno(errp, errno,
  95. "failed to truncate migration file to offset %" PRIx64,
  96. offset);
  97. return;
  98. }
  99. outgoing_args.fname = g_strdup(filename);
  100. ioc = QIO_CHANNEL(fioc);
  101. if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) {
  102. return;
  103. }
  104. qio_channel_set_name(ioc, "migration-file-outgoing");
  105. migration_channel_connect(s, ioc, NULL, NULL);
  106. }
  107. static gboolean file_accept_incoming_migration(QIOChannel *ioc,
  108. GIOCondition condition,
  109. gpointer opaque)
  110. {
  111. migration_channel_process_incoming(ioc);
  112. object_unref(OBJECT(ioc));
  113. return G_SOURCE_REMOVE;
  114. }
  115. static void file_create_incoming_channels(QIOChannel *ioc, char *filename,
  116. Error **errp)
  117. {
  118. int i, channels = 1;
  119. g_autofree QIOChannel **iocs = NULL;
  120. int flags = O_RDONLY;
  121. if (migrate_multifd()) {
  122. channels += migrate_multifd_channels();
  123. if (migrate_direct_io()) {
  124. file_enable_direct_io(&flags);
  125. }
  126. }
  127. iocs = g_new0(QIOChannel *, channels);
  128. iocs[0] = ioc;
  129. for (i = 1; i < channels; i++) {
  130. QIOChannelFile *fioc = qio_channel_file_new_path(filename, flags, 0, errp);
  131. if (!fioc) {
  132. while (i) {
  133. object_unref(iocs[--i]);
  134. }
  135. return;
  136. }
  137. iocs[i] = QIO_CHANNEL(fioc);
  138. }
  139. for (i = 0; i < channels; i++) {
  140. qio_channel_set_name(iocs[i], "migration-file-incoming");
  141. qio_channel_add_watch_full(iocs[i], G_IO_IN,
  142. file_accept_incoming_migration,
  143. NULL, NULL,
  144. g_main_context_get_thread_default());
  145. }
  146. }
  147. void file_start_incoming_migration(FileMigrationArgs *file_args, Error **errp)
  148. {
  149. g_autofree char *filename = g_strdup(file_args->filename);
  150. QIOChannelFile *fioc = NULL;
  151. uint64_t offset = file_args->offset;
  152. trace_migration_file_incoming(filename);
  153. fioc = qio_channel_file_new_path(filename, O_RDONLY, 0, errp);
  154. if (!fioc) {
  155. return;
  156. }
  157. if (offset &&
  158. qio_channel_io_seek(QIO_CHANNEL(fioc), offset, SEEK_SET, errp) < 0) {
  159. object_unref(OBJECT(fioc));
  160. return;
  161. }
  162. file_create_incoming_channels(QIO_CHANNEL(fioc), filename, errp);
  163. }
  164. int file_write_ramblock_iov(QIOChannel *ioc, const struct iovec *iov,
  165. int niov, MultiFDPages_t *pages, Error **errp)
  166. {
  167. ssize_t ret = 0;
  168. int i, slice_idx, slice_num;
  169. uintptr_t base, next, offset;
  170. size_t len;
  171. RAMBlock *block = pages->block;
  172. slice_idx = 0;
  173. slice_num = 1;
  174. /*
  175. * If the iov array doesn't have contiguous elements, we need to
  176. * split it in slices because we only have one file offset for the
  177. * whole iov. Do this here so callers don't need to break the iov
  178. * array themselves.
  179. */
  180. for (i = 0; i < niov; i++, slice_num++) {
  181. base = (uintptr_t) iov[i].iov_base;
  182. if (i != niov - 1) {
  183. len = iov[i].iov_len;
  184. next = (uintptr_t) iov[i + 1].iov_base;
  185. if (base + len == next) {
  186. continue;
  187. }
  188. }
  189. /*
  190. * Use the offset of the first element of the segment that
  191. * we're sending.
  192. */
  193. offset = (uintptr_t) iov[slice_idx].iov_base - (uintptr_t) block->host;
  194. if (offset >= block->used_length) {
  195. error_setg(errp, "offset %" PRIxPTR
  196. "outside of ramblock %s range", offset, block->idstr);
  197. ret = -1;
  198. break;
  199. }
  200. ret = qio_channel_pwritev(ioc, &iov[slice_idx], slice_num,
  201. block->pages_offset + offset, errp);
  202. if (ret < 0) {
  203. break;
  204. }
  205. slice_idx += slice_num;
  206. slice_num = 0;
  207. }
  208. return (ret < 0) ? ret : 0;
  209. }
  210. int multifd_file_recv_data(MultiFDRecvParams *p, Error **errp)
  211. {
  212. MultiFDRecvData *data = p->data;
  213. size_t ret;
  214. ret = qio_channel_pread(p->c, (char *) data->opaque,
  215. data->size, data->file_offset, errp);
  216. if (ret != data->size) {
  217. error_prepend(errp,
  218. "multifd recv (%u): read 0x%zx, expected 0x%zx",
  219. p->id, ret, data->size);
  220. return -1;
  221. }
  222. return 0;
  223. }