2 * QEMU Block driver for NBD
4 * Copyright (C) 2016 Red Hat, Inc.
5 * Copyright (C) 2008 Bull S.A.S.
6 * Author: Laurent Vivier <Laurent.Vivier@bull.net>
9 * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 #include "qemu/osdep.h"
33 #include "qapi/error.h"
34 #include "nbd-client.h"
36 #define HANDLE_TO_INDEX(bs, handle) ((handle) ^ (uint64_t)(intptr_t)(bs))
37 #define INDEX_TO_HANDLE(bs, index) ((index) ^ (uint64_t)(intptr_t)(bs))
39 static void nbd_recv_coroutines_wake_all(NBDClientSession
*s
)
43 for (i
= 0; i
< MAX_NBD_REQUESTS
; i
++) {
44 NBDClientRequest
*req
= &s
->requests
[i
];
46 if (req
->coroutine
&& req
->receiving
) {
47 aio_co_wake(req
->coroutine
);
52 static void nbd_teardown_connection(BlockDriverState
*bs
)
54 NBDClientSession
*client
= nbd_get_client_session(bs
);
56 if (!client
->ioc
) { /* Already closed */
60 /* finish any pending coroutines */
61 qio_channel_shutdown(client
->ioc
,
62 QIO_CHANNEL_SHUTDOWN_BOTH
,
64 BDRV_POLL_WHILE(bs
, client
->read_reply_co
);
66 nbd_client_detach_aio_context(bs
);
67 object_unref(OBJECT(client
->sioc
));
69 object_unref(OBJECT(client
->ioc
));
73 static coroutine_fn
void nbd_read_reply_entry(void *opaque
)
75 NBDClientSession
*s
= opaque
;
78 Error
*local_err
= NULL
;
81 assert(s
->reply
.handle
== 0);
82 ret
= nbd_receive_reply(s
->ioc
, &s
->reply
, &local_err
);
84 trace_nbd_read_reply_entry_fail(ret
, error_get_pretty(local_err
));
85 error_free(local_err
);
91 /* There's no need for a mutex on the receive side, because the
92 * handler acts as a synchronization point and ensures that only
93 * one coroutine is called until the reply finishes.
95 i
= HANDLE_TO_INDEX(s
, s
->reply
.handle
);
96 if (i
>= MAX_NBD_REQUESTS
||
97 !s
->requests
[i
].coroutine
||
98 !s
->requests
[i
].receiving
||
99 (nbd_reply_is_structured(&s
->reply
) && !s
->info
.structured_reply
))
104 /* We're woken up again by the request itself. Note that there
105 * is no race between yielding and reentering read_reply_co. This
108 * - if the request runs on the same AioContext, it is only
109 * entered after we yield
111 * - if the request runs on a different AioContext, reentering
112 * read_reply_co happens through a bottom half, which can only
113 * run after we yield.
115 aio_co_wake(s
->requests
[i
].coroutine
);
116 qemu_coroutine_yield();
120 nbd_recv_coroutines_wake_all(s
);
121 s
->read_reply_co
= NULL
;
124 static int nbd_co_send_request(BlockDriverState
*bs
,
128 NBDClientSession
*s
= nbd_get_client_session(bs
);
131 qemu_co_mutex_lock(&s
->send_mutex
);
132 while (s
->in_flight
== MAX_NBD_REQUESTS
) {
133 qemu_co_queue_wait(&s
->free_sema
, &s
->send_mutex
);
137 for (i
= 0; i
< MAX_NBD_REQUESTS
; i
++) {
138 if (s
->requests
[i
].coroutine
== NULL
) {
143 g_assert(qemu_in_coroutine());
144 assert(i
< MAX_NBD_REQUESTS
);
146 s
->requests
[i
].coroutine
= qemu_coroutine_self();
147 s
->requests
[i
].offset
= request
->from
;
148 s
->requests
[i
].receiving
= false;
150 request
->handle
= INDEX_TO_HANDLE(s
, i
);
162 qio_channel_set_cork(s
->ioc
, true);
163 rc
= nbd_send_request(s
->ioc
, request
);
164 if (rc
>= 0 && !s
->quit
) {
165 if (qio_channel_writev_all(s
->ioc
, qiov
->iov
, qiov
->niov
,
169 } else if (rc
>= 0) {
172 qio_channel_set_cork(s
->ioc
, false);
174 rc
= nbd_send_request(s
->ioc
, request
);
180 s
->requests
[i
].coroutine
= NULL
;
182 qemu_co_queue_next(&s
->free_sema
);
184 qemu_co_mutex_unlock(&s
->send_mutex
);
188 static inline uint16_t payload_advance16(uint8_t **payload
)
191 return lduw_be_p(*payload
- 2);
194 static inline uint32_t payload_advance32(uint8_t **payload
)
197 return ldl_be_p(*payload
- 4);
200 static inline uint64_t payload_advance64(uint8_t **payload
)
203 return ldq_be_p(*payload
- 8);
206 static int nbd_parse_offset_hole_payload(NBDStructuredReplyChunk
*chunk
,
207 uint8_t *payload
, uint64_t orig_offset
,
208 QEMUIOVector
*qiov
, Error
**errp
)
213 if (chunk
->length
!= sizeof(offset
) + sizeof(hole_size
)) {
214 error_setg(errp
, "Protocol error: invalid payload for "
215 "NBD_REPLY_TYPE_OFFSET_HOLE");
219 offset
= payload_advance64(&payload
);
220 hole_size
= payload_advance32(&payload
);
222 if (!hole_size
|| offset
< orig_offset
|| hole_size
> qiov
->size
||
223 offset
> orig_offset
+ qiov
->size
- hole_size
) {
224 error_setg(errp
, "Protocol error: server sent chunk exceeding requested"
229 qemu_iovec_memset(qiov
, offset
- orig_offset
, 0, hole_size
);
234 /* nbd_parse_blockstatus_payload
235 * support only one extent in reply and only for
236 * base:allocation context
238 static int nbd_parse_blockstatus_payload(NBDClientSession
*client
,
239 NBDStructuredReplyChunk
*chunk
,
240 uint8_t *payload
, uint64_t orig_length
,
241 NBDExtent
*extent
, Error
**errp
)
245 if (chunk
->length
!= sizeof(context_id
) + sizeof(*extent
)) {
246 error_setg(errp
, "Protocol error: invalid payload for "
247 "NBD_REPLY_TYPE_BLOCK_STATUS");
251 context_id
= payload_advance32(&payload
);
252 if (client
->info
.meta_base_allocation_id
!= context_id
) {
253 error_setg(errp
, "Protocol error: unexpected context id %d for "
254 "NBD_REPLY_TYPE_BLOCK_STATUS, when negotiated context "
255 "id is %d", context_id
,
256 client
->info
.meta_base_allocation_id
);
260 extent
->length
= payload_advance32(&payload
);
261 extent
->flags
= payload_advance32(&payload
);
263 if (extent
->length
== 0 ||
264 (client
->info
.min_block
&& !QEMU_IS_ALIGNED(extent
->length
,
265 client
->info
.min_block
))) {
266 error_setg(errp
, "Protocol error: server sent status chunk with "
271 /* The server is allowed to send us extra information on the final
272 * extent; just clamp it to the length we requested. */
273 if (extent
->length
> orig_length
) {
274 extent
->length
= orig_length
;
280 /* nbd_parse_error_payload
281 * on success @errp contains message describing nbd error reply
283 static int nbd_parse_error_payload(NBDStructuredReplyChunk
*chunk
,
284 uint8_t *payload
, int *request_ret
,
288 uint16_t message_size
;
290 assert(chunk
->type
& (1 << 15));
292 if (chunk
->length
< sizeof(error
) + sizeof(message_size
)) {
294 "Protocol error: invalid payload for structured error");
298 error
= nbd_errno_to_system_errno(payload_advance32(&payload
));
300 error_setg(errp
, "Protocol error: server sent structured error chunk "
305 *request_ret
= -error
;
306 message_size
= payload_advance16(&payload
);
308 if (message_size
> chunk
->length
- sizeof(error
) - sizeof(message_size
)) {
309 error_setg(errp
, "Protocol error: server sent structured error chunk "
310 "with incorrect message size");
314 /* TODO: Add a trace point to mention the server complaint */
316 /* TODO handle ERROR_OFFSET */
321 static int nbd_co_receive_offset_data_payload(NBDClientSession
*s
,
322 uint64_t orig_offset
,
323 QEMUIOVector
*qiov
, Error
**errp
)
325 QEMUIOVector sub_qiov
;
329 NBDStructuredReplyChunk
*chunk
= &s
->reply
.structured
;
331 assert(nbd_reply_is_structured(&s
->reply
));
333 /* The NBD spec requires at least one byte of payload */
334 if (chunk
->length
<= sizeof(offset
)) {
335 error_setg(errp
, "Protocol error: invalid payload for "
336 "NBD_REPLY_TYPE_OFFSET_DATA");
340 if (nbd_read(s
->ioc
, &offset
, sizeof(offset
), errp
) < 0) {
343 be64_to_cpus(&offset
);
345 data_size
= chunk
->length
- sizeof(offset
);
347 if (offset
< orig_offset
|| data_size
> qiov
->size
||
348 offset
> orig_offset
+ qiov
->size
- data_size
) {
349 error_setg(errp
, "Protocol error: server sent chunk exceeding requested"
354 qemu_iovec_init(&sub_qiov
, qiov
->niov
);
355 qemu_iovec_concat(&sub_qiov
, qiov
, offset
- orig_offset
, data_size
);
356 ret
= qio_channel_readv_all(s
->ioc
, sub_qiov
.iov
, sub_qiov
.niov
, errp
);
357 qemu_iovec_destroy(&sub_qiov
);
359 return ret
< 0 ? -EIO
: 0;
362 #define NBD_MAX_MALLOC_PAYLOAD 1000
363 /* nbd_co_receive_structured_payload
365 static coroutine_fn
int nbd_co_receive_structured_payload(
366 NBDClientSession
*s
, void **payload
, Error
**errp
)
371 assert(nbd_reply_is_structured(&s
->reply
));
373 len
= s
->reply
.structured
.length
;
379 if (payload
== NULL
) {
380 error_setg(errp
, "Unexpected structured payload");
384 if (len
> NBD_MAX_MALLOC_PAYLOAD
) {
385 error_setg(errp
, "Payload too large");
389 *payload
= g_new(char, len
);
390 ret
= nbd_read(s
->ioc
, *payload
, len
, errp
);
400 /* nbd_co_do_receive_one_chunk
402 * set request_ret to received reply error
403 * if qiov is not NULL: read payload to @qiov
404 * for structured reply chunk:
405 * if error chunk: read payload, set @request_ret, do not set @payload
406 * else if offset_data chunk: read payload data to @qiov, do not set @payload
407 * else: read payload to @payload
409 * If function fails, @errp contains corresponding error message, and the
410 * connection with the server is suspect. If it returns 0, then the
411 * transaction succeeded (although @request_ret may be a negative errno
412 * corresponding to the server's error reply), and errp is unchanged.
414 static coroutine_fn
int nbd_co_do_receive_one_chunk(
415 NBDClientSession
*s
, uint64_t handle
, bool only_structured
,
416 int *request_ret
, QEMUIOVector
*qiov
, void **payload
, Error
**errp
)
419 int i
= HANDLE_TO_INDEX(s
, handle
);
420 void *local_payload
= NULL
;
421 NBDStructuredReplyChunk
*chunk
;
428 /* Wait until we're woken up by nbd_read_reply_entry. */
429 s
->requests
[i
].receiving
= true;
430 qemu_coroutine_yield();
431 s
->requests
[i
].receiving
= false;
432 if (!s
->ioc
|| s
->quit
) {
433 error_setg(errp
, "Connection closed");
437 assert(s
->reply
.handle
== handle
);
439 if (nbd_reply_is_simple(&s
->reply
)) {
440 if (only_structured
) {
441 error_setg(errp
, "Protocol error: simple reply when structured "
442 "reply chunk was expected");
446 *request_ret
= -nbd_errno_to_system_errno(s
->reply
.simple
.error
);
447 if (*request_ret
< 0 || !qiov
) {
451 return qio_channel_readv_all(s
->ioc
, qiov
->iov
, qiov
->niov
,
452 errp
) < 0 ? -EIO
: 0;
455 /* handle structured reply chunk */
456 assert(s
->info
.structured_reply
);
457 chunk
= &s
->reply
.structured
;
459 if (chunk
->type
== NBD_REPLY_TYPE_NONE
) {
460 if (!(chunk
->flags
& NBD_REPLY_FLAG_DONE
)) {
461 error_setg(errp
, "Protocol error: NBD_REPLY_TYPE_NONE chunk without"
462 " NBD_REPLY_FLAG_DONE flag set");
466 error_setg(errp
, "Protocol error: NBD_REPLY_TYPE_NONE chunk with"
473 if (chunk
->type
== NBD_REPLY_TYPE_OFFSET_DATA
) {
475 error_setg(errp
, "Unexpected NBD_REPLY_TYPE_OFFSET_DATA chunk");
479 return nbd_co_receive_offset_data_payload(s
, s
->requests
[i
].offset
,
483 if (nbd_reply_type_is_error(chunk
->type
)) {
484 payload
= &local_payload
;
487 ret
= nbd_co_receive_structured_payload(s
, payload
, errp
);
492 if (nbd_reply_type_is_error(chunk
->type
)) {
493 ret
= nbd_parse_error_payload(chunk
, local_payload
, request_ret
, errp
);
494 g_free(local_payload
);
501 /* nbd_co_receive_one_chunk
502 * Read reply, wake up read_reply_co and set s->quit if needed.
503 * Return value is a fatal error code or normal nbd reply error code
505 static coroutine_fn
int nbd_co_receive_one_chunk(
506 NBDClientSession
*s
, uint64_t handle
, bool only_structured
,
507 QEMUIOVector
*qiov
, NBDReply
*reply
, void **payload
, Error
**errp
)
510 int ret
= nbd_co_do_receive_one_chunk(s
, handle
, only_structured
,
511 &request_ret
, qiov
, payload
, errp
);
516 /* For assert at loop start in nbd_read_reply_entry */
524 if (s
->read_reply_co
) {
525 aio_co_wake(s
->read_reply_co
);
531 typedef struct NBDReplyChunkIter
{
535 bool done
, only_structured
;
538 static void nbd_iter_error(NBDReplyChunkIter
*iter
, bool fatal
,
539 int ret
, Error
**local_err
)
543 if ((fatal
&& !iter
->fatal
) || iter
->ret
== 0) {
544 if (iter
->ret
!= 0) {
545 error_free(iter
->err
);
550 error_propagate(&iter
->err
, *local_err
);
552 error_free(*local_err
);
558 /* NBD_FOREACH_REPLY_CHUNK
560 #define NBD_FOREACH_REPLY_CHUNK(s, iter, handle, structured, \
561 qiov, reply, payload) \
562 for (iter = (NBDReplyChunkIter) { .only_structured = structured }; \
563 nbd_reply_chunk_iter_receive(s, &iter, handle, qiov, reply, payload);)
565 /* nbd_reply_chunk_iter_receive
567 static bool nbd_reply_chunk_iter_receive(NBDClientSession
*s
,
568 NBDReplyChunkIter
*iter
,
570 QEMUIOVector
*qiov
, NBDReply
*reply
,
574 NBDReply local_reply
;
575 NBDStructuredReplyChunk
*chunk
;
576 Error
*local_err
= NULL
;
578 error_setg(&local_err
, "Connection closed");
579 nbd_iter_error(iter
, true, -EIO
, &local_err
);
584 /* Previous iteration was last. */
589 reply
= &local_reply
;
592 ret
= nbd_co_receive_one_chunk(s
, handle
, iter
->only_structured
,
593 qiov
, reply
, payload
, &local_err
);
595 /* If it is a fatal error s->quit is set by nbd_co_receive_one_chunk */
596 nbd_iter_error(iter
, s
->quit
, ret
, &local_err
);
599 /* Do not execute the body of NBD_FOREACH_REPLY_CHUNK for simple reply. */
600 if (nbd_reply_is_simple(&s
->reply
) || s
->quit
) {
604 chunk
= &reply
->structured
;
605 iter
->only_structured
= true;
607 if (chunk
->type
== NBD_REPLY_TYPE_NONE
) {
608 /* NBD_REPLY_FLAG_DONE is already checked in nbd_co_receive_one_chunk */
609 assert(chunk
->flags
& NBD_REPLY_FLAG_DONE
);
613 if (chunk
->flags
& NBD_REPLY_FLAG_DONE
) {
614 /* This iteration is last. */
618 /* Execute the loop body */
622 s
->requests
[HANDLE_TO_INDEX(s
, handle
)].coroutine
= NULL
;
624 qemu_co_mutex_lock(&s
->send_mutex
);
626 qemu_co_queue_next(&s
->free_sema
);
627 qemu_co_mutex_unlock(&s
->send_mutex
);
632 static int nbd_co_receive_return_code(NBDClientSession
*s
, uint64_t handle
,
635 NBDReplyChunkIter iter
;
637 NBD_FOREACH_REPLY_CHUNK(s
, iter
, handle
, false, NULL
, NULL
, NULL
) {
638 /* nbd_reply_chunk_iter_receive does all the work */
641 error_propagate(errp
, iter
.err
);
645 static int nbd_co_receive_cmdread_reply(NBDClientSession
*s
, uint64_t handle
,
646 uint64_t offset
, QEMUIOVector
*qiov
,
649 NBDReplyChunkIter iter
;
651 void *payload
= NULL
;
652 Error
*local_err
= NULL
;
654 NBD_FOREACH_REPLY_CHUNK(s
, iter
, handle
, s
->info
.structured_reply
,
655 qiov
, &reply
, &payload
)
658 NBDStructuredReplyChunk
*chunk
= &reply
.structured
;
660 assert(nbd_reply_is_structured(&reply
));
662 switch (chunk
->type
) {
663 case NBD_REPLY_TYPE_OFFSET_DATA
:
664 /* special cased in nbd_co_receive_one_chunk, data is already
667 case NBD_REPLY_TYPE_OFFSET_HOLE
:
668 ret
= nbd_parse_offset_hole_payload(&reply
.structured
, payload
,
669 offset
, qiov
, &local_err
);
672 nbd_iter_error(&iter
, true, ret
, &local_err
);
676 if (!nbd_reply_type_is_error(chunk
->type
)) {
677 /* not allowed reply type */
679 error_setg(&local_err
,
680 "Unexpected reply type: %d (%s) for CMD_READ",
681 chunk
->type
, nbd_reply_type_lookup(chunk
->type
));
682 nbd_iter_error(&iter
, true, -EINVAL
, &local_err
);
690 error_propagate(errp
, iter
.err
);
694 static int nbd_co_receive_blockstatus_reply(NBDClientSession
*s
,
695 uint64_t handle
, uint64_t length
,
696 NBDExtent
*extent
, Error
**errp
)
698 NBDReplyChunkIter iter
;
700 void *payload
= NULL
;
701 Error
*local_err
= NULL
;
702 bool received
= false;
704 assert(!extent
->length
);
705 NBD_FOREACH_REPLY_CHUNK(s
, iter
, handle
, s
->info
.structured_reply
,
706 NULL
, &reply
, &payload
)
709 NBDStructuredReplyChunk
*chunk
= &reply
.structured
;
711 assert(nbd_reply_is_structured(&reply
));
713 switch (chunk
->type
) {
714 case NBD_REPLY_TYPE_BLOCK_STATUS
:
717 error_setg(&local_err
, "Several BLOCK_STATUS chunks in reply");
718 nbd_iter_error(&iter
, true, -EINVAL
, &local_err
);
722 ret
= nbd_parse_blockstatus_payload(s
, &reply
.structured
,
723 payload
, length
, extent
,
727 nbd_iter_error(&iter
, true, ret
, &local_err
);
731 if (!nbd_reply_type_is_error(chunk
->type
)) {
733 error_setg(&local_err
,
734 "Unexpected reply type: %d (%s) "
735 "for CMD_BLOCK_STATUS",
736 chunk
->type
, nbd_reply_type_lookup(chunk
->type
));
737 nbd_iter_error(&iter
, true, -EINVAL
, &local_err
);
745 if (!extent
->length
&& !iter
.err
) {
746 error_setg(&iter
.err
,
747 "Server did not reply with any status extents");
752 error_propagate(errp
, iter
.err
);
756 static int nbd_co_request(BlockDriverState
*bs
, NBDRequest
*request
,
757 QEMUIOVector
*write_qiov
)
760 Error
*local_err
= NULL
;
761 NBDClientSession
*client
= nbd_get_client_session(bs
);
763 assert(request
->type
!= NBD_CMD_READ
);
765 assert(request
->type
== NBD_CMD_WRITE
);
766 assert(request
->len
== iov_size(write_qiov
->iov
, write_qiov
->niov
));
768 assert(request
->type
!= NBD_CMD_WRITE
);
770 ret
= nbd_co_send_request(bs
, request
, write_qiov
);
775 ret
= nbd_co_receive_return_code(client
, request
->handle
, &local_err
);
777 trace_nbd_co_request_fail(request
->from
, request
->len
, request
->handle
,
778 request
->flags
, request
->type
,
779 nbd_cmd_lookup(request
->type
),
780 ret
, error_get_pretty(local_err
));
781 error_free(local_err
);
786 int nbd_client_co_preadv(BlockDriverState
*bs
, uint64_t offset
,
787 uint64_t bytes
, QEMUIOVector
*qiov
, int flags
)
790 Error
*local_err
= NULL
;
791 NBDClientSession
*client
= nbd_get_client_session(bs
);
792 NBDRequest request
= {
793 .type
= NBD_CMD_READ
,
798 assert(bytes
<= NBD_MAX_BUFFER_SIZE
);
804 ret
= nbd_co_send_request(bs
, &request
, NULL
);
809 ret
= nbd_co_receive_cmdread_reply(client
, request
.handle
, offset
, qiov
,
812 trace_nbd_co_request_fail(request
.from
, request
.len
, request
.handle
,
813 request
.flags
, request
.type
,
814 nbd_cmd_lookup(request
.type
),
815 ret
, error_get_pretty(local_err
));
816 error_free(local_err
);
821 int nbd_client_co_pwritev(BlockDriverState
*bs
, uint64_t offset
,
822 uint64_t bytes
, QEMUIOVector
*qiov
, int flags
)
824 NBDClientSession
*client
= nbd_get_client_session(bs
);
825 NBDRequest request
= {
826 .type
= NBD_CMD_WRITE
,
831 assert(!(client
->info
.flags
& NBD_FLAG_READ_ONLY
));
832 if (flags
& BDRV_REQ_FUA
) {
833 assert(client
->info
.flags
& NBD_FLAG_SEND_FUA
);
834 request
.flags
|= NBD_CMD_FLAG_FUA
;
837 assert(bytes
<= NBD_MAX_BUFFER_SIZE
);
842 return nbd_co_request(bs
, &request
, qiov
);
845 int nbd_client_co_pwrite_zeroes(BlockDriverState
*bs
, int64_t offset
,
846 int bytes
, BdrvRequestFlags flags
)
848 NBDClientSession
*client
= nbd_get_client_session(bs
);
849 NBDRequest request
= {
850 .type
= NBD_CMD_WRITE_ZEROES
,
855 assert(!(client
->info
.flags
& NBD_FLAG_READ_ONLY
));
856 if (!(client
->info
.flags
& NBD_FLAG_SEND_WRITE_ZEROES
)) {
860 if (flags
& BDRV_REQ_FUA
) {
861 assert(client
->info
.flags
& NBD_FLAG_SEND_FUA
);
862 request
.flags
|= NBD_CMD_FLAG_FUA
;
864 if (!(flags
& BDRV_REQ_MAY_UNMAP
)) {
865 request
.flags
|= NBD_CMD_FLAG_NO_HOLE
;
871 return nbd_co_request(bs
, &request
, NULL
);
874 int nbd_client_co_flush(BlockDriverState
*bs
)
876 NBDClientSession
*client
= nbd_get_client_session(bs
);
877 NBDRequest request
= { .type
= NBD_CMD_FLUSH
};
879 if (!(client
->info
.flags
& NBD_FLAG_SEND_FLUSH
)) {
886 return nbd_co_request(bs
, &request
, NULL
);
889 int nbd_client_co_pdiscard(BlockDriverState
*bs
, int64_t offset
, int bytes
)
891 NBDClientSession
*client
= nbd_get_client_session(bs
);
892 NBDRequest request
= {
893 .type
= NBD_CMD_TRIM
,
898 assert(!(client
->info
.flags
& NBD_FLAG_READ_ONLY
));
899 if (!(client
->info
.flags
& NBD_FLAG_SEND_TRIM
) || !bytes
) {
903 return nbd_co_request(bs
, &request
, NULL
);
906 int coroutine_fn
nbd_client_co_block_status(BlockDriverState
*bs
,
908 int64_t offset
, int64_t bytes
,
909 int64_t *pnum
, int64_t *map
,
910 BlockDriverState
**file
)
913 NBDExtent extent
= { 0 };
914 NBDClientSession
*client
= nbd_get_client_session(bs
);
915 Error
*local_err
= NULL
;
917 NBDRequest request
= {
918 .type
= NBD_CMD_BLOCK_STATUS
,
920 .len
= MIN(MIN_NON_ZERO(QEMU_ALIGN_DOWN(INT_MAX
,
921 bs
->bl
.request_alignment
),
922 client
->info
.max_block
), bytes
),
923 .flags
= NBD_CMD_FLAG_REQ_ONE
,
926 if (!client
->info
.base_allocation
) {
928 return BDRV_BLOCK_DATA
;
931 ret
= nbd_co_send_request(bs
, &request
, NULL
);
936 ret
= nbd_co_receive_blockstatus_reply(client
, request
.handle
, bytes
,
937 &extent
, &local_err
);
939 trace_nbd_co_request_fail(request
.from
, request
.len
, request
.handle
,
940 request
.flags
, request
.type
,
941 nbd_cmd_lookup(request
.type
),
942 ret
, error_get_pretty(local_err
));
943 error_free(local_err
);
949 assert(extent
.length
);
950 *pnum
= extent
.length
;
951 return (extent
.flags
& NBD_STATE_HOLE
? 0 : BDRV_BLOCK_DATA
) |
952 (extent
.flags
& NBD_STATE_ZERO
? BDRV_BLOCK_ZERO
: 0);
955 void nbd_client_detach_aio_context(BlockDriverState
*bs
)
957 NBDClientSession
*client
= nbd_get_client_session(bs
);
958 qio_channel_detach_aio_context(QIO_CHANNEL(client
->ioc
));
961 void nbd_client_attach_aio_context(BlockDriverState
*bs
,
962 AioContext
*new_context
)
964 NBDClientSession
*client
= nbd_get_client_session(bs
);
965 qio_channel_attach_aio_context(QIO_CHANNEL(client
->ioc
), new_context
);
966 aio_co_schedule(new_context
, client
->read_reply_co
);
969 void nbd_client_close(BlockDriverState
*bs
)
971 NBDClientSession
*client
= nbd_get_client_session(bs
);
972 NBDRequest request
= { .type
= NBD_CMD_DISC
};
974 if (client
->ioc
== NULL
) {
978 nbd_send_request(client
->ioc
, &request
);
980 nbd_teardown_connection(bs
);
983 int nbd_client_init(BlockDriverState
*bs
,
984 QIOChannelSocket
*sioc
,
986 QCryptoTLSCreds
*tlscreds
,
987 const char *hostname
,
988 const char *x_dirty_bitmap
,
991 NBDClientSession
*client
= nbd_get_client_session(bs
);
995 logout("session init %s\n", export
);
996 qio_channel_set_blocking(QIO_CHANNEL(sioc
), true, NULL
);
998 client
->info
.request_sizes
= true;
999 client
->info
.structured_reply
= true;
1000 client
->info
.base_allocation
= true;
1001 client
->info
.x_dirty_bitmap
= g_strdup(x_dirty_bitmap
);
1002 ret
= nbd_receive_negotiate(QIO_CHANNEL(sioc
), export
,
1004 &client
->ioc
, &client
->info
, errp
);
1005 g_free(client
->info
.x_dirty_bitmap
);
1007 logout("Failed to negotiate with the NBD server\n");
1010 if (x_dirty_bitmap
&& !client
->info
.base_allocation
) {
1011 error_setg(errp
, "requested x-dirty-bitmap %s not found",
1016 if (client
->info
.flags
& NBD_FLAG_READ_ONLY
) {
1017 ret
= bdrv_apply_auto_read_only(bs
, "NBD export is read-only", errp
);
1022 if (client
->info
.flags
& NBD_FLAG_SEND_FUA
) {
1023 bs
->supported_write_flags
= BDRV_REQ_FUA
;
1024 bs
->supported_zero_flags
|= BDRV_REQ_FUA
;
1026 if (client
->info
.flags
& NBD_FLAG_SEND_WRITE_ZEROES
) {
1027 bs
->supported_zero_flags
|= BDRV_REQ_MAY_UNMAP
;
1030 qemu_co_mutex_init(&client
->send_mutex
);
1031 qemu_co_queue_init(&client
->free_sema
);
1032 client
->sioc
= sioc
;
1033 object_ref(OBJECT(client
->sioc
));
1036 client
->ioc
= QIO_CHANNEL(sioc
);
1037 object_ref(OBJECT(client
->ioc
));
1040 /* Now that we're connected, set the socket to be non-blocking and
1041 * kick the reply mechanism. */
1042 qio_channel_set_blocking(QIO_CHANNEL(sioc
), false, NULL
);
1043 client
->read_reply_co
= qemu_coroutine_create(nbd_read_reply_entry
, client
);
1044 nbd_client_attach_aio_context(bs
, bdrv_get_aio_context(bs
));
1046 logout("Established connection with NBD server\n");
1051 * We have connected, but must fail for other reasons. The
1052 * connection is still blocking; send NBD_CMD_DISC as a courtesy
1056 NBDRequest request
= { .type
= NBD_CMD_DISC
};
1058 nbd_send_request(client
->ioc
?: QIO_CHANNEL(sioc
), &request
);