From 01919ef8a123de84c6b4f7d21fb455d0d32db3a0 Mon Sep 17 00:00:00 2001 From: comatose Date: Sat, 1 Dec 2012 00:42:29 +0900 Subject: [PATCH 1/3] initial trim support --- buse.c | 234 ++++++++++++++++++++++++++++-------------------------- buse.h | 6 ++ busexmp.c | 40 +++++++--- 3 files changed, 155 insertions(+), 125 deletions(-) diff --git a/buse.c b/buse.c index 3992cd3..d92f908 100644 --- a/buse.c +++ b/buse.c @@ -18,149 +18,157 @@ */ #ifdef WORDS_BIGENDIAN u_int64_t ntohll(u_int64_t a) { - return a; + return a; } #else u_int64_t ntohll(u_int64_t a) { - u_int32_t lo = a & 0xffffffff; - u_int32_t hi = a >> 32U; - lo = ntohl(lo); - hi = ntohl(hi); - return ((u_int64_t) lo) << 32U | hi; + u_int32_t lo = a & 0xffffffff; + u_int32_t hi = a >> 32U; + lo = ntohl(lo); + hi = ntohl(hi); + return ((u_int64_t) lo) << 32U | hi; } #endif #define htonll ntohll static int read_all(int fd, void *buf, size_t count) { - int bytes_read; + int bytes_read; - while (count > 0) { - bytes_read = read(fd, buf, count); - assert(bytes_read > 0); - buf = (char *)buf + bytes_read; - count -= bytes_read; - } - assert(count == 0); + while (count > 0) { + bytes_read = read(fd, buf, count); + assert(bytes_read > 0); + buf = (char *)buf + bytes_read; + count -= bytes_read; + } + assert(count == 0); - return 0; + return 0; } static int write_all(int fd, const void *buf, size_t count) { - int bytes_written; + int bytes_written; - while (count > 0) { - bytes_written = write(fd, buf, count); - assert(bytes_written > 0); - buf = (char *)buf + bytes_written; - count -= bytes_written; - } - assert(count == 0); + while (count > 0) { + bytes_written = write(fd, buf, count); + assert(bytes_written > 0); + buf = (char *)buf + bytes_written; + count -= bytes_written; + } + assert(count == 0); - return 0; + return 0; } int buse_main(int argc, char *argv[], const struct buse_operations *aop, void *userdata) { - int sp[2]; - int nbd, sk, err, tmp_fd; - u_int64_t from; - u_int32_t len, bytes_read; - char *dev_file; - struct nbd_request request; - struct nbd_reply reply; - void *chunk; + int sp[2]; + int nbd, sk, err, tmp_fd; + u_int64_t from; + u_int32_t len; + ssize_t bytes_read; + char *dev_file; + struct nbd_request request; + struct nbd_reply reply; + void *chunk; - (void) userdata; + (void) userdata; - assert(argc == 3); - dev_file = argv[2]; + assert(argc == 3); + dev_file = argv[2]; - assert(!socketpair(AF_UNIX, SOCK_STREAM, 0, sp)); + assert(!socketpair(AF_UNIX, SOCK_STREAM, 0, sp)); - nbd = open(dev_file, O_RDWR); - assert(nbd != -1); + nbd = open(dev_file, O_RDWR); + assert(nbd != -1); - assert(ioctl(nbd, NBD_SET_SIZE, aop->size) != -1); + assert(ioctl(nbd, NBD_SET_SIZE, aop->size) != -1); + assert(ioctl(nbd, NBD_CLEAR_SOCK) != -1); + + if (!fork()) { + /* The child needs to continue setting things up. */ + close(sp[0]); + sk = sp[1]; + + if(ioctl(nbd, NBD_SET_SOCK, sk) == -1){ + fprintf(stderr, "ioctl(nbd, NBD_SET_SOCK, sk) failed.[%s]\n", strerror(errno)); + } + else if(ioctl(nbd, NBD_SET_FLAGS, NBD_FLAG_SEND_TRIM) == -1){ + fprintf(stderr, "ioctl(nbd, NBD_SET_FLAGS, NBD_FLAG_SEND_TRIM) failed.[%s]\n", strerror(errno)); + } + else{ + err = ioctl(nbd, NBD_DO_IT); + fprintf(stderr, "nbd device terminated with code %d\n", err); + if (err == -1) + fprintf(stderr, "%s\n", strerror(errno)); + } + + assert(ioctl(nbd, NBD_CLEAR_QUE) != -1); assert(ioctl(nbd, NBD_CLEAR_SOCK) != -1); - if (!fork()) { - /* The child needs to continue setting things up. */ - close(sp[0]); - sk = sp[1]; + exit(0); + } - assert(ioctl(nbd, NBD_SET_SOCK, sk) != -1); - err = ioctl(nbd, NBD_DO_IT); - fprintf(stderr, "nbd device terminated with code %d\n", err); - if (err == -1) - fprintf(stderr, "%s\n", strerror(errno)); + /* The parent opens the device file at least once, to make sure the + * partition table is updated. Then it closes it and starts serving up + * requests. */ - assert(ioctl(nbd, NBD_CLEAR_QUE) != -1); - assert(ioctl(nbd, NBD_CLEAR_SOCK) != -1); + tmp_fd = open(dev_file, O_RDONLY); + assert(tmp_fd != -1); + close(tmp_fd); - exit(0); + close(sp[1]); + sk = sp[0]; + + reply.magic = htonl(NBD_REPLY_MAGIC); + reply.error = htonl(0); + + while ((bytes_read = read(sk, &request, sizeof(request))) > 0) { + assert(bytes_read == sizeof(request)); + memcpy(reply.handle, request.handle, sizeof(reply.handle)); + + len = ntohl(request.len); + from = ntohll(request.from); + assert(request.magic == htonl(NBD_REQUEST_MAGIC)); + + switch(ntohl(request.type)) { + /* I may at some point need to deal with the the fact that the + * official nbd server has a maximum buffer size, and divides up + * oversized requests into multiple pieces. This applies to reads + * and writes. + */ + case NBD_CMD_READ: + /* fprintf(stderr, "Request for read of size %d\n", len); */ + chunk = malloc(len + sizeof(struct nbd_reply)); + aop->read((char *)chunk + sizeof(struct nbd_reply), len, from); + memcpy(chunk, &reply, sizeof(struct nbd_reply)); + write_all(sk, chunk, len + sizeof(struct nbd_reply)); + free(chunk); + break; + case NBD_CMD_WRITE: + /* fprintf(stderr, "Request for write of size %d\n", len); */ + chunk = malloc(len); + read_all(sk, chunk, len); + aop->write(chunk, len, from); + free(chunk); + write_all(sk, &reply, sizeof(struct nbd_reply)); + break; + case NBD_CMD_DISC: + /* Handle a disconnect request. */ + aop->disc(); + return 0; + case NBD_CMD_FLUSH: + aop->flush(); + break; + case NBD_CMD_TRIM: + aop->trim(from, len); + break; + default: + assert(0); } - - /* The parent opens the device file at least once, to make sure the - * partition table is updated. Then it closes it and starts serving up - * requests. */ - - tmp_fd = open(dev_file, O_RDONLY); - assert(tmp_fd != -1); - close(tmp_fd); - - close(sp[1]); - sk = sp[0]; - - reply.magic = htonl(NBD_REPLY_MAGIC); - reply.error = htonl(0); - - while (1) { - bytes_read = read(sk, &request, sizeof(request)); - assert(bytes_read == sizeof(request)); - memcpy(reply.handle, request.handle, sizeof(reply.handle)); - - len = ntohl(request.len); - from = ntohll(request.from); - assert(request.magic == htonl(NBD_REQUEST_MAGIC)); - - switch(ntohl(request.type)) { - /* I may at some point need to deal with the the fact that the - * official nbd server has a maximum buffer size, and divides up - * oversized requests into multiple pieces. This applies to reads - * and writes. - */ - case NBD_CMD_READ: - /* fprintf(stderr, "Request for read of size %d\n", len); */ - chunk = malloc(len + sizeof(struct nbd_reply)); - aop->read((char *)chunk + sizeof(struct nbd_reply), len, from); - memcpy(chunk, &reply, sizeof(struct nbd_reply)); - write_all(sk, chunk, len + sizeof(struct nbd_reply)); - free(chunk); - break; - case NBD_CMD_WRITE: - /* fprintf(stderr, "Request for write of size %d\n", len); */ - chunk = malloc(len); - read_all(sk, chunk, len); - aop->write(chunk, len, from); - free(chunk); - write_all(sk, &reply, sizeof(struct nbd_reply)); - break; - case NBD_CMD_DISC: - /* Handle a disconnect request. */ - aop->disc(); - return 0; - case NBD_CMD_FLUSH: - aop->flush(); - break; - case NBD_CMD_TRIM: - aop->trim(from, len); - break; - default: - assert(0); - } - } - - return 0; + } + if (bytes_read == -1) + fprintf(stderr, "%s\n", strerror(errno)); + return 0; } diff --git a/buse.h b/buse.h index a130d63..5d30b03 100644 --- a/buse.h +++ b/buse.h @@ -26,6 +26,12 @@ enum { NBD_CMD_TRIM = 4 }; +/* values for flags field */ +#define NBD_FLAG_HAS_FLAGS (1 << 0) +#define NBD_FLAG_READ_ONLY (1 << 1) +/* there is a gap here to match userspace */ +#define NBD_FLAG_SEND_TRIM (1 << 5) /* send trim/discard */ + /* Magic numbers */ #define NBD_REQUEST_MAGIC 0x25609513 #define NBD_REPLY_MAGIC 0x67446698 diff --git a/busexmp.c b/busexmp.c index 0045a8f..19ac257 100644 --- a/busexmp.c +++ b/busexmp.c @@ -8,32 +8,48 @@ static void *data; static int xmp_read(void *buf, u_int32_t len, u_int64_t offset) { - memcpy(buf, (char *)data + offset, len); - return 0; + memcpy(buf, (char *)data + offset, len); + fprintf(stderr, "R %lu %u\n", offset, len); + return 0; } static int xmp_write(const void *buf, u_int32_t len, u_int64_t offset) { - memcpy((char *)data + offset, buf, len); - return 0; + memcpy((char *)data + offset, buf, len); + fprintf(stderr, "W %lu %u\n", offset, len); + return 0; } static int xmp_disc() { - fprintf(stderr, "Received a disconnect request.\n"); - return 0; + fprintf(stderr, "Received a disconnect request.\n"); + return 0; +} + +static int xmp_flush() +{ + fprintf(stderr, "Received a flush request.\n"); + return 0; +} + +static int xmp_trim(u_int64_t from, u_int32_t len) +{ + fprintf(stderr, "T %lu %u\n", from, len); + return 0; } static struct buse_operations aop = { - .read = xmp_read, - .write = xmp_write, - .disc = xmp_disc, - .size = 128 * 1024 * 1024, + .read = xmp_read, + .write = xmp_write, + .disc = xmp_disc, + .flush = xmp_flush, + .trim = xmp_trim, + .size = 128 * 1024 * 1024, }; int main(int argc, char *argv[]) { - data = malloc(aop.size); + data = malloc(aop.size); - return buse_main(argc, argv, &aop, NULL); + return buse_main(argc, argv, &aop, NULL); } From 44b2f13ad448d5eaffa80a64d7b16a2ce2fd367e Mon Sep 17 00:00:00 2001 From: comatose Date: Sat, 1 Dec 2012 14:35:46 +0900 Subject: [PATCH 2/3] Add trim support. --- buse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/buse.c b/buse.c index d92f908..66bfde2 100644 --- a/buse.c +++ b/buse.c @@ -163,6 +163,7 @@ int buse_main(int argc, char *argv[], const struct buse_operations *aop, void *u break; case NBD_CMD_TRIM: aop->trim(from, len); + write_all(sk, &reply, sizeof(struct nbd_reply)); break; default: assert(0); From 408c99ba0b68f6486920cc057e466a98741a48f4 Mon Sep 17 00:00:00 2001 From: comatose Date: Sun, 2 Dec 2012 01:08:13 +0900 Subject: [PATCH 3/3] Added some error handling. --- buse.c | 32 +++++++++++++++++--------------- buse.h | 2 +- busexmp.c | 3 +-- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/buse.c b/buse.c index 66bfde2..1f4a403 100644 --- a/buse.c +++ b/buse.c @@ -31,14 +31,14 @@ u_int64_t ntohll(u_int64_t a) { #endif #define htonll ntohll -static int read_all(int fd, void *buf, size_t count) +static int read_all(int fd, char* buf, size_t count) { int bytes_read; while (count > 0) { bytes_read = read(fd, buf, count); assert(bytes_read > 0); - buf = (char *)buf + bytes_read; + buf += bytes_read; count -= bytes_read; } assert(count == 0); @@ -46,14 +46,14 @@ static int read_all(int fd, void *buf, size_t count) return 0; } -static int write_all(int fd, const void *buf, size_t count) +static int write_all(int fd, char* buf, size_t count) { int bytes_written; while (count > 0) { bytes_written = write(fd, buf, count); assert(bytes_written > 0); - buf = (char *)buf + bytes_written; + buf += bytes_written; count -= bytes_written; } assert(count == 0); @@ -71,7 +71,7 @@ int buse_main(int argc, char *argv[], const struct buse_operations *aop, void *u char *dev_file; struct nbd_request request; struct nbd_reply reply; - void *chunk; + char *chunk; (void) userdata; @@ -104,8 +104,8 @@ int buse_main(int argc, char *argv[], const struct buse_operations *aop, void *u fprintf(stderr, "%s\n", strerror(errno)); } - assert(ioctl(nbd, NBD_CLEAR_QUE) != -1); - assert(ioctl(nbd, NBD_CLEAR_SOCK) != -1); + ioctl(nbd, NBD_CLEAR_QUE); + ioctl(nbd, NBD_CLEAR_SOCK); exit(0); } @@ -141,29 +141,31 @@ int buse_main(int argc, char *argv[], const struct buse_operations *aop, void *u case NBD_CMD_READ: /* fprintf(stderr, "Request for read of size %d\n", len); */ chunk = malloc(len + sizeof(struct nbd_reply)); - aop->read((char *)chunk + sizeof(struct nbd_reply), len, from); - memcpy(chunk, &reply, sizeof(struct nbd_reply)); - write_all(sk, chunk, len + sizeof(struct nbd_reply)); + reply.error = aop->read((char *)chunk + sizeof(struct nbd_reply), len, from); + write_all(sk, (char*)&reply, sizeof(struct nbd_reply)); + if(reply.error == 0) + write_all(sk, (char*)chunk, len); free(chunk); break; case NBD_CMD_WRITE: /* fprintf(stderr, "Request for write of size %d\n", len); */ chunk = malloc(len); read_all(sk, chunk, len); - aop->write(chunk, len, from); + reply.error = aop->write(chunk, len, from); free(chunk); - write_all(sk, &reply, sizeof(struct nbd_reply)); + write_all(sk, (char*)&reply, sizeof(struct nbd_reply)); break; case NBD_CMD_DISC: /* Handle a disconnect request. */ aop->disc(); return 0; case NBD_CMD_FLUSH: - aop->flush(); + reply.error = aop->flush(); + write_all(sk, (char*)&reply, sizeof(struct nbd_reply)); break; case NBD_CMD_TRIM: - aop->trim(from, len); - write_all(sk, &reply, sizeof(struct nbd_reply)); + reply.error = aop->trim(from, len); + write_all(sk, (char*)&reply, sizeof(struct nbd_reply)); break; default: assert(0); diff --git a/buse.h b/buse.h index 5d30b03..bc4e43d 100644 --- a/buse.h +++ b/buse.h @@ -61,7 +61,7 @@ struct nbd_reply { struct buse_operations { int (*read)(void *buf, u_int32_t len, u_int64_t offset); int (*write)(const void *buf, u_int32_t len, u_int64_t offset); - int (*disc)(); + void (*disc)(); int (*flush)(); int (*trim)(u_int64_t from, u_int32_t len); diff --git a/busexmp.c b/busexmp.c index 19ac257..c4cb8be 100644 --- a/busexmp.c +++ b/busexmp.c @@ -20,10 +20,9 @@ static int xmp_write(const void *buf, u_int32_t len, u_int64_t offset) return 0; } -static int xmp_disc() +static void xmp_disc() { fprintf(stderr, "Received a disconnect request.\n"); - return 0; } static int xmp_flush()