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 : 0 : 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 : 1 : 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 : 0 : 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 : 0 : 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 : 0 : struct nbd_structured_reply reply;
183 : 0 : struct nbd_block_descriptor *blocks;
184 : 0 : size_t i, nr_blocks = extents->count;
185 : 0 : 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 : 0 : ret = -1;
192 : 0 : goto done;
193 : : }
194 : :
195 : 0 : reply.magic = htobe32 (NBD_STRUCTURED_REPLY_MAGIC);
196 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : struct nbd_fixed_new_option_reply *reply;
276 : 0 : 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 : 0 : 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 : 0 : goto fail2;
296 : : }
297 : 0 : free(reply);
298 : 0 : return 0;
299 : :
300 : 0 : 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 : 0 : struct nbd_fixed_new_option_reply fixed_new_option_reply;
358 : 0 : 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 : 0 : 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 : 0 : struct nbd_fixed_new_option_reply fixed_new_option_reply;
390 : 0 : 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 : 0 : 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 : 0 : struct nbd_fixed_new_option_reply fixed_new_option_reply;
420 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : uint32_t exportnamelen;
466 : 0 : uint16_t nrInfoReq;
467 : 0 : char *exportname = NULL;
468 : :
469 [ # # ]: 0 : if (recv_fully_or_fail(fd, &exportnamelen, sizeof(exportnamelen)) < 0)
470 : 0 : 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 : 0 : 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 : 0 : goto fail;
483 : : }
484 [ # # ]: 0 : if (recv_fully_or_fail(fd, exportname, exportnamelen) < 0)
485 : 0 : 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 : 0 : goto fail1;
491 : :
492 : 0 : nrInfoReq = be16toh(nrInfoReq);
493 : 0 : INFO("nrInfoReq is %d", nrInfoReq);
494 : :
495 [ # # ]: 0 : while(nrInfoReq--) {
496 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : goto fail1;
519 : : }
520 : 0 : free(exportname);
521 : 0 : return 0;
522 : :
523 : 0 : 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 : 0 : struct nbd_new_option n_option;
540 : 0 : size_t n_options;
541 : 0 : uint32_t opt_code;
542 : 0 : uint32_t opt_len;
543 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : goto fail;
559 : : }
560 [ # # # # : 0 : opt_code = be32toh (n_option.option);
# # # # #
# ]
561 : :
562 [ # # # # : 0 : switch (opt_code) {
# # # # #
# ]
563 : 0 : 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 [ # # ]: 0 : 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 : 0 : break;
592 : 0 : 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 : 0 : goto done;
598 : 0 : break;
599 : 0 : 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 : 0 : goto fail;
603 [ # # ]: 0 : if (send_fixed_option_reply(new_fd, opt_code, NBD_REP_ACK))
604 : 0 : goto fail;
605 : : break;
606 : 0 : 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 : 0 : goto fail;
610 : : break;
611 : 0 : 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 : 0 : goto fail;
615 : : break;
616 : 0 : 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 : 0 : goto done;
621 : 0 : break;
622 : 0 : 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 : 0 : goto fail;
627 : : }
628 : :
629 [ # # ]: 0 : if (send_fixed_option_reply(new_fd, opt_code, NBD_REP_ACK) == -1)
630 : 0 : goto fail;
631 : :
632 : 0 : client->structured_reply = true;
633 : 0 : break;
634 : 0 : 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 : 0 : case NBD_OPT_SET_META_CONTEXT:
646 : : {
647 : 0 : char *buf = NULL;
648 : 0 : uint32_t opt_index;
649 : 0 : uint32_t exportnamelen;
650 : 0 : uint32_t nr_queries;
651 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : default:
691 : 0 : INFO("Unknown NBD option %u", opt_code);
692 [ # # ]: 0 : if (send_fixed_option_reply(new_fd, opt_code, NBD_REP_ERR_UNSUP)) goto fail;
693 : : }
694 : : }
695 : :
696 : 0 : if (n_options >= MAX_OPTIONS) {
697 : 0 : ERR("Max number of nbd options exceeded (%d)", MAX_OPTIONS);
698 : 0 : goto fail;
699 : : }
700 : :
701 : : done:
702 : 0 : return 0;
703 : :
704 : : fail:
705 : : return -1;
706 : : }
707 : :
708 : : int
709 : 0 : tapdisk_nbdserver_reqs_init(td_nbdserver_client_t *client, int n_reqs)
710 : : {
711 : 0 : int i, err;
712 : :
713 [ # # ]: 0 : ASSERT(client);
714 [ # # ]: 0 : ASSERT(n_reqs > 0);
715 : :
716 : 0 : INFO("Reqs init");
717 : :
718 : 0 : client->reqs = malloc(n_reqs * sizeof(td_nbdserver_req_t));
719 [ # # ]: 0 : if (!client->reqs) {
720 : 0 : err = -errno;
721 : 0 : goto fail;
722 : : }
723 : :
724 : 0 : client->iovecs = malloc(n_reqs * sizeof(struct td_iovec));
725 [ # # ]: 0 : if (!client->iovecs) {
726 : 0 : err = - errno;
727 : 0 : goto fail;
728 : : }
729 : :
730 : 0 : client->reqs_free = malloc(n_reqs * sizeof(td_nbdserver_req_t*));
731 [ # # ]: 0 : if (!client->reqs_free) {
732 : 0 : err = -errno;
733 : 0 : goto fail;
734 : : }
735 : :
736 : 0 : client->n_reqs = n_reqs;
737 : 0 : client->n_reqs_free = 0;
738 : 0 : client->max_used_reqs = 0;
739 : :
740 [ # # ]: 0 : for (i = 0; i < n_reqs; i++) {
741 : 0 : client->reqs[i].vreq.iov = &client->iovecs[i];
742 : 0 : tapdisk_nbdserver_set_free_request(client, &client->reqs[i]);
743 : : }
744 : :
745 : : return 0;
746 : :
747 : 0 : fail:
748 : 0 : tapdisk_nbdserver_reqs_free(client);
749 : 0 : return err;
750 : : }
751 : :
752 : : static int
753 : 0 : tapdisk_nbdserver_enable_client(td_nbdserver_client_t *client)
754 : : {
755 [ # # ]: 0 : ASSERT(client);
756 [ # # ]: 0 : ASSERT(client->client_event_id == -1);
757 [ # # ]: 0 : ASSERT(client->client_fd >= 0);
758 : :
759 : 0 : INFO("Enable client");
760 : :
761 : 0 : client->client_event_id = tapdisk_server_register_event(
762 : : SCHEDULER_POLL_READ_FD,
763 : 0 : client->client_fd, TV_ZERO,
764 : : tapdisk_nbdserver_clientcb,
765 : : client);
766 : :
767 [ # # ]: 0 : if (client->client_event_id < 0) {
768 : 0 : ERR("Error registering events on client: %d",
769 : : client->client_event_id);
770 : 0 : return client->client_event_id;
771 : : }
772 : :
773 : : return client->client_event_id;
774 : : }
775 : :
776 : : static void
777 : 0 : tapdisk_nbdserver_disable_client(td_nbdserver_client_t *client)
778 : : {
779 [ # # ]: 0 : ASSERT(client);
780 [ # # ]: 0 : ASSERT(client->client_event_id >= 0);
781 : :
782 : 0 : INFO("Disable client");
783 : :
784 : 0 : tapdisk_server_unregister_event(client->client_event_id);
785 : 0 : client->client_event_id = -1;
786 : 0 : }
787 : :
788 : : td_nbdserver_client_t *
789 : 0 : tapdisk_nbdserver_alloc_client(td_nbdserver_t *server)
790 : : {
791 : 0 : td_nbdserver_client_t *client = NULL;
792 : 0 : int err;
793 : :
794 [ # # ]: 0 : ASSERT(server);
795 : :
796 : 0 : INFO("Alloc client");
797 : :
798 : 0 : client = calloc(1, sizeof(td_nbdserver_client_t));
799 [ # # ]: 0 : if (!client) {
800 : 0 : ERR("Couldn't allocate client structure: %s",
801 : : strerror(errno));
802 : 0 : goto fail;
803 : : }
804 : :
805 : 0 : err = tapdisk_nbdserver_reqs_init(client, NBD_SERVER_NUM_REQS);
806 [ # # ]: 0 : if (err < 0) {
807 : 0 : ERR("Couldn't allocate client reqs: %d", err);
808 : 0 : goto fail;
809 : : }
810 : :
811 : 0 : client->client_fd = -1;
812 : 0 : client->client_event_id = -1;
813 : 0 : client->server = server;
814 : 0 : INIT_LIST_HEAD(&client->clientlist);
815 : 0 : list_add(&client->clientlist, &server->clients);
816 : :
817 : 0 : client->paused = 0;
818 : 0 : client->dead = false;
819 : 0 : client->structured_reply = false;
820 : :
821 : 0 : return client;
822 : :
823 : 0 : fail:
824 [ # # ]: 0 : if (client)
825 : 0 : free(client);
826 : :
827 : : return NULL;
828 : : }
829 : :
830 : : void
831 : 0 : tapdisk_nbdserver_free_client(td_nbdserver_client_t *client)
832 : : {
833 : 0 : INFO("Free client");
834 : :
835 [ # # ]: 0 : ASSERT(client);
836 : :
837 [ # # ]: 0 : if (client->client_event_id >= 0)
838 : 0 : tapdisk_nbdserver_disable_client(client);
839 : :
840 : 0 : INFO("Freeing client, max used requests %d", client->max_used_reqs);
841 : :
842 [ # # ]: 0 : if (likely(!tapdisk_nbdserver_reqs_pending(client))) {
843 : 0 : list_del(&client->clientlist);
844 : 0 : tapdisk_nbdserver_reqs_free(client);
845 : 0 : free(client);
846 : : } else
847 : 0 : client->dead = true;
848 : 0 : }
849 : :
850 : : static void
851 : 0 : *get_in_addr(struct sockaddr_storage *ss)
852 : : {
853 : 0 : if (ss->ss_family == AF_INET)
854 : : return &(((struct sockaddr_in*)ss)->sin_addr);
855 : :
856 : 0 : return &(((struct sockaddr_in6*)ss)->sin6_addr);
857 : : }
858 : :
859 : 0 : static void tapdisk_nbd_server_free_vreq(
860 : : td_nbdserver_client_t *client, td_vbd_request_t *vreq, bool free_client_if_dead)
861 : : {
862 : 0 : td_nbdserver_req_t *req = container_of(vreq, td_nbdserver_req_t, vreq);
863 : 0 : free(vreq->iov->base);
864 : 0 : tapdisk_nbdserver_free_request(client, req, free_client_if_dead);
865 : 0 : }
866 : :
867 : :
868 : : static void
869 : 0 : __tapdisk_nbdserver_block_status_cb(td_vbd_request_t *vreq, int err,
870 : : void *token, int final)
871 : : {
872 : 0 : td_nbdserver_client_t *client = token;
873 : 0 : td_nbdserver_req_t *req = container_of(vreq, td_nbdserver_req_t, vreq);
874 : 0 : tapdisk_extents_t* extents = (tapdisk_extents_t *)(vreq->data);
875 : 0 : send_structured_reply_block_status (client->client_fd, req->id, extents);
876 : 0 : free_extents(extents);
877 : 0 : tapdisk_nbd_server_free_vreq(client, vreq, true);
878 : 0 : }
879 : :
880 : : static int
881 : 0 : __tapdisk_nbdserver_send_structured_reply(
882 : : int fd, uint16_t type, uint16_t flags, char *handle, uint32_t length)
883 : : {
884 : 0 : struct nbd_structured_reply reply;
885 : 0 : int rc = 0;
886 : :
887 : 0 : reply.magic = htobe32(NBD_STRUCTURED_REPLY_MAGIC);
888 : 0 : reply.flags = htobe16(flags);
889 : 0 : reply.type = htobe16(type);
890 : 0 : memcpy(&reply.handle, handle, sizeof(reply.handle));
891 : 0 : reply.length = htobe32(length);
892 : :
893 : 0 : rc = send_fully_or_fail(fd, &reply, sizeof(reply));
894 [ # # ]: 0 : if (rc < 0) {
895 : 0 : ERR("Short send/error in callback");
896 : 0 : return -1;
897 : : }
898 : :
899 : : return 0;
900 : : }
901 : :
902 : : static void
903 : 0 : __tapdisk_nbdserver_structured_read_cb(
904 : : td_vbd_request_t *vreq, int error, void *token, int final)
905 : : {
906 : 0 : td_nbdserver_client_t *client = token;
907 : 0 : td_nbdserver_t *server = client->server;
908 : 0 : td_nbdserver_req_t *req = container_of(vreq, td_nbdserver_req_t, vreq);
909 : 0 : unsigned long long interval;
910 : 0 : struct timeval now;
911 : 0 : uint64_t offset;
912 : 0 : int rc = 0;
913 : 0 : int len = 0;
914 : :
915 : 0 : gettimeofday(&now, NULL);
916 [ # # ]: 0 : interval = timeval_to_us(&now) - timeval_to_us(&vreq->ts);
917 : :
918 [ # # ]: 0 : if (interval > 20 * 1000 * 1000) {
919 : 0 : INFO("Structured read took %llu microseconds to complete", interval);
920 : : }
921 : :
922 [ # # ]: 0 : if (client->client_fd < 0) {
923 : 0 : ERR("Finishing request for client that has disappeared");
924 : 0 : goto finish;
925 : : }
926 : :
927 : 0 : len = vreq->iov->secs << SECTOR_SHIFT;
928 : :
929 : : /* For now, say we're done, if we have to support multiple chunks it will be harder */
930 [ # # ]: 0 : if (__tapdisk_nbdserver_send_structured_reply(
931 : : client->client_fd, NBD_REPLY_TYPE_OFFSET_DATA,
932 : 0 : NBD_REPLY_FLAG_DONE, req->id, len + sizeof(uint64_t)) == -1)
933 : : {
934 : 0 : ERR("Failed to send structured reply header");
935 : 0 : goto finish;
936 : : }
937 : :
938 : 0 : offset = vreq->sec << SECTOR_SHIFT;
939 : 0 : offset = htobe64(offset);
940 : 0 : rc = send_fully_or_fail(client->client_fd, &offset, sizeof(offset));
941 [ # # ]: 0 : if (rc < 0) {
942 : 0 : ERR("Failed to send offset for structured read reply");
943 : 0 : goto finish;
944 : : }
945 : :
946 : 0 : server->nbd_stats.stats->read_reqs_completed++;
947 : 0 : server->nbd_stats.stats->read_sectors += vreq->iov->secs;
948 : 0 : server->nbd_stats.stats->read_total_ticks += interval;
949 : 0 : rc = send_fully_or_fail(client->client_fd,
950 : : vreq->iov->base, len);
951 [ # # ]: 0 : if (rc < 0) {
952 : 0 : ERR("Short send/error in callback");
953 : 0 : goto finish;
954 : : }
955 : :
956 [ # # ]: 0 : if (error)
957 : 0 : server->nbd_stats.stats->io_errors++;
958 : :
959 : 0 : finish:
960 : 0 : free(vreq->iov->base);
961 : 0 : tapdisk_nbdserver_free_request(client, req, true);
962 : 0 : }
963 : :
964 : : static void
965 : 0 : __tapdisk_nbdserver_request_cb(td_vbd_request_t *vreq, int error,
966 : : void *token, int final)
967 : : {
968 : 0 : td_nbdserver_client_t *client = token;
969 : 0 : td_nbdserver_t *server = client->server;
970 : 0 : td_nbdserver_req_t *req = container_of(vreq, td_nbdserver_req_t, vreq);
971 : 0 : unsigned long long interval;
972 : 0 : struct timeval now;
973 : 0 : struct nbd_reply reply;
974 : 0 : int rc = 0;
975 : :
976 : 0 : reply.magic = htonl(NBD_REPLY_MAGIC);
977 : 0 : reply.error = htonl(error);
978 : 0 : memcpy(reply.handle, req->id, sizeof(reply.handle));
979 : :
980 : 0 : gettimeofday(&now, NULL);
981 [ # # ]: 0 : interval = timeval_to_us(&now) - timeval_to_us(&vreq->ts);
982 : :
983 [ # # ]: 0 : if (interval > 20 * 1000 * 1000) {
984 : 0 : INFO("Op %d request took %llu microseconds to complete", vreq->op, interval);
985 : : }
986 : :
987 [ # # ]: 0 : if (client->client_fd < 0) {
988 : 0 : ERR("Finishing request for client that has disappeared");
989 : 0 : goto finish;
990 : : }
991 : :
992 : 0 : rc = send_fully_or_fail(client->client_fd,
993 : : &reply,
994 : : sizeof(reply));
995 [ # # ]: 0 : if (rc < 0) {
996 : 0 : ERR("Short send/error in callback");
997 : 0 : goto finish;
998 : : }
999 : :
1000 [ # # # ]: 0 : switch(vreq->op) {
1001 : 0 : case TD_OP_READ:
1002 : 0 : server->nbd_stats.stats->read_reqs_completed++;
1003 : 0 : server->nbd_stats.stats->read_sectors += vreq->iov->secs;
1004 : 0 : server->nbd_stats.stats->read_total_ticks += interval;
1005 : 0 : rc = send_fully_or_fail(client->client_fd,
1006 : : vreq->iov->base,
1007 : 0 : vreq->iov->secs << SECTOR_SHIFT);
1008 [ # # ]: 0 : if (rc < 0) {
1009 : 0 : ERR("Short send/error in callback");
1010 : 0 : goto finish;
1011 : : }
1012 : : break;
1013 : 0 : case TD_OP_WRITE:
1014 : 0 : server->nbd_stats.stats->write_reqs_completed++;
1015 : 0 : server->nbd_stats.stats->write_sectors += vreq->iov->secs;
1016 : 0 : server->nbd_stats.stats->write_total_ticks += interval;
1017 : : default:
1018 : : break;
1019 : : }
1020 : :
1021 [ # # ]: 0 : if (error)
1022 : 0 : server->nbd_stats.stats->io_errors++;
1023 : :
1024 : 0 : finish:
1025 : 0 : free(vreq->iov->base);
1026 : 0 : tapdisk_nbdserver_free_request(client, req, true);
1027 : 0 : }
1028 : :
1029 : : void
1030 : 0 : tapdisk_nbdserver_handshake_cb(event_id_t id, char mode, void *data)
1031 : : {
1032 : 0 : uint32_t cflags = 0;
1033 : 0 : int tmp_fd;
1034 : :
1035 : 0 : td_nbdserver_client_t *client = (td_nbdserver_client_t*)data;
1036 : 0 : td_nbdserver_t *server = client->server;
1037 : :
1038 : 0 : int rc = recv_fully_or_fail(server->handshake_fd, &cflags, sizeof(cflags));
1039 [ # # ]: 0 : if(rc < 0) {
1040 : 0 : ERR("Could not receive client flags");
1041 : 0 : close(server->handshake_fd);
1042 : 0 : goto out;
1043 : : }
1044 : :
1045 : 0 : cflags = be32toh (cflags);
1046 : 0 : bool no_zeroes = (NBD_FLAG_NO_ZEROES & cflags) != 0;
1047 : :
1048 : : /* Receive newstyle options. */
1049 [ # # ]: 0 : if (receive_newstyle_options(client, server->handshake_fd, no_zeroes) == -1) {
1050 : 0 : INFO("Option negotiation terminated");
1051 : 0 : close(server->handshake_fd);
1052 : : }
1053 : :
1054 : 0 : INFO("About to enable client on fd %d", client->client_fd);
1055 [ # # ]: 0 : if (tapdisk_nbdserver_enable_client(client) < 0) {
1056 : 0 : ERR("Error enabling client");
1057 : 0 : tmp_fd = client->client_fd;
1058 : 0 : tapdisk_nbdserver_free_client(client);
1059 : 0 : close(tmp_fd);
1060 : : }
1061 : :
1062 : 0 : out:
1063 : 0 : tapdisk_server_unregister_event(id);
1064 : 0 : }
1065 : :
1066 : : int
1067 : 1 : tapdisk_nbdserver_new_protocol_handshake(td_nbdserver_client_t *client, int new_fd)
1068 : : {
1069 : 1 : td_nbdserver_t *server = client->server;
1070 : 1 : struct nbd_new_handshake handshake;
1071 : :
1072 : 1 : handshake.nbdmagic = htobe64 (NBD_MAGIC);
1073 : 1 : handshake.version = htobe64 (NBD_OPT_MAGIC);
1074 : 1 : handshake.gflags = htobe16 (gflags);
1075 : :
1076 : 1 : int rc = send_fully_or_fail(new_fd, &handshake, sizeof(handshake));
1077 [ - + ]: 1 : if (rc < 0) {
1078 : 0 : ERR("Sending newstyle handshake");
1079 : 0 : return -1;
1080 : : }
1081 : 1 : server->handshake_fd = new_fd;
1082 : : /* We may need to wait upto 40 seconds for a reply especially during
1083 : : * SXM contexts, so setup an event and return so that tapdisk is
1084 : : * reponsive during the interim*/
1085 : :
1086 : 1 : tapdisk_server_register_event( SCHEDULER_POLL_READ_FD,
1087 : 1 : new_fd, TV_ZERO,
1088 : : tapdisk_nbdserver_handshake_cb,
1089 : : client);
1090 : : return 0;
1091 : : }
1092 : :
1093 : : static void
1094 : 0 : tapdisk_nbdserver_newclient_fd_old(td_nbdserver_t *server, int new_fd)
1095 : : {
1096 : 0 : td_nbdserver_client_t *client;
1097 : 0 : char buffer[256];
1098 : 0 : int rc;
1099 : 0 : uint64_t tmp64;
1100 : 0 : uint32_t tmp32;
1101 : :
1102 [ # # ]: 0 : ASSERT(server);
1103 [ # # ]: 0 : ASSERT(new_fd >= 0);
1104 : :
1105 : 0 : INFO("Got a new client!");
1106 : :
1107 : : /* Spit out the NBD connection stuff */
1108 : :
1109 : 0 : memcpy(buffer, "NBDMAGIC", 8);
1110 : 0 : tmp64 = htonll(NBD_NEGOTIATION_MAGIC);
1111 : 0 : memcpy(buffer + 8, &tmp64, sizeof(tmp64));
1112 : 0 : tmp64 = htonll(server->info.size * server->info.sector_size);
1113 : 0 : INFO("Sending size %"PRIu64"", ntohll(tmp64));
1114 : 0 : memcpy(buffer + 16, &tmp64, sizeof(tmp64));
1115 : 0 : tmp32 = htonl(0);
1116 : 0 : memcpy(buffer + 24, &tmp32, sizeof(tmp32));
1117 : 0 : bzero(buffer + 28, 124);
1118 : :
1119 : 0 : rc = send_fully_or_fail(new_fd, buffer, 152);
1120 [ # # ]: 0 : if (rc < 0) {
1121 : 0 : close(new_fd);
1122 : 0 : INFO("Write failed in negotiation");
1123 : 0 : return;
1124 : : }
1125 : :
1126 : 0 : INFO("About to alloc client");
1127 : 0 : client = tapdisk_nbdserver_alloc_client(server);
1128 [ # # ]: 0 : if (client == NULL) {
1129 : 0 : ERR("Error allocating client");
1130 : 0 : close(new_fd);
1131 : 0 : return;
1132 : : }
1133 : :
1134 : 0 : INFO("Got an allocated client at %p", client);
1135 : 0 : client->client_fd = new_fd;
1136 : :
1137 : 0 : INFO("About to enable client on fd %d", client->client_fd);
1138 [ # # ]: 0 : if (tapdisk_nbdserver_enable_client(client) < 0) {
1139 : 0 : ERR("Error enabling client");
1140 : 0 : tapdisk_nbdserver_free_client(client);
1141 : 0 : close(new_fd);
1142 : : }
1143 : : }
1144 : :
1145 : : static void
1146 : 0 : tapdisk_nbdserver_newclient_fd_new_fixed(td_nbdserver_t *server, int new_fd)
1147 : : {
1148 : 0 : td_nbdserver_client_t *client;
1149 : :
1150 [ # # ]: 0 : ASSERT(server);
1151 [ # # ]: 0 : ASSERT(new_fd >= 0);
1152 : :
1153 : 0 : INFO("Got a new client!");
1154 : :
1155 : 0 : INFO("About to alloc client");
1156 : 0 : client = tapdisk_nbdserver_alloc_client(server);
1157 [ # # ]: 0 : if (client == NULL) {
1158 : 0 : ERR("Error allocating client");
1159 : 0 : close(new_fd);
1160 : 0 : return;
1161 : : }
1162 : 0 : INFO("Got an allocated client at %p", client);
1163 : :
1164 : 0 : client->client_fd = new_fd;
1165 : :
1166 [ # # ]: 0 : if(tapdisk_nbdserver_new_protocol_handshake(client, new_fd) != 0) {
1167 : 0 : ERR("Error handshaking new client connection");
1168 : 0 : tapdisk_nbdserver_free_client(client);
1169 : 0 : close(new_fd);
1170 : 0 : return;
1171 : : }
1172 : : }
1173 : :
1174 : : static void
1175 : 0 : tapdisk_nbdserver_newclient_fd(td_nbdserver_t *server, int new_fd)
1176 : : {
1177 [ # # # ]: 0 : switch (server->style) {
1178 : 0 : case TAPDISK_NBD_PROTOCOL_OLD:
1179 : 0 : tapdisk_nbdserver_newclient_fd_old(server, new_fd);
1180 : 0 : break;
1181 : 0 : case TAPDISK_NBD_PROTOCOL_NEW:
1182 : 0 : tapdisk_nbdserver_newclient_fd_new_fixed(server, new_fd);
1183 : 0 : break;
1184 : 0 : };
1185 : 0 : }
1186 : :
1187 : 0 : static td_vbd_request_t *create_request_vreq(
1188 : : td_nbdserver_client_t *client, struct nbd_request request, uint32_t len)
1189 : : {
1190 : 0 : int rc;
1191 : 0 : td_nbdserver_t *server = client->server;
1192 : 0 : td_vbd_request_t *vreq;
1193 : 0 : td_nbdserver_req_t *req;
1194 : :
1195 : 0 : req = tapdisk_nbdserver_alloc_request(client);
1196 [ # # ]: 0 : if (!req) {
1197 : 0 : ERR("Couldn't allocate request in clientcb - killing client");
1198 : 0 : goto failreq;
1199 : : }
1200 : :
1201 : 0 : vreq = &req->vreq;
1202 : :
1203 [ # # ]: 0 : memset(req, 0, sizeof(td_nbdserver_req_t));
1204 : :
1205 : 0 : bzero(req->id, sizeof(req->id));
1206 [ # # ]: 0 : memcpy(req->id, request.handle, sizeof(request.handle));
1207 : :
1208 [ # # ]: 0 : rc = posix_memalign(&req->iov.base, 512, len);
1209 [ # # ]: 0 : if (rc < 0) {
1210 : 0 : ERR("posix_memalign failed (%d)", rc);
1211 : 0 : goto fail;
1212 : : }
1213 : :
1214 : 0 : vreq->sec = request.from >> SECTOR_SHIFT;
1215 : 0 : vreq->iovcnt = 1;
1216 : 0 : vreq->iov = &req->iov;
1217 : 0 : vreq->iov->secs = len >> SECTOR_SHIFT;
1218 : 0 : vreq->token = client;
1219 : 0 : vreq->name = req->id;
1220 : 0 : vreq->vbd = server->vbd;
1221 : :
1222 : 0 : return vreq;
1223 : :
1224 : 0 : fail:
1225 : 0 : tapdisk_nbdserver_set_free_request(client, req);
1226 : : failreq:
1227 : : return NULL;
1228 : : }
1229 : :
1230 : :
1231 : : void
1232 : 0 : tapdisk_nbdserver_clientcb(event_id_t id, char mode, void *data)
1233 : : {
1234 : 0 : td_nbdserver_client_t *client = data;
1235 : 0 : td_nbdserver_t *server = client->server;
1236 : 0 : int rc;
1237 : 0 : uint32_t len;
1238 : 0 : int fd = client->client_fd;
1239 : 0 : td_vbd_request_t *vreq = NULL;
1240 : 0 : struct nbd_request request;
1241 : :
1242 : : /* Read the request the client has sent */
1243 : 0 : rc = recv_fully_or_fail(fd, &request, sizeof(request));
1244 [ # # ]: 0 : if (rc < 0) {
1245 : 0 : ERR("failed to receive from client. Closing connection");
1246 : 0 : goto fail;
1247 : : }
1248 : :
1249 [ # # ]: 0 : if (request.magic != htonl(NBD_REQUEST_MAGIC)) {
1250 : 0 : ERR("Not enough magic, %X", request.magic);
1251 : 0 : goto fail;
1252 : : }
1253 : :
1254 : 0 : request.from = ntohll(request.from);
1255 [ # # ]: 0 : request.type = ntohl(request.type);
1256 : 0 : len = ntohl(request.len);
1257 [ # # # # ]: 0 : if (((len & 0x1ff) != 0) || ((request.from & 0x1ff) != 0)) {
1258 : 0 : ERR("Non sector-aligned request (%"PRIu64", %d)",
1259 : : request.from, len);
1260 : : }
1261 : :
1262 [ # # # # : 0 : switch(request.type) {
# ]
1263 : 0 : case TAPDISK_NBD_CMD_READ:
1264 : 0 : vreq = create_request_vreq(client, request, len);
1265 [ # # ]: 0 : if (!vreq) {
1266 : 0 : ERR("Failed to create vreq");
1267 : 0 : goto fail;
1268 : : }
1269 : 0 : vreq->cb = client->structured_reply ?
1270 [ # # ]: 0 : __tapdisk_nbdserver_structured_read_cb :
1271 : : __tapdisk_nbdserver_request_cb;
1272 : 0 : vreq->op = TD_OP_READ;
1273 : 0 : server->nbd_stats.stats->read_reqs_submitted++;
1274 : 0 : break;
1275 : 0 : case TAPDISK_NBD_CMD_WRITE:
1276 : 0 : vreq = create_request_vreq(client, request, len);
1277 [ # # ]: 0 : if (!vreq) {
1278 : 0 : ERR("Failed to create vreq");
1279 : 0 : goto fail;
1280 : : }
1281 : 0 : vreq->cb = __tapdisk_nbdserver_request_cb;
1282 : 0 : vreq->op = TD_OP_WRITE;
1283 : 0 : server->nbd_stats.stats->write_reqs_submitted++;
1284 : 0 : rc = recv_fully_or_fail(fd, vreq->iov->base, len);
1285 [ # # ]: 0 : if (rc < 0) {
1286 : 0 : ERR("Short send or error in "
1287 : : "callback: %d", rc);
1288 : 0 : goto fail;
1289 : : }
1290 : :
1291 : : break;
1292 : 0 : case TAPDISK_NBD_CMD_DISC:
1293 : 0 : INFO("Received close message. Sending reconnect header");
1294 : 0 : tapdisk_nbdserver_free_client(client);
1295 : 0 : INFO("About to send initial connection message");
1296 : 0 : tapdisk_nbdserver_newclient_fd(server, fd);
1297 : 0 : INFO("Sent initial connection message");
1298 : 0 : return;
1299 : 0 : case TAPDISK_NBD_CMD_BLOCK_STATUS:
1300 : : {
1301 [ # # ]: 0 : if (!client->structured_reply)
1302 : 0 : ERR("NBD_CMD_BLOCK_STATUS: when not in structured reply");
1303 : :
1304 : 0 : if (len > 2 * MEGABYTES) {
1305 : : /* limit request to 2MB */
1306 : : len = 2 * MEGABYTES;
1307 : : }
1308 : :
1309 : 0 : vreq = create_request_vreq(client, request, len);
1310 [ # # ]: 0 : if (!vreq) {
1311 : 0 : ERR("Failed to create vreq");
1312 : 0 : goto fail;
1313 : : }
1314 : 0 : tapdisk_extents_t *extents = (tapdisk_extents_t*)malloc(sizeof(tapdisk_extents_t));
1315 [ # # ]: 0 : if(extents == NULL) {
1316 : 0 : ERR("Could not allocate memory for tapdisk_extents_t");
1317 : 0 : goto fail;
1318 : : }
1319 : 0 : bzero(extents, sizeof(tapdisk_extents_t));
1320 : 0 : vreq->data = extents;
1321 : 0 : vreq->cb = __tapdisk_nbdserver_block_status_cb;
1322 : 0 : vreq->op = TD_OP_BLOCK_STATUS;
1323 : : }
1324 : 0 : break;
1325 : 0 : default:
1326 : 0 : ERR("Unsupported operation: 0x%x", request.type);
1327 : 0 : goto fail;
1328 : : }
1329 : :
1330 : 0 : rc = tapdisk_vbd_queue_request(server->vbd, vreq);
1331 [ # # ]: 0 : if (rc) {
1332 : 0 : ERR("tapdisk_vbd_queue_request failed: %d", rc);
1333 : 0 : goto fail;
1334 : : }
1335 : :
1336 : : return;
1337 : :
1338 : 0 : fail:
1339 [ # # ]: 0 : if (vreq)
1340 : 0 : tapdisk_nbd_server_free_vreq(client, vreq, false);
1341 : 0 : close(client->client_fd);
1342 : 0 : tapdisk_nbdserver_free_client(client);
1343 : : return;
1344 : : }
1345 : :
1346 : : static void
1347 : 0 : tapdisk_nbdserver_fdreceiver_cb(int fd, char *msg, void *data)
1348 : : {
1349 : 0 : td_nbdserver_t *server = data;
1350 : :
1351 [ # # ]: 0 : ASSERT(server);
1352 [ # # ]: 0 : ASSERT(msg);
1353 [ # # ]: 0 : ASSERT(fd >= 0);
1354 : :
1355 : 0 : INFO("Received fd %d with msg: %s", fd, msg);
1356 : :
1357 : 0 : tapdisk_nbdserver_newclient_fd(server, fd);
1358 : 0 : }
1359 : :
1360 : : static void
1361 : 0 : tapdisk_nbdserver_newclient(event_id_t id, char mode, void *data)
1362 : : {
1363 : 0 : struct sockaddr_storage their_addr;
1364 : 0 : socklen_t sin_size = sizeof(their_addr);
1365 : 0 : char s[INET6_ADDRSTRLEN+1];
1366 : 0 : int new_fd;
1367 : 0 : td_nbdserver_t *server = data;
1368 : :
1369 [ # # ]: 0 : ASSERT(server);
1370 : :
1371 : 0 : INFO("About to accept (server->fdrecv_listening_fd = %d)",
1372 : : server->fdrecv_listening_fd);
1373 : :
1374 : 0 : new_fd = accept(server->fdrecv_listening_fd,
1375 : : (struct sockaddr *)&their_addr, &sin_size);
1376 : :
1377 [ # # ]: 0 : if (new_fd == -1) {
1378 : 0 : ERR("failed to accept connection on the fd receiver socket: %s",
1379 : : strerror(errno));
1380 : 0 : return;
1381 : : }
1382 : :
1383 [ # # ]: 0 : memset(s, 0, sizeof(s));
1384 [ # # ]: 0 : inet_ntop(their_addr.ss_family, get_in_addr(&their_addr), s, sizeof(s)-1);
1385 : :
1386 : 0 : INFO("server: got connection from %s\n", s);
1387 : :
1388 : 0 : tapdisk_nbdserver_newclient_fd(server, new_fd);
1389 : : }
1390 : :
1391 : : static void
1392 : 0 : tapdisk_nbdserver_newclient_unix(event_id_t id, char mode, void *data)
1393 : : {
1394 : 0 : int new_fd = 0;
1395 : 0 : struct sockaddr_un remote;
1396 : 0 : socklen_t t = sizeof(remote);
1397 : 0 : td_nbdserver_t *server = data;
1398 : :
1399 [ # # ]: 0 : ASSERT(server);
1400 : :
1401 : 0 : INFO("About to accept (server->unix_listening_fd = %d)",
1402 : : server->unix_listening_fd);
1403 : :
1404 : 0 : new_fd = accept(server->unix_listening_fd, (struct sockaddr *)&remote, &t);
1405 [ # # ]: 0 : if (new_fd == -1) {
1406 : 0 : ERR("failed to accept connection: %s\n", strerror(errno));
1407 : 0 : return;
1408 : : }
1409 : :
1410 : 0 : INFO("server: got connection fd = %d\n", new_fd);
1411 : :
1412 : 0 : tapdisk_nbdserver_newclient_fd_new_fixed(server, new_fd);
1413 : : }
1414 : :
1415 : : td_nbdserver_t *
1416 : 0 : tapdisk_nbdserver_alloc(td_vbd_t *vbd, td_disk_info_t info, nbd_protocol_style_t style)
1417 : : {
1418 : 0 : td_nbdserver_t *server;
1419 : 0 : char fdreceiver_path[TAPDISK_NBDSERVER_MAX_PATH_LEN];
1420 : :
1421 : 0 : server = calloc(1, sizeof(*server));
1422 [ # # ]: 0 : if (!server) {
1423 : 0 : ERR("Failed to allocate memory for nbdserver: %s",
1424 : : strerror(errno));
1425 : 0 : goto fail;
1426 : : }
1427 : :
1428 : 0 : server->vbd = vbd;
1429 : 0 : server->info = info;
1430 : 0 : server->fdrecv_listening_fd = -1;
1431 : 0 : server->fdrecv_listening_event_id = -1;
1432 : 0 : server->unix_listening_fd = -1;
1433 : 0 : server->unix_listening_event_id = -1;
1434 : 0 : server->style = style;
1435 [ # # # ]: 0 : INIT_LIST_HEAD(&server->clients);
1436 : :
1437 [ # # # ]: 0 : switch (style) {
1438 : 0 : case TAPDISK_NBD_PROTOCOL_OLD:
1439 [ # # ]: 0 : if (td_metrics_nbd_start_old(&server->nbd_stats, server->vbd->uuid)) {
1440 : 0 : ERR("failed to create metrics file for nbdserver");
1441 : 0 : goto fail;
1442 : : }
1443 : : break;
1444 : 0 : case TAPDISK_NBD_PROTOCOL_NEW:
1445 [ # # ]: 0 : if (td_metrics_nbd_start_new(&server->nbd_stats, server->vbd->uuid)) {
1446 : 0 : ERR("failed to create metrics file for nbdserver");
1447 : 0 : goto fail;
1448 : : }
1449 : : break;
1450 : : }
1451 : :
1452 [ # # # # ]: 0 : if (snprintf(fdreceiver_path, TAPDISK_NBDSERVER_MAX_PATH_LEN,
1453 : : "%s%d.%d",
1454 : : (style == TAPDISK_NBD_PROTOCOL_OLD)?TAPDISK_NBDSERVER_OLD_LISTEN_SOCK_PATH:TAPDISK_NBDSERVER_NEW_LISTEN_SOCK_PATH,
1455 : : getpid(),
1456 : 0 : vbd->uuid) < 0) {
1457 : 0 : ERR("Failed to snprintf fdreceiver_path");
1458 : 0 : goto fail;
1459 : : }
1460 : :
1461 : 0 : server->fdreceiver = td_fdreceiver_start(fdreceiver_path,
1462 : : tapdisk_nbdserver_fdreceiver_cb, server);
1463 [ # # ]: 0 : if (!server->fdreceiver) {
1464 : 0 : ERR("Error setting up fd receiver");
1465 : 0 : goto fail;
1466 : : }
1467 : :
1468 [ # # # # ]: 0 : if (snprintf(server->sockpath, TAPDISK_NBDSERVER_MAX_PATH_LEN,
1469 : : "%s%d.%d",
1470 : : (style == TAPDISK_NBD_PROTOCOL_OLD)?TAPDISK_NBDSERVER_OLD_SOCK_PATH:TAPDISK_NBDSERVER_NEW_SOCK_PATH,
1471 : : getpid(),
1472 : 0 : vbd->uuid) < 0) {
1473 : 0 : ERR("Failed to snprintf sockpath");
1474 : 0 : goto fail;
1475 : : }
1476 : :
1477 : 0 : return server;
1478 : :
1479 : 0 : fail:
1480 [ # # ]: 0 : if (server) {
1481 [ # # ]: 0 : if (server->fdreceiver)
1482 : 0 : td_fdreceiver_stop(server->fdreceiver);
1483 : 0 : free(server);
1484 : : }
1485 : :
1486 : : return NULL;
1487 : : }
1488 : :
1489 : : void
1490 : 0 : tapdisk_nbdserver_pause(td_nbdserver_t *server, bool log)
1491 : : {
1492 : 0 : struct td_nbdserver_client *pos, *q;
1493 : :
1494 [ # # ]: 0 : if (log) {
1495 : 0 : INFO("NBD server pause(%p)", server);
1496 : : }
1497 : :
1498 [ # # # # ]: 0 : list_for_each_entry_safe(pos, q, &server->clients, clientlist){
1499 [ # # # # ]: 0 : if (pos->paused != 1 && pos->client_event_id >= 0) {
1500 : 0 : tapdisk_nbdserver_disable_client(pos);
1501 : 0 : pos->paused = 1;
1502 : : }
1503 : : }
1504 : :
1505 [ # # ]: 0 : if (server->fdrecv_listening_event_id >= 0) {
1506 : 0 : tapdisk_server_unregister_event(server->fdrecv_listening_event_id);
1507 : 0 : server->fdrecv_listening_event_id = -1;
1508 : : }
1509 : :
1510 [ # # ]: 0 : if (server->unix_listening_event_id >= 0) {
1511 : 0 : tapdisk_server_unregister_event(server->unix_listening_event_id);
1512 : 0 : server->unix_listening_event_id = -1;
1513 : : }
1514 : 0 : }
1515 : :
1516 : : static int
1517 : 0 : tapdisk_nbdserver_unpause_fdrecv(td_nbdserver_t *server)
1518 : : {
1519 : 0 : int err = 0;
1520 : :
1521 [ # # ]: 0 : ASSERT(server);
1522 : :
1523 [ # # ]: 0 : if (server->fdrecv_listening_event_id < 0
1524 [ # # ]: 0 : && server->fdrecv_listening_fd >= 0) {
1525 : 0 : INFO("registering for fdrecv_listening_fd");
1526 : 0 : server->fdrecv_listening_event_id =
1527 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
1528 : 0 : server->fdrecv_listening_fd, TV_ZERO,
1529 : : tapdisk_nbdserver_newclient,
1530 : : server);
1531 [ # # ]: 0 : if (server->fdrecv_listening_event_id < 0) {
1532 : 0 : err = server->fdrecv_listening_event_id;
1533 : 0 : server->fdrecv_listening_event_id = -1;
1534 : : }
1535 : : }
1536 : :
1537 : 0 : return err;
1538 : : }
1539 : :
1540 : : static int
1541 : 0 : tapdisk_nbdserver_unpause_unix(td_nbdserver_t *server)
1542 : : {
1543 : 0 : int err = 0;
1544 : :
1545 [ # # ]: 0 : ASSERT(server);
1546 : :
1547 [ # # ]: 0 : if (server->unix_listening_event_id < 0
1548 [ # # ]: 0 : && server->unix_listening_fd >= 0) {
1549 : 0 : INFO("registering for unix_listening_fd");
1550 : 0 : server->unix_listening_event_id =
1551 : 0 : tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
1552 : 0 : server->unix_listening_fd, TV_ZERO,
1553 : : tapdisk_nbdserver_newclient_unix,
1554 : : server);
1555 [ # # ]: 0 : if (server->unix_listening_event_id < 0) {
1556 : 0 : err = server->unix_listening_event_id;
1557 : 0 : server->unix_listening_event_id = -1;
1558 : : }
1559 : :
1560 : : /* Note: any failures after this point need to unregister the event */
1561 : : }
1562 : :
1563 : 0 : return err;
1564 : : }
1565 : :
1566 : : int
1567 : 0 : tapdisk_nbdserver_listen_inet(td_nbdserver_t *server, const int port)
1568 : : {
1569 : 0 : struct addrinfo hints, *servinfo, *p;
1570 : 0 : char portstr[10];
1571 : 0 : int err;
1572 : 0 : int yes = 1;
1573 : :
1574 [ # # ]: 0 : ASSERT(server);
1575 [ # # ]: 0 : ASSERT(server->fdrecv_listening_fd == -1);
1576 : :
1577 : 0 : memset(&hints, 0, sizeof(hints));
1578 : 0 : hints.ai_family = AF_UNSPEC;
1579 : 0 : hints.ai_socktype = SOCK_STREAM;
1580 : 0 : hints.ai_flags = AI_PASSIVE;
1581 : :
1582 : 0 : snprintf(portstr, 10, "%d", port);
1583 : :
1584 : 0 : err = getaddrinfo(NULL, portstr, &hints, &servinfo);
1585 [ # # ]: 0 : if (err) {
1586 [ # # ]: 0 : if (err == EAI_SYSTEM) {
1587 : 0 : ERR("Failed to getaddrinfo: %s", strerror(errno));
1588 : 0 : return -errno;
1589 : : } else {
1590 : 0 : ERR("Failed to getaddrinfo: %s", gai_strerror(err));
1591 : 0 : return -1;
1592 : : }
1593 : : }
1594 : :
1595 [ # # ]: 0 : for (p = servinfo; p != NULL; p = p->ai_next) {
1596 [ # # ]: 0 : if ((server->fdrecv_listening_fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0)) ==
1597 : : -1) {
1598 : 0 : ERR("Failed to create socket");
1599 : 0 : continue;
1600 : : }
1601 : :
1602 [ # # ]: 0 : if (setsockopt(server->fdrecv_listening_fd, SOL_SOCKET, SO_REUSEADDR,
1603 : : &yes, sizeof(int)) == -1) {
1604 : 0 : ERR("Failed to setsockopt");
1605 : 0 : close(server->fdrecv_listening_fd);
1606 : 0 : server->fdrecv_listening_fd = -1;
1607 : 0 : continue;
1608 : : }
1609 : :
1610 [ # # ]: 0 : if (bind(server->fdrecv_listening_fd, p->ai_addr, p->ai_addrlen) ==
1611 : : -1) {
1612 : 0 : ERR("Failed to bind");
1613 : 0 : close(server->fdrecv_listening_fd);
1614 : 0 : server->fdrecv_listening_fd = -1;
1615 : 0 : continue;
1616 : : }
1617 : :
1618 : : break;
1619 : : }
1620 : :
1621 : 0 : freeaddrinfo(servinfo);
1622 : :
1623 [ # # ]: 0 : if (p == NULL) {
1624 : 0 : ERR("Failed to bind");
1625 : 0 : err = -1;
1626 : 0 : goto out;
1627 : : }
1628 : :
1629 : 0 : err = listen(server->fdrecv_listening_fd, 10);
1630 [ # # ]: 0 : if (err) {
1631 : 0 : err = -errno;
1632 : 0 : ERR("listen: %s", strerror(-err));
1633 : 0 : goto out;
1634 : : }
1635 : :
1636 : 0 : err = tapdisk_nbdserver_unpause_fdrecv(server);
1637 [ # # ]: 0 : if (err) {
1638 : 0 : ERR("failed to unpause the NBD server (fdrecv): %s\n",
1639 : : strerror(-err));
1640 : 0 : goto out;
1641 : : }
1642 : :
1643 : 0 : INFO("Successfully started NBD server (fdrecv)");
1644 : :
1645 : 0 : out:
1646 [ # # # # ]: 0 : if (err && (server->fdrecv_listening_fd != -1)) {
1647 : 0 : close(server->fdrecv_listening_fd);
1648 : 0 : server->fdrecv_listening_fd = -1;
1649 : : }
1650 : : return err;
1651 : : }
1652 : :
1653 : : int
1654 : 0 : tapdisk_nbdserver_listen_unix(td_nbdserver_t *server)
1655 : : {
1656 : 0 : size_t len = 0;
1657 : 0 : int err = 0;
1658 : 0 : int new_fd;
1659 [ # # ]: 0 : ASSERT(server);
1660 [ # # ]: 0 : ASSERT(server->unix_listening_fd == -1);
1661 : :
1662 : 0 : new_fd = socket(AF_UNIX, SOCK_STREAM, 0);
1663 [ # # ]: 0 : if (new_fd == -1) {
1664 : 0 : err = -errno;
1665 : 0 : ERR("failed to create UNIX domain socket: %s\n", strerror(-err));
1666 : 0 : goto fail;
1667 : : }
1668 : :
1669 : 0 : server->local.sun_family = AF_UNIX;
1670 : :
1671 [ # # ]: 0 : if (unlikely(strlen(server->sockpath) >
1672 : : (sizeof(server->local.sun_path) - 1))) {
1673 : 0 : err = -ENAMETOOLONG;
1674 : 0 : ERR("socket name too long: %s\n", server->sockpath);
1675 : 0 : goto fail;
1676 : : }
1677 : :
1678 : 0 : safe_strncpy(server->local.sun_path, server->sockpath, sizeof(server->local.sun_path));
1679 : 0 : err = unlink(server->local.sun_path);
1680 [ # # # # ]: 0 : if (err == -1 && errno != ENOENT) {
1681 : 0 : err = -errno;
1682 : 0 : ERR("failed to remove %s: %s\n", server->local.sun_path,
1683 : : strerror(-err));
1684 : 0 : goto fail;
1685 : : }
1686 : 0 : len = strlen(server->local.sun_path) + sizeof(server->local.sun_family);
1687 : 0 : err = bind(new_fd, (struct sockaddr *)&server->local,
1688 : : len);
1689 [ # # ]: 0 : if (err == -1) {
1690 : 0 : err = -errno;
1691 : 0 : ERR("failed to bind: %s\n", strerror(-err));
1692 : 0 : goto fail;
1693 : : }
1694 : :
1695 : 0 : err = listen(new_fd, 10);
1696 [ # # ]: 0 : if (err == -1) {
1697 : 0 : err = -errno;
1698 : 0 : ERR("failed to listen: %s\n", strerror(-err));
1699 : 0 : goto fail;
1700 : : }
1701 : :
1702 : 0 : server->unix_listening_fd = new_fd;
1703 : :
1704 : 0 : err = tapdisk_nbdserver_unpause_unix(server);
1705 [ # # ]: 0 : if (err) {
1706 : 0 : ERR("failed to unpause the NBD server (unix): %s\n",
1707 : : strerror(-err));
1708 : 0 : goto fail;
1709 : : }
1710 : :
1711 : 0 : INFO("Successfully started NBD server on %s\n", server->sockpath);
1712 : :
1713 : 0 : return 0;
1714 : :
1715 : 0 : fail:
1716 [ # # ]: 0 : if (new_fd > -1) {
1717 : 0 : close(new_fd);
1718 : : }
1719 : 0 : server->unix_listening_fd = -1;
1720 : :
1721 : 0 : return err;
1722 : : }
1723 : :
1724 : : int
1725 : 0 : tapdisk_nbdserver_unpause(td_nbdserver_t *server)
1726 : : {
1727 : 0 : struct td_nbdserver_client *pos, *q;
1728 : 0 : int err;
1729 : :
1730 [ # # ]: 0 : ASSERT(server);
1731 : :
1732 : 0 : INFO("NBD server unpause(%p) - fdrecv_listening_fd %d, "
1733 : : "unix_listening_fd=%d", server, server->fdrecv_listening_fd,
1734 : : server->unix_listening_fd);
1735 : :
1736 [ # # # # ]: 0 : list_for_each_entry_safe(pos, q, &server->clients, clientlist){
1737 [ # # ]: 0 : if (pos->paused == 1) {
1738 [ # # ]: 0 : if((err = tapdisk_nbdserver_enable_client(pos)) < 0) {
1739 : 0 : ERR("Failed to enable nbd client after pause");
1740 : 0 : return err;
1741 : : }
1742 : 0 : pos->paused = 0;
1743 : : }
1744 : : }
1745 : :
1746 : 0 : err = tapdisk_nbdserver_unpause_fdrecv(server);
1747 [ # # ]: 0 : if (err)
1748 : : return err;
1749 : :
1750 : 0 : err = tapdisk_nbdserver_unpause_unix(server);
1751 : 0 : if (err)
1752 : : return err;
1753 : :
1754 : : return 0;
1755 : : }
1756 : :
1757 : : void
1758 : 0 : tapdisk_nbdserver_free(td_nbdserver_t *server)
1759 : : {
1760 : 0 : struct td_nbdserver_client *pos, *q;
1761 : 0 : int err;
1762 : :
1763 : 0 : INFO("NBD server free(%p)", server);
1764 : :
1765 [ # # ]: 0 : list_for_each_entry_safe(pos, q, &server->clients, clientlist)
1766 : 0 : tapdisk_nbdserver_free_client(pos);
1767 : :
1768 [ # # ]: 0 : if (server->fdrecv_listening_event_id >= 0) {
1769 : 0 : tapdisk_server_unregister_event(server->fdrecv_listening_event_id);
1770 : 0 : server->fdrecv_listening_event_id = -1;
1771 : : }
1772 : :
1773 [ # # ]: 0 : if (server->fdrecv_listening_fd >= 0) {
1774 : 0 : close(server->fdrecv_listening_fd);
1775 : 0 : server->fdrecv_listening_fd = -1;
1776 : : }
1777 : :
1778 [ # # ]: 0 : if (server->fdreceiver)
1779 : 0 : td_fdreceiver_stop(server->fdreceiver);
1780 : :
1781 [ # # ]: 0 : if (server->unix_listening_event_id >= 0) {
1782 : 0 : tapdisk_server_unregister_event(server->unix_listening_event_id);
1783 : 0 : server->unix_listening_event_id = -1;
1784 : : }
1785 : :
1786 [ # # ]: 0 : if (server->unix_listening_fd >= 0) {
1787 : 0 : close(server->unix_listening_fd);
1788 : 0 : server->unix_listening_fd = -1;
1789 : : }
1790 : :
1791 : 0 : err = unlink(server->sockpath);
1792 [ # # ]: 0 : if (err)
1793 : 0 : ERR("failed to remove UNIX domain socket %s: %s\n", server->sockpath,
1794 : : strerror(errno));
1795 : 0 : err = td_metrics_nbd_stop(&server->nbd_stats);
1796 : :
1797 [ # # ]: 0 : if (err)
1798 : 0 : ERR("failed to delete NBD metrics: %s\n", strerror(errno));
1799 : :
1800 : 0 : free(server);
1801 : 0 : }
1802 : :
1803 : : int
1804 : 0 : tapdisk_nbdserver_reqs_pending(td_nbdserver_client_t *client)
1805 : : {
1806 [ # # ]: 0 : ASSERT(client);
1807 : :
1808 : 0 : return client->n_reqs - client->n_reqs_free;
1809 : : }
1810 : :
1811 : : bool
1812 : 0 : tapdisk_nbdserver_contains_client(td_nbdserver_t *server,
1813 : : td_nbdserver_client_t *client)
1814 : : {
1815 : 0 : td_nbdserver_client_t *_client;
1816 : :
1817 [ # # ]: 0 : ASSERT(server);
1818 : :
1819 [ # # ]: 0 : list_for_each_entry(_client, &server->clients, clientlist)
1820 [ # # ]: 0 : if (client == _client)
1821 : : return true;
1822 : : return false;
1823 : : }
|