Commit 75818250ba0f61d9e3008b11d8c63b7b46d80ba2

Authored by ths
1 parent 3b05a8e9

Allow QEMU to connect directly to an NBD server, by Laurent Vivier.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4838 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile
... ... @@ -42,7 +42,7 @@ recurse-all: $(SUBDIR_RULES)
42 42 BLOCK_OBJS=cutils.o qemu-malloc.o
43 43 BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
44 44 BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
45   -BLOCK_OBJS+=block-qcow2.o block-parallels.o
  45 +BLOCK_OBJS+=block-qcow2.o block-parallels.o block-nbd.o
46 46  
47 47 ######################################################################
48 48 # libqemu_common.a: Target independent part of system emulation. The
... ... @@ -50,7 +50,7 @@ BLOCK_OBJS+=block-qcow2.o block-parallels.o
50 50 # system emulation, i.e. a single QEMU executable should support all
51 51 # CPUs and machines.
52 52  
53   -OBJS=$(BLOCK_OBJS)
  53 +OBJS=nbd.o $(BLOCK_OBJS)
54 54 OBJS+=readline.o console.o
55 55 OBJS+=block.o
56 56  
... ... @@ -159,7 +159,7 @@ libqemu_user.a: $(USER_OBJS)
159 159 rm -f $@
160 160 $(AR) rcs $@ $(USER_OBJS)
161 161  
162   -QEMU_IMG_BLOCK_OBJS = $(BLOCK_OBJS)
  162 +QEMU_IMG_BLOCK_OBJS = nbd.o $(BLOCK_OBJS)
163 163 ifdef CONFIG_WIN32
164 164 QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-win32.o
165 165 else
... ... @@ -180,7 +180,7 @@ qemu-img-%.o: %.c
180 180 qemu-nbd-%.o: %.c
181 181 $(CC) $(CFLAGS) $(CPPFLAGS) -DQEMU_NBD -c -o $@ $<
182 182  
183   -qemu-nbd$(EXESUF): qemu-nbd.o nbd.o qemu-img-block.o \
  183 +qemu-nbd$(EXESUF): qemu-nbd.o qemu-nbd-nbd.o qemu-img-block.o \
184 184 osdep.o qemu-nbd-block-raw-posix.o $(BLOCK_OBJS)
185 185 $(CC) $(LDFLAGS) -o $@ $^ -lz $(LIBS)
186 186  
... ...
block-nbd.c 0 → 100644
  1 +/*
  2 + * QEMU Block driver for NBD
  3 + *
  4 + * Copyright (C) 2008 Bull S.A.S.
  5 + * Author: Laurent Vivier <Laurent.Vivier@bull;net>
  6 + *
  7 + * Some parts:
  8 + * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
  9 + *
  10 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  11 + * of this software and associated documentation files (the "Software"), to deal
  12 + * in the Software without restriction, including without limitation the rights
  13 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14 + * copies of the Software, and to permit persons to whom the Software is
  15 + * furnished to do so, subject to the following conditions:
  16 + *
  17 + * The above copyright notice and this permission notice shall be included in
  18 + * all copies or substantial portions of the Software.
  19 + *
  20 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  23 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  26 + * THE SOFTWARE.
  27 + */
  28 +
  29 +#include "qemu-common.h"
  30 +#include "nbd.h"
  31 +
  32 +#include <sys/types.h>
  33 +#include <unistd.h>
  34 +#include <sys/socket.h>
  35 +#include <sys/un.h>
  36 +#include <netinet/in.h>
  37 +#include <arpa/inet.h>
  38 +#include <pthread.h>
  39 +
  40 +typedef struct BDRVNBDState {
  41 + int sock;
  42 + off_t size;
  43 + size_t blocksize;
  44 +} BDRVNBDState;
  45 +
  46 +static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
  47 +{
  48 + BDRVNBDState *s = bs->opaque;
  49 + const char *host;
  50 + const char *unixpath;
  51 + int sock;
  52 + off_t size;
  53 + size_t blocksize;
  54 + int ret;
  55 +
  56 + if ((flags & BDRV_O_CREAT))
  57 + return -EINVAL;
  58 +
  59 + if (!strstart(filename, "nbd:", &host))
  60 + return -EINVAL;
  61 +
  62 + if (strstart(host, "unix:", &unixpath)) {
  63 +
  64 + if (unixpath[0] != '/')
  65 + return -EINVAL;
  66 +
  67 + sock = unix_socket_outgoing(unixpath);
  68 +
  69 + } else {
  70 + uint16_t port;
  71 + char *p, *r;
  72 + char hostname[128];
  73 +
  74 + pstrcpy(hostname, 128, host);
  75 +
  76 + p = strchr(hostname, ':');
  77 + if (p == NULL)
  78 + return -EINVAL;
  79 +
  80 + *p = '\0';
  81 + p++;
  82 +
  83 + port = strtol(p, &r, 0);
  84 + if (r == p)
  85 + return -EINVAL;
  86 + sock = tcp_socket_outgoing(hostname, port);
  87 + }
  88 +
  89 + if (sock == -1)
  90 + return -errno;
  91 +
  92 + ret = nbd_receive_negotiate(sock, &size, &blocksize);
  93 + if (ret == -1)
  94 + return -errno;
  95 +
  96 + s->sock = sock;
  97 + s->size = size;
  98 + s->blocksize = blocksize;
  99 +
  100 + return 0;
  101 +}
  102 +
  103 +static int nbd_read(BlockDriverState *bs, int64_t sector_num,
  104 + uint8_t *buf, int nb_sectors)
  105 +{
  106 + BDRVNBDState *s = bs->opaque;
  107 + struct nbd_request request;
  108 + struct nbd_reply reply;
  109 +
  110 + request.type = NBD_CMD_READ;
  111 + request.handle = (uint64_t)(intptr_t)bs;
  112 + request.from = sector_num * 512;;
  113 + request.len = nb_sectors * 512;
  114 +
  115 + if (nbd_send_request(s->sock, &request) == -1)
  116 + return -errno;
  117 +
  118 + if (nbd_receive_reply(s->sock, &reply) == -1)
  119 + return -errno;
  120 +
  121 + if (reply.error !=0)
  122 + return -reply.error;
  123 +
  124 + if (reply.handle != request.handle)
  125 + return -EIO;
  126 +
  127 + if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
  128 + return -EIO;
  129 +
  130 + return 0;
  131 +}
  132 +
  133 +static int nbd_write(BlockDriverState *bs, int64_t sector_num,
  134 + const uint8_t *buf, int nb_sectors)
  135 +{
  136 + BDRVNBDState *s = bs->opaque;
  137 + struct nbd_request request;
  138 + struct nbd_reply reply;
  139 +
  140 + request.type = NBD_CMD_WRITE;
  141 + request.handle = (uint64_t)(intptr_t)bs;
  142 + request.from = sector_num * 512;;
  143 + request.len = nb_sectors * 512;
  144 +
  145 + if (nbd_send_request(s->sock, &request) == -1)
  146 + return -errno;
  147 +
  148 + if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len)
  149 + return -EIO;
  150 +
  151 + if (nbd_receive_reply(s->sock, &reply) == -1)
  152 + return -errno;
  153 +
  154 + if (reply.error !=0)
  155 + return -reply.error;
  156 +
  157 + if (reply.handle != request.handle)
  158 + return -EIO;
  159 +
  160 + return 0;
  161 +}
  162 +
  163 +static void nbd_close(BlockDriverState *bs)
  164 +{
  165 + BDRVNBDState *s = bs->opaque;
  166 + struct nbd_request request;
  167 +
  168 + request.type = NBD_CMD_DISC;
  169 + request.handle = (uint64_t)(intptr_t)bs;
  170 + request.from = 0;
  171 + request.len = 0;
  172 + nbd_send_request(s->sock, &request);
  173 +
  174 + close(s->sock);
  175 +}
  176 +
  177 +static int64_t nbd_getlength(BlockDriverState *bs)
  178 +{
  179 + BDRVNBDState *s = bs->opaque;
  180 +
  181 + return s->size;
  182 +}
  183 +
  184 +BlockDriver bdrv_nbd = {
  185 + "nbd",
  186 + sizeof(BDRVNBDState),
  187 + NULL, /* no probe for protocols */
  188 + nbd_open,
  189 + nbd_read,
  190 + nbd_write,
  191 + nbd_close,
  192 + .bdrv_getlength = nbd_getlength,
  193 + .protocol_name = "nbd",
  194 +};
... ...
... ... @@ -1332,6 +1332,7 @@ void bdrv_init(void)
1332 1332 bdrv_register(&bdrv_vvfat);
1333 1333 bdrv_register(&bdrv_qcow2);
1334 1334 bdrv_register(&bdrv_parallels);
  1335 + bdrv_register(&bdrv_nbd);
1335 1336 }
1336 1337  
1337 1338 void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
... ...
... ... @@ -16,6 +16,7 @@ extern BlockDriver bdrv_vpc;
16 16 extern BlockDriver bdrv_vvfat;
17 17 extern BlockDriver bdrv_qcow2;
18 18 extern BlockDriver bdrv_parallels;
  19 +extern BlockDriver bdrv_nbd;
19 20  
20 21 typedef struct BlockDriverInfo {
21 22 /* in bytes, 0 if irrelevant */
... ...
1   -/*\
  1 +/*
2 2 * Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
3 3 *
4 4 * Network Block Device
... ... @@ -15,7 +15,7 @@
15 15 * You should have received a copy of the GNU General Public License
16 16 * along with this program; if not, write to the Free Software
17 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18   -\*/
  18 + */
19 19  
20 20 #include "nbd.h"
21 21  
... ... @@ -31,17 +31,21 @@
31 31 #include <arpa/inet.h>
32 32 #include <netdb.h>
33 33  
  34 +#if defined(QEMU_NBD)
34 35 extern int verbose;
  36 +#else
  37 +static int verbose = 0;
  38 +#endif
  39 +
  40 +#define TRACE(msg, ...) do { \
  41 + if (verbose) LOG(msg, ## __VA_ARGS__); \
  42 +} while(0)
35 43  
36 44 #define LOG(msg, ...) do { \
37 45 fprintf(stderr, "%s:%s():L%d: " msg "\n", \
38 46 __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
39 47 } while(0)
40 48  
41   -#define TRACE(msg, ...) do { \
42   - if (verbose) LOG(msg, ## __VA_ARGS__); \
43   -} while(0)
44   -
45 49 /* This is all part of the "official" NBD API */
46 50  
47 51 #define NBD_REQUEST_MAGIC 0x25609513
... ... @@ -59,10 +63,10 @@ extern int verbose;
59 63  
60 64 /* That's all folks */
61 65  
62   -#define read_sync(fd, buffer, size) wr_sync(fd, buffer, size, true)
63   -#define write_sync(fd, buffer, size) wr_sync(fd, buffer, size, false)
  66 +#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
  67 +#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
64 68  
65   -static size_t wr_sync(int fd, void *buffer, size_t size, bool do_read)
  69 +size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
66 70 {
67 71 size_t offset = 0;
68 72  
... ... @@ -76,7 +80,7 @@ static size_t wr_sync(int fd, void *buffer, size_t size, bool do_read)
76 80 }
77 81  
78 82 /* recoverable error */
79   - if (len == -1 && errno == EAGAIN) {
  83 + if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
80 84 continue;
81 85 }
82 86  
... ... @@ -96,7 +100,7 @@ static size_t wr_sync(int fd, void *buffer, size_t size, bool do_read)
96 100 return offset;
97 101 }
98 102  
99   -static int tcp_socket_outgoing(const char *address, uint16_t port)
  103 +int tcp_socket_outgoing(const char *address, uint16_t port)
100 104 {
101 105 int s;
102 106 struct in_addr in;
... ... @@ -404,16 +408,31 @@ int nbd_client(int fd, int csock)
404 408 return ret;
405 409 }
406 410  
407   -int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
408   - off_t *offset, bool readonly, uint8_t *data, int data_size)
  411 +int nbd_send_request(int csock, struct nbd_request *request)
409 412 {
410 413 uint8_t buf[4 + 4 + 8 + 8 + 4];
411   - uint32_t magic;
412   - uint32_t type;
413   - uint64_t from;
414   - uint32_t len;
415 414  
416   - TRACE("Reading request.");
  415 + cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
  416 + cpu_to_be32w((uint32_t*)(buf + 4), request->type);
  417 + cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
  418 + cpu_to_be64w((uint64_t*)(buf + 16), request->from);
  419 + cpu_to_be32w((uint32_t*)(buf + 24), request->len);
  420 +
  421 + TRACE("Sending request to client");
  422 +
  423 + if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
  424 + LOG("writing to socket failed");
  425 + errno = EINVAL;
  426 + return -1;
  427 + }
  428 + return 0;
  429 +}
  430 +
  431 +
  432 +static int nbd_receive_request(int csock, struct nbd_request *request)
  433 +{
  434 + uint8_t buf[4 + 4 + 8 + 8 + 4];
  435 + uint32_t magic;
417 436  
418 437 if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
419 438 LOG("read failed");
... ... @@ -422,97 +441,158 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
422 441 }
423 442  
424 443 /* Request
425   - [ 0 .. 3] magic (NBD_REQUEST_MAGIC)
426   - [ 4 .. 7] type (0 == READ, 1 == WRITE)
427   - [ 8 .. 15] handle
428   - [16 .. 23] from
429   - [24 .. 27] len
  444 + [ 0 .. 3] magic (NBD_REQUEST_MAGIC)
  445 + [ 4 .. 7] type (0 == READ, 1 == WRITE)
  446 + [ 8 .. 15] handle
  447 + [16 .. 23] from
  448 + [24 .. 27] len
430 449 */
431 450  
432 451 magic = be32_to_cpup((uint32_t*)buf);
433   - type = be32_to_cpup((uint32_t*)(buf + 4));
434   - from = be64_to_cpup((uint64_t*)(buf + 16));
435   - len = be32_to_cpup((uint32_t*)(buf + 24));
  452 + request->type = be32_to_cpup((uint32_t*)(buf + 4));
  453 + request->handle = be64_to_cpup((uint64_t*)(buf + 8));
  454 + request->from = be64_to_cpup((uint64_t*)(buf + 16));
  455 + request->len = be32_to_cpup((uint32_t*)(buf + 24));
436 456  
437 457 TRACE("Got request: "
438 458 "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
439   - magic, type, from, len);
440   -
  459 + magic, request->type, request->from, request->len);
441 460  
442 461 if (magic != NBD_REQUEST_MAGIC) {
443 462 LOG("invalid magic (got 0x%x)", magic);
444 463 errno = EINVAL;
445 464 return -1;
446 465 }
  466 +}
  467 +
  468 +int nbd_receive_reply(int csock, struct nbd_reply *reply)
  469 +{
  470 + uint8_t buf[4 + 4 + 8];
  471 + uint32_t magic;
  472 +
  473 + memset(buf, 0xAA, sizeof(buf));
  474 +
  475 + if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
  476 + LOG("read failed");
  477 + errno = EINVAL;
  478 + return -1;
  479 + }
  480 +
  481 + /* Reply
  482 + [ 0 .. 3] magic (NBD_REPLY_MAGIC)
  483 + [ 4 .. 7] error (0 == no error)
  484 + [ 7 .. 15] handle
  485 + */
  486 +
  487 + magic = be32_to_cpup((uint32_t*)buf);
  488 + reply->error = be32_to_cpup((uint32_t*)(buf + 4));
  489 + reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
  490 +
  491 + TRACE("Got reply: "
  492 + "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
  493 + magic, reply->error, reply->handle);
  494 +
  495 + if (magic != NBD_REPLY_MAGIC) {
  496 + LOG("invalid magic (got 0x%x)", magic);
  497 + errno = EINVAL;
  498 + return -1;
  499 + }
  500 + return 0;
  501 +}
  502 +
  503 +static int nbd_send_reply(int csock, struct nbd_reply *reply)
  504 +{
  505 + uint8_t buf[4 + 4 + 8];
  506 +
  507 + /* Reply
  508 + [ 0 .. 3] magic (NBD_REPLY_MAGIC)
  509 + [ 4 .. 7] error (0 == no error)
  510 + [ 7 .. 15] handle
  511 + */
  512 + cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
  513 + cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
  514 + cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
  515 +
  516 + TRACE("Sending response to client");
  517 +
  518 + if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
  519 + LOG("writing to socket failed");
  520 + errno = EINVAL;
  521 + return -1;
  522 + }
  523 + return 0;
  524 +}
447 525  
448   - if (len > data_size) {
  526 +int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
  527 + off_t *offset, bool readonly, uint8_t *data, int data_size)
  528 +{
  529 + struct nbd_request request;
  530 + struct nbd_reply reply;
  531 +
  532 + TRACE("Reading request.");
  533 +
  534 + if (nbd_receive_request(csock, &request) == -1)
  535 + return -1;
  536 +
  537 + if (request.len > data_size) {
449 538 LOG("len (%u) is larger than max len (%u)",
450   - len, data_size);
  539 + request.len, data_size);
451 540 errno = EINVAL;
452 541 return -1;
453 542 }
454 543  
455   - if ((from + len) < from) {
  544 + if ((request.from + request.len) < request.from) {
456 545 LOG("integer overflow detected! "
457 546 "you're probably being attacked");
458 547 errno = EINVAL;
459 548 return -1;
460 549 }
461 550  
462   - if ((from + len) > size) {
  551 + if ((request.from + request.len) > size) {
463 552 LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
464 553 ", Offset: %" PRIu64 "\n",
465   - from, len, size, dev_offset);
  554 + request.from, request.len, size, dev_offset);
466 555 LOG("requested operation past EOF--bad client?");
467 556 errno = EINVAL;
468 557 return -1;
469 558 }
470 559  
471   - /* Reply
472   - [ 0 .. 3] magic (NBD_REPLY_MAGIC)
473   - [ 4 .. 7] error (0 == no error)
474   - [ 7 .. 15] handle
475   - */
476   - cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
477   - cpu_to_be32w((uint32_t*)(buf + 4), 0);
478   -
479 560 TRACE("Decoding type");
480 561  
481   - switch (type) {
482   - case 0:
  562 + reply.handle = request.handle;
  563 + reply.error = 0;
  564 +
  565 + switch (request.type) {
  566 + case NBD_CMD_READ:
483 567 TRACE("Request type is READ");
484 568  
485   - if (bdrv_read(bs, (from + dev_offset) / 512, data, len / 512) == -1) {
  569 + if (bdrv_read(bs, (request.from + dev_offset) / 512, data,
  570 + request.len / 512) == -1) {
486 571 LOG("reading from file failed");
487 572 errno = EINVAL;
488 573 return -1;
489 574 }
490   - *offset += len;
491   -
492   - TRACE("Read %u byte(s)", len);
  575 + *offset += request.len;
493 576  
494   - TRACE("Sending OK response");
  577 + TRACE("Read %u byte(s)", request.len);
495 578  
496   - if (write_sync(csock, buf, 16) != 16) {
497   - LOG("writing to socket failed");
498   - errno = EINVAL;
  579 + if (nbd_send_reply(csock, &reply) == -1)
499 580 return -1;
500   - }
501 581  
502 582 TRACE("Sending data to client");
503 583  
504   - if (write_sync(csock, data, len) != len) {
  584 + if (write_sync(csock, data, request.len) != request.len) {
505 585 LOG("writing to socket failed");
506 586 errno = EINVAL;
507 587 return -1;
508 588 }
509 589 break;
510   - case 1:
  590 + case NBD_CMD_WRITE:
511 591 TRACE("Request type is WRITE");
512 592  
513   - TRACE("Reading %u byte(s)", len);
  593 + TRACE("Reading %u byte(s)", request.len);
514 594  
515   - if (read_sync(csock, data, len) != len) {
  595 + if (read_sync(csock, data, request.len) != request.len) {
516 596 LOG("reading from socket failed");
517 597 errno = EINVAL;
518 598 return -1;
... ... @@ -520,34 +600,29 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
520 600  
521 601 if (readonly) {
522 602 TRACE("Server is read-only, return error");
523   -
524   - cpu_to_be32w((uint32_t*)(buf + 4), 1);
  603 + reply.error = 1;
525 604 } else {
526 605 TRACE("Writing to device");
527 606  
528   - if (bdrv_write(bs, (from + dev_offset) / 512, data, len / 512) == -1) {
  607 + if (bdrv_write(bs, (request.from + dev_offset) / 512,
  608 + data, request.len / 512) == -1) {
529 609 LOG("writing to file failed");
530 610 errno = EINVAL;
531 611 return -1;
532 612 }
533 613  
534   - *offset += len;
  614 + *offset += request.len;
535 615 }
536 616  
537   - TRACE("Sending response to client");
538   -
539   - if (write_sync(csock, buf, 16) != 16) {
540   - LOG("writing to socket failed");
541   - errno = EINVAL;
  617 + if (nbd_send_reply(csock, &reply) == -1)
542 618 return -1;
543   - }
544 619 break;
545   - case 2:
  620 + case NBD_CMD_DISC:
546 621 TRACE("Request type is DISCONNECT");
547 622 errno = 0;
548 623 return 1;
549 624 default:
550   - LOG("invalid request type (%u) received", type);
  625 + LOG("invalid request type (%u) received", request.type);
551 626 errno = EINVAL;
552 627 return -1;
553 628 }
... ...
1   -/*\
  1 +/*
2 2 * Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
3 3 *
4 4 * Network Block Device
... ... @@ -15,7 +15,7 @@
15 15 * You should have received a copy of the GNU General Public License
16 16 * along with this program; if not, write to the Free Software
17 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18   -\*/
  18 + */
19 19  
20 20 #ifndef NBD_H
21 21 #define NBD_H
... ... @@ -26,6 +26,26 @@
26 26 #include <qemu-common.h>
27 27 #include "block_int.h"
28 28  
  29 +struct nbd_request {
  30 + uint32_t type;
  31 + uint64_t handle;
  32 + uint64_t from;
  33 + uint32_t len;
  34 +};
  35 +
  36 +struct nbd_reply {
  37 + uint32_t error;
  38 + uint64_t handle;
  39 +};
  40 +
  41 +enum {
  42 + NBD_CMD_READ = 0,
  43 + NBD_CMD_WRITE = 1,
  44 + NBD_CMD_DISC = 2
  45 +};
  46 +
  47 +size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
  48 +int tcp_socket_outgoing(const char *address, uint16_t port);
29 49 int tcp_socket_incoming(const char *address, uint16_t port);
30 50 int unix_socket_outgoing(const char *path);
31 51 int unix_socket_incoming(const char *path);
... ... @@ -33,6 +53,8 @@ int unix_socket_incoming(const char *path);
33 53 int nbd_negotiate(BlockDriverState *bs, int csock, off_t size);
34 54 int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize);
35 55 int nbd_init(int fd, int csock, off_t size, size_t blocksize);
  56 +int nbd_send_request(int csock, struct nbd_request *request);
  57 +int nbd_receive_reply(int csock, struct nbd_reply *reply);
36 58 int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
37 59 off_t *offset, bool readonly, uint8_t *data, int data_size);
38 60 int nbd_client(int fd, int csock);
... ...
qemu-doc.texi
... ... @@ -1321,6 +1321,7 @@ snapshots.
1321 1321 * qemu_nbd_invocation:: qemu-nbd Invocation
1322 1322 * host_drives:: Using host drives
1323 1323 * disk_images_fat_images:: Virtual FAT disk images
  1324 +* disk_images_nbd:: NBD access
1324 1325 @end menu
1325 1326  
1326 1327 @node disk_images_quickstart
... ... @@ -1503,6 +1504,40 @@ What you should @emph{never} do:
1503 1504 @item write to the FAT directory on the host system while accessing it with the guest system.
1504 1505 @end itemize
1505 1506  
  1507 +@node disk_images_nbd
  1508 +@subsection NBD access
  1509 +
  1510 +QEMU can access directly to block device exported using the Network Block Device
  1511 +protocol.
  1512 +
  1513 +@example
  1514 +qemu linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
  1515 +@end example
  1516 +
  1517 +If the NBD server is located on the same host, you can use an unix socket instead
  1518 +of an inet socket:
  1519 +
  1520 +@example
  1521 +qemu linux.img -hdb nbd:unix:/tmp/my_socket
  1522 +@end example
  1523 +
  1524 +In this case, the block device must be exported using qemu-nbd:
  1525 +
  1526 +@example
  1527 +qemu-nbd --socket=/tmp/my_socket my_disk.qcow2
  1528 +@end example
  1529 +
  1530 +The use of qemu-nbd allows to share a disk between several guests:
  1531 +@example
  1532 +qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2
  1533 +@end example
  1534 +
  1535 +and then you can use it with two guests:
  1536 +@example
  1537 +qemu linux1.img -hdb nbd:unix:/tmp/my_socket
  1538 +qemu linux2.img -hdb nbd:unix:/tmp/my_socket
  1539 +@end example
  1540 +
1506 1541 @node pcsys_network
1507 1542 @section Network emulation
1508 1543  
... ...
qemu-nbd.c
... ... @@ -56,6 +56,7 @@ static void usage(const char *name)
56 56 " -c, --connect=DEV connect FILE to the local NBD device DEV\n"
57 57 " -d, --disconnect disconnect the specified device\n"
58 58 " -e, --shared=NUM device can be shared by NUM clients (default '1')\n"
  59 +" -t, --persistent don't exit on the last connection\n"
59 60 " -v, --verbose display extra debugging information\n"
60 61 " -h, --help display this help and exit\n"
61 62 " -V, --version output version information and exit\n"
... ... @@ -189,7 +190,7 @@ int main(int argc, char **argv)
189 190 char *device = NULL;
190 191 char *socket = NULL;
191 192 char sockpath[128];
192   - const char *sopt = "hVbo:p:rsnP:c:dvk:e:";
  193 + const char *sopt = "hVbo:p:rsnP:c:dvk:e:t";
193 194 struct option lopt[] = {
194 195 { "help", 0, 0, 'h' },
195 196 { "version", 0, 0, 'V' },
... ... @@ -204,6 +205,7 @@ int main(int argc, char **argv)
204 205 { "snapshot", 0, 0, 's' },
205 206 { "nocache", 0, 0, 'n' },
206 207 { "shared", 1, 0, 'e' },
  208 + { "persistent", 0, 0, 't' },
207 209 { "verbose", 0, 0, 'v' },
208 210 { NULL, 0, 0, 0 }
209 211 };
... ... @@ -222,6 +224,7 @@ int main(int argc, char **argv)
222 224 int i;
223 225 int nb_fds = 0;
224 226 int max_fd;
  227 + int persistent = 0;
225 228  
226 229 while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
227 230 switch (ch) {
... ... @@ -283,6 +286,9 @@ int main(int argc, char **argv)
283 286 errx(EINVAL, "Shared device number must be greater than 0\n");
284 287 }
285 288 break;
  289 + case 't':
  290 + persistent = 1;
  291 + break;
286 292 case 'v':
287 293 verbose = 1;
288 294 break;
... ... @@ -459,7 +465,7 @@ int main(int argc, char **argv)
459 465 }
460 466 }
461 467 }
462   - } while (nb_fds > 1);
  468 + } while (persistent || nb_fds > 1);
463 469 qemu_free(data);
464 470  
465 471 close(sharing_fds[0]);
... ...
qemu-nbd.texi
... ... @@ -36,6 +36,8 @@ Export Qemu disk image using NBD protocol.
36 36 disconnect the specified device
37 37 @item -e, --shared=NUM
38 38 device can be shared by NUM clients (default '1')
  39 +@item -t, --persistent
  40 + don't exit on the last connection
39 41 @item -v, --verbose
40 42 display extra debugging information
41 43 @item -h, --help
... ...