diff options
author | Hani Benhabiles <kroosec@gmail.com> | 2014-06-07 01:32:32 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-06-30 12:50:17 +0200 |
commit | 32d7d2e068756874518f97d5a114e43d8977980b (patch) | |
tree | df8d79c7d4d4693e95f4f28373171c28c856b373 /nbd.c | |
parent | f5076b5a759cb9b25ab377bbad453801db78a43e (diff) | |
download | qemu-32d7d2e068756874518f97d5a114e43d8977980b.tar.gz qemu-32d7d2e068756874518f97d5a114e43d8977980b.tar.bz2 qemu-32d7d2e068756874518f97d5a114e43d8977980b.zip |
nbd: Handle NBD_OPT_LIST option.
Signed-off-by: Hani Benhabiles <kroosec@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'nbd.c')
-rw-r--r-- | nbd.c | 65 |
1 files changed, 65 insertions, 0 deletions
@@ -84,6 +84,7 @@ #define NBD_OPT_EXPORT_NAME (1) #define NBD_OPT_ABORT (2) +#define NBD_OPT_LIST (3) /* Definitions for opaque data types */ @@ -249,6 +250,64 @@ static int nbd_send_rep(int csock, uint32_t type, uint32_t opt) return 0; } +static int nbd_send_rep_list(int csock, NBDExport *exp) +{ + uint64_t magic, name_len; + uint32_t opt, type, len; + + name_len = strlen(exp->name); + magic = cpu_to_be64(NBD_REP_MAGIC); + if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) { + LOG("write failed (magic)"); + return -EINVAL; + } + opt = cpu_to_be32(NBD_OPT_LIST); + if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) { + LOG("write failed (opt)"); + return -EINVAL; + } + type = cpu_to_be32(NBD_REP_SERVER); + if (write_sync(csock, &type, sizeof(type)) != sizeof(type)) { + LOG("write failed (reply type)"); + return -EINVAL; + } + len = cpu_to_be32(name_len + sizeof(len)); + if (write_sync(csock, &len, sizeof(len)) != sizeof(len)) { + LOG("write failed (length)"); + return -EINVAL; + } + len = cpu_to_be32(name_len); + if (write_sync(csock, &len, sizeof(len)) != sizeof(len)) { + LOG("write failed (length)"); + return -EINVAL; + } + if (write_sync(csock, exp->name, name_len) != name_len) { + LOG("write failed (buffer)"); + return -EINVAL; + } + return 0; +} + +static int nbd_handle_list(NBDClient *client, uint32_t length) +{ + int csock; + NBDExport *exp; + + csock = client->sock; + if (length) { + return nbd_send_rep(csock, NBD_REP_ERR_INVALID, NBD_OPT_LIST); + } + + /* For each export, send a NBD_REP_SERVER reply. */ + QTAILQ_FOREACH(exp, &exports, next) { + if (nbd_send_rep_list(csock, exp)) { + return -EINVAL; + } + } + /* Finish with a NBD_REP_ACK. */ + return nbd_send_rep(csock, NBD_REP_ACK, NBD_OPT_LIST); +} + static int nbd_handle_export_name(NBDClient *client, uint32_t length) { int rc = -EINVAL, csock = client->sock; @@ -330,6 +389,12 @@ static int nbd_receive_options(NBDClient *client) TRACE("Checking option"); switch (be32_to_cpu(tmp)) { + case NBD_OPT_LIST: + if (nbd_handle_list(client, length) < 0) { + return 1; + } + break; + case NBD_OPT_ABORT: return -EINVAL; |