Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #include <stdio.h>
32 : : #include <stdlib.h>
33 : : #include <unistd.h>
34 : : #include <errno.h>
35 : : #include <string.h>
36 : : #include <sys/types.h>
37 : : #include <sys/socket.h>
38 : : #include <netinet/in.h>
39 : : #include <netdb.h>
40 : : #include <arpa/inet.h>
41 : : #include <sys/wait.h>
42 : : #include <sys/un.h>
43 : : #include "tapdisk-protocol-new.h"
44 : : #include <byteswap.h>
45 : :
46 : : #include "debug.h"
47 : : #include "tapdisk.h"
48 : : #include "tapdisk-log.h"
49 : : #include "tapdisk-server.h"
50 : : #include "tapdisk-driver.h"
51 : : #include "tapdisk-interface.h"
52 : : #include "tapdisk-utils.h"
53 : : #include "tapdisk-nbdserver.h"
54 : : #include "tapdisk-fdreceiver.h"
55 : :
56 : : #include "timeout-math.h"
57 : : #include "util.h"
58 : :
59 : : #ifdef HAVE_CONFIG_H
60 : : #include "config.h"
61 : : #endif
62 : :
63 : : #define MAX_OPTIONS 32
64 : :
65 : : #define MAX_NBD_EXPORT_NAME_LEN 256
66 : :
67 : : #define MEGABYTES 1024 * 1024
68 : :
69 : : #define NBD_SERVER_NUM_REQS 8
70 : : #define MAX_REQUEST_SIZE (64 * MEGABYTES)
71 : :
72 : : uint16_t gflags = (NBD_FLAG_FIXED_NEWSTYLE | NBD_FLAG_NO_ZEROES);
73 : : static const int SERVER_USE_OLD_PROTOCOL = 1;
74 : :
75 : : /*
76 : : * Server
77 : : */
78 : :
79 : : #define INFO(_f, _a...) tlog_syslog(TLOG_INFO, "nbd: " _f, ##_a)
80 : : #define ERR(_f, _a...) tlog_syslog(TLOG_WARN, "nbd: " _f, ##_a)
81 : : #define BUG() do { \
82 : : ERR("Aborting"); \
83 : : abort(); \
84 : : } while (0)
85 : : #define BUG_ON(_cond) \
86 : : if (unlikely(_cond)) { \
87 : : ERR("(%s) = %d", #_cond, _cond); \
88 : : BUG(); \
89 : : }
90 : :
91 : : struct td_nbdserver_req {
92 : : td_vbd_request_t vreq;
93 : : char id[16];
94 : : struct td_iovec iov;
95 : : };
96 : :
97 : 0 : int recv_fully_or_fail(int f, void *buf, size_t len) {
98 : : ssize_t res;
99 : 0 : int err = 0;
100 [ # # ]: 0 : while (len > 0) {
101 : 0 : res = recv(f, buf, len, 0);
102 [ # # ]: 0 : if (res > 0) {
103 : 0 : len -= res;
104 : 0 : buf += res;
105 [ # # ]: 0 : } else if (res == 0) {
106 : : /* EOF */
107 : 0 : INFO("Zero return from recv");
108 : 0 : return -1;
109 : : } else {
110 : 0 : err = errno;
111 [ # # ]: 0 : if(err != EAGAIN && err != EINTR) {
112 : 0 : ERR("Read failed: %s", strerror(err));
113 : 0 : break;
114 : : }
115 : : err = 0;
116 : : }
117 : : }
118 : :
119 : 0 : return -err;
120 : : }
121 : :
122 : 1 : int send_fully_or_fail(int f, void *buf, size_t len) {
123 : : ssize_t res;
124 : 1 : int err = 0;
125 [ + + ]: 2 : while (len > 0) {
126 : 1 : res = send(f, buf, len, 0);
127 [ + - ]: 1 : if (res > 0) {
128 : 1 : len -= res;
129 : 1 : buf += res;
130 [ # # ]: 0 : } else if (res == 0) {
131 : : /* EOF */
132 : 0 : INFO("Zero return from send");
133 : 0 : return -1;
134 : : } else {
135 : 0 : err = errno;
136 [ # # ]: 0 : if(err != EAGAIN && err != EINTR) {
137 : 0 : ERR("Send failed: %s", strerror(err));
138 : 1 : break;
139 : : }
140 : : err = 0;
141 : : }
142 : : }
143 : :
144 : 1 : return -err;
145 : : }
146 : :
147 : : void
148 : 0 : free_extents(struct tapdisk_extents *extents)
149 : : {
150 : 0 : tapdisk_extent_t *next, *curr_extent = extents->head;
151 [ # # ]: 0 : while (curr_extent) {
152 : 0 : next = curr_extent->next;
153 : 0 : free(curr_extent);
154 : 0 : curr_extent = next;
155 : : }
156 : :
157 : 0 : free(extents);
158 : 0 : }
159 : :
160 : : struct nbd_block_descriptor *
161 : 0 : convert_extents_to_block_descriptors (struct tapdisk_extents *extents)
162 : : {
163 : 0 : size_t i, nr_extents = extents->count;
164 : : struct nbd_block_descriptor *blocks;
165 : 0 : tapdisk_extent_t *curr_extent = extents->head;
166 : :
167 : 0 : blocks = calloc (nr_extents, sizeof (struct nbd_block_descriptor));
168 [ # # ]: 0 : if(blocks == NULL) {
169 : : return NULL;
170 : : }
171 : :
172 [ # # ]: 0 : for (i = 0; i < nr_extents; ++i) {
173 : 0 : blocks[i].length = htobe32 ((curr_extent->length << SECTOR_SHIFT));
174 : 0 : blocks[i].status_flags = htobe32(curr_extent->flag);
175 : 0 : curr_extent = curr_extent->next;
176 : : }
177 : : return blocks;
178 : : }
179 : :
180 : : static int
181 : 0 : send_structured_reply_block_status (int fd, char* id, struct tapdisk_extents *extents)
182 : : {
183 : : struct nbd_structured_reply reply;
184 : : struct nbd_block_descriptor *blocks;
185 : 0 : size_t i, nr_blocks = extents->count;
186 : : uint32_t context_id;
187 : 0 : int ret = 0;
188 : :
189 : 0 : blocks = convert_extents_to_block_descriptors (extents);
190 [ # # ]: 0 : if(blocks == NULL) {
191 : 0 : ERR("Could not allocate blocks for extents");
192 : : ret = -1;
193 : : goto done;
194 : : }
195 : :
196 : 0 : reply.magic = htobe32 (NBD_STRUCTURED_REPLY_MAGIC);
197 : : memcpy(&reply.handle, id, sizeof(reply.handle));
198 : 0 : reply.flags = htobe16 (NBD_REPLY_FLAG_DONE);
199 : 0 : reply.type = htobe16 (NBD_REPLY_TYPE_BLOCK_STATUS);
200 : 0 : reply.length = htobe32 (sizeof context_id +
201 : : nr_blocks * sizeof (struct nbd_block_descriptor));
202 : :
203 : 0 : int rc = send (fd, &reply, sizeof(reply), 0);
204 [ # # ]: 0 : if(rc != sizeof(reply)) {
205 : 0 : ERR("Could not send stuctured reply struct");
206 : 0 : ret = -errno;
207 : 0 : goto done;
208 : : }
209 : :
210 : 0 : context_id = htobe32 (base_allocation_id);
211 : 0 : rc = send (fd, &context_id, sizeof(context_id), 0);
212 [ # # ]: 0 : if(rc != sizeof(context_id)) {
213 : 0 : ERR("Could not send contect_id");
214 : 0 : ret = -errno;
215 : 0 : goto done;
216 : : }
217 : :
218 [ # # ]: 0 : for (i = 0; i < nr_blocks; ++i) {
219 : 0 : rc = send (fd, &blocks[i], sizeof blocks[i], 0);
220 [ # # ]: 0 : if(rc != sizeof(blocks[i])) {
221 : 0 : ERR("Could not send extent block");
222 : 0 : ret = -errno;
223 : 0 : goto done;
224 : : }
225 : : }
226 : : done:
227 : 0 : free(blocks);
228 : 0 : return ret;
229 : : }
230 : :
231 : : td_nbdserver_req_t *
232 : 0 : tapdisk_nbdserver_alloc_request(td_nbdserver_client_t *client)
233 : : {
234 : 0 : td_nbdserver_req_t *req = NULL;
235 : : int pending;
236 : :
237 [ # # ]: 0 : ASSERT(client);
238 : :
239 [ # # ]: 0 : if (likely(client->n_reqs_free))
240 : 0 : req = client->reqs_free[--client->n_reqs_free];
241 : :
242 : 0 : pending = tapdisk_nbdserver_reqs_pending(client);
243 [ # # ]: 0 : if (pending > client->max_used_reqs)
244 : 0 : client->max_used_reqs = pending;
245 : :
246 [ # # ]: 0 : if (unlikely(client->n_reqs_free == 0)) {
247 : : /* last free request, mask the events */
248 : 0 : tapdisk_server_mask_event(client->client_event_id, 1);
249 : : }
250 : :
251 : :
252 : 0 : return req;
253 : : }
254 : :
255 : : static int
256 : 0 : send_option_reply (int new_fd, uint32_t option, uint32_t reply)
257 : : {
258 : : struct nbd_fixed_new_option_reply fixed_new_option_reply;
259 : :
260 : 0 : fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
261 : 0 : fixed_new_option_reply.option = htobe32 (option);
262 : 0 : fixed_new_option_reply.reply = htobe32 (reply);
263 : 0 : fixed_new_option_reply.replylen = htobe32 (0);
264 : :
265 : 0 : int rc = send_fully_or_fail(new_fd, &fixed_new_option_reply, sizeof(fixed_new_option_reply));
266 [ # # ]: 0 : if(rc < 0) {
267 : 0 : ERR("Failed to send new_option_reply");
268 : 0 : return -1;
269 : : }
270 : : return 0;
271 : : }
272 : :
273 : : static void
274 : 0 : tapdisk_nbdserver_set_free_request(td_nbdserver_client_t *client,
275 : : td_nbdserver_req_t *req)
276 : : {
277 [ # # ]: 0 : ASSERT(client);
278 [ # # ]: 0 : ASSERT(req);
279 [ # # ]: 0 : BUG_ON(client->n_reqs_free >= client->n_reqs);
280 : :
281 : 0 : client->reqs_free[client->n_reqs_free++] = req;
282 : 0 : }
283 : :
284 : : void
285 : 0 : tapdisk_nbdserver_free_request(td_nbdserver_client_t *client,
286 : : td_nbdserver_req_t *req, bool free_client_if_dead)
287 : : {
288 : 0 : tapdisk_nbdserver_set_free_request(client, req);
289 : :
290 [ # # ]: 0 : if (unlikely(client->n_reqs_free == (client->n_reqs / 4))) {
291 : : /* free requests, unmask the events */
292 : 0 : tapdisk_server_mask_event(client->client_event_id, 0);
293 : : }
294 : :
295 [ # # ][ # # ]: 0 : if (unlikely(free_client_if_dead &&
[ # # ][ # # ]
296 : : client->dead &&
297 : : !tapdisk_nbdserver_reqs_pending(client)))
298 : 0 : tapdisk_nbdserver_free_client(client);
299 : 0 : }
300 : :
301 : : static void
302 : 0 : tapdisk_nbdserver_reqs_free(td_nbdserver_client_t *client)
303 : : {
304 [ # # ]: 0 : if (client->reqs) {
305 : 0 : free(client->reqs);
306 : 0 : client->reqs = NULL;
307 : : }
308 : :
309 [ # # ]: 0 : if (client->iovecs) {
310 : 0 : free(client->iovecs);
311 : 0 : client->iovecs = NULL;
312 : : }
313 : :
314 [ # # ]: 0 : if (client->reqs_free) {
315 : 0 : free(client->reqs_free);
316 : 0 : client->reqs_free = NULL;
317 : : }
318 : 0 : }
319 : :
320 : : void
321 : 0 : provide_server_info (td_nbdserver_t *server, uint64_t *exportsize, uint16_t *flags)
322 : : {
323 : : int64_t size;
324 : 0 : uint16_t eflags = NBD_FLAG_HAS_FLAGS;
325 : :
326 : 0 : size = server->info.size * server->info.sector_size;
327 : :
328 : 0 : *exportsize = size;
329 : 0 : *flags = eflags;
330 : 0 : }
331 : :
332 : : static int
333 : 0 : send_info_export (int new_fd, uint32_t option, uint32_t reply, uint16_t info, uint64_t exportsize,
334 : : uint16_t flags)
335 : : {
336 : : struct nbd_fixed_new_option_reply fixed_new_option_reply;
337 : : struct nbd_fixed_new_option_reply_info_export export;
338 : :
339 : 0 : fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
340 : 0 : fixed_new_option_reply.option = htobe32 (option);
341 : 0 : fixed_new_option_reply.reply = htobe32 (reply);
342 : 0 : fixed_new_option_reply.replylen = htobe32 (sizeof(export));
343 : :
344 [ # # ]: 0 : export.info = htobe16 (info);
345 : 0 : export.exportsize = htobe64 (exportsize);
346 [ # # ]: 0 : export.eflags = htobe16 (flags);
347 : :
348 : 0 : int rc = send_fully_or_fail(new_fd, &fixed_new_option_reply, sizeof(fixed_new_option_reply));
349 [ # # ]: 0 : if(rc < 0) {
350 : 0 : ERR("Failed to send new_option_reply");
351 : 0 : return -1;
352 : : }
353 : :
354 : 0 : rc = send_fully_or_fail(new_fd, &export, sizeof(export));
355 [ # # ]: 0 : if(rc < 0) {
356 : 0 : ERR("Failed to send info export");
357 : : return -1;
358 : : }
359 : :
360 : : return 0;
361 : : }
362 : :
363 : : int
364 : 0 : send_info_block_size (int new_fd, uint32_t option, uint32_t reply, uint16_t info,
365 : : uint32_t min_block_size, uint32_t preferred_block_size,
366 : : uint32_t max_block_size)
367 : : {
368 : : struct nbd_fixed_new_option_reply fixed_new_option_reply;
369 : : struct nbd_fixed_new_option_reply_info_block_size block_info;
370 : :
371 : 0 : fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
372 : 0 : fixed_new_option_reply.option = htobe32 (option);
373 : 0 : fixed_new_option_reply.reply = htobe32 (reply);
374 : 0 : fixed_new_option_reply.replylen = htobe32 (sizeof (block_info));
375 : :
376 [ # # ]: 0 : block_info.info = htobe16 (info);
377 : 0 : block_info.min_block_size = htobe32(min_block_size);
378 : 0 : block_info.preferred_block_size = htobe32(preferred_block_size);
379 : 0 : block_info.max_block_size = htobe32(max_block_size);
380 : 0 : int rc = send_fully_or_fail(new_fd, &fixed_new_option_reply, sizeof(fixed_new_option_reply));
381 [ # # ]: 0 : if (rc < 0) {
382 : 0 : ERR("Failed to send new_option_reply");
383 : 0 : return -1;
384 : : }
385 : :
386 : 0 : rc = send_fully_or_fail(new_fd, &block_info, sizeof(block_info));
387 [ # # ]: 0 : if (rc < 0) {
388 : 0 : ERR("Failed to send info block size");
389 : : return -1;
390 : : }
391 : :
392 : : return 0;
393 : : }
394 : :
395 : : int
396 : 0 : send_meta_context (int new_fd, uint32_t reply, uint32_t context_id, const char *name)
397 : : {
398 : : struct nbd_fixed_new_option_reply fixed_new_option_reply;
399 : : struct nbd_fixed_new_option_reply_meta_context context;
400 : 0 : const size_t namelen = strlen (name);
401 : :
402 : 0 : fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
403 : 0 : fixed_new_option_reply.option = htobe32 (NBD_OPT_SET_META_CONTEXT);
404 : 0 : fixed_new_option_reply.reply = htobe32 (reply);
405 : 0 : fixed_new_option_reply.replylen = htobe32 (sizeof context + namelen);
406 : 0 : context.context_id = htobe32 (context_id);
407 : :
408 : 0 : int rc = send (new_fd, &fixed_new_option_reply, sizeof(fixed_new_option_reply), 0);
409 [ # # ]: 0 : if(rc != sizeof(fixed_new_option_reply)) {
410 : 0 : ERR("Failed to send new_option_reply, sent %d of %lu",
411 : : rc, sizeof(fixed_new_option_reply));
412 : 0 : return -1;
413 : : }
414 : 0 : rc = send (new_fd, &context, sizeof(context), 0);
415 [ # # ]: 0 : if(rc != sizeof(context)) {
416 : 0 : ERR("Failed to send context, sent %d of %lu",
417 : : rc, sizeof(context));
418 : : return -1;
419 : : }
420 : 0 : rc = send (new_fd, name, namelen, 0);
421 [ # # ]: 0 : if(rc != namelen) {
422 : 0 : ERR("Failed to send name, sent %d of %lu",
423 : : rc, namelen);
424 : : return -1;
425 : : }
426 : :
427 : : return 0;
428 : : }
429 : :
430 : : int
431 : 0 : receive_info(int fd, char* buf, int size)
432 : : {
433 : 0 : return recv_fully_or_fail(fd, buf, size);
434 : : }
435 : :
436 : : static int
437 : 0 : receive_newstyle_options(td_nbdserver_client_t *client, int new_fd, bool no_zeroes)
438 : : {
439 : : struct nbd_new_option n_option;
440 : : size_t n_options;
441 : : uint32_t opt_code;
442 : : uint32_t opt_len;
443 : : uint64_t opt_version;
444 : : uint64_t exportsize;
445 : : struct nbd_export_name_option_reply handshake_finish;
446 : 0 : char *buf = NULL;
447 : 0 : char *exportname = NULL;
448 : 0 : int ret = 0;
449 : 0 : td_nbdserver_t *server = client->server;
450 : :
451 [ # # ]: 0 : for (n_options = 0; n_options < MAX_OPTIONS; n_options++) {
452 : :
453 [ # # ]: 0 : if(receive_info(new_fd, (char *)&n_option, sizeof(n_option)) < 0){
454 : 0 : return -1;
455 : : }
456 : :
457 : 0 : opt_version = be64toh(n_option.version);
458 [ # # ]: 0 : if (NBD_OPT_MAGIC != opt_version){
459 : 0 : ERR("Bad NBD option version %" PRIx64
460 : : ", expected %" PRIx64,
461 : : opt_version, NBD_OPT_MAGIC);
462 : : ret = -1;
463 : : goto done;
464 : : }
465 : :
466 : 0 : opt_len = be32toh (n_option.optlen);
467 [ # # ]: 0 : if (opt_len > MAX_REQUEST_SIZE) {
468 : 0 : ERR ("NBD optlen to big (%" PRIu32 ")", opt_len);
469 : : ret = -1;
470 : : goto done;
471 : : }
472 : :
473 : 0 : buf = malloc (opt_len + 1);
474 [ # # ]: 0 : if (buf == NULL) {
475 : 0 : ERR("Could not malloc option data buff");
476 : : ret = -1;
477 : : goto done;
478 : : }
479 : :
480 : 0 : opt_code = be32toh (n_option.option);
481 : :
482 [ # # # # : 0 : switch (opt_code) {
# # # # #
# ]
483 : : case NBD_OPT_EXPORT_NAME:
484 : : {
485 : 0 : INFO("Processing NBD_OPT_EXPORT_NAME");
486 : 0 : uint16_t flags = 0;
487 [ # # ]: 0 : if(receive_info(new_fd, (char *)buf, opt_len) < 0) {
488 : 0 : ERR ("Failed to received data for NBD_OPT_EXPORT_NAME");
489 : : ret = -1;
490 : 0 : goto done;
491 : : }
492 : 0 : buf[opt_len] = '\0';
493 : 0 : INFO("Exportname %s", buf);
494 : :
495 : 0 : provide_server_info(server, &exportsize, &flags);
496 : :
497 : : bzero(&handshake_finish, sizeof handshake_finish);
498 : 0 : handshake_finish.exportsize = htobe64 (exportsize);
499 [ # # ]: 0 : handshake_finish.eflags = htobe16 (flags);
500 [ # # ]: 0 : ssize_t len = no_zeroes ? 10 : sizeof(handshake_finish);
501 : 0 : ssize_t sent = send (new_fd, &handshake_finish,len, 0);
502 [ # # ]: 0 : if(sent != len) {
503 : 0 : ERR ("Failed to send handshake finish");
504 : : ret = -1;
505 : : goto done;
506 : : }
507 : : }
508 : 0 : break;
509 : : case NBD_OPT_ABORT:
510 : 0 : INFO("Processing NBD_OPT_ABORT");
511 [ # # ]: 0 : if (send_option_reply (new_fd, opt_code, NBD_REP_ACK) == -1){
512 : : ret = -1;
513 : : goto done;
514 : : }
515 : : break;
516 : : case NBD_OPT_LIST:
517 : 0 : ERR("NBD_OPT_LIST: not implemented");
518 : : break;
519 : : case NBD_OPT_STARTTLS:
520 : 0 : ERR("NBD_OPT_STARTTLS: not implemented");
521 : : break;
522 : : case NBD_OPT_INFO:
523 : 0 : ERR("NBD_OPT_INFO: not implemented");
524 : : break;
525 : : case NBD_OPT_GO:
526 : : {
527 : : uint16_t flags;
528 : : uint32_t exportnamelen;
529 : : uint16_t nrInfoReq;
530 : :
531 : 0 : INFO("Processing NBD_OPT_GO");
532 : :
533 [ # # ]: 0 : if (recv_fully_or_fail(new_fd, &exportnamelen, sizeof(exportnamelen)) < 0) {
534 : : ret = -1;
535 : 0 : goto done;
536 : : }
537 : 0 : exportnamelen = be32toh(exportnamelen);
538 : :
539 [ # # ]: 0 : if (exportnamelen > MAX_NBD_EXPORT_NAME_LEN) {
540 : 0 : ERR("Received %u as export name length which exceeds the maximum of %u",
541 : : exportnamelen, MAX_NBD_EXPORT_NAME_LEN);
542 : : ret = -1;
543 : : goto done;
544 : : }
545 : :
546 : 0 : exportname = malloc(exportnamelen + 1);
547 [ # # ]: 0 : if (exportname == NULL) {
548 : 0 : ERR("Could not malloc space for export name");
549 : : ret = -1;
550 : : goto done;
551 : : }
552 [ # # ]: 0 : if (recv_fully_or_fail(new_fd, exportname, exportnamelen) < 0) {
553 : : ret = -1;
554 : : goto done;
555 : : }
556 : 0 : exportname[exportnamelen] = '\0';
557 : 0 : INFO("Exportname %s", exportname);
558 : :
559 [ # # ]: 0 : if (recv_fully_or_fail(new_fd, &nrInfoReq, sizeof(nrInfoReq)) < 0) {
560 : : ret = -1;
561 : : goto done;
562 : : }
563 [ # # ]: 0 : nrInfoReq = be16toh(nrInfoReq);
564 : 0 : INFO("nrInfoReq is %d", nrInfoReq);
565 : :
566 [ # # ]: 0 : while(nrInfoReq--) {
567 : : uint16_t request;
568 [ # # ]: 0 : if (recv_fully_or_fail(new_fd, &request, sizeof(request)) < 0) {
569 : 0 : ERR("Failed to read NBD_INFO");
570 : 0 : ret = -1;
571 : 0 : goto done;
572 : : }
573 [ # # ]: 0 : request = be16toh(request);
574 : 0 : INFO("Client requested NBD_INFO %u", request);
575 : : }
576 : :
577 : 0 : provide_server_info(server, &exportsize, &flags);
578 : :
579 : : /* Always send NBD_INFO_EXPORT*/
580 [ # # ]: 0 : if (send_info_export (new_fd, opt_code,
581 : : NBD_REP_INFO,
582 : : NBD_INFO_EXPORT,
583 : : exportsize, flags) == -1){
584 : 0 : ERR("Could not send reply info export");
585 : : ret = -1;
586 : : goto done;
587 : : }
588 : :
589 [ # # ]: 0 : if (send_info_block_size(new_fd, opt_code,
590 : : NBD_REP_INFO,
591 : : NBD_INFO_BLOCK_SIZE,
592 : : 1, 4096, 2 * MEGABYTES) == -1) {
593 : 0 : ERR("Could not send reply info block size");
594 : : ret = -1;
595 : : goto done;
596 : : }
597 : :
598 [ # # ]: 0 : if (send_option_reply (new_fd, NBD_OPT_GO, NBD_REP_ACK) == -1){
599 : 0 : ERR("Could not send new style option reply");
600 : : ret = -1;
601 : : goto done;
602 : : }
603 : : }
604 : 0 : break;
605 : : case NBD_OPT_STRUCTURED_REPLY:
606 : 0 : INFO("Processing NBD_OPT_STRUCTURED_REPLY");
607 [ # # ]: 0 : if (opt_len != 0) {
608 : 0 : send_option_reply (new_fd, opt_code, NBD_REP_ERR_INVALID);
609 : : ret = -1;
610 : : goto done;
611 : : }
612 : :
613 [ # # ]: 0 : if (send_option_reply (new_fd, opt_code, NBD_REP_ACK) == -1){
614 : : ret = -1;
615 : : goto done;
616 : : }
617 : :
618 : 0 : client->structured_reply = true;
619 : 0 : break;
620 : : case NBD_OPT_LIST_META_CONTEXT:
621 : 0 : ERR("NBD_OPT_LIST_META_CONTEXT: not implemented");
622 : : break;
623 : : case NBD_OPT_SET_META_CONTEXT:
624 : : {
625 : 0 : INFO("Processing NBD_OPT_SET_META_CONTEXT");
626 : : uint32_t opt_index;
627 : : uint32_t exportnamelen;
628 : : uint32_t nr_queries;
629 : : uint32_t querylen;
630 [ # # ]: 0 : if (recv_fully_or_fail(new_fd, buf, opt_len) < 0){
631 : : ret = -1;
632 : 0 : goto done;
633 : : }
634 : :
635 : : memcpy (&exportnamelen, &buf[0], 4);
636 : 0 : exportnamelen = be32toh (exportnamelen);
637 : 0 : opt_index = 4 + exportnamelen;
638 : :
639 : 0 : memcpy (&nr_queries, &buf[opt_index], 4);
640 : 0 : nr_queries = be32toh (nr_queries);
641 : 0 : opt_index += 4;
642 [ # # ]: 0 : while (nr_queries > 0) {
643 : : char temp[16];
644 : 0 : memcpy (&querylen, &buf[opt_index], 4);
645 : 0 : querylen = be32toh (querylen);
646 : 0 : opt_index += 4;
647 : 0 : memcpy (temp, &buf[opt_index], 15);
648 : 0 : temp[15]= '\0';
649 : 0 : INFO("actual string %s\n", temp);
650 [ # # ][ # # ]: 0 : if (querylen == 15 && strncmp (&buf[opt_index], "base:allocation", 15) == 0) {
651 [ # # ]: 0 : if(send_meta_context (new_fd, NBD_REP_META_CONTEXT, 1, "base:allocation") !=0) {
652 : 0 : ret = -1;
653 : 0 : goto done;
654 : : }
655 : : }
656 : 0 : nr_queries--;
657 : : }
658 [ # # ]: 0 : if (send_option_reply (new_fd, opt_code, NBD_REP_ACK) == -1){
659 : : ret = -1;
660 : : goto done;
661 : : }
662 : : }
663 : 0 : break;
664 : : default:
665 : : ret = -1;
666 : : goto done;
667 : : }
668 : :
669 : 0 : free(buf);
670 : 0 : buf = NULL;
671 : :
672 : : /* Loop ends here for these commands */
673 [ # # ]: 0 : if (opt_code == NBD_OPT_GO || opt_code == NBD_OPT_EXPORT_NAME )
674 : : break;
675 : : }
676 : :
677 [ # # ]: 0 : if (n_options >= MAX_OPTIONS) {
678 : 0 : ERR("Max number of nbd options exceeded (%d)", MAX_OPTIONS);
679 : : ret = -1;
680 : : goto done;
681 : : }
682 : :
683 : : done:
684 : 0 : free(buf);
685 : 0 : free(exportname);
686 : 0 : return ret;
687 : : }
688 : :
689 : : int
690 : 0 : tapdisk_nbdserver_reqs_init(td_nbdserver_client_t *client, int n_reqs)
691 : : {
692 : : int i, err;
693 : :
694 [ # # ]: 0 : ASSERT(client);
695 [ # # ]: 0 : ASSERT(n_reqs > 0);
696 : :
697 : 0 : INFO("Reqs init");
698 : :
699 : 0 : client->reqs = malloc(n_reqs * sizeof(td_nbdserver_req_t));
700 [ # # ]: 0 : if (!client->reqs) {
701 : 0 : err = -errno;
702 : 0 : goto fail;
703 : : }
704 : :
705 : 0 : client->iovecs = malloc(n_reqs * sizeof(struct td_iovec));
706 [ # # ]: 0 : if (!client->iovecs) {
707 : 0 : err = - errno;
708 : 0 : goto fail;
709 : : }
710 : :
711 : 0 : client->reqs_free = malloc(n_reqs * sizeof(td_nbdserver_req_t*));
712 [ # # ]: 0 : if (!client->reqs_free) {
713 : 0 : err = -errno;
714 : 0 : goto fail;
715 : : }
716 : :
717 : 0 : client->n_reqs = n_reqs;
718 : 0 : client->n_reqs_free = 0;
719 : 0 : client->max_used_reqs = 0;
720 : :
721 [ # # ]: 0 : for (i = 0; i < n_reqs; i++) {
722 : 0 : client->reqs[i].vreq.iov = &client->iovecs[i];
723 : 0 : tapdisk_nbdserver_set_free_request(client, &client->reqs[i]);
724 : : }
725 : :
726 : : return 0;
727 : :
728 : : fail:
729 : 0 : tapdisk_nbdserver_reqs_free(client);
730 : 0 : return err;
731 : : }
732 : :
733 : : static int
734 : 0 : tapdisk_nbdserver_enable_client(td_nbdserver_client_t *client)
735 : : {
736 [ # # ]: 0 : ASSERT(client);
737 [ # # ]: 0 : ASSERT(client->client_event_id == -1);
738 [ # # ]: 0 : ASSERT(client->client_fd >= 0);
739 : :
740 : 0 : INFO("Enable client");
741 : :
742 : 0 : client->client_event_id = tapdisk_server_register_event(
743 : : SCHEDULER_POLL_READ_FD,
744 : 0 : client->client_fd, TV_ZERO,
745 : : tapdisk_nbdserver_clientcb,
746 : : client);
747 : :
748 [ # # ]: 0 : if (client->client_event_id < 0) {
749 : 0 : ERR("Error registering events on client: %d",
750 : : client->client_event_id);
751 : 0 : return client->client_event_id;
752 : : }
753 : :
754 : : return client->client_event_id;
755 : : }
756 : :
757 : : static void
758 : 0 : tapdisk_nbdserver_disable_client(td_nbdserver_client_t *client)
759 : : {
760 [ # # ]: 0 : ASSERT(client);
761 [ # # ]: 0 : ASSERT(client->client_event_id >= 0);
762 : :
763 : 0 : INFO("Disable client");
764 : :
765 : 0 : tapdisk_server_unregister_event(client->client_event_id);
766 : 0 : client->client_event_id = -1;
767 : 0 : }
768 : :
769 : : td_nbdserver_client_t *
770 : 0 : tapdisk_nbdserver_alloc_client(td_nbdserver_t *server)
771 : : {
772 : 0 : td_nbdserver_client_t *client = NULL;
773 : : int err;
774 : :
775 [ # # ]: 0 : ASSERT(server);
776 : :
777 : 0 : INFO("Alloc client");
778 : :
779 : 0 : client = calloc(1, sizeof(td_nbdserver_client_t));
780 [ # # ]: 0 : if (!client) {
781 : 0 : ERR("Couldn't allocate client structure: %s",
782 : : strerror(errno));
783 : 0 : goto fail;
784 : : }
785 : :
786 : 0 : err = tapdisk_nbdserver_reqs_init(client, NBD_SERVER_NUM_REQS);
787 [ # # ]: 0 : if (err < 0) {
788 : 0 : ERR("Couldn't allocate client reqs: %d", err);
789 : 0 : goto fail;
790 : : }
791 : :
792 : 0 : client->client_fd = -1;
793 : 0 : client->client_event_id = -1;
794 : 0 : client->server = server;
795 : 0 : INIT_LIST_HEAD(&client->clientlist);
796 : 0 : list_add(&client->clientlist, &server->clients);
797 : :
798 : 0 : client->paused = 0;
799 : 0 : client->dead = false;
800 : 0 : client->structured_reply = false;
801 : :
802 : 0 : return client;
803 : :
804 : : fail:
805 [ # # ]: 0 : if (client)
806 : 0 : free(client);
807 : :
808 : : return NULL;
809 : : }
810 : :
811 : : void
812 : 0 : tapdisk_nbdserver_free_client(td_nbdserver_client_t *client)
813 : : {
814 : 0 : INFO("Free client");
815 : :
816 [ # # ]: 0 : ASSERT(client);
817 : :
818 [ # # ]: 0 : if (client->client_event_id >= 0)
819 : 0 : tapdisk_nbdserver_disable_client(client);
820 : :
821 : 0 : INFO("Freeing client, max used requests %d", client->max_used_reqs);
822 : :
823 [ # # ]: 0 : if (likely(!tapdisk_nbdserver_reqs_pending(client))) {
824 : 0 : list_del(&client->clientlist);
825 : 0 : tapdisk_nbdserver_reqs_free(client);
826 : 0 : free(client);
827 : : } else
828 : 0 : client->dead = true;
829 : 0 : }
830 : :
831 : : static void
832 : : *get_in_addr(struct sockaddr_storage *ss)
833 : : {
834 [ # # ]: 0 : if (ss->ss_family == AF_INET)
835 : : return &(((struct sockaddr_in*)ss)->sin_addr);
836 : :
837 : : return &(((struct sockaddr_in6*)ss)->sin6_addr);
838 : : }
839 : :
840 : 0 : static void tapdisk_nbd_server_free_vreq(
841 : : td_nbdserver_client_t *client, td_vbd_request_t *vreq, bool free_client_if_dead)
842 : : {
843 : 0 : td_nbdserver_req_t *req = container_of(vreq, td_nbdserver_req_t, vreq);
844 : 0 : free(vreq->iov->base);
845 : 0 : tapdisk_nbdserver_free_request(client, req, free_client_if_dead);
846 : 0 : }
847 : :
848 : :
849 : : static void
850 : 0 : __tapdisk_nbdserver_block_status_cb(td_vbd_request_t *vreq, int err,
851 : : void *token, int final)
852 : : {
853 : 0 : td_nbdserver_client_t *client = token;
854 : 0 : td_nbdserver_req_t *req = container_of(vreq, td_nbdserver_req_t, vreq);
855 : 0 : tapdisk_extents_t* extents = (tapdisk_extents_t *)(vreq->data);
856 : 0 : send_structured_reply_block_status (client->client_fd, req->id, extents);
857 : 0 : free_extents(extents);
858 : 0 : tapdisk_nbd_server_free_vreq(client, vreq, true);
859 : 0 : }
860 : :
861 : : static int
862 : 0 : __tapdisk_nbdserver_send_structured_reply(
863 : : int fd, uint16_t type, uint16_t flags, char *handle, uint32_t length)
864 : : {
865 : : struct nbd_structured_reply reply;
866 : 0 : int rc = 0;
867 : :
868 : 0 : reply.magic = htobe32(NBD_STRUCTURED_REPLY_MAGIC);
869 [ # # ]: 0 : reply.flags = htobe16(flags);
870 [ # # ]: 0 : reply.type = htobe16(type);
871 : : memcpy(&reply.handle, handle, sizeof(reply.handle));
872 : 0 : reply.length = htobe32(length);
873 : :
874 : 0 : rc = send_fully_or_fail(fd, &reply, sizeof(reply));
875 [ # # ]: 0 : if (rc < 0) {
876 : 0 : ERR("Short send/error in callback");
877 : 0 : return -1;
878 : : }
879 : :
880 : : return 0;
881 : : }
882 : :
883 : : static void
884 : 0 : __tapdisk_nbdserver_structured_read_cb(
885 : : td_vbd_request_t *vreq, int error, void *token, int final)
886 : : {
887 : 0 : td_nbdserver_client_t *client = token;
888 : 0 : td_nbdserver_t *server = client->server;
889 : 0 : td_nbdserver_req_t *req = container_of(vreq, td_nbdserver_req_t, vreq);
890 : : unsigned long long interval;
891 : : struct timeval now;
892 : : uint64_t offset;
893 : 0 : int rc = 0;
894 : 0 : int len = 0;
895 : :
896 : 0 : gettimeofday(&now, NULL);
897 : 0 : interval = timeval_to_us(&now) - timeval_to_us(&vreq->ts);
898 : :
899 [ # # ]: 0 : if (interval > 20 * 1000 * 1000) {
900 : 0 : INFO("request took %llu microseconds to complete", interval);
901 : : }
902 : :
903 [ # # ]: 0 : if (client->client_fd < 0) {
904 : 0 : ERR("Finishing request for client that has disappeared");
905 : : goto finish;
906 : : }
907 : :
908 : 0 : len = vreq->iov->secs << SECTOR_SHIFT;
909 : :
910 : : /* For now, say we're done, if we have to support multiple chunks it will be harder */
911 [ # # ]: 0 : if (__tapdisk_nbdserver_send_structured_reply(
912 : : client->client_fd, NBD_REPLY_TYPE_OFFSET_DATA,
913 : 0 : NBD_REPLY_FLAG_DONE, req->id, len + sizeof(uint64_t)) == -1)
914 : : {
915 : 0 : ERR("Failed to send structured reply header");
916 : : goto finish;
917 : : }
918 : :
919 : 0 : offset = vreq->sec << SECTOR_SHIFT;
920 : 0 : offset = htobe64(offset);
921 : 0 : rc = send_fully_or_fail(client->client_fd, &offset, sizeof(offset));
922 [ # # ]: 0 : if (rc < 0) {
923 : 0 : ERR("Failed to send offset for structured read reply");
924 : : goto finish;
925 : : }
926 : :
927 : 0 : server->nbd_stats.stats->read_reqs_completed++;
928 : 0 : server->nbd_stats.stats->read_sectors += vreq->iov->secs;
929 : 0 : server->nbd_stats.stats->read_total_ticks += interval;
930 : 0 : rc = send_fully_or_fail(client->client_fd,
931 : : vreq->iov->base, len);
932 [ # # ]: 0 : if (rc < 0) {
933 : 0 : ERR("Short send/error in callback");
934 : : goto finish;
935 : : }
936 : :
937 [ # # ]: 0 : if (error)
938 : 0 : server->nbd_stats.stats->io_errors++;
939 : :
940 : : finish:
941 : 0 : free(vreq->iov->base);
942 : 0 : tapdisk_nbdserver_free_request(client, req, true);
943 : 0 : }
944 : :
945 : : static void
946 : 0 : __tapdisk_nbdserver_request_cb(td_vbd_request_t *vreq, int error,
947 : : void *token, int final)
948 : : {
949 : 0 : td_nbdserver_client_t *client = token;
950 : 0 : td_nbdserver_t *server = client->server;
951 : 0 : td_nbdserver_req_t *req = container_of(vreq, td_nbdserver_req_t, vreq);
952 : : unsigned long long interval;
953 : : struct timeval now;
954 : : struct nbd_reply reply;
955 : 0 : int rc = 0;
956 : :
957 : 0 : reply.magic = htonl(NBD_REPLY_MAGIC);
958 : 0 : reply.error = htonl(error);
959 : 0 : memcpy(reply.handle, req->id, sizeof(reply.handle));
960 : :
961 : 0 : gettimeofday(&now, NULL);
962 : 0 : interval = timeval_to_us(&now) - timeval_to_us(&vreq->ts);
963 : :
964 [ # # ]: 0 : if (interval > 20 * 1000 * 1000) {
965 : 0 : INFO("request took %llu microseconds to complete", interval);
966 : : }
967 : :
968 [ # # ]: 0 : if (client->client_fd < 0) {
969 : 0 : ERR("Finishing request for client that has disappeared");
970 : : goto finish;
971 : : }
972 : :
973 : 0 : rc = send_fully_or_fail(client->client_fd,
974 : : &reply,
975 : : sizeof(reply));
976 [ # # ]: 0 : if (rc < 0) {
977 : 0 : ERR("Short send/error in callback");
978 : : goto finish;
979 : : }
980 : :
981 [ # # # ]: 0 : switch(vreq->op) {
982 : : case TD_OP_READ:
983 : 0 : server->nbd_stats.stats->read_reqs_completed++;
984 : 0 : server->nbd_stats.stats->read_sectors += vreq->iov->secs;
985 : 0 : server->nbd_stats.stats->read_total_ticks += interval;
986 : 0 : rc = send_fully_or_fail(client->client_fd,
987 : : vreq->iov->base,
988 : 0 : vreq->iov->secs << SECTOR_SHIFT);
989 [ # # ]: 0 : if (rc < 0) {
990 : 0 : ERR("Short send/error in callback");
991 : : goto finish;
992 : : }
993 : : break;
994 : : case TD_OP_WRITE:
995 : 0 : server->nbd_stats.stats->write_reqs_completed++;
996 : 0 : server->nbd_stats.stats->write_sectors += vreq->iov->secs;
997 : 0 : server->nbd_stats.stats->write_total_ticks += interval;
998 : : default:
999 : : break;
1000 : : }
1001 : :
1002 [ # # ]: 0 : if (error)
1003 : 0 : server->nbd_stats.stats->io_errors++;
1004 : :
1005 : : finish:
1006 : 0 : free(vreq->iov->base);
1007 : 0 : tapdisk_nbdserver_free_request(client, req, true);
1008 : 0 : }
1009 : :
1010 : : void
1011 : 0 : tapdisk_nbdserver_handshake_cb(event_id_t id, char mode, void *data)
1012 : : {
1013 : 0 : uint32_t cflags = 0;
1014 : :
1015 : 0 : td_nbdserver_client_t *client = (td_nbdserver_client_t*)data;
1016 : 0 : td_nbdserver_t *server = client->server;
1017 : :
1018 : 0 : int rc = recv_fully_or_fail(server->handshake_fd, &cflags, sizeof(cflags));
1019 [ # # ]: 0 : if(rc < 0) {
1020 : 0 : ERR("Could not receive client flags");
1021 : 0 : return;
1022 : : }
1023 : :
1024 : 0 : cflags = be32toh (cflags);
1025 : 0 : bool no_zeroes = (NBD_FLAG_NO_ZEROES & cflags) != 0;
1026 : :
1027 : : /* Receive newstyle options. */
1028 [ # # ]: 0 : if (receive_newstyle_options (client, server->handshake_fd, no_zeroes) == -1){
1029 : 0 : ERR("Option negotiation messed up");
1030 : : }
1031 : :
1032 : 0 : tapdisk_server_unregister_event(id);
1033 : : }
1034 : :
1035 : : int
1036 : 1 : tapdisk_nbdserver_new_protocol_handshake(td_nbdserver_client_t *client, int new_fd)
1037 : : {
1038 : 1 : td_nbdserver_t *server = client->server;
1039 : : struct nbd_new_handshake handshake;
1040 : :
1041 : 1 : handshake.nbdmagic = htobe64 (NBD_MAGIC);
1042 : 1 : handshake.version = htobe64 (NBD_NEW_VERSION);
1043 [ - + ]: 1 : handshake.gflags = htobe16 (gflags);
1044 : :
1045 : 1 : int rc = send_fully_or_fail(new_fd, &handshake, sizeof(handshake));
1046 [ - + ]: 1 : if (rc < 0) {
1047 : 0 : ERR("Sending newstyle handshake");
1048 : 1 : return -1;
1049 : : }
1050 : 1 : server->handshake_fd = new_fd;
1051 : : /* We may need to wait upto 40 seconds for a reply especially during
1052 : : * SXM contexts, so setup an event and return so that tapdisk is
1053 : : * reponsive during the interim*/
1054 : :
1055 : 1 : tapdisk_server_register_event( SCHEDULER_POLL_READ_FD,
1056 : 1 : new_fd, TV_ZERO,
1057 : : tapdisk_nbdserver_handshake_cb,
1058 : : client);
1059 : : return 0;
1060 : : }
1061 : :
1062 : : static void
1063 : 0 : tapdisk_nbdserver_newclient_fd_old(td_nbdserver_t *server, int new_fd)
1064 : : {
1065 : : td_nbdserver_client_t *client;
1066 : : char buffer[256];
1067 : : int rc;
1068 : : uint64_t tmp64;
1069 : : uint32_t tmp32;
1070 : :
1071 [ # # ]: 0 : ASSERT(server);
1072 [ # # ]: 0 : ASSERT(new_fd >= 0);
1073 : :
1074 : 0 : INFO("Got a new client!");
1075 : :
1076 : : /* Spit out the NBD connection stuff */
1077 : :
1078 : : memcpy(buffer, "NBDMAGIC", 8);
1079 : 0 : tmp64 = htonll(NBD_NEGOTIATION_MAGIC);
1080 : : memcpy(buffer + 8, &tmp64, sizeof(tmp64));
1081 : 0 : tmp64 = htonll(server->info.size * server->info.sector_size);
1082 : 0 : INFO("Sending size %"PRIu64"", ntohll(tmp64));
1083 : : memcpy(buffer + 16, &tmp64, sizeof(tmp64));
1084 : 0 : tmp32 = htonl(0);
1085 : : memcpy(buffer + 24, &tmp32, sizeof(tmp32));
1086 : : bzero(buffer + 28, 124);
1087 : :
1088 : 0 : rc = send_fully_or_fail(new_fd, buffer, 152);
1089 [ # # ]: 0 : if (rc < 0) {
1090 : 0 : close(new_fd);
1091 : 0 : INFO("Write failed in negotiation");
1092 : 0 : return;
1093 : : }
1094 : :
1095 : 0 : INFO("About to alloc client");
1096 : 0 : client = tapdisk_nbdserver_alloc_client(server);
1097 [ # # ]: 0 : if (client == NULL) {
1098 : 0 : ERR("Error allocating client");
1099 : 0 : close(new_fd);
1100 : : return;
1101 : : }
1102 : :
1103 : 0 : INFO("Got an allocated client at %p", client);
1104 : 0 : client->client_fd = new_fd;
1105 : :
1106 : 0 : INFO("About to enable client on fd %d", client->client_fd);
1107 [ # # ]: 0 : if (tapdisk_nbdserver_enable_client(client) < 0) {
1108 : 0 : ERR("Error enabling client");
1109 : 0 : tapdisk_nbdserver_free_client(client);
1110 : 0 : close(new_fd);
1111 : : }
1112 : : }
1113 : :
1114 : : static void
1115 : 0 : tapdisk_nbdserver_newclient_fd_new_fixed(td_nbdserver_t *server, int new_fd)
1116 : : {
1117 : : td_nbdserver_client_t *client;
1118 : :
1119 [ # # ]: 0 : ASSERT(server);
1120 [ # # ]: 0 : ASSERT(new_fd >= 0);
1121 : :
1122 : 0 : INFO("Got a new client!");
1123 : :
1124 : 0 : INFO("About to alloc client");
1125 : 0 : client = tapdisk_nbdserver_alloc_client(server);
1126 [ # # ]: 0 : if (client == NULL) {
1127 : 0 : ERR("Error allocating client");
1128 : 0 : close(new_fd);
1129 : 0 : return;
1130 : : }
1131 : 0 : INFO("Got an allocated client at %p", client);
1132 : :
1133 [ # # ]: 0 : if(tapdisk_nbdserver_new_protocol_handshake(client, new_fd) != 0) {
1134 : 0 : ERR("Error handshaking new client connection");
1135 : 0 : tapdisk_nbdserver_free_client(client);
1136 : 0 : return;
1137 : : }
1138 : :
1139 : 0 : client->client_fd = new_fd;
1140 : :
1141 : 0 : INFO("About to enable client on fd %d", client->client_fd);
1142 [ # # ]: 0 : if (tapdisk_nbdserver_enable_client(client) < 0) {
1143 : 0 : ERR("Error enabling client");
1144 : 0 : tapdisk_nbdserver_free_client(client);
1145 : 0 : close(new_fd);
1146 : : }
1147 : : }
1148 : :
1149 : : static void
1150 : : tapdisk_nbdserver_newclient_fd(td_nbdserver_t *server, int new_fd)
1151 : : {
1152 : : if(SERVER_USE_OLD_PROTOCOL){
1153 : 0 : tapdisk_nbdserver_newclient_fd_old(server, new_fd);
1154 : : } else {
1155 : : tapdisk_nbdserver_newclient_fd_new_fixed(server, new_fd);
1156 : : }
1157 : : }
1158 : :
1159 : 0 : static td_vbd_request_t *create_request_vreq(
1160 : : td_nbdserver_client_t *client, struct nbd_request request, uint32_t len)
1161 : : {
1162 : : int rc;
1163 : 0 : td_nbdserver_t *server = client->server;
1164 : : td_vbd_request_t *vreq;
1165 : : td_nbdserver_req_t *req;
1166 : :
1167 : 0 : req = tapdisk_nbdserver_alloc_request(client);
1168 [ # # ]: 0 : if (!req) {
1169 : 0 : ERR("Couldn't allocate request in clientcb - killing client");
1170 : 0 : goto failreq;
1171 : : }
1172 : :
1173 : 0 : vreq = &req->vreq;
1174 : :
1175 : : memset(req, 0, sizeof(td_nbdserver_req_t));
1176 : :
1177 : 0 : bzero(req->id, sizeof(req->id));
1178 : 0 : memcpy(req->id, request.handle, sizeof(request.handle));
1179 : :
1180 : 0 : rc = posix_memalign(&req->iov.base, 512, len);
1181 [ # # ]: 0 : if (rc < 0) {
1182 : 0 : ERR("posix_memalign failed (%d)", rc);
1183 : : goto fail;
1184 : : }
1185 : :
1186 : 0 : vreq->sec = request.from >> SECTOR_SHIFT;
1187 : 0 : vreq->iovcnt = 1;
1188 : 0 : vreq->iov = &req->iov;
1189 : 0 : vreq->iov->secs = len >> SECTOR_SHIFT;
1190 : 0 : vreq->token = client;
1191 : 0 : vreq->name = req->id;
1192 : 0 : vreq->vbd = server->vbd;
1193 : :
1194 : 0 : return vreq;
1195 : :
1196 : : fail:
1197 : 0 : tapdisk_nbdserver_set_free_request(client, req);
1198 : : failreq:
1199 : : return NULL;
1200 : : }
1201 : :
1202 : :
1203 : : void
1204 : 0 : tapdisk_nbdserver_clientcb(event_id_t id, char mode, void *data)
1205 : : {
1206 : 0 : td_nbdserver_client_t *client = data;
1207 : 0 : td_nbdserver_t *server = client->server;
1208 : : int rc;
1209 : : uint32_t len;
1210 : 0 : int fd = client->client_fd;
1211 : 0 : td_vbd_request_t *vreq = NULL;
1212 : : struct nbd_request request;
1213 : :
1214 : : /* Read the request the client has sent */
1215 : 0 : rc = recv_fully_or_fail(fd, &request, sizeof(request));
1216 [ # # ]: 0 : if (rc < 0) {
1217 : 0 : ERR("failed to receive from client. Closing connection");
1218 : : goto fail;
1219 : : }
1220 : :
1221 [ # # ]: 0 : if (request.magic != htonl(NBD_REQUEST_MAGIC)) {
1222 : 0 : ERR("Not enough magic, %X", request.magic);
1223 : : goto fail;
1224 : : }
1225 : :
1226 : 0 : request.from = ntohll(request.from);
1227 : 0 : request.type = ntohl(request.type);
1228 : 0 : len = ntohl(request.len);
1229 [ # # ][ # # ]: 0 : if (((len & 0x1ff) != 0) || ((request.from & 0x1ff) != 0)) {
1230 : 0 : ERR("Non sector-aligned request (%"PRIu64", %d)",
1231 : : request.from, len);
1232 : : }
1233 : :
1234 [ # # # # : 0 : switch(request.type) {
# ]
1235 : : case TAPDISK_NBD_CMD_READ:
1236 : 0 : vreq = create_request_vreq(client, request, len);
1237 [ # # ]: 0 : if (!vreq) {
1238 : 0 : ERR("Failed to create vreq");
1239 : : goto fail;
1240 : : }
1241 : 0 : vreq->cb = client->structured_reply ?
1242 [ # # ]: 0 : __tapdisk_nbdserver_structured_read_cb :
1243 : : __tapdisk_nbdserver_request_cb;
1244 : 0 : vreq->op = TD_OP_READ;
1245 : 0 : server->nbd_stats.stats->read_reqs_submitted++;
1246 : 0 : break;
1247 : : case TAPDISK_NBD_CMD_WRITE:
1248 : 0 : vreq = create_request_vreq(client, request, len);
1249 [ # # ]: 0 : if (!vreq) {
1250 : 0 : ERR("Failed to create vreq");
1251 : : goto fail;
1252 : : }
1253 : 0 : vreq->cb = __tapdisk_nbdserver_request_cb;
1254 : 0 : vreq->op = TD_OP_WRITE;
1255 : 0 : server->nbd_stats.stats->write_reqs_submitted++;
1256 : 0 : rc = recv_fully_or_fail(fd, vreq->iov->base, len);
1257 [ # # ]: 0 : if (rc < 0) {
1258 : 0 : ERR("Short send or error in "
1259 : : "callback: %d", rc);
1260 : : goto fail;
1261 : : }
1262 : :
1263 : : break;
1264 : : case TAPDISK_NBD_CMD_DISC:
1265 : 0 : INFO("Received close message. Sending reconnect "
1266 : : "header");
1267 : 0 : tapdisk_nbdserver_free_client(client);
1268 : 0 : INFO("About to send initial connection message");
1269 : : tapdisk_nbdserver_newclient_fd(server, fd);
1270 : 0 : INFO("Sent initial connection message");
1271 : 0 : return;
1272 : : case TAPDISK_NBD_CMD_BLOCK_STATUS:
1273 : : {
1274 [ # # ]: 0 : if (!client->structured_reply)
1275 : 0 : ERR("NBD_CMD_BLOCK_STATUS: when not in structured reply");
1276 : :
1277 [ # # ]: 0 : if (len > 2 * MEGABYTES) {
1278 : : /* limit request to 2MB */
1279 : 0 : len = 2 * MEGABYTES;
1280 : : }
1281 : :
1282 : 0 : vreq = create_request_vreq(client, request, len);
1283 [ # # ]: 0 : if (!vreq) {
1284 : 0 : ERR("Failed to create vreq");
1285 : : goto fail;
1286 : : }
1287 : 0 : tapdisk_extents_t *extents = (tapdisk_extents_t*)malloc(sizeof(tapdisk_extents_t));
1288 [ # # ]: 0 : if(extents == NULL) {
1289 : 0 : ERR("Could not allocate memory for tapdisk_extents_t");
1290 : : goto fail;
1291 : : }
1292 : : bzero(extents, sizeof(tapdisk_extents_t));
1293 : 0 : vreq->data = extents;
1294 : 0 : vreq->cb = __tapdisk_nbdserver_block_status_cb;
1295 : 0 : vreq->op = TD_OP_BLOCK_STATUS;
1296 : : }
1297 : 0 : break;
1298 : : default:
1299 : 0 : ERR("Unsupported operation: 0x%x", request.type);
1300 : : goto fail;
1301 : : }
1302 : :
1303 : 0 : rc = tapdisk_vbd_queue_request(server->vbd, vreq);
1304 [ # # ]: 0 : if (rc) {
1305 : 0 : ERR("tapdisk_vbd_queue_request failed: %d", rc);
1306 : : goto fail;
1307 : : }
1308 : :
1309 : : return;
1310 : :
1311 : : fail:
1312 [ # # ]: 0 : if (vreq)
1313 : 0 : tapdisk_nbd_server_free_vreq(client, vreq, false);
1314 : :
1315 : 0 : tapdisk_nbdserver_free_client(client);
1316 : : return;
1317 : : }
1318 : :
1319 : : static void
1320 : 0 : tapdisk_nbdserver_fdreceiver_cb(int fd, char *msg, void *data)
1321 : : {
1322 : 0 : td_nbdserver_t *server = data;
1323 : :
1324 [ # # ]: 0 : ASSERT(server);
1325 [ # # ]: 0 : ASSERT(msg);
1326 [ # # ]: 0 : ASSERT(fd >= 0);
1327 : :
1328 : 0 : INFO("Received fd %d with msg: %s", fd, msg);
1329 : :
1330 : : tapdisk_nbdserver_newclient_fd(server, fd);
1331 : 0 : }
1332 : :
1333 : : static void
1334 : 0 : tapdisk_nbdserver_newclient(event_id_t id, char mode, void *data)
1335 : : {
1336 : : struct sockaddr_storage their_addr;
1337 : 0 : socklen_t sin_size = sizeof(their_addr);
1338 : : char s[INET6_ADDRSTRLEN+1];
1339 : : int new_fd;
1340 : 0 : td_nbdserver_t *server = data;
1341 : :
1342 [ # # ]: 0 : ASSERT(server);
1343 : :
1344 : 0 : INFO("About to accept (server->fdrecv_listening_fd = %d)",
1345 : : server->fdrecv_listening_fd);
1346 : :
1347 : 0 : new_fd = accept(server->fdrecv_listening_fd,
1348 : : (struct sockaddr *)&their_addr, &sin_size);
1349 : :
1350 [ # # ]: 0 : if (new_fd == -1) {
1351 : 0 : ERR("failed to accept connection on the fd receiver socket: %s",
1352 : : strerror(errno));
1353 : 0 : return;
1354 : : }
1355 : :
1356 : : memset(s, 0, sizeof(s));
1357 : 0 : inet_ntop(their_addr.ss_family, get_in_addr(&their_addr), s, sizeof(s)-1);
1358 : :
1359 : 0 : INFO("server: got connection from %s\n", s);
1360 : :
1361 : : tapdisk_nbdserver_newclient_fd(server, new_fd);
1362 : : }
1363 : :
1364 : : static void
1365 : 0 : tapdisk_nbdserver_newclient_unix(event_id_t id, char mode, void *data)
1366 : : {
1367 : 0 : int new_fd = 0;
1368 : : struct sockaddr_un remote;
1369 : 0 : socklen_t t = sizeof(remote);
1370 : 0 : td_nbdserver_t *server = data;
1371 : :
1372 [ # # ]: 0 : ASSERT(server);
1373 : :
1374 : 0 : INFO("About to accept (server->unix_listening_fd = %d)",
1375 : : server->unix_listening_fd);
1376 : :
1377 : 0 : new_fd = accept(server->unix_listening_fd, (struct sockaddr *)&remote, &t);
1378 [ # # ]: 0 : if (new_fd == -1) {
1379 : 0 : ERR("failed to accept connection: %s\n", strerror(errno));
1380 : 0 : return;
1381 : : }
1382 : :
1383 : 0 : INFO("server: got connection\n");
1384 : :
1385 : 0 : tapdisk_nbdserver_newclient_fd_new_fixed(server, new_fd);
1386 : : }
1387 : :
1388 : : td_nbdserver_t *
1389 : 0 : tapdisk_nbdserver_alloc(td_vbd_t *vbd, td_disk_info_t info)
1390 : : {
1391 : : td_nbdserver_t *server;
1392 : : char fdreceiver_path[TAPDISK_NBDSERVER_MAX_PATH_LEN];
1393 : :
1394 : 0 : server = calloc(1, sizeof(*server));
1395 [ # # ]: 0 : if (!server) {
1396 : 0 : ERR("Failed to allocate memory for nbdserver: %s",
1397 : : strerror(errno));
1398 : : goto fail;
1399 : : }
1400 : :
1401 : 0 : server->vbd = vbd;
1402 : 0 : server->info = info;
1403 : 0 : server->fdrecv_listening_fd = -1;
1404 : 0 : server->fdrecv_listening_event_id = -1;
1405 : 0 : server->unix_listening_fd = -1;
1406 : 0 : server->unix_listening_event_id = -1;
1407 : 0 : INIT_LIST_HEAD(&server->clients);
1408 : :
1409 [ # # ]: 0 : if (td_metrics_nbd_start(&server->nbd_stats, server->vbd->tap->minor)) {
1410 : 0 : ERR("failed to create metrics file for nbdserver");
1411 : : goto fail;
1412 : : }
1413 : :
1414 [ # # ]: 0 : if (snprintf(fdreceiver_path, TAPDISK_NBDSERVER_MAX_PATH_LEN,
1415 : : "%s%d.%d", TAPDISK_NBDSERVER_LISTEN_SOCK_PATH, getpid(),
1416 : 0 : vbd->uuid) < 0) {
1417 : 0 : ERR("Failed to snprintf fdreceiver_path");
1418 : : goto fail;
1419 : : }
1420 : :
1421 : 0 : server->fdreceiver = td_fdreceiver_start(fdreceiver_path,
1422 : : tapdisk_nbdserver_fdreceiver_cb, server);
1423 [ # # ]: 0 : if (!server->fdreceiver) {
1424 : 0 : ERR("Error setting up fd receiver");
1425 : : goto fail;
1426 : : }
1427 : :
1428 [ # # ]: 0 : if (snprintf(server->sockpath, TAPDISK_NBDSERVER_MAX_PATH_LEN,
1429 : : "%s%d.%d", TAPDISK_NBDSERVER_SOCK_PATH, getpid(),
1430 : 0 : vbd->uuid) < 0) {
1431 : 0 : ERR("Failed to snprintf sockpath");
1432 : : goto fail;
1433 : : }
1434 : :
1435 : 0 : return server;
1436 : :
1437 : : fail:
1438 [ # # ]: 0 : if (server) {
1439 [ # # ]: 0 : if (server->fdreceiver)
1440 : 0 : td_fdreceiver_stop(server->fdreceiver);
1441 : 0 : free(server);
1442 : : }
1443 : :
1444 : : return NULL;
1445 : : }
1446 : :
1447 : : void
1448 : 0 : tapdisk_nbdserver_pause(td_nbdserver_t *server, bool log)
1449 : : {
1450 : : struct td_nbdserver_client *pos, *q;
1451 : :
1452 [ # # ]: 0 : if (log) {
1453 : 0 : INFO("NBD server pause(%p)", server);
1454 : : }
1455 : :
1456 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &server->clients, clientlist){
1457 [ # # ][ # # ]: 0 : if (pos->paused != 1 && pos->client_event_id >= 0) {
1458 : 0 : tapdisk_nbdserver_disable_client(pos);
1459 : 0 : pos->paused = 1;
1460 : : }
1461 : : }
1462 : :
1463 [ # # ]: 0 : if (server->fdrecv_listening_event_id >= 0) {
1464 : 0 : tapdisk_server_unregister_event(server->fdrecv_listening_event_id);
1465 : 0 : server->fdrecv_listening_event_id = -1;
1466 : : }
1467 : :
1468 [ # # ]: 0 : if (server->unix_listening_event_id >= 0) {
1469 : 0 : tapdisk_server_unregister_event(server->unix_listening_event_id);
1470 : 0 : server->unix_listening_event_id = -1;
1471 : : }
1472 : 0 : }
1473 : :
1474 : : static int
1475 : 0 : tapdisk_nbdserver_unpause_fdrecv(td_nbdserver_t *server)
1476 : : {
1477 : 0 : int err = 0;
1478 : :
1479 [ # # ]: 0 : ASSERT(server);
1480 : :
1481 [ # # ]: 0 : if (server->fdrecv_listening_event_id < 0
1482 [ # # ]: 0 : && server->fdrecv_listening_fd >= 0) {
1483 : 0 : INFO("registering for fdrecv_listening_fd");
1484 : 0 : server->fdrecv_listening_event_id =
1485 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
1486 : 0 : server->fdrecv_listening_fd, TV_ZERO,
1487 : : tapdisk_nbdserver_newclient,
1488 : : server);
1489 [ # # ]: 0 : if (server->fdrecv_listening_event_id < 0) {
1490 : 0 : err = server->fdrecv_listening_event_id;
1491 : 0 : server->fdrecv_listening_event_id = -1;
1492 : : }
1493 : : }
1494 : :
1495 : 0 : return err;
1496 : : }
1497 : :
1498 : : static int
1499 : 0 : tapdisk_nbdserver_unpause_unix(td_nbdserver_t *server)
1500 : : {
1501 : 0 : int err = 0;
1502 : :
1503 [ # # ]: 0 : ASSERT(server);
1504 : :
1505 [ # # ]: 0 : if (server->unix_listening_event_id < 0
1506 [ # # ]: 0 : && server->unix_listening_fd >= 0) {
1507 : 0 : INFO("registering for unix_listening_fd");
1508 : 0 : server->unix_listening_event_id =
1509 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
1510 : 0 : server->unix_listening_fd, TV_ZERO,
1511 : : tapdisk_nbdserver_newclient_unix,
1512 : : server);
1513 [ # # ]: 0 : if (server->unix_listening_event_id < 0) {
1514 : 0 : err = server->unix_listening_event_id;
1515 : 0 : server->unix_listening_event_id = -1;
1516 : : }
1517 : :
1518 : : /* Note: any failures after this point need to unregister the event */
1519 : : }
1520 : :
1521 : 0 : return err;
1522 : : }
1523 : :
1524 : : int
1525 : 0 : tapdisk_nbdserver_listen_inet(td_nbdserver_t *server, const int port)
1526 : : {
1527 : : struct addrinfo hints, *servinfo, *p;
1528 : : char portstr[10];
1529 : : int err;
1530 : 0 : int yes = 1;
1531 : :
1532 [ # # ]: 0 : ASSERT(server);
1533 [ # # ]: 0 : ASSERT(server->fdrecv_listening_fd == -1);
1534 : :
1535 : : memset(&hints, 0, sizeof(hints));
1536 : : hints.ai_family = AF_UNSPEC;
1537 : 0 : hints.ai_socktype = SOCK_STREAM;
1538 : 0 : hints.ai_flags = AI_PASSIVE;
1539 : :
1540 : : snprintf(portstr, 10, "%d", port);
1541 : :
1542 : 0 : err = getaddrinfo(NULL, portstr, &hints, &servinfo);
1543 [ # # ]: 0 : if (err) {
1544 [ # # ]: 0 : if (err == EAI_SYSTEM) {
1545 : 0 : ERR("Failed to getaddrinfo: %s", strerror(errno));
1546 : 0 : return -errno;
1547 : : } else {
1548 : 0 : ERR("Failed to getaddrinfo: %s", gai_strerror(err));
1549 : : return -1;
1550 : : }
1551 : : }
1552 : :
1553 [ # # ]: 0 : for (p = servinfo; p != NULL; p = p->ai_next) {
1554 [ # # ]: 0 : if ((server->fdrecv_listening_fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0)) ==
1555 : : -1) {
1556 : 0 : ERR("Failed to create socket");
1557 : 0 : continue;
1558 : : }
1559 : :
1560 [ # # ]: 0 : if (setsockopt(server->fdrecv_listening_fd, SOL_SOCKET, SO_REUSEADDR,
1561 : : &yes, sizeof(int)) == -1) {
1562 : 0 : ERR("Failed to setsockopt");
1563 : 0 : close(server->fdrecv_listening_fd);
1564 : 0 : server->fdrecv_listening_fd = -1;
1565 : 0 : continue;
1566 : : }
1567 : :
1568 [ # # ]: 0 : if (bind(server->fdrecv_listening_fd, p->ai_addr, p->ai_addrlen) ==
1569 : : -1) {
1570 : 0 : ERR("Failed to bind");
1571 : 0 : close(server->fdrecv_listening_fd);
1572 : 0 : server->fdrecv_listening_fd = -1;
1573 : 0 : continue;
1574 : : }
1575 : :
1576 : : break;
1577 : : }
1578 : :
1579 : 0 : freeaddrinfo(servinfo);
1580 : :
1581 [ # # ]: 0 : if (p == NULL) {
1582 : 0 : ERR("Failed to bind");
1583 : : err = -1;
1584 : : goto out;
1585 : : }
1586 : :
1587 : 0 : err = listen(server->fdrecv_listening_fd, 10);
1588 [ # # ]: 0 : if (err) {
1589 : 0 : err = -errno;
1590 : 0 : ERR("listen: %s", strerror(-err));
1591 : : goto out;
1592 : : }
1593 : :
1594 : 0 : err = tapdisk_nbdserver_unpause_fdrecv(server);
1595 [ # # ]: 0 : if (err) {
1596 : 0 : ERR("failed to unpause the NBD server (fdrecv): %s\n",
1597 : : strerror(-err));
1598 : : goto out;
1599 : : }
1600 : :
1601 : 0 : INFO("Successfully started NBD server (fdrecv)");
1602 : :
1603 : : out:
1604 [ # # ][ # # ]: 0 : if (err && (server->fdrecv_listening_fd != -1)) {
1605 : 0 : close(server->fdrecv_listening_fd);
1606 : 0 : server->fdrecv_listening_fd = -1;
1607 : : }
1608 : 0 : return err;
1609 : : }
1610 : :
1611 : : int
1612 : 0 : tapdisk_nbdserver_listen_unix(td_nbdserver_t *server)
1613 : : {
1614 : 0 : size_t len = 0;
1615 : 0 : int err = 0;
1616 : : int new_fd;
1617 [ # # ]: 0 : ASSERT(server);
1618 [ # # ]: 0 : ASSERT(server->unix_listening_fd == -1);
1619 : :
1620 : 0 : new_fd = socket(AF_UNIX, SOCK_STREAM, 0);
1621 [ # # ]: 0 : if (new_fd == -1) {
1622 : 0 : err = -errno;
1623 : 0 : ERR("failed to create UNIX domain socket: %s\n", strerror(-err));
1624 : 0 : goto fail;
1625 : : }
1626 : :
1627 : 0 : server->local.sun_family = AF_UNIX;
1628 : :
1629 [ # # ]: 0 : if (unlikely(strlen(server->sockpath) >
1630 : : (sizeof(server->local.sun_path) - 1))) {
1631 : 0 : err = -ENAMETOOLONG;
1632 : 0 : ERR("socket name too long: %s\n", server->sockpath);
1633 : 0 : goto fail;
1634 : : }
1635 : :
1636 : 0 : safe_strncpy(server->local.sun_path, server->sockpath, sizeof(server->local.sun_path));
1637 : 0 : err = unlink(server->local.sun_path);
1638 [ # # ][ # # ]: 0 : if (err == -1 && errno != ENOENT) {
1639 : 0 : err = -errno;
1640 : 0 : ERR("failed to remove %s: %s\n", server->local.sun_path,
1641 : : strerror(-err));
1642 : 0 : goto fail;
1643 : : }
1644 : 0 : len = strlen(server->local.sun_path) + sizeof(server->local.sun_family);
1645 : 0 : err = bind(new_fd, (struct sockaddr *)&server->local,
1646 : : len);
1647 [ # # ]: 0 : if (err == -1) {
1648 : 0 : err = -errno;
1649 : 0 : ERR("failed to bind: %s\n", strerror(-err));
1650 : 0 : goto fail;
1651 : : }
1652 : :
1653 : 0 : err = listen(new_fd, 10);
1654 [ # # ]: 0 : if (err == -1) {
1655 : 0 : err = -errno;
1656 : 0 : ERR("failed to listen: %s\n", strerror(-err));
1657 : 0 : goto fail;
1658 : : }
1659 : :
1660 : 0 : server->unix_listening_fd = new_fd;
1661 : :
1662 : 0 : err = tapdisk_nbdserver_unpause_unix(server);
1663 [ # # ]: 0 : if (err) {
1664 : 0 : ERR("failed to unpause the NBD server (unix): %s\n",
1665 : : strerror(-err));
1666 : 0 : goto fail;
1667 : : }
1668 : :
1669 : 0 : INFO("Successfully started NBD server on %s\n", server->sockpath);
1670 : :
1671 : 0 : return 0;
1672 : :
1673 : : fail:
1674 [ # # ]: 0 : if (new_fd > -1) {
1675 : 0 : close(new_fd);
1676 : : }
1677 : 0 : server->unix_listening_fd = -1;
1678 : :
1679 : 0 : return err;
1680 : : }
1681 : :
1682 : : int
1683 : 0 : tapdisk_nbdserver_unpause(td_nbdserver_t *server)
1684 : : {
1685 : : struct td_nbdserver_client *pos, *q;
1686 : : int err;
1687 : :
1688 [ # # ]: 0 : ASSERT(server);
1689 : :
1690 : 0 : INFO("NBD server unpause(%p) - fdrecv_listening_fd %d, "
1691 : : "unix_listening_fd=%d", server, server->fdrecv_listening_fd,
1692 : : server->unix_listening_fd);
1693 : :
1694 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &server->clients, clientlist){
1695 [ # # ]: 0 : if (pos->paused == 1) {
1696 [ # # ]: 0 : if((err = tapdisk_nbdserver_enable_client(pos)) < 0) {
1697 : 0 : ERR("Failed to enable nbd client after pause");
1698 : 0 : return err;
1699 : : }
1700 : 0 : pos->paused = 0;
1701 : : }
1702 : : }
1703 : :
1704 : 0 : err = tapdisk_nbdserver_unpause_fdrecv(server);
1705 [ # # ]: 0 : if (err)
1706 : : return err;
1707 : :
1708 : 0 : err = tapdisk_nbdserver_unpause_unix(server);
1709 [ # # ]: 0 : if (err)
1710 : 0 : return err;
1711 : :
1712 : : return 0;
1713 : : }
1714 : :
1715 : : void
1716 : 0 : tapdisk_nbdserver_free(td_nbdserver_t *server)
1717 : : {
1718 : : struct td_nbdserver_client *pos, *q;
1719 : : int err;
1720 : :
1721 : 0 : INFO("NBD server free(%p)", server);
1722 : :
1723 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &server->clients, clientlist)
1724 : 0 : tapdisk_nbdserver_free_client(pos);
1725 : :
1726 [ # # ]: 0 : if (server->fdrecv_listening_event_id >= 0) {
1727 : 0 : tapdisk_server_unregister_event(server->fdrecv_listening_event_id);
1728 : 0 : server->fdrecv_listening_event_id = -1;
1729 : : }
1730 : :
1731 [ # # ]: 0 : if (server->fdrecv_listening_fd >= 0) {
1732 : 0 : close(server->fdrecv_listening_fd);
1733 : 0 : server->fdrecv_listening_fd = -1;
1734 : : }
1735 : :
1736 [ # # ]: 0 : if (server->fdreceiver)
1737 : 0 : td_fdreceiver_stop(server->fdreceiver);
1738 : :
1739 [ # # ]: 0 : if (server->unix_listening_event_id >= 0) {
1740 : 0 : tapdisk_server_unregister_event(server->unix_listening_event_id);
1741 : 0 : server->unix_listening_event_id = -1;
1742 : : }
1743 : :
1744 [ # # ]: 0 : if (server->unix_listening_fd >= 0) {
1745 : 0 : close(server->unix_listening_fd);
1746 : 0 : server->unix_listening_fd = -1;
1747 : : }
1748 : :
1749 : 0 : err = unlink(server->sockpath);
1750 [ # # ]: 0 : if (err)
1751 : 0 : ERR("failed to remove UNIX domain socket %s: %s\n", server->sockpath,
1752 : : strerror(errno));
1753 : 0 : err = td_metrics_nbd_stop(&server->nbd_stats);
1754 : :
1755 [ # # ]: 0 : if (err)
1756 : 0 : ERR("failed to delete NBD metrics: %s\n", strerror(errno));
1757 : :
1758 : 0 : free(server);
1759 : 0 : }
1760 : :
1761 : : int
1762 : 0 : tapdisk_nbdserver_reqs_pending(td_nbdserver_client_t *client)
1763 : : {
1764 [ # # ]: 0 : ASSERT(client);
1765 : :
1766 : 0 : return client->n_reqs - client->n_reqs_free;
1767 : : }
1768 : :
1769 : : bool
1770 : 0 : tapdisk_nbdserver_contains_client(td_nbdserver_t *server,
1771 : : td_nbdserver_client_t *client)
1772 : : {
1773 : : td_nbdserver_client_t *_client;
1774 : :
1775 [ # # ]: 0 : ASSERT(server);
1776 : :
1777 [ # # ]: 0 : list_for_each_entry(_client, &server->clients, clientlist)
1778 [ # # ]: 0 : if (client == _client)
1779 : : return true;
1780 : : return false;
1781 : : }
|