qemu-nbd: introduce NBDExport
Wrap the common parameters of nbd_trip and nbd_negotiate in a single opaque struct. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
a030b347aa
commit
af49bbbe78
64
nbd.c
64
nbd.c
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include "nbd.h"
|
#include "nbd.h"
|
||||||
#include "block.h"
|
#include "block.h"
|
||||||
|
#include "block_int.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -186,7 +187,7 @@ int unix_socket_outgoing(const char *path)
|
||||||
Request (type == 2)
|
Request (type == 2)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int nbd_negotiate(int csock, off_t size, uint32_t flags)
|
static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
|
||||||
{
|
{
|
||||||
char buf[8 + 8 + 8 + 128];
|
char buf[8 + 8 + 8 + 128];
|
||||||
|
|
||||||
|
@ -583,6 +584,33 @@ static int nbd_send_reply(int csock, struct nbd_reply *reply)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct NBDExport {
|
||||||
|
BlockDriverState *bs;
|
||||||
|
off_t dev_offset;
|
||||||
|
off_t size;
|
||||||
|
uint8_t *data;
|
||||||
|
uint32_t nbdflags;
|
||||||
|
};
|
||||||
|
|
||||||
|
NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset,
|
||||||
|
off_t size, uint32_t nbdflags)
|
||||||
|
{
|
||||||
|
NBDExport *exp = g_malloc0(sizeof(NBDExport));
|
||||||
|
exp->bs = bs;
|
||||||
|
exp->dev_offset = dev_offset;
|
||||||
|
exp->nbdflags = nbdflags;
|
||||||
|
exp->size = size == -1 ? exp->bs->total_sectors * 512 : size;
|
||||||
|
exp->data = qemu_blockalign(exp->bs, NBD_BUFFER_SIZE);
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nbd_export_close(NBDExport *exp)
|
||||||
|
{
|
||||||
|
qemu_vfree(exp->data);
|
||||||
|
bdrv_close(exp->bs);
|
||||||
|
g_free(exp);
|
||||||
|
}
|
||||||
|
|
||||||
static int nbd_do_send_reply(int csock, struct nbd_reply *reply,
|
static int nbd_do_send_reply(int csock, struct nbd_reply *reply,
|
||||||
uint8_t *data, int len)
|
uint8_t *data, int len)
|
||||||
{
|
{
|
||||||
|
@ -652,9 +680,7 @@ out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nbd_trip(BlockDriverState *bs, int csock, off_t size,
|
int nbd_trip(NBDExport *exp, int csock)
|
||||||
uint64_t dev_offset, uint32_t nbdflags,
|
|
||||||
uint8_t *data)
|
|
||||||
{
|
{
|
||||||
struct nbd_request request;
|
struct nbd_request request;
|
||||||
struct nbd_reply reply;
|
struct nbd_reply reply;
|
||||||
|
@ -662,7 +688,7 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size,
|
||||||
|
|
||||||
TRACE("Reading request.");
|
TRACE("Reading request.");
|
||||||
|
|
||||||
ret = nbd_do_receive_request(csock, &request, data);
|
ret = nbd_do_receive_request(csock, &request, exp->data);
|
||||||
if (ret == -EIO) {
|
if (ret == -EIO) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -675,10 +701,11 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size,
|
||||||
goto error_reply;
|
goto error_reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((request.from + request.len) > size) {
|
if ((request.from + request.len) > exp->size) {
|
||||||
LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
|
LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
|
||||||
", Offset: %" PRIu64 "\n",
|
", Offset: %" PRIu64 "\n",
|
||||||
request.from, request.len, (uint64_t)size, dev_offset);
|
request.from, request.len,
|
||||||
|
(uint64_t)exp->size, exp->dev_offset);
|
||||||
LOG("requested operation past EOF--bad client?");
|
LOG("requested operation past EOF--bad client?");
|
||||||
goto invalid_request;
|
goto invalid_request;
|
||||||
}
|
}
|
||||||
|
@ -687,8 +714,8 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size,
|
||||||
case NBD_CMD_READ:
|
case NBD_CMD_READ:
|
||||||
TRACE("Request type is READ");
|
TRACE("Request type is READ");
|
||||||
|
|
||||||
ret = bdrv_read(bs, (request.from + dev_offset) / 512,
|
ret = bdrv_read(exp->bs, (request.from + exp->dev_offset) / 512,
|
||||||
data, request.len / 512);
|
exp->data, request.len / 512);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG("reading from file failed");
|
LOG("reading from file failed");
|
||||||
reply.error = -ret;
|
reply.error = -ret;
|
||||||
|
@ -696,13 +723,13 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size,
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("Read %u byte(s)", request.len);
|
TRACE("Read %u byte(s)", request.len);
|
||||||
if (nbd_do_send_reply(csock, &reply, data, request.len) < 0)
|
if (nbd_do_send_reply(csock, &reply, exp->data, request.len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
case NBD_CMD_WRITE:
|
case NBD_CMD_WRITE:
|
||||||
TRACE("Request type is WRITE");
|
TRACE("Request type is WRITE");
|
||||||
|
|
||||||
if (nbdflags & NBD_FLAG_READ_ONLY) {
|
if (exp->nbdflags & NBD_FLAG_READ_ONLY) {
|
||||||
TRACE("Server is read-only, return error");
|
TRACE("Server is read-only, return error");
|
||||||
reply.error = EROFS;
|
reply.error = EROFS;
|
||||||
goto error_reply;
|
goto error_reply;
|
||||||
|
@ -710,8 +737,8 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size,
|
||||||
|
|
||||||
TRACE("Writing to device");
|
TRACE("Writing to device");
|
||||||
|
|
||||||
ret = bdrv_write(bs, (request.from + dev_offset) / 512,
|
ret = bdrv_write(exp->bs, (request.from + exp->dev_offset) / 512,
|
||||||
data, request.len / 512);
|
exp->data, request.len / 512);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG("writing to file failed");
|
LOG("writing to file failed");
|
||||||
reply.error = -ret;
|
reply.error = -ret;
|
||||||
|
@ -719,7 +746,7 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.type & NBD_CMD_FLAG_FUA) {
|
if (request.type & NBD_CMD_FLAG_FUA) {
|
||||||
ret = bdrv_flush(bs);
|
ret = bdrv_flush(exp->bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG("flush failed");
|
LOG("flush failed");
|
||||||
reply.error = -ret;
|
reply.error = -ret;
|
||||||
|
@ -737,7 +764,7 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size,
|
||||||
case NBD_CMD_FLUSH:
|
case NBD_CMD_FLUSH:
|
||||||
TRACE("Request type is FLUSH");
|
TRACE("Request type is FLUSH");
|
||||||
|
|
||||||
ret = bdrv_flush(bs);
|
ret = bdrv_flush(exp->bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG("flush failed");
|
LOG("flush failed");
|
||||||
reply.error = -ret;
|
reply.error = -ret;
|
||||||
|
@ -748,7 +775,7 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size,
|
||||||
break;
|
break;
|
||||||
case NBD_CMD_TRIM:
|
case NBD_CMD_TRIM:
|
||||||
TRACE("Request type is TRIM");
|
TRACE("Request type is TRIM");
|
||||||
ret = bdrv_discard(bs, (request.from + dev_offset) / 512,
|
ret = bdrv_discard(exp->bs, (request.from + exp->dev_offset) / 512,
|
||||||
request.len / 512);
|
request.len / 512);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG("discard failed");
|
LOG("discard failed");
|
||||||
|
@ -771,3 +798,8 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nbd_negotiate(NBDExport *exp, int csock)
|
||||||
|
{
|
||||||
|
return nbd_send_negotiate(csock, exp->size, exp->nbdflags);
|
||||||
|
}
|
||||||
|
|
11
nbd.h
11
nbd.h
|
@ -67,15 +67,20 @@ int tcp_socket_incoming_spec(const char *address_and_port);
|
||||||
int unix_socket_outgoing(const char *path);
|
int unix_socket_outgoing(const char *path);
|
||||||
int unix_socket_incoming(const char *path);
|
int unix_socket_incoming(const char *path);
|
||||||
|
|
||||||
int nbd_negotiate(int csock, off_t size, uint32_t flags);
|
|
||||||
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
|
||||||
off_t *size, size_t *blocksize);
|
off_t *size, size_t *blocksize);
|
||||||
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
|
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
|
||||||
int nbd_send_request(int csock, struct nbd_request *request);
|
int nbd_send_request(int csock, struct nbd_request *request);
|
||||||
int nbd_receive_reply(int csock, struct nbd_reply *reply);
|
int nbd_receive_reply(int csock, struct nbd_reply *reply);
|
||||||
int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
|
|
||||||
uint32_t nbdflags, uint8_t *data);
|
|
||||||
int nbd_client(int fd);
|
int nbd_client(int fd);
|
||||||
int nbd_disconnect(int fd);
|
int nbd_disconnect(int fd);
|
||||||
|
|
||||||
|
typedef struct NBDExport NBDExport;
|
||||||
|
|
||||||
|
NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset,
|
||||||
|
off_t size, uint32_t nbdflags);
|
||||||
|
void nbd_export_close(NBDExport *exp);
|
||||||
|
int nbd_negotiate(NBDExport *exp, int csock);
|
||||||
|
int nbd_trip(NBDExport *exp, int csock);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
15
qemu-nbd.c
15
qemu-nbd.c
|
@ -36,6 +36,7 @@
|
||||||
#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
|
#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
|
||||||
|
|
||||||
static int sigterm_wfd;
|
static int sigterm_wfd;
|
||||||
|
static NBDExport *exp;
|
||||||
static int verbose;
|
static int verbose;
|
||||||
static char *device;
|
static char *device;
|
||||||
static char *srcpath;
|
static char *srcpath;
|
||||||
|
@ -280,7 +281,6 @@ int main(int argc, char **argv)
|
||||||
int partition = -1;
|
int partition = -1;
|
||||||
int ret;
|
int ret;
|
||||||
int shared = 1;
|
int shared = 1;
|
||||||
uint8_t *data;
|
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
int *sharing_fds;
|
int *sharing_fds;
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -489,6 +489,7 @@ int main(int argc, char **argv)
|
||||||
err(EXIT_FAILURE, "Could not find partition %d", partition);
|
err(EXIT_FAILURE, "Could not find partition %d", partition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags);
|
||||||
sharing_fds = g_malloc((shared + 1) * sizeof(int));
|
sharing_fds = g_malloc((shared + 1) * sizeof(int));
|
||||||
|
|
||||||
if (sockpath) {
|
if (sockpath) {
|
||||||
|
@ -516,11 +517,6 @@ int main(int argc, char **argv)
|
||||||
max_fd = sharing_fds[0];
|
max_fd = sharing_fds[0];
|
||||||
nb_fds++;
|
nb_fds++;
|
||||||
|
|
||||||
data = qemu_blockalign(bs, NBD_BUFFER_SIZE);
|
|
||||||
if (data == NULL) {
|
|
||||||
errx(EXIT_FAILURE, "Cannot allocate data buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(sigterm_fd[0], &fds);
|
FD_SET(sigterm_fd[0], &fds);
|
||||||
|
@ -538,8 +534,7 @@ int main(int argc, char **argv)
|
||||||
ret--;
|
ret--;
|
||||||
for (i = 1; i < nb_fds && ret; i++) {
|
for (i = 1; i < nb_fds && ret; i++) {
|
||||||
if (FD_ISSET(sharing_fds[i], &fds)) {
|
if (FD_ISSET(sharing_fds[i], &fds)) {
|
||||||
if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
|
if (nbd_trip(exp, sharing_fds[i]) != 0) {
|
||||||
nbdflags, data) != 0) {
|
|
||||||
close(sharing_fds[i]);
|
close(sharing_fds[i]);
|
||||||
nb_fds--;
|
nb_fds--;
|
||||||
sharing_fds[i] = sharing_fds[nb_fds];
|
sharing_fds[i] = sharing_fds[nb_fds];
|
||||||
|
@ -555,7 +550,7 @@ int main(int argc, char **argv)
|
||||||
(struct sockaddr *)&addr,
|
(struct sockaddr *)&addr,
|
||||||
&addr_len);
|
&addr_len);
|
||||||
if (sharing_fds[nb_fds] != -1 &&
|
if (sharing_fds[nb_fds] != -1 &&
|
||||||
nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) {
|
nbd_negotiate(exp, sharing_fds[nb_fds]) != -1) {
|
||||||
if (sharing_fds[nb_fds] > max_fd)
|
if (sharing_fds[nb_fds] > max_fd)
|
||||||
max_fd = sharing_fds[nb_fds];
|
max_fd = sharing_fds[nb_fds];
|
||||||
nb_fds++;
|
nb_fds++;
|
||||||
|
@ -563,9 +558,9 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (persistent || nb_fds > 1);
|
} while (persistent || nb_fds > 1);
|
||||||
qemu_vfree(data);
|
|
||||||
|
|
||||||
close(sharing_fds[0]);
|
close(sharing_fds[0]);
|
||||||
|
nbd_export_close(exp);
|
||||||
g_free(sharing_fds);
|
g_free(sharing_fds);
|
||||||
if (sockpath) {
|
if (sockpath) {
|
||||||
unlink(sockpath);
|
unlink(sockpath);
|
||||||
|
|
Reference in New Issue