enable multi-function hot-add
[qemu/ar7.git] / migration / qemu-file-unix.c
blob809bf070d73e2aa7c99d0ebb7673ab6383a07781
1 /*
2 * QEMU System Emulator
4 * Copyright (c) 2003-2008 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include "qemu-common.h"
25 #include "qemu/iov.h"
26 #include "qemu/sockets.h"
27 #include "qemu/coroutine.h"
28 #include "migration/qemu-file.h"
29 #include "migration/qemu-file-internal.h"
31 typedef struct QEMUFileSocket {
32 int fd;
33 QEMUFile *file;
34 } QEMUFileSocket;
36 static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
37 int64_t pos)
39 QEMUFileSocket *s = opaque;
40 ssize_t len;
41 ssize_t size = iov_size(iov, iovcnt);
43 len = iov_send(s->fd, iov, iovcnt, 0, size);
44 if (len < size) {
45 len = -socket_error();
47 return len;
50 static int socket_get_fd(void *opaque)
52 QEMUFileSocket *s = opaque;
54 return s->fd;
57 static ssize_t socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
58 size_t size)
60 QEMUFileSocket *s = opaque;
61 ssize_t len;
63 for (;;) {
64 len = qemu_recv(s->fd, buf, size, 0);
65 if (len != -1) {
66 break;
68 if (socket_error() == EAGAIN) {
69 yield_until_fd_readable(s->fd);
70 } else if (socket_error() != EINTR) {
71 break;
75 if (len == -1) {
76 len = -socket_error();
78 return len;
81 static int socket_close(void *opaque)
83 QEMUFileSocket *s = opaque;
84 closesocket(s->fd);
85 g_free(s);
86 return 0;
89 static int socket_shutdown(void *opaque, bool rd, bool wr)
91 QEMUFileSocket *s = opaque;
93 if (shutdown(s->fd, rd ? (wr ? SHUT_RDWR : SHUT_RD) : SHUT_WR)) {
94 return -errno;
95 } else {
96 return 0;
100 static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
101 int64_t pos)
103 QEMUFileSocket *s = opaque;
104 ssize_t len, offset;
105 ssize_t size = iov_size(iov, iovcnt);
106 ssize_t total = 0;
108 assert(iovcnt > 0);
109 offset = 0;
110 while (size > 0) {
111 /* Find the next start position; skip all full-sized vector elements */
112 while (offset >= iov[0].iov_len) {
113 offset -= iov[0].iov_len;
114 iov++, iovcnt--;
117 /* skip `offset' bytes from the (now) first element, undo it on exit */
118 assert(iovcnt > 0);
119 iov[0].iov_base += offset;
120 iov[0].iov_len -= offset;
122 do {
123 len = writev(s->fd, iov, iovcnt);
124 } while (len == -1 && errno == EINTR);
125 if (len == -1) {
126 return -errno;
129 /* Undo the changes above */
130 iov[0].iov_base -= offset;
131 iov[0].iov_len += offset;
133 /* Prepare for the next iteration */
134 offset += len;
135 total += len;
136 size -= len;
139 return total;
142 static ssize_t unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
143 size_t size)
145 QEMUFileSocket *s = opaque;
146 ssize_t len;
148 for (;;) {
149 len = read(s->fd, buf, size);
150 if (len != -1) {
151 break;
153 if (errno == EAGAIN) {
154 yield_until_fd_readable(s->fd);
155 } else if (errno != EINTR) {
156 break;
160 if (len == -1) {
161 len = -errno;
163 return len;
166 static int unix_close(void *opaque)
168 QEMUFileSocket *s = opaque;
169 close(s->fd);
170 g_free(s);
171 return 0;
174 static const QEMUFileOps unix_read_ops = {
175 .get_fd = socket_get_fd,
176 .get_buffer = unix_get_buffer,
177 .close = unix_close
180 static const QEMUFileOps unix_write_ops = {
181 .get_fd = socket_get_fd,
182 .writev_buffer = unix_writev_buffer,
183 .close = unix_close
186 QEMUFile *qemu_fdopen(int fd, const char *mode)
188 QEMUFileSocket *s;
190 if (mode == NULL ||
191 (mode[0] != 'r' && mode[0] != 'w') ||
192 mode[1] != 'b' || mode[2] != 0) {
193 fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
194 return NULL;
197 s = g_new0(QEMUFileSocket, 1);
198 s->fd = fd;
200 if (mode[0] == 'r') {
201 s->file = qemu_fopen_ops(s, &unix_read_ops);
202 } else {
203 s->file = qemu_fopen_ops(s, &unix_write_ops);
205 return s->file;
208 static const QEMUFileOps socket_read_ops = {
209 .get_fd = socket_get_fd,
210 .get_buffer = socket_get_buffer,
211 .close = socket_close,
212 .shut_down = socket_shutdown
216 static const QEMUFileOps socket_write_ops = {
217 .get_fd = socket_get_fd,
218 .writev_buffer = socket_writev_buffer,
219 .close = socket_close,
220 .shut_down = socket_shutdown
223 QEMUFile *qemu_fopen_socket(int fd, const char *mode)
225 QEMUFileSocket *s;
227 if (qemu_file_mode_is_not_valid(mode)) {
228 return NULL;
231 s = g_new0(QEMUFileSocket, 1);
232 s->fd = fd;
233 if (mode[0] == 'w') {
234 qemu_set_block(s->fd);
235 s->file = qemu_fopen_ops(s, &socket_write_ops);
236 } else {
237 s->file = qemu_fopen_ops(s, &socket_read_ops);
239 return s->file;