Commit cd831bd7874916c4eb3f0f47218e4a65c46bb905

Authored by ths
1 parent f8d39c01

Merge NBD client/server, by Laurent Vivier.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4834 c046a42c-6fe2-441c-8c8c-71466251a162
... ... @@ -25,6 +25,7 @@
25 25 #include <ctype.h>
26 26 #include <inttypes.h>
27 27 #include <sys/socket.h>
  28 +#include <sys/un.h>
28 29 #include <netinet/in.h>
29 30 #include <netinet/tcp.h>
30 31 #include <arpa/inet.h>
... ... @@ -183,6 +184,65 @@ error:
183 184 return -1;
184 185 }
185 186  
  187 +int unix_socket_incoming(const char *path)
  188 +{
  189 + int s;
  190 + struct sockaddr_un addr;
  191 + int serrno;
  192 +
  193 + s = socket(PF_UNIX, SOCK_STREAM, 0);
  194 + if (s == -1) {
  195 + return -1;
  196 + }
  197 +
  198 + memset(&addr, 0, sizeof(addr));
  199 + addr.sun_family = AF_UNIX;
  200 + pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
  201 +
  202 + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
  203 + goto error;
  204 + }
  205 +
  206 + if (listen(s, 128) == -1) {
  207 + goto error;
  208 + }
  209 +
  210 + return s;
  211 +error:
  212 + serrno = errno;
  213 + close(s);
  214 + errno = serrno;
  215 + return -1;
  216 +}
  217 +
  218 +int unix_socket_outgoing(const char *path)
  219 +{
  220 + int s;
  221 + struct sockaddr_un addr;
  222 + int serrno;
  223 +
  224 + s = socket(PF_UNIX, SOCK_STREAM, 0);
  225 + if (s == -1) {
  226 + return -1;
  227 + }
  228 +
  229 + memset(&addr, 0, sizeof(addr));
  230 + addr.sun_family = AF_UNIX;
  231 + pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
  232 +
  233 + if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
  234 + goto error;
  235 + }
  236 +
  237 + return s;
  238 +error:
  239 + serrno = errno;
  240 + close(s);
  241 + errno = serrno;
  242 + return -1;
  243 +}
  244 +
  245 +
186 246 /* Basic flow
187 247  
188 248 Server Client
... ... @@ -225,12 +285,10 @@ int nbd_negotiate(BlockDriverState *bs, int csock, off_t size)
225 285 return 0;
226 286 }
227 287  
228   -int nbd_receive_negotiate(int fd, int csock)
  288 +int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
229 289 {
230 290 char buf[8 + 8 + 8 + 128];
231 291 uint64_t magic;
232   - off_t size;
233   - size_t blocksize;
234 292  
235 293 TRACE("Receiving negotation.");
236 294  
... ... @@ -241,8 +299,8 @@ int nbd_receive_negotiate(int fd, int csock)
241 299 }
242 300  
243 301 magic = be64_to_cpup((uint64_t*)(buf + 8));
244   - size = be64_to_cpup((uint64_t*)(buf + 16));
245   - blocksize = 1024;
  302 + *size = be64_to_cpup((uint64_t*)(buf + 16));
  303 + *blocksize = 1024;
246 304  
247 305 TRACE("Magic is %c%c%c%c%c%c%c%c",
248 306 isprint(buf[0]) ? buf[0] : '.',
... ... @@ -254,7 +312,7 @@ int nbd_receive_negotiate(int fd, int csock)
254 312 isprint(buf[6]) ? buf[6] : '.',
255 313 isprint(buf[7]) ? buf[7] : '.');
256 314 TRACE("Magic is 0x%" PRIx64, magic);
257   - TRACE("Size is %" PRIu64, size);
  315 + TRACE("Size is %" PRIu64, *size);
258 316  
259 317 if (memcmp(buf, "NBDMAGIC", 8) != 0) {
260 318 LOG("Invalid magic received");
... ... @@ -269,7 +327,11 @@ int nbd_receive_negotiate(int fd, int csock)
269 327 errno = EINVAL;
270 328 return -1;
271 329 }
  330 + return 0;
  331 +}
272 332  
  333 +int nbd_init(int fd, int csock, off_t size, size_t blocksize)
  334 +{
273 335 TRACE("Setting block size to %lu", (unsigned long)blocksize);
274 336  
275 337 if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
... ...
... ... @@ -27,9 +27,12 @@
27 27 #include "block_int.h"
28 28  
29 29 int tcp_socket_incoming(const char *address, uint16_t port);
  30 +int unix_socket_outgoing(const char *path);
  31 +int unix_socket_incoming(const char *path);
30 32  
31 33 int nbd_negotiate(BlockDriverState *bs, int csock, off_t size);
32   -int nbd_receive_negotiate(int fd, int csock);
  34 +int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize);
  35 +int nbd_init(int fd, int csock, off_t size, size_t blocksize);
33 36 int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, off_t *offset, bool readonly);
34 37 int nbd_client(int fd, int csock);
35 38 int nbd_disconnect(int fd);
... ...
qemu-nbd.c
1   -/*\
  1 +/*
2 2 * Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
3 3 *
4 4 * Network Block Device
... ... @@ -25,10 +25,14 @@
25 25 #include <stdio.h>
26 26 #include <getopt.h>
27 27 #include <err.h>
  28 +#include <sys/types.h>
28 29 #include <sys/socket.h>
29 30 #include <netinet/in.h>
30 31 #include <netinet/tcp.h>
31 32 #include <arpa/inet.h>
  33 +#include <signal.h>
  34 +
  35 +#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
32 36  
33 37 int verbose;
34 38  
... ... @@ -41,14 +45,18 @@ static void usage(const char *name)
41 45 " -p, --port=PORT port to listen on (default `1024')\n"
42 46 " -o, --offset=OFFSET offset into the image\n"
43 47 " -b, --bind=IFACE interface to bind to (default `0.0.0.0')\n"
  48 +" -k, --socket=PATH path to the unix socket\n"
  49 +" (default '"SOCKET_PATH"')\n"
44 50 " -r, --read-only export read-only\n"
45 51 " -P, --partition=NUM only expose partition NUM\n"
  52 +" -c, --connect=DEV connect FILE to the local NBD device DEV\n"
  53 +" -d, --disconnect disconnect the specified device\n"
46 54 " -v, --verbose display extra debugging information\n"
47 55 " -h, --help display this help and exit\n"
48 56 " -V, --version output version information and exit\n"
49 57 "\n"
50 58 "Report bugs to <anthony@codemonkey.ws>\n"
51   - , name);
  59 + , name, "DEVICE");
52 60 }
53 61  
54 62 static void version(const char *name)
... ... @@ -144,27 +152,51 @@ static int find_partition(BlockDriverState *bs, int partition,
144 152 return -1;
145 153 }
146 154  
  155 +static void show_parts(const char *device)
  156 +{
  157 + if (fork() == 0) {
  158 + int nbd;
  159 +
  160 + /* linux just needs an open() to trigger
  161 + * the partition table update
  162 + * but remember to load the module with max_part != 0 :
  163 + * modprobe nbd max_part=63
  164 + */
  165 + nbd = open(device, O_RDWR);
  166 + if (nbd != -1)
  167 + close(nbd);
  168 + exit(0);
  169 + }
  170 +}
  171 +
147 172 int main(int argc, char **argv)
148 173 {
149 174 BlockDriverState *bs;
150 175 off_t dev_offset = 0;
151 176 off_t offset = 0;
152 177 bool readonly = false;
  178 + bool disconnect = false;
153 179 const char *bindto = "0.0.0.0";
154 180 int port = 1024;
155 181 int sock, csock;
156 182 struct sockaddr_in addr;
157 183 socklen_t addr_len = sizeof(addr);
158 184 off_t fd_size;
159   - const char *sopt = "hVbo:p:rsP:v";
  185 + char *device = NULL;
  186 + char *socket = NULL;
  187 + char sockpath[128];
  188 + const char *sopt = "hVbo:p:rsP:c:dvk:";
160 189 struct option lopt[] = {
161 190 { "help", 0, 0, 'h' },
162 191 { "version", 0, 0, 'V' },
163 192 { "bind", 1, 0, 'b' },
164 193 { "port", 1, 0, 'p' },
  194 + { "socket", 1, 0, 'k' },
165 195 { "offset", 1, 0, 'o' },
166 196 { "read-only", 0, 0, 'r' },
167 197 { "partition", 1, 0, 'P' },
  198 + { "connect", 1, 0, 'c' },
  199 + { "disconnect", 0, 0, 'd' },
168 200 { "snapshot", 0, 0, 's' },
169 201 { "verbose", 0, 0, 'v' },
170 202 { NULL, 0, 0, 0 }
... ... @@ -175,6 +207,8 @@ int main(int argc, char **argv)
175 207 char *end;
176 208 bool snapshot = false;
177 209 int partition = -1;
  210 + int fd;
  211 + int ret;
178 212  
179 213 while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
180 214 switch (ch) {
... ... @@ -213,6 +247,17 @@ int main(int argc, char **argv)
213 247 if (partition < 1 || partition > 8)
214 248 errx(EINVAL, "Invalid partition %d", partition);
215 249 break;
  250 + case 'k':
  251 + socket = optarg;
  252 + if (socket[0] != '/')
  253 + errx(EINVAL, "socket path must be absolute\n");
  254 + break;
  255 + case 'd':
  256 + disconnect = true;
  257 + break;
  258 + case 'c':
  259 + device = optarg;
  260 + break;
216 261 case 'v':
217 262 verbose = 1;
218 263 break;
... ... @@ -236,6 +281,20 @@ int main(int argc, char **argv)
236 281 argv[0]);
237 282 }
238 283  
  284 + if (disconnect) {
  285 + fd = open(argv[optind], O_RDWR);
  286 + if (fd == -1)
  287 + errx(errno, "Cannot open %s", argv[optind]);
  288 +
  289 + nbd_disconnect(fd);
  290 +
  291 + close(fd);
  292 +
  293 + printf("%s disconnected\n", argv[optind]);
  294 +
  295 + return 0;
  296 + }
  297 +
239 298 bdrv_init();
240 299  
241 300 bs = bdrv_new("hda");
... ... @@ -251,7 +310,77 @@ int main(int argc, char **argv)
251 310 find_partition(bs, partition, &dev_offset, &fd_size))
252 311 errx(errno, "Could not find partition %d", partition);
253 312  
254   - sock = tcp_socket_incoming(bindto, port);
  313 + if (device) {
  314 + pid_t pid;
  315 + if (!verbose)
  316 + daemon(0, 0); /* detach client and server */
  317 +
  318 + if (socket == NULL) {
  319 + sprintf(sockpath, SOCKET_PATH, basename(device));
  320 + socket = sockpath;
  321 + }
  322 +
  323 + pid = fork();
  324 + if (pid < 0)
  325 + return 1;
  326 + if (pid != 0) {
  327 + off_t size;
  328 + size_t blocksize;
  329 +
  330 + ret = 0;
  331 + bdrv_close(bs);
  332 +
  333 + do {
  334 + sock = unix_socket_outgoing(socket);
  335 + if (sock == -1) {
  336 + if (errno != ENOENT && errno != ECONNREFUSED)
  337 + goto out;
  338 + sleep(1); /* wait children */
  339 + }
  340 + } while (sock == -1);
  341 +
  342 + fd = open(device, O_RDWR);
  343 + if (fd == -1) {
  344 + ret = 1;
  345 + goto out;
  346 + }
  347 +
  348 + ret = nbd_receive_negotiate(sock, &size, &blocksize);
  349 + if (ret == -1) {
  350 + ret = 1;
  351 + goto out;
  352 + }
  353 +
  354 + ret = nbd_init(fd, sock, size, blocksize);
  355 + if (ret == -1) {
  356 + ret = 1;
  357 + goto out;
  358 + }
  359 +
  360 + printf("NBD device %s is now connected to file %s\n",
  361 + device, argv[optind]);
  362 +
  363 + /* update partition table */
  364 +
  365 + show_parts(device);
  366 +
  367 + nbd_client(fd, sock);
  368 + close(fd);
  369 + out:
  370 + kill(pid, SIGTERM);
  371 + unlink(socket);
  372 +
  373 + return ret;
  374 + }
  375 + /* children */
  376 + }
  377 +
  378 + if (socket) {
  379 + sock = unix_socket_incoming(socket);
  380 + } else {
  381 + sock = tcp_socket_incoming(bindto, port);
  382 + }
  383 +
255 384 if (sock == -1)
256 385 return 1;
257 386  
... ... @@ -270,6 +399,8 @@ int main(int argc, char **argv)
270 399 close(csock);
271 400 close(sock);
272 401 bdrv_close(bs);
  402 + if (socket)
  403 + unlink(socket);
273 404  
274 405 return 0;
275 406 }
... ...
qemu-nbd.texi
... ... @@ -20,10 +20,16 @@ Export Qemu disk image using NBD protocol.
20 20 offset into the image
21 21 @item -b, --bind=IFACE
22 22 interface to bind to (default `0.0.0.0')
  23 +@item -k, --socket=PATH
  24 + Use a unix socket with path PATH
23 25 @item -r, --read-only
24 26 export read-only
25 27 @item -P, --partition=NUM
26 28 only expose partition NUM
  29 +@item -c, --connect
  30 + connect FILE to NBD device DEV
  31 +@item -d, --disconnect
  32 + disconnect the specified device
27 33 @item -v, --verbose
28 34 display extra debugging information
29 35 @item -h, --help
... ...