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 : :
1033 : 0 : td_nbdserver_client_t *client = (td_nbdserver_client_t*)data;
1034 : 0 : td_nbdserver_t *server = client->server;
1035 : :
1036 : 0 : int rc = recv_fully_or_fail(server->handshake_fd, &cflags, sizeof(cflags));
1037 [ # # ]: 0 : if(rc < 0) {
1038 : 0 : ERR("Could not receive client flags");
1039 : 0 : return;
1040 : : }
1041 : :
1042 : 0 : cflags = be32toh (cflags);
1043 : 0 : bool no_zeroes = (NBD_FLAG_NO_ZEROES & cflags) != 0;
1044 : :
1045 : : /* Receive newstyle options. */
1046 [ # # ]: 0 : if (receive_newstyle_options(client, server->handshake_fd, no_zeroes) == -1) {
1047 : 0 : INFO("Option negotiation terminated");
1048 : 0 : close(server->handshake_fd);
1049 : : }
1050 : :
1051 : 0 : tapdisk_server_unregister_event(id);
1052 : : }
1053 : :
1054 : : int
1055 : 1 : tapdisk_nbdserver_new_protocol_handshake(td_nbdserver_client_t *client, int new_fd)
1056 : : {
1057 : 1 : td_nbdserver_t *server = client->server;
1058 : : struct nbd_new_handshake handshake;
1059 : :
1060 : 1 : handshake.nbdmagic = htobe64 (NBD_MAGIC);
1061 : 1 : handshake.version = htobe64 (NBD_OPT_MAGIC);
1062 [ - + ]: 1 : handshake.gflags = htobe16 (gflags);
1063 : :
1064 : 1 : int rc = send_fully_or_fail(new_fd, &handshake, sizeof(handshake));
1065 [ - + ]: 1 : if (rc < 0) {
1066 : 0 : ERR("Sending newstyle handshake");
1067 : 1 : return -1;
1068 : : }
1069 : 1 : server->handshake_fd = new_fd;
1070 : : /* We may need to wait upto 40 seconds for a reply especially during
1071 : : * SXM contexts, so setup an event and return so that tapdisk is
1072 : : * reponsive during the interim*/
1073 : :
1074 : 1 : tapdisk_server_register_event( SCHEDULER_POLL_READ_FD,
1075 : 1 : new_fd, TV_ZERO,
1076 : : tapdisk_nbdserver_handshake_cb,
1077 : : client);
1078 : : return 0;
1079 : : }
1080 : :
1081 : : static void
1082 : 0 : tapdisk_nbdserver_newclient_fd_old(td_nbdserver_t *server, int new_fd)
1083 : : {
1084 : : td_nbdserver_client_t *client;
1085 : : char buffer[256];
1086 : : int rc;
1087 : : uint64_t tmp64;
1088 : : uint32_t tmp32;
1089 : :
1090 [ # # ]: 0 : ASSERT(server);
1091 [ # # ]: 0 : ASSERT(new_fd >= 0);
1092 : :
1093 : 0 : INFO("Got a new client!");
1094 : :
1095 : : /* Spit out the NBD connection stuff */
1096 : :
1097 : : memcpy(buffer, "NBDMAGIC", 8);
1098 : 0 : tmp64 = htonll(NBD_NEGOTIATION_MAGIC);
1099 : : memcpy(buffer + 8, &tmp64, sizeof(tmp64));
1100 : 0 : tmp64 = htonll(server->info.size * server->info.sector_size);
1101 : 0 : INFO("Sending size %"PRIu64"", ntohll(tmp64));
1102 : : memcpy(buffer + 16, &tmp64, sizeof(tmp64));
1103 : 0 : tmp32 = htonl(0);
1104 : : memcpy(buffer + 24, &tmp32, sizeof(tmp32));
1105 : : bzero(buffer + 28, 124);
1106 : :
1107 : 0 : rc = send_fully_or_fail(new_fd, buffer, 152);
1108 [ # # ]: 0 : if (rc < 0) {
1109 : 0 : close(new_fd);
1110 : 0 : INFO("Write failed in negotiation");
1111 : 0 : return;
1112 : : }
1113 : :
1114 : 0 : INFO("About to alloc client");
1115 : 0 : client = tapdisk_nbdserver_alloc_client(server);
1116 [ # # ]: 0 : if (client == NULL) {
1117 : 0 : ERR("Error allocating client");
1118 : 0 : close(new_fd);
1119 : : return;
1120 : : }
1121 : :
1122 : 0 : INFO("Got an allocated client at %p", client);
1123 : 0 : client->client_fd = new_fd;
1124 : :
1125 : 0 : INFO("About to enable client on fd %d", client->client_fd);
1126 [ # # ]: 0 : if (tapdisk_nbdserver_enable_client(client) < 0) {
1127 : 0 : ERR("Error enabling client");
1128 : 0 : tapdisk_nbdserver_free_client(client);
1129 : 0 : close(new_fd);
1130 : : }
1131 : : }
1132 : :
1133 : : static void
1134 : 0 : tapdisk_nbdserver_newclient_fd_new_fixed(td_nbdserver_t *server, int new_fd)
1135 : : {
1136 : : td_nbdserver_client_t *client;
1137 : :
1138 [ # # ]: 0 : ASSERT(server);
1139 [ # # ]: 0 : ASSERT(new_fd >= 0);
1140 : :
1141 : 0 : INFO("Got a new client!");
1142 : :
1143 : 0 : INFO("About to alloc client");
1144 : 0 : client = tapdisk_nbdserver_alloc_client(server);
1145 [ # # ]: 0 : if (client == NULL) {
1146 : 0 : ERR("Error allocating client");
1147 : 0 : close(new_fd);
1148 : 0 : return;
1149 : : }
1150 : 0 : INFO("Got an allocated client at %p", client);
1151 : :
1152 : 0 : client->client_fd = new_fd;
1153 : :
1154 [ # # ]: 0 : if(tapdisk_nbdserver_new_protocol_handshake(client, new_fd) != 0) {
1155 : 0 : ERR("Error handshaking new client connection");
1156 : 0 : tapdisk_nbdserver_free_client(client);
1157 : 0 : close(new_fd);
1158 : 0 : return;
1159 : : }
1160 : :
1161 : 0 : INFO("About to enable client on fd %d", client->client_fd);
1162 [ # # ]: 0 : if (tapdisk_nbdserver_enable_client(client) < 0) {
1163 : 0 : ERR("Error enabling client");
1164 : 0 : tapdisk_nbdserver_free_client(client);
1165 : 0 : close(new_fd);
1166 : : }
1167 : : }
1168 : :
1169 : : static void
1170 : 0 : tapdisk_nbdserver_newclient_fd(td_nbdserver_t *server, int new_fd)
1171 : : {
1172 [ # # # ]: 0 : switch (server->style) {
1173 : : case TAPDISK_NBD_PROTOCOL_OLD:
1174 : 0 : tapdisk_nbdserver_newclient_fd_old(server, new_fd);
1175 : 0 : break;
1176 : : case TAPDISK_NBD_PROTOCOL_NEW:
1177 : 0 : tapdisk_nbdserver_newclient_fd_new_fixed(server, new_fd);
1178 : 0 : break;
1179 : : };
1180 : 0 : }
1181 : :
1182 : 0 : static td_vbd_request_t *create_request_vreq(
1183 : : td_nbdserver_client_t *client, struct nbd_request request, uint32_t len)
1184 : : {
1185 : : int rc;
1186 : 0 : td_nbdserver_t *server = client->server;
1187 : : td_vbd_request_t *vreq;
1188 : : td_nbdserver_req_t *req;
1189 : :
1190 : 0 : req = tapdisk_nbdserver_alloc_request(client);
1191 [ # # ]: 0 : if (!req) {
1192 : 0 : ERR("Couldn't allocate request in clientcb - killing client");
1193 : 0 : goto failreq;
1194 : : }
1195 : :
1196 : 0 : vreq = &req->vreq;
1197 : :
1198 : : memset(req, 0, sizeof(td_nbdserver_req_t));
1199 : :
1200 : 0 : bzero(req->id, sizeof(req->id));
1201 : 0 : memcpy(req->id, request.handle, sizeof(request.handle));
1202 : :
1203 : 0 : rc = posix_memalign(&req->iov.base, 512, len);
1204 [ # # ]: 0 : if (rc < 0) {
1205 : 0 : ERR("posix_memalign failed (%d)", rc);
1206 : : goto fail;
1207 : : }
1208 : :
1209 : 0 : vreq->sec = request.from >> SECTOR_SHIFT;
1210 : 0 : vreq->iovcnt = 1;
1211 : 0 : vreq->iov = &req->iov;
1212 : 0 : vreq->iov->secs = len >> SECTOR_SHIFT;
1213 : 0 : vreq->token = client;
1214 : 0 : vreq->name = req->id;
1215 : 0 : vreq->vbd = server->vbd;
1216 : :
1217 : 0 : return vreq;
1218 : :
1219 : : fail:
1220 : 0 : tapdisk_nbdserver_set_free_request(client, req);
1221 : : failreq:
1222 : : return NULL;
1223 : : }
1224 : :
1225 : :
1226 : : void
1227 : 0 : tapdisk_nbdserver_clientcb(event_id_t id, char mode, void *data)
1228 : : {
1229 : 0 : td_nbdserver_client_t *client = data;
1230 : 0 : td_nbdserver_t *server = client->server;
1231 : : int rc;
1232 : : uint32_t len;
1233 : 0 : int fd = client->client_fd;
1234 : 0 : td_vbd_request_t *vreq = NULL;
1235 : : struct nbd_request request;
1236 : :
1237 : : /* Read the request the client has sent */
1238 : 0 : rc = recv_fully_or_fail(fd, &request, sizeof(request));
1239 [ # # ]: 0 : if (rc < 0) {
1240 : 0 : ERR("failed to receive from client. Closing connection");
1241 : : goto fail;
1242 : : }
1243 : :
1244 [ # # ]: 0 : if (request.magic != htonl(NBD_REQUEST_MAGIC)) {
1245 : 0 : ERR("Not enough magic, %X", request.magic);
1246 : : goto fail;
1247 : : }
1248 : :
1249 : 0 : request.from = ntohll(request.from);
1250 : 0 : request.type = ntohl(request.type);
1251 : 0 : len = ntohl(request.len);
1252 [ # # ][ # # ]: 0 : if (((len & 0x1ff) != 0) || ((request.from & 0x1ff) != 0)) {
1253 : 0 : ERR("Non sector-aligned request (%"PRIu64", %d)",
1254 : : request.from, len);
1255 : : }
1256 : :
1257 [ # # # # : 0 : switch(request.type) {
# ]
1258 : : case TAPDISK_NBD_CMD_READ:
1259 : 0 : vreq = create_request_vreq(client, request, len);
1260 [ # # ]: 0 : if (!vreq) {
1261 : 0 : ERR("Failed to create vreq");
1262 : : goto fail;
1263 : : }
1264 : 0 : vreq->cb = client->structured_reply ?
1265 [ # # ]: 0 : __tapdisk_nbdserver_structured_read_cb :
1266 : : __tapdisk_nbdserver_request_cb;
1267 : 0 : vreq->op = TD_OP_READ;
1268 : 0 : server->nbd_stats.stats->read_reqs_submitted++;
1269 : 0 : break;
1270 : : case TAPDISK_NBD_CMD_WRITE:
1271 : 0 : vreq = create_request_vreq(client, request, len);
1272 [ # # ]: 0 : if (!vreq) {
1273 : 0 : ERR("Failed to create vreq");
1274 : : goto fail;
1275 : : }
1276 : 0 : vreq->cb = __tapdisk_nbdserver_request_cb;
1277 : 0 : vreq->op = TD_OP_WRITE;
1278 : 0 : server->nbd_stats.stats->write_reqs_submitted++;
1279 : 0 : rc = recv_fully_or_fail(fd, vreq->iov->base, len);
1280 [ # # ]: 0 : if (rc < 0) {
1281 : 0 : ERR("Short send or error in "
1282 : : "callback: %d", rc);
1283 : : goto fail;
1284 : : }
1285 : :
1286 : : break;
1287 : : case TAPDISK_NBD_CMD_DISC:
1288 : 0 : INFO("Received close message. Sending reconnect header");
1289 : 0 : tapdisk_nbdserver_free_client(client);
1290 : 0 : INFO("About to send initial connection message");
1291 : 0 : tapdisk_nbdserver_newclient_fd(server, fd);
1292 : 0 : INFO("Sent initial connection message");
1293 : 0 : return;
1294 : : case TAPDISK_NBD_CMD_BLOCK_STATUS:
1295 : : {
1296 [ # # ]: 0 : if (!client->structured_reply)
1297 : 0 : ERR("NBD_CMD_BLOCK_STATUS: when not in structured reply");
1298 : :
1299 [ # # ]: 0 : if (len > 2 * MEGABYTES) {
1300 : : /* limit request to 2MB */
1301 : 0 : len = 2 * MEGABYTES;
1302 : : }
1303 : :
1304 : 0 : vreq = create_request_vreq(client, request, len);
1305 [ # # ]: 0 : if (!vreq) {
1306 : 0 : ERR("Failed to create vreq");
1307 : : goto fail;
1308 : : }
1309 : 0 : tapdisk_extents_t *extents = (tapdisk_extents_t*)malloc(sizeof(tapdisk_extents_t));
1310 [ # # ]: 0 : if(extents == NULL) {
1311 : 0 : ERR("Could not allocate memory for tapdisk_extents_t");
1312 : : goto fail;
1313 : : }
1314 : : bzero(extents, sizeof(tapdisk_extents_t));
1315 : 0 : vreq->data = extents;
1316 : 0 : vreq->cb = __tapdisk_nbdserver_block_status_cb;
1317 : 0 : vreq->op = TD_OP_BLOCK_STATUS;
1318 : : }
1319 : 0 : break;
1320 : : default:
1321 : 0 : ERR("Unsupported operation: 0x%x", request.type);
1322 : : goto fail;
1323 : : }
1324 : :
1325 : 0 : rc = tapdisk_vbd_queue_request(server->vbd, vreq);
1326 [ # # ]: 0 : if (rc) {
1327 : 0 : ERR("tapdisk_vbd_queue_request failed: %d", rc);
1328 : : goto fail;
1329 : : }
1330 : :
1331 : : return;
1332 : :
1333 : : fail:
1334 [ # # ]: 0 : if (vreq)
1335 : 0 : tapdisk_nbd_server_free_vreq(client, vreq, false);
1336 : 0 : close(client->client_fd);
1337 : 0 : tapdisk_nbdserver_free_client(client);
1338 : : return;
1339 : : }
1340 : :
1341 : : static void
1342 : 0 : tapdisk_nbdserver_fdreceiver_cb(int fd, char *msg, void *data)
1343 : : {
1344 : 0 : td_nbdserver_t *server = data;
1345 : :
1346 [ # # ]: 0 : ASSERT(server);
1347 [ # # ]: 0 : ASSERT(msg);
1348 [ # # ]: 0 : ASSERT(fd >= 0);
1349 : :
1350 : 0 : INFO("Received fd %d with msg: %s", fd, msg);
1351 : :
1352 : 0 : tapdisk_nbdserver_newclient_fd(server, fd);
1353 : 0 : }
1354 : :
1355 : : static void
1356 : 0 : tapdisk_nbdserver_newclient(event_id_t id, char mode, void *data)
1357 : : {
1358 : : struct sockaddr_storage their_addr;
1359 : 0 : socklen_t sin_size = sizeof(their_addr);
1360 : : char s[INET6_ADDRSTRLEN+1];
1361 : : int new_fd;
1362 : 0 : td_nbdserver_t *server = data;
1363 : :
1364 [ # # ]: 0 : ASSERT(server);
1365 : :
1366 : 0 : INFO("About to accept (server->fdrecv_listening_fd = %d)",
1367 : : server->fdrecv_listening_fd);
1368 : :
1369 : 0 : new_fd = accept(server->fdrecv_listening_fd,
1370 : : (struct sockaddr *)&their_addr, &sin_size);
1371 : :
1372 [ # # ]: 0 : if (new_fd == -1) {
1373 : 0 : ERR("failed to accept connection on the fd receiver socket: %s",
1374 : : strerror(errno));
1375 : 0 : return;
1376 : : }
1377 : :
1378 : : memset(s, 0, sizeof(s));
1379 : 0 : inet_ntop(their_addr.ss_family, get_in_addr(&their_addr), s, sizeof(s)-1);
1380 : :
1381 : 0 : INFO("server: got connection from %s\n", s);
1382 : :
1383 : 0 : tapdisk_nbdserver_newclient_fd(server, new_fd);
1384 : : }
1385 : :
1386 : : static void
1387 : 0 : tapdisk_nbdserver_newclient_unix(event_id_t id, char mode, void *data)
1388 : : {
1389 : 0 : int new_fd = 0;
1390 : : struct sockaddr_un remote;
1391 : 0 : socklen_t t = sizeof(remote);
1392 : 0 : td_nbdserver_t *server = data;
1393 : :
1394 [ # # ]: 0 : ASSERT(server);
1395 : :
1396 : 0 : INFO("About to accept (server->unix_listening_fd = %d)",
1397 : : server->unix_listening_fd);
1398 : :
1399 : 0 : new_fd = accept(server->unix_listening_fd, (struct sockaddr *)&remote, &t);
1400 [ # # ]: 0 : if (new_fd == -1) {
1401 : 0 : ERR("failed to accept connection: %s\n", strerror(errno));
1402 : 0 : return;
1403 : : }
1404 : :
1405 : 0 : INFO("server: got connection\n");
1406 : :
1407 : 0 : tapdisk_nbdserver_newclient_fd_new_fixed(server, new_fd);
1408 : : }
1409 : :
1410 : : td_nbdserver_t *
1411 : 0 : tapdisk_nbdserver_alloc(td_vbd_t *vbd, td_disk_info_t info, nbd_protocol_style_t style)
1412 : : {
1413 : : td_nbdserver_t *server;
1414 : : char fdreceiver_path[TAPDISK_NBDSERVER_MAX_PATH_LEN];
1415 : :
1416 : 0 : server = calloc(1, sizeof(*server));
1417 [ # # ]: 0 : if (!server) {
1418 : 0 : ERR("Failed to allocate memory for nbdserver: %s",
1419 : : strerror(errno));
1420 : : goto fail;
1421 : : }
1422 : :
1423 : 0 : server->vbd = vbd;
1424 : 0 : server->info = info;
1425 : 0 : server->fdrecv_listening_fd = -1;
1426 : 0 : server->fdrecv_listening_event_id = -1;
1427 : 0 : server->unix_listening_fd = -1;
1428 : 0 : server->unix_listening_event_id = -1;
1429 : 0 : server->style = style;
1430 : 0 : INIT_LIST_HEAD(&server->clients);
1431 : :
1432 [ # # # ]: 0 : switch (style) {
1433 : : case TAPDISK_NBD_PROTOCOL_OLD:
1434 [ # # ]: 0 : if (td_metrics_nbd_start_old(&server->nbd_stats, server->vbd->tap->minor)) {
1435 : 0 : ERR("failed to create metrics file for nbdserver");
1436 : : goto fail;
1437 : : }
1438 : : break;
1439 : : case TAPDISK_NBD_PROTOCOL_NEW:
1440 [ # # ]: 0 : if (td_metrics_nbd_start_new(&server->nbd_stats, server->vbd->tap->minor)) {
1441 : 0 : ERR("failed to create metrics file for nbdserver");
1442 : : goto fail;
1443 : : }
1444 : : break;
1445 : : }
1446 : :
1447 [ # # ][ # # ]: 0 : if (snprintf(fdreceiver_path, TAPDISK_NBDSERVER_MAX_PATH_LEN,
1448 : : "%s%d.%d",
1449 : : (style == TAPDISK_NBD_PROTOCOL_OLD)?TAPDISK_NBDSERVER_OLD_LISTEN_SOCK_PATH:TAPDISK_NBDSERVER_NEW_LISTEN_SOCK_PATH,
1450 : : getpid(),
1451 : 0 : vbd->uuid) < 0) {
1452 : 0 : ERR("Failed to snprintf fdreceiver_path");
1453 : : goto fail;
1454 : : }
1455 : :
1456 : 0 : server->fdreceiver = td_fdreceiver_start(fdreceiver_path,
1457 : : tapdisk_nbdserver_fdreceiver_cb, server);
1458 [ # # ]: 0 : if (!server->fdreceiver) {
1459 : 0 : ERR("Error setting up fd receiver");
1460 : : goto fail;
1461 : : }
1462 : :
1463 [ # # ][ # # ]: 0 : if (snprintf(server->sockpath, TAPDISK_NBDSERVER_MAX_PATH_LEN,
1464 : : "%s%d.%d",
1465 : : (style == TAPDISK_NBD_PROTOCOL_OLD)?TAPDISK_NBDSERVER_OLD_SOCK_PATH:TAPDISK_NBDSERVER_NEW_SOCK_PATH,
1466 : : getpid(),
1467 : 0 : vbd->uuid) < 0) {
1468 : 0 : ERR("Failed to snprintf sockpath");
1469 : : goto fail;
1470 : : }
1471 : :
1472 : 0 : return server;
1473 : :
1474 : : fail:
1475 [ # # ]: 0 : if (server) {
1476 [ # # ]: 0 : if (server->fdreceiver)
1477 : 0 : td_fdreceiver_stop(server->fdreceiver);
1478 : 0 : free(server);
1479 : : }
1480 : :
1481 : : return NULL;
1482 : : }
1483 : :
1484 : : void
1485 : 0 : tapdisk_nbdserver_pause(td_nbdserver_t *server, bool log)
1486 : : {
1487 : : struct td_nbdserver_client *pos, *q;
1488 : :
1489 [ # # ]: 0 : if (log) {
1490 : 0 : INFO("NBD server pause(%p)", server);
1491 : : }
1492 : :
1493 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &server->clients, clientlist){
1494 [ # # ][ # # ]: 0 : if (pos->paused != 1 && pos->client_event_id >= 0) {
1495 : 0 : tapdisk_nbdserver_disable_client(pos);
1496 : 0 : pos->paused = 1;
1497 : : }
1498 : : }
1499 : :
1500 [ # # ]: 0 : if (server->fdrecv_listening_event_id >= 0) {
1501 : 0 : tapdisk_server_unregister_event(server->fdrecv_listening_event_id);
1502 : 0 : server->fdrecv_listening_event_id = -1;
1503 : : }
1504 : :
1505 [ # # ]: 0 : if (server->unix_listening_event_id >= 0) {
1506 : 0 : tapdisk_server_unregister_event(server->unix_listening_event_id);
1507 : 0 : server->unix_listening_event_id = -1;
1508 : : }
1509 : 0 : }
1510 : :
1511 : : static int
1512 : 0 : tapdisk_nbdserver_unpause_fdrecv(td_nbdserver_t *server)
1513 : : {
1514 : 0 : int err = 0;
1515 : :
1516 [ # # ]: 0 : ASSERT(server);
1517 : :
1518 [ # # ]: 0 : if (server->fdrecv_listening_event_id < 0
1519 [ # # ]: 0 : && server->fdrecv_listening_fd >= 0) {
1520 : 0 : INFO("registering for fdrecv_listening_fd");
1521 : 0 : server->fdrecv_listening_event_id =
1522 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
1523 : 0 : server->fdrecv_listening_fd, TV_ZERO,
1524 : : tapdisk_nbdserver_newclient,
1525 : : server);
1526 [ # # ]: 0 : if (server->fdrecv_listening_event_id < 0) {
1527 : 0 : err = server->fdrecv_listening_event_id;
1528 : 0 : server->fdrecv_listening_event_id = -1;
1529 : : }
1530 : : }
1531 : :
1532 : 0 : return err;
1533 : : }
1534 : :
1535 : : static int
1536 : 0 : tapdisk_nbdserver_unpause_unix(td_nbdserver_t *server)
1537 : : {
1538 : 0 : int err = 0;
1539 : :
1540 [ # # ]: 0 : ASSERT(server);
1541 : :
1542 [ # # ]: 0 : if (server->unix_listening_event_id < 0
1543 [ # # ]: 0 : && server->unix_listening_fd >= 0) {
1544 : 0 : INFO("registering for unix_listening_fd");
1545 : 0 : server->unix_listening_event_id =
1546 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
1547 : 0 : server->unix_listening_fd, TV_ZERO,
1548 : : tapdisk_nbdserver_newclient_unix,
1549 : : server);
1550 [ # # ]: 0 : if (server->unix_listening_event_id < 0) {
1551 : 0 : err = server->unix_listening_event_id;
1552 : 0 : server->unix_listening_event_id = -1;
1553 : : }
1554 : :
1555 : : /* Note: any failures after this point need to unregister the event */
1556 : : }
1557 : :
1558 : 0 : return err;
1559 : : }
1560 : :
1561 : : int
1562 : 0 : tapdisk_nbdserver_listen_inet(td_nbdserver_t *server, const int port)
1563 : : {
1564 : : struct addrinfo hints, *servinfo, *p;
1565 : : char portstr[10];
1566 : : int err;
1567 : 0 : int yes = 1;
1568 : :
1569 [ # # ]: 0 : ASSERT(server);
1570 [ # # ]: 0 : ASSERT(server->fdrecv_listening_fd == -1);
1571 : :
1572 : : memset(&hints, 0, sizeof(hints));
1573 : : hints.ai_family = AF_UNSPEC;
1574 : 0 : hints.ai_socktype = SOCK_STREAM;
1575 : 0 : hints.ai_flags = AI_PASSIVE;
1576 : :
1577 : : snprintf(portstr, 10, "%d", port);
1578 : :
1579 : 0 : err = getaddrinfo(NULL, portstr, &hints, &servinfo);
1580 [ # # ]: 0 : if (err) {
1581 [ # # ]: 0 : if (err == EAI_SYSTEM) {
1582 : 0 : ERR("Failed to getaddrinfo: %s", strerror(errno));
1583 : 0 : return -errno;
1584 : : } else {
1585 : 0 : ERR("Failed to getaddrinfo: %s", gai_strerror(err));
1586 : : return -1;
1587 : : }
1588 : : }
1589 : :
1590 [ # # ]: 0 : for (p = servinfo; p != NULL; p = p->ai_next) {
1591 [ # # ]: 0 : if ((server->fdrecv_listening_fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0)) ==
1592 : : -1) {
1593 : 0 : ERR("Failed to create socket");
1594 : 0 : continue;
1595 : : }
1596 : :
1597 [ # # ]: 0 : if (setsockopt(server->fdrecv_listening_fd, SOL_SOCKET, SO_REUSEADDR,
1598 : : &yes, sizeof(int)) == -1) {
1599 : 0 : ERR("Failed to setsockopt");
1600 : 0 : close(server->fdrecv_listening_fd);
1601 : 0 : server->fdrecv_listening_fd = -1;
1602 : 0 : continue;
1603 : : }
1604 : :
1605 [ # # ]: 0 : if (bind(server->fdrecv_listening_fd, p->ai_addr, p->ai_addrlen) ==
1606 : : -1) {
1607 : 0 : ERR("Failed to bind");
1608 : 0 : close(server->fdrecv_listening_fd);
1609 : 0 : server->fdrecv_listening_fd = -1;
1610 : 0 : continue;
1611 : : }
1612 : :
1613 : : break;
1614 : : }
1615 : :
1616 : 0 : freeaddrinfo(servinfo);
1617 : :
1618 [ # # ]: 0 : if (p == NULL) {
1619 : 0 : ERR("Failed to bind");
1620 : : err = -1;
1621 : : goto out;
1622 : : }
1623 : :
1624 : 0 : err = listen(server->fdrecv_listening_fd, 10);
1625 [ # # ]: 0 : if (err) {
1626 : 0 : err = -errno;
1627 : 0 : ERR("listen: %s", strerror(-err));
1628 : : goto out;
1629 : : }
1630 : :
1631 : 0 : err = tapdisk_nbdserver_unpause_fdrecv(server);
1632 [ # # ]: 0 : if (err) {
1633 : 0 : ERR("failed to unpause the NBD server (fdrecv): %s\n",
1634 : : strerror(-err));
1635 : : goto out;
1636 : : }
1637 : :
1638 : 0 : INFO("Successfully started NBD server (fdrecv)");
1639 : :
1640 : : out:
1641 [ # # ][ # # ]: 0 : if (err && (server->fdrecv_listening_fd != -1)) {
1642 : 0 : close(server->fdrecv_listening_fd);
1643 : 0 : server->fdrecv_listening_fd = -1;
1644 : : }
1645 : 0 : return err;
1646 : : }
1647 : :
1648 : : int
1649 : 0 : tapdisk_nbdserver_listen_unix(td_nbdserver_t *server)
1650 : : {
1651 : 0 : size_t len = 0;
1652 : 0 : int err = 0;
1653 : : int new_fd;
1654 [ # # ]: 0 : ASSERT(server);
1655 [ # # ]: 0 : ASSERT(server->unix_listening_fd == -1);
1656 : :
1657 : 0 : new_fd = socket(AF_UNIX, SOCK_STREAM, 0);
1658 [ # # ]: 0 : if (new_fd == -1) {
1659 : 0 : err = -errno;
1660 : 0 : ERR("failed to create UNIX domain socket: %s\n", strerror(-err));
1661 : 0 : goto fail;
1662 : : }
1663 : :
1664 : 0 : server->local.sun_family = AF_UNIX;
1665 : :
1666 [ # # ]: 0 : if (unlikely(strlen(server->sockpath) >
1667 : : (sizeof(server->local.sun_path) - 1))) {
1668 : 0 : err = -ENAMETOOLONG;
1669 : 0 : ERR("socket name too long: %s\n", server->sockpath);
1670 : 0 : goto fail;
1671 : : }
1672 : :
1673 : 0 : safe_strncpy(server->local.sun_path, server->sockpath, sizeof(server->local.sun_path));
1674 : 0 : err = unlink(server->local.sun_path);
1675 [ # # ][ # # ]: 0 : if (err == -1 && errno != ENOENT) {
1676 : 0 : err = -errno;
1677 : 0 : ERR("failed to remove %s: %s\n", server->local.sun_path,
1678 : : strerror(-err));
1679 : 0 : goto fail;
1680 : : }
1681 : 0 : len = strlen(server->local.sun_path) + sizeof(server->local.sun_family);
1682 : 0 : err = bind(new_fd, (struct sockaddr *)&server->local,
1683 : : len);
1684 [ # # ]: 0 : if (err == -1) {
1685 : 0 : err = -errno;
1686 : 0 : ERR("failed to bind: %s\n", strerror(-err));
1687 : 0 : goto fail;
1688 : : }
1689 : :
1690 : 0 : err = listen(new_fd, 10);
1691 [ # # ]: 0 : if (err == -1) {
1692 : 0 : err = -errno;
1693 : 0 : ERR("failed to listen: %s\n", strerror(-err));
1694 : 0 : goto fail;
1695 : : }
1696 : :
1697 : 0 : server->unix_listening_fd = new_fd;
1698 : :
1699 : 0 : err = tapdisk_nbdserver_unpause_unix(server);
1700 [ # # ]: 0 : if (err) {
1701 : 0 : ERR("failed to unpause the NBD server (unix): %s\n",
1702 : : strerror(-err));
1703 : 0 : goto fail;
1704 : : }
1705 : :
1706 : 0 : INFO("Successfully started NBD server on %s\n", server->sockpath);
1707 : :
1708 : 0 : return 0;
1709 : :
1710 : : fail:
1711 [ # # ]: 0 : if (new_fd > -1) {
1712 : 0 : close(new_fd);
1713 : : }
1714 : 0 : server->unix_listening_fd = -1;
1715 : :
1716 : 0 : return err;
1717 : : }
1718 : :
1719 : : int
1720 : 0 : tapdisk_nbdserver_unpause(td_nbdserver_t *server)
1721 : : {
1722 : : struct td_nbdserver_client *pos, *q;
1723 : : int err;
1724 : :
1725 [ # # ]: 0 : ASSERT(server);
1726 : :
1727 : 0 : INFO("NBD server unpause(%p) - fdrecv_listening_fd %d, "
1728 : : "unix_listening_fd=%d", server, server->fdrecv_listening_fd,
1729 : : server->unix_listening_fd);
1730 : :
1731 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &server->clients, clientlist){
1732 [ # # ]: 0 : if (pos->paused == 1) {
1733 [ # # ]: 0 : if((err = tapdisk_nbdserver_enable_client(pos)) < 0) {
1734 : 0 : ERR("Failed to enable nbd client after pause");
1735 : 0 : return err;
1736 : : }
1737 : 0 : pos->paused = 0;
1738 : : }
1739 : : }
1740 : :
1741 : 0 : err = tapdisk_nbdserver_unpause_fdrecv(server);
1742 [ # # ]: 0 : if (err)
1743 : : return err;
1744 : :
1745 : 0 : err = tapdisk_nbdserver_unpause_unix(server);
1746 [ # # ]: 0 : if (err)
1747 : 0 : return err;
1748 : :
1749 : : return 0;
1750 : : }
1751 : :
1752 : : void
1753 : 0 : tapdisk_nbdserver_free(td_nbdserver_t *server)
1754 : : {
1755 : : struct td_nbdserver_client *pos, *q;
1756 : : int err;
1757 : :
1758 : 0 : INFO("NBD server free(%p)", server);
1759 : :
1760 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &server->clients, clientlist)
1761 : 0 : tapdisk_nbdserver_free_client(pos);
1762 : :
1763 [ # # ]: 0 : if (server->fdrecv_listening_event_id >= 0) {
1764 : 0 : tapdisk_server_unregister_event(server->fdrecv_listening_event_id);
1765 : 0 : server->fdrecv_listening_event_id = -1;
1766 : : }
1767 : :
1768 [ # # ]: 0 : if (server->fdrecv_listening_fd >= 0) {
1769 : 0 : close(server->fdrecv_listening_fd);
1770 : 0 : server->fdrecv_listening_fd = -1;
1771 : : }
1772 : :
1773 [ # # ]: 0 : if (server->fdreceiver)
1774 : 0 : td_fdreceiver_stop(server->fdreceiver);
1775 : :
1776 [ # # ]: 0 : if (server->unix_listening_event_id >= 0) {
1777 : 0 : tapdisk_server_unregister_event(server->unix_listening_event_id);
1778 : 0 : server->unix_listening_event_id = -1;
1779 : : }
1780 : :
1781 [ # # ]: 0 : if (server->unix_listening_fd >= 0) {
1782 : 0 : close(server->unix_listening_fd);
1783 : 0 : server->unix_listening_fd = -1;
1784 : : }
1785 : :
1786 : 0 : err = unlink(server->sockpath);
1787 [ # # ]: 0 : if (err)
1788 : 0 : ERR("failed to remove UNIX domain socket %s: %s\n", server->sockpath,
1789 : : strerror(errno));
1790 : 0 : err = td_metrics_nbd_stop(&server->nbd_stats);
1791 : :
1792 [ # # ]: 0 : if (err)
1793 : 0 : ERR("failed to delete NBD metrics: %s\n", strerror(errno));
1794 : :
1795 : 0 : free(server);
1796 : 0 : }
1797 : :
1798 : : int
1799 : 0 : tapdisk_nbdserver_reqs_pending(td_nbdserver_client_t *client)
1800 : : {
1801 [ # # ]: 0 : ASSERT(client);
1802 : :
1803 : 0 : return client->n_reqs - client->n_reqs_free;
1804 : : }
1805 : :
1806 : : bool
1807 : 0 : tapdisk_nbdserver_contains_client(td_nbdserver_t *server,
1808 : : td_nbdserver_client_t *client)
1809 : : {
1810 : : td_nbdserver_client_t *_client;
1811 : :
1812 [ # # ]: 0 : ASSERT(server);
1813 : :
1814 [ # # ]: 0 : list_for_each_entry(_client, &server->clients, clientlist)
1815 [ # # ]: 0 : if (client == _client)
1816 : : return true;
1817 : : return false;
1818 : : }
|