mirror of https://github.com/xqemu/xqemu.git
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"
|
||||
" -c, --connect=DEV connect FILE to the local NBD device DEV\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"
|
||||
" -h, --help display this help and exit\n"
|
||||
" -V, --version output version information and exit\n"
|
||||
|
@ -182,14 +183,13 @@ int main(int argc, char **argv)
|
|||
bool disconnect = false;
|
||||
const char *bindto = "0.0.0.0";
|
||||
int port = 1024;
|
||||
int sock, csock;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
off_t fd_size;
|
||||
char *device = NULL;
|
||||
char *socket = NULL;
|
||||
char sockpath[128];
|
||||
const char *sopt = "hVbo:p:rsnP:c:dvk:";
|
||||
const char *sopt = "hVbo:p:rsnP:c:dvk:e:";
|
||||
struct option lopt[] = {
|
||||
{ "help", 0, 0, 'h' },
|
||||
{ "version", 0, 0, 'V' },
|
||||
|
@ -203,6 +203,7 @@ int main(int argc, char **argv)
|
|||
{ "disconnect", 0, 0, 'd' },
|
||||
{ "snapshot", 0, 0, 's' },
|
||||
{ "nocache", 0, 0, 'n' },
|
||||
{ "shared", 1, 0, 'e' },
|
||||
{ "verbose", 0, 0, 'v' },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
@ -212,9 +213,15 @@ int main(int argc, char **argv)
|
|||
char *end;
|
||||
int flags = 0;
|
||||
int partition = -1;
|
||||
int fd;
|
||||
int ret;
|
||||
int shared = 1;
|
||||
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) {
|
||||
switch (ch) {
|
||||
|
@ -267,6 +274,15 @@ int main(int argc, char **argv)
|
|||
case 'c':
|
||||
device = optarg;
|
||||
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':
|
||||
verbose = 1;
|
||||
break;
|
||||
|
@ -320,8 +336,10 @@ int main(int argc, char **argv)
|
|||
errx(errno, "Could not find partition %d", partition);
|
||||
|
||||
if (device) {
|
||||
pid_t pid;
|
||||
if (!verbose)
|
||||
pid_t pid;
|
||||
int sock;
|
||||
|
||||
if (!verbose)
|
||||
daemon(0, 0); /* detach client and server */
|
||||
|
||||
if (socket == NULL) {
|
||||
|
@ -384,33 +402,69 @@ int main(int argc, char **argv)
|
|||
/* children */
|
||||
}
|
||||
|
||||
sharing_fds = qemu_malloc((shared + 1) * sizeof(int));
|
||||
if (sharing_fds == NULL)
|
||||
errx(ENOMEM, "Cannot allocate sharing fds");
|
||||
|
||||
if (socket) {
|
||||
sock = unix_socket_incoming(socket);
|
||||
sharing_fds[0] = unix_socket_incoming(socket);
|
||||
} else {
|
||||
sock = tcp_socket_incoming(bindto, port);
|
||||
sharing_fds[0] = tcp_socket_incoming(bindto, port);
|
||||
}
|
||||
|
||||
if (sock == -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)
|
||||
if (sharing_fds[0] == -1)
|
||||
return 1;
|
||||
max_fd = sharing_fds[0];
|
||||
nb_fds++;
|
||||
|
||||
data = qemu_memalign(512, NBD_BUFFER_SIZE);
|
||||
while (nbd_trip(bs, csock, fd_size, dev_offset, &offset, readonly,
|
||||
data, NBD_BUFFER_SIZE) == 0);
|
||||
if (data == NULL)
|
||||
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);
|
||||
|
||||
close(csock);
|
||||
close(sock);
|
||||
close(sharing_fds[0]);
|
||||
bdrv_close(bs);
|
||||
qemu_free(sharing_fds);
|
||||
if (socket)
|
||||
unlink(socket);
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ Export Qemu disk image using NBD protocol.
|
|||
connect FILE to NBD device DEV
|
||||
@item -d, --disconnect
|
||||
disconnect the specified device
|
||||
@item -e, --shared=NUM
|
||||
device can be shared by NUM clients (default '1')
|
||||
@item -v, --verbose
|
||||
display extra debugging information
|
||||
@item -h, --help
|
||||
|
|
Loading…
Reference in New Issue