Allow to share a disk image via nbd, by Laurent Vivier.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4837 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
2f7264888a
commit
3b05a8e91b
98
qemu-nbd.c
98
qemu-nbd.c
|
@ -55,6 +55,7 @@ static void usage(const char *name)
|
||||||
" -n, --nocache disable host cache\n"
|
" -n, --nocache disable host cache\n"
|
||||||
" -c, --connect=DEV connect FILE to the local NBD device DEV\n"
|
" -c, --connect=DEV connect FILE to the local NBD device DEV\n"
|
||||||
" -d, --disconnect disconnect the specified device\n"
|
" -d, --disconnect disconnect the specified device\n"
|
||||||
|
" -e, --shared=NUM device can be shared by NUM clients (default '1')\n"
|
||||||
" -v, --verbose display extra debugging information\n"
|
" -v, --verbose display extra debugging information\n"
|
||||||
" -h, --help display this help and exit\n"
|
" -h, --help display this help and exit\n"
|
||||||
" -V, --version output version information and exit\n"
|
" -V, --version output version information and exit\n"
|
||||||
|
@ -182,14 +183,13 @@ int main(int argc, char **argv)
|
||||||
bool disconnect = false;
|
bool disconnect = false;
|
||||||
const char *bindto = "0.0.0.0";
|
const char *bindto = "0.0.0.0";
|
||||||
int port = 1024;
|
int port = 1024;
|
||||||
int sock, csock;
|
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
socklen_t addr_len = sizeof(addr);
|
socklen_t addr_len = sizeof(addr);
|
||||||
off_t fd_size;
|
off_t fd_size;
|
||||||
char *device = NULL;
|
char *device = NULL;
|
||||||
char *socket = NULL;
|
char *socket = NULL;
|
||||||
char sockpath[128];
|
char sockpath[128];
|
||||||
const char *sopt = "hVbo:p:rsnP:c:dvk:";
|
const char *sopt = "hVbo:p:rsnP:c:dvk:e:";
|
||||||
struct option lopt[] = {
|
struct option lopt[] = {
|
||||||
{ "help", 0, 0, 'h' },
|
{ "help", 0, 0, 'h' },
|
||||||
{ "version", 0, 0, 'V' },
|
{ "version", 0, 0, 'V' },
|
||||||
|
@ -203,6 +203,7 @@ int main(int argc, char **argv)
|
||||||
{ "disconnect", 0, 0, 'd' },
|
{ "disconnect", 0, 0, 'd' },
|
||||||
{ "snapshot", 0, 0, 's' },
|
{ "snapshot", 0, 0, 's' },
|
||||||
{ "nocache", 0, 0, 'n' },
|
{ "nocache", 0, 0, 'n' },
|
||||||
|
{ "shared", 1, 0, 'e' },
|
||||||
{ "verbose", 0, 0, 'v' },
|
{ "verbose", 0, 0, 'v' },
|
||||||
{ NULL, 0, 0, 0 }
|
{ NULL, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
@ -212,9 +213,15 @@ int main(int argc, char **argv)
|
||||||
char *end;
|
char *end;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
int partition = -1;
|
int partition = -1;
|
||||||
int fd;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
int shared = 1;
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
|
fd_set fds;
|
||||||
|
int *sharing_fds;
|
||||||
|
int fd;
|
||||||
|
int i;
|
||||||
|
int nb_fds = 0;
|
||||||
|
int max_fd;
|
||||||
|
|
||||||
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
|
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
|
@ -267,6 +274,15 @@ int main(int argc, char **argv)
|
||||||
case 'c':
|
case 'c':
|
||||||
device = optarg;
|
device = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
|
shared = strtol(optarg, &end, 0);
|
||||||
|
if (*end) {
|
||||||
|
errx(EINVAL, "Invalid shared device number '%s'", optarg);
|
||||||
|
}
|
||||||
|
if (shared < 1) {
|
||||||
|
errx(EINVAL, "Shared device number must be greater than 0\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = 1;
|
verbose = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -320,8 +336,10 @@ int main(int argc, char **argv)
|
||||||
errx(errno, "Could not find partition %d", partition);
|
errx(errno, "Could not find partition %d", partition);
|
||||||
|
|
||||||
if (device) {
|
if (device) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
if (!verbose)
|
int sock;
|
||||||
|
|
||||||
|
if (!verbose)
|
||||||
daemon(0, 0); /* detach client and server */
|
daemon(0, 0); /* detach client and server */
|
||||||
|
|
||||||
if (socket == NULL) {
|
if (socket == NULL) {
|
||||||
|
@ -384,33 +402,69 @@ int main(int argc, char **argv)
|
||||||
/* children */
|
/* children */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sharing_fds = qemu_malloc((shared + 1) * sizeof(int));
|
||||||
|
if (sharing_fds == NULL)
|
||||||
|
errx(ENOMEM, "Cannot allocate sharing fds");
|
||||||
|
|
||||||
if (socket) {
|
if (socket) {
|
||||||
sock = unix_socket_incoming(socket);
|
sharing_fds[0] = unix_socket_incoming(socket);
|
||||||
} else {
|
} else {
|
||||||
sock = tcp_socket_incoming(bindto, port);
|
sharing_fds[0] = tcp_socket_incoming(bindto, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sock == -1)
|
if (sharing_fds[0] == -1)
|
||||||
return 1;
|
|
||||||
|
|
||||||
csock = accept(sock,
|
|
||||||
(struct sockaddr *)&addr,
|
|
||||||
&addr_len);
|
|
||||||
if (csock == -1)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* new fd_size is calculated by find_partition */
|
|
||||||
if (nbd_negotiate(bs, csock, fd_size) == -1)
|
|
||||||
return 1;
|
return 1;
|
||||||
|
max_fd = sharing_fds[0];
|
||||||
|
nb_fds++;
|
||||||
|
|
||||||
data = qemu_memalign(512, NBD_BUFFER_SIZE);
|
data = qemu_memalign(512, NBD_BUFFER_SIZE);
|
||||||
while (nbd_trip(bs, csock, fd_size, dev_offset, &offset, readonly,
|
if (data == NULL)
|
||||||
data, NBD_BUFFER_SIZE) == 0);
|
errx(ENOMEM, "Cannot allocate data buffer");
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
for (i = 0; i < nb_fds; i++)
|
||||||
|
FD_SET(sharing_fds[i], &fds);
|
||||||
|
|
||||||
|
ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
|
||||||
|
if (ret == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (FD_ISSET(sharing_fds[0], &fds))
|
||||||
|
ret--;
|
||||||
|
for (i = 1; i < nb_fds && ret; i++) {
|
||||||
|
if (FD_ISSET(sharing_fds[i], &fds)) {
|
||||||
|
if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
|
||||||
|
&offset, readonly, data, NBD_BUFFER_SIZE) != 0) {
|
||||||
|
close(sharing_fds[i]);
|
||||||
|
nb_fds--;
|
||||||
|
sharing_fds[i] = sharing_fds[nb_fds];
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
ret--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* new connection ? */
|
||||||
|
if (FD_ISSET(sharing_fds[0], &fds)) {
|
||||||
|
if (nb_fds < shared + 1) {
|
||||||
|
sharing_fds[nb_fds] = accept(sharing_fds[0],
|
||||||
|
(struct sockaddr *)&addr,
|
||||||
|
&addr_len);
|
||||||
|
if (sharing_fds[nb_fds] != -1 &&
|
||||||
|
nbd_negotiate(bs, sharing_fds[nb_fds], fd_size) != -1) {
|
||||||
|
if (sharing_fds[nb_fds] > max_fd)
|
||||||
|
max_fd = sharing_fds[nb_fds];
|
||||||
|
nb_fds++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (nb_fds > 1);
|
||||||
qemu_free(data);
|
qemu_free(data);
|
||||||
|
|
||||||
close(csock);
|
close(sharing_fds[0]);
|
||||||
close(sock);
|
|
||||||
bdrv_close(bs);
|
bdrv_close(bs);
|
||||||
|
qemu_free(sharing_fds);
|
||||||
if (socket)
|
if (socket)
|
||||||
unlink(socket);
|
unlink(socket);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,8 @@ Export Qemu disk image using NBD protocol.
|
||||||
connect FILE to NBD device DEV
|
connect FILE to NBD device DEV
|
||||||
@item -d, --disconnect
|
@item -d, --disconnect
|
||||||
disconnect the specified device
|
disconnect the specified device
|
||||||
|
@item -e, --shared=NUM
|
||||||
|
device can be shared by NUM clients (default '1')
|
||||||
@item -v, --verbose
|
@item -v, --verbose
|
||||||
display extra debugging information
|
display extra debugging information
|
||||||
@item -h, --help
|
@item -h, --help
|
||||||
|
|
Loading…
Reference in New Issue