]> Git Repo - qemu.git/blob - migration/qemu-file-unix.c
sd.c: Handle NULL block backend in sd_get_inserted()
[qemu.git] / migration / qemu-file-unix.c
1 /*
2  * QEMU System Emulator
3  *
4  * Copyright (c) 2003-2008 Fabrice Bellard
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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.
23  */
24 #include "qemu/osdep.h"
25 #include "qemu-common.h"
26 #include "qemu/error-report.h"
27 #include "qemu/iov.h"
28 #include "qemu/sockets.h"
29 #include "qemu/coroutine.h"
30 #include "migration/qemu-file.h"
31 #include "migration/qemu-file-internal.h"
32
33 typedef struct QEMUFileSocket {
34     int fd;
35     QEMUFile *file;
36 } QEMUFileSocket;
37
38 static ssize_t socket_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
39                                     int64_t pos)
40 {
41     QEMUFileSocket *s = opaque;
42     ssize_t len;
43     ssize_t size = iov_size(iov, iovcnt);
44     ssize_t offset = 0;
45     int     err;
46
47     while (size > 0) {
48         len = iov_send(s->fd, iov, iovcnt, offset, size);
49
50         if (len > 0) {
51             size -= len;
52             offset += len;
53         }
54
55         if (size > 0) {
56             err = socket_error();
57
58             if (err != EAGAIN && err != EWOULDBLOCK) {
59                 error_report("socket_writev_buffer: Got err=%d for (%zu/%zu)",
60                              err, (size_t)size, (size_t)len);
61                 /*
62                  * If I've already sent some but only just got the error, I
63                  * could return the amount validly sent so far and wait for the
64                  * next call to report the error, but I'd rather flag the error
65                  * immediately.
66                  */
67                 return -err;
68             }
69
70             /* Emulate blocking */
71             GPollFD pfd;
72
73             pfd.fd = s->fd;
74             pfd.events = G_IO_OUT | G_IO_ERR;
75             pfd.revents = 0;
76             TFR(err = g_poll(&pfd, 1, -1 /* no timeout */));
77             /* Errors other than EINTR intentionally ignored */
78         }
79      }
80
81     return offset;
82 }
83
84 static int socket_get_fd(void *opaque)
85 {
86     QEMUFileSocket *s = opaque;
87
88     return s->fd;
89 }
90
91 static ssize_t socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
92                                  size_t size)
93 {
94     QEMUFileSocket *s = opaque;
95     ssize_t len;
96
97     for (;;) {
98         len = qemu_recv(s->fd, buf, size, 0);
99         if (len != -1) {
100             break;
101         }
102         if (socket_error() == EAGAIN) {
103             yield_until_fd_readable(s->fd);
104         } else if (socket_error() != EINTR) {
105             break;
106         }
107     }
108
109     if (len == -1) {
110         len = -socket_error();
111     }
112     return len;
113 }
114
115 static int socket_close(void *opaque)
116 {
117     QEMUFileSocket *s = opaque;
118     closesocket(s->fd);
119     g_free(s);
120     return 0;
121 }
122
123 static int socket_shutdown(void *opaque, bool rd, bool wr)
124 {
125     QEMUFileSocket *s = opaque;
126
127     if (shutdown(s->fd, rd ? (wr ? SHUT_RDWR : SHUT_RD) : SHUT_WR)) {
128         return -errno;
129     } else {
130         return 0;
131     }
132 }
133
134 static int socket_return_close(void *opaque)
135 {
136     QEMUFileSocket *s = opaque;
137     /*
138      * Note: We don't close the socket, that should be done by the forward
139      * path.
140      */
141     g_free(s);
142     return 0;
143 }
144
145 static const QEMUFileOps socket_return_read_ops = {
146     .get_fd          = socket_get_fd,
147     .get_buffer      = socket_get_buffer,
148     .close           = socket_return_close,
149     .shut_down       = socket_shutdown,
150 };
151
152 static const QEMUFileOps socket_return_write_ops = {
153     .get_fd          = socket_get_fd,
154     .writev_buffer   = socket_writev_buffer,
155     .close           = socket_return_close,
156     .shut_down       = socket_shutdown,
157 };
158
159 /*
160  * Give a QEMUFile* off the same socket but data in the opposite
161  * direction.
162  */
163 static QEMUFile *socket_get_return_path(void *opaque)
164 {
165     QEMUFileSocket *forward = opaque;
166     QEMUFileSocket *reverse;
167
168     if (qemu_file_get_error(forward->file)) {
169         /* If the forward file is in error, don't try and open a return */
170         return NULL;
171     }
172
173     reverse = g_malloc0(sizeof(QEMUFileSocket));
174     reverse->fd = forward->fd;
175     /* I don't think there's a better way to tell which direction 'this' is */
176     if (forward->file->ops->get_buffer != NULL) {
177         /* being called from the read side, so we need to be able to write */
178         return qemu_fopen_ops(reverse, &socket_return_write_ops);
179     } else {
180         return qemu_fopen_ops(reverse, &socket_return_read_ops);
181     }
182 }
183
184 static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt,
185                                   int64_t pos)
186 {
187     QEMUFileSocket *s = opaque;
188     ssize_t len, offset;
189     ssize_t size = iov_size(iov, iovcnt);
190     ssize_t total = 0;
191
192     assert(iovcnt > 0);
193     offset = 0;
194     while (size > 0) {
195         /* Find the next start position; skip all full-sized vector elements  */
196         while (offset >= iov[0].iov_len) {
197             offset -= iov[0].iov_len;
198             iov++, iovcnt--;
199         }
200
201         /* skip `offset' bytes from the (now) first element, undo it on exit */
202         assert(iovcnt > 0);
203         iov[0].iov_base += offset;
204         iov[0].iov_len -= offset;
205
206         do {
207             len = writev(s->fd, iov, iovcnt);
208         } while (len == -1 && errno == EINTR);
209         if (len == -1) {
210             return -errno;
211         }
212
213         /* Undo the changes above */
214         iov[0].iov_base -= offset;
215         iov[0].iov_len += offset;
216
217         /* Prepare for the next iteration */
218         offset += len;
219         total += len;
220         size -= len;
221     }
222
223     return total;
224 }
225
226 static ssize_t unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
227                               size_t size)
228 {
229     QEMUFileSocket *s = opaque;
230     ssize_t len;
231
232     for (;;) {
233         len = read(s->fd, buf, size);
234         if (len != -1) {
235             break;
236         }
237         if (errno == EAGAIN) {
238             yield_until_fd_readable(s->fd);
239         } else if (errno != EINTR) {
240             break;
241         }
242     }
243
244     if (len == -1) {
245         len = -errno;
246     }
247     return len;
248 }
249
250 static int unix_close(void *opaque)
251 {
252     QEMUFileSocket *s = opaque;
253     close(s->fd);
254     g_free(s);
255     return 0;
256 }
257
258 static const QEMUFileOps unix_read_ops = {
259     .get_fd =     socket_get_fd,
260     .get_buffer = unix_get_buffer,
261     .close =      unix_close
262 };
263
264 static const QEMUFileOps unix_write_ops = {
265     .get_fd =     socket_get_fd,
266     .writev_buffer = unix_writev_buffer,
267     .close =      unix_close
268 };
269
270 QEMUFile *qemu_fdopen(int fd, const char *mode)
271 {
272     QEMUFileSocket *s;
273
274     if (mode == NULL ||
275         (mode[0] != 'r' && mode[0] != 'w') ||
276         mode[1] != 'b' || mode[2] != 0) {
277         fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
278         return NULL;
279     }
280
281     s = g_new0(QEMUFileSocket, 1);
282     s->fd = fd;
283
284     if (mode[0] == 'r') {
285         s->file = qemu_fopen_ops(s, &unix_read_ops);
286     } else {
287         s->file = qemu_fopen_ops(s, &unix_write_ops);
288     }
289     return s->file;
290 }
291
292 static const QEMUFileOps socket_read_ops = {
293     .get_fd          = socket_get_fd,
294     .get_buffer      = socket_get_buffer,
295     .close           = socket_close,
296     .shut_down       = socket_shutdown,
297     .get_return_path = socket_get_return_path
298 };
299
300 static const QEMUFileOps socket_write_ops = {
301     .get_fd          = socket_get_fd,
302     .writev_buffer   = socket_writev_buffer,
303     .close           = socket_close,
304     .shut_down       = socket_shutdown,
305     .get_return_path = socket_get_return_path
306 };
307
308 QEMUFile *qemu_fopen_socket(int fd, const char *mode)
309 {
310     QEMUFileSocket *s;
311
312     if (qemu_file_mode_is_not_valid(mode)) {
313         return NULL;
314     }
315
316     s = g_new0(QEMUFileSocket, 1);
317     s->fd = fd;
318     if (mode[0] == 'w') {
319         qemu_set_block(s->fd);
320         s->file = qemu_fopen_ops(s, &socket_write_ops);
321     } else {
322         s->file = qemu_fopen_ops(s, &socket_read_ops);
323     }
324     return s->file;
325 }
This page took 0.04198 seconds and 4 git commands to generate.