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