]> Git Repo - qemu.git/blob - block/nbd-client.c
target-arm: Set CPU has_el3 prop during virt init
[qemu.git] / block / nbd-client.c
1 /*
2  * QEMU Block driver for  NBD
3  *
4  * Copyright (C) 2008 Bull S.A.S.
5  *     Author: Laurent Vivier <[email protected]>
6  *
7  * Some parts:
8  *    Copyright (C) 2007 Anthony Liguori <[email protected]>
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  */
28
29 #include "nbd-client.h"
30 #include "qemu/sockets.h"
31
32 #define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs))
33 #define INDEX_TO_HANDLE(bs, index)  ((index)  ^ ((uint64_t)(intptr_t)bs))
34
35 static void nbd_recv_coroutines_enter_all(NbdClientSession *s)
36 {
37     int i;
38
39     for (i = 0; i < MAX_NBD_REQUESTS; i++) {
40         if (s->recv_coroutine[i]) {
41             qemu_coroutine_enter(s->recv_coroutine[i], NULL);
42         }
43     }
44 }
45
46 static void nbd_teardown_connection(NbdClientSession *client)
47 {
48     /* finish any pending coroutines */
49     shutdown(client->sock, 2);
50     nbd_recv_coroutines_enter_all(client);
51
52     nbd_client_session_detach_aio_context(client);
53     closesocket(client->sock);
54     client->sock = -1;
55 }
56
57 static void nbd_reply_ready(void *opaque)
58 {
59     NbdClientSession *s = opaque;
60     uint64_t i;
61     int ret;
62
63     if (s->reply.handle == 0) {
64         /* No reply already in flight.  Fetch a header.  It is possible
65          * that another thread has done the same thing in parallel, so
66          * the socket is not readable anymore.
67          */
68         ret = nbd_receive_reply(s->sock, &s->reply);
69         if (ret == -EAGAIN) {
70             return;
71         }
72         if (ret < 0) {
73             s->reply.handle = 0;
74             goto fail;
75         }
76     }
77
78     /* There's no need for a mutex on the receive side, because the
79      * handler acts as a synchronization point and ensures that only
80      * one coroutine is called until the reply finishes.  */
81     i = HANDLE_TO_INDEX(s, s->reply.handle);
82     if (i >= MAX_NBD_REQUESTS) {
83         goto fail;
84     }
85
86     if (s->recv_coroutine[i]) {
87         qemu_coroutine_enter(s->recv_coroutine[i], NULL);
88         return;
89     }
90
91 fail:
92     nbd_teardown_connection(s);
93 }
94
95 static void nbd_restart_write(void *opaque)
96 {
97     NbdClientSession *s = opaque;
98
99     qemu_coroutine_enter(s->send_coroutine, NULL);
100 }
101
102 static int nbd_co_send_request(NbdClientSession *s,
103     struct nbd_request *request,
104     QEMUIOVector *qiov, int offset)
105 {
106     AioContext *aio_context;
107     int rc, ret;
108
109     qemu_co_mutex_lock(&s->send_mutex);
110     s->send_coroutine = qemu_coroutine_self();
111     aio_context = bdrv_get_aio_context(s->bs);
112     aio_set_fd_handler(aio_context, s->sock,
113                        nbd_reply_ready, nbd_restart_write, s);
114     if (qiov) {
115         if (!s->is_unix) {
116             socket_set_cork(s->sock, 1);
117         }
118         rc = nbd_send_request(s->sock, request);
119         if (rc >= 0) {
120             ret = qemu_co_sendv(s->sock, qiov->iov, qiov->niov,
121                                 offset, request->len);
122             if (ret != request->len) {
123                 rc = -EIO;
124             }
125         }
126         if (!s->is_unix) {
127             socket_set_cork(s->sock, 0);
128         }
129     } else {
130         rc = nbd_send_request(s->sock, request);
131     }
132     aio_set_fd_handler(aio_context, s->sock, nbd_reply_ready, NULL, s);
133     s->send_coroutine = NULL;
134     qemu_co_mutex_unlock(&s->send_mutex);
135     return rc;
136 }
137
138 static void nbd_co_receive_reply(NbdClientSession *s,
139     struct nbd_request *request, struct nbd_reply *reply,
140     QEMUIOVector *qiov, int offset)
141 {
142     int ret;
143
144     /* Wait until we're woken up by the read handler.  TODO: perhaps
145      * peek at the next reply and avoid yielding if it's ours?  */
146     qemu_coroutine_yield();
147     *reply = s->reply;
148     if (reply->handle != request->handle) {
149         reply->error = EIO;
150     } else {
151         if (qiov && reply->error == 0) {
152             ret = qemu_co_recvv(s->sock, qiov->iov, qiov->niov,
153                                 offset, request->len);
154             if (ret != request->len) {
155                 reply->error = EIO;
156             }
157         }
158
159         /* Tell the read handler to read another header.  */
160         s->reply.handle = 0;
161     }
162 }
163
164 static void nbd_coroutine_start(NbdClientSession *s,
165    struct nbd_request *request)
166 {
167     int i;
168
169     /* Poor man semaphore.  The free_sema is locked when no other request
170      * can be accepted, and unlocked after receiving one reply.  */
171     if (s->in_flight >= MAX_NBD_REQUESTS - 1) {
172         qemu_co_mutex_lock(&s->free_sema);
173         assert(s->in_flight < MAX_NBD_REQUESTS);
174     }
175     s->in_flight++;
176
177     for (i = 0; i < MAX_NBD_REQUESTS; i++) {
178         if (s->recv_coroutine[i] == NULL) {
179             s->recv_coroutine[i] = qemu_coroutine_self();
180             break;
181         }
182     }
183
184     assert(i < MAX_NBD_REQUESTS);
185     request->handle = INDEX_TO_HANDLE(s, i);
186 }
187
188 static void nbd_coroutine_end(NbdClientSession *s,
189     struct nbd_request *request)
190 {
191     int i = HANDLE_TO_INDEX(s, request->handle);
192     s->recv_coroutine[i] = NULL;
193     if (s->in_flight-- == MAX_NBD_REQUESTS) {
194         qemu_co_mutex_unlock(&s->free_sema);
195     }
196 }
197
198 static int nbd_co_readv_1(NbdClientSession *client, int64_t sector_num,
199                           int nb_sectors, QEMUIOVector *qiov,
200                           int offset)
201 {
202     struct nbd_request request = { .type = NBD_CMD_READ };
203     struct nbd_reply reply;
204     ssize_t ret;
205
206     request.from = sector_num * 512;
207     request.len = nb_sectors * 512;
208
209     nbd_coroutine_start(client, &request);
210     ret = nbd_co_send_request(client, &request, NULL, 0);
211     if (ret < 0) {
212         reply.error = -ret;
213     } else {
214         nbd_co_receive_reply(client, &request, &reply, qiov, offset);
215     }
216     nbd_coroutine_end(client, &request);
217     return -reply.error;
218
219 }
220
221 static int nbd_co_writev_1(NbdClientSession *client, int64_t sector_num,
222                            int nb_sectors, QEMUIOVector *qiov,
223                            int offset)
224 {
225     struct nbd_request request = { .type = NBD_CMD_WRITE };
226     struct nbd_reply reply;
227     ssize_t ret;
228
229     if (!bdrv_enable_write_cache(client->bs) &&
230         (client->nbdflags & NBD_FLAG_SEND_FUA)) {
231         request.type |= NBD_CMD_FLAG_FUA;
232     }
233
234     request.from = sector_num * 512;
235     request.len = nb_sectors * 512;
236
237     nbd_coroutine_start(client, &request);
238     ret = nbd_co_send_request(client, &request, qiov, offset);
239     if (ret < 0) {
240         reply.error = -ret;
241     } else {
242         nbd_co_receive_reply(client, &request, &reply, NULL, 0);
243     }
244     nbd_coroutine_end(client, &request);
245     return -reply.error;
246 }
247
248 /* qemu-nbd has a limit of slightly less than 1M per request.  Try to
249  * remain aligned to 4K. */
250 #define NBD_MAX_SECTORS 2040
251
252 int nbd_client_session_co_readv(NbdClientSession *client, int64_t sector_num,
253     int nb_sectors, QEMUIOVector *qiov)
254 {
255     int offset = 0;
256     int ret;
257     while (nb_sectors > NBD_MAX_SECTORS) {
258         ret = nbd_co_readv_1(client, sector_num,
259                              NBD_MAX_SECTORS, qiov, offset);
260         if (ret < 0) {
261             return ret;
262         }
263         offset += NBD_MAX_SECTORS * 512;
264         sector_num += NBD_MAX_SECTORS;
265         nb_sectors -= NBD_MAX_SECTORS;
266     }
267     return nbd_co_readv_1(client, sector_num, nb_sectors, qiov, offset);
268 }
269
270 int nbd_client_session_co_writev(NbdClientSession *client, int64_t sector_num,
271                                  int nb_sectors, QEMUIOVector *qiov)
272 {
273     int offset = 0;
274     int ret;
275     while (nb_sectors > NBD_MAX_SECTORS) {
276         ret = nbd_co_writev_1(client, sector_num,
277                               NBD_MAX_SECTORS, qiov, offset);
278         if (ret < 0) {
279             return ret;
280         }
281         offset += NBD_MAX_SECTORS * 512;
282         sector_num += NBD_MAX_SECTORS;
283         nb_sectors -= NBD_MAX_SECTORS;
284     }
285     return nbd_co_writev_1(client, sector_num, nb_sectors, qiov, offset);
286 }
287
288 int nbd_client_session_co_flush(NbdClientSession *client)
289 {
290     struct nbd_request request = { .type = NBD_CMD_FLUSH };
291     struct nbd_reply reply;
292     ssize_t ret;
293
294     if (!(client->nbdflags & NBD_FLAG_SEND_FLUSH)) {
295         return 0;
296     }
297
298     if (client->nbdflags & NBD_FLAG_SEND_FUA) {
299         request.type |= NBD_CMD_FLAG_FUA;
300     }
301
302     request.from = 0;
303     request.len = 0;
304
305     nbd_coroutine_start(client, &request);
306     ret = nbd_co_send_request(client, &request, NULL, 0);
307     if (ret < 0) {
308         reply.error = -ret;
309     } else {
310         nbd_co_receive_reply(client, &request, &reply, NULL, 0);
311     }
312     nbd_coroutine_end(client, &request);
313     return -reply.error;
314 }
315
316 int nbd_client_session_co_discard(NbdClientSession *client, int64_t sector_num,
317     int nb_sectors)
318 {
319     struct nbd_request request = { .type = NBD_CMD_TRIM };
320     struct nbd_reply reply;
321     ssize_t ret;
322
323     if (!(client->nbdflags & NBD_FLAG_SEND_TRIM)) {
324         return 0;
325     }
326     request.from = sector_num * 512;
327     request.len = nb_sectors * 512;
328
329     nbd_coroutine_start(client, &request);
330     ret = nbd_co_send_request(client, &request, NULL, 0);
331     if (ret < 0) {
332         reply.error = -ret;
333     } else {
334         nbd_co_receive_reply(client, &request, &reply, NULL, 0);
335     }
336     nbd_coroutine_end(client, &request);
337     return -reply.error;
338
339 }
340
341 void nbd_client_session_detach_aio_context(NbdClientSession *client)
342 {
343     aio_set_fd_handler(bdrv_get_aio_context(client->bs), client->sock,
344                        NULL, NULL, NULL);
345 }
346
347 void nbd_client_session_attach_aio_context(NbdClientSession *client,
348                                            AioContext *new_context)
349 {
350     aio_set_fd_handler(new_context, client->sock,
351                        nbd_reply_ready, NULL, client);
352 }
353
354 void nbd_client_session_close(NbdClientSession *client)
355 {
356     struct nbd_request request = {
357         .type = NBD_CMD_DISC,
358         .from = 0,
359         .len = 0
360     };
361
362     if (!client->bs) {
363         return;
364     }
365     if (client->sock == -1) {
366         return;
367     }
368
369     nbd_send_request(client->sock, &request);
370
371     nbd_teardown_connection(client);
372     client->bs = NULL;
373 }
374
375 int nbd_client_session_init(NbdClientSession *client, BlockDriverState *bs,
376     int sock, const char *export)
377 {
378     int ret;
379
380     /* NBD handshake */
381     logout("session init %s\n", export);
382     qemu_set_block(sock);
383     ret = nbd_receive_negotiate(sock, export,
384                                 &client->nbdflags, &client->size,
385                                 &client->blocksize);
386     if (ret < 0) {
387         logout("Failed to negotiate with the NBD server\n");
388         closesocket(sock);
389         return ret;
390     }
391
392     qemu_co_mutex_init(&client->send_mutex);
393     qemu_co_mutex_init(&client->free_sema);
394     client->bs = bs;
395     client->sock = sock;
396
397     /* Now that we're connected, set the socket to be non-blocking and
398      * kick the reply mechanism.  */
399     qemu_set_nonblock(sock);
400     nbd_client_session_attach_aio_context(client, bdrv_get_aio_context(bs));
401
402     logout("Established connection with NBD server\n");
403     return 0;
404 }
This page took 0.044776 seconds and 4 git commands to generate.