]> git.proxmox.com Git - qemu.git/blobdiff - nbd.c
QMP: Don't use do_info()
[qemu.git] / nbd.c
diff --git a/nbd.c b/nbd.c
index b397a5f48755e771ef9daf9c6f338c5a5fc00038..4bf2eb7cb07fafcd72f1e66be50c2a7951aef284 100644 (file)
--- a/nbd.c
+++ b/nbd.c
@@ -13,8 +13,7 @@
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "nbd.h"
@@ -50,6 +49,7 @@
 
 /* This is all part of the "official" NBD API */
 
+#define NBD_REPLY_SIZE         (4 + 4 + 8)
 #define NBD_REQUEST_MAGIC       0x25609513
 #define NBD_REPLY_MAGIC         0x67446698
 
@@ -63,6 +63,8 @@
 #define NBD_SET_SIZE_BLOCKS    _IO(0xab, 7)
 #define NBD_DISCONNECT          _IO(0xab, 8)
 
+#define NBD_OPT_EXPORT_NAME    (1 << 0)
+
 /* That's all folks */
 
 #define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
@@ -297,22 +299,27 @@ int nbd_negotiate(int csock, off_t size)
        return 0;
 }
 
-int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
+int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
+                          off_t *size, size_t *blocksize)
 {
-       char buf[8 + 8 + 8 + 128];
-       uint64_t magic;
+       char buf[256];
+       uint64_t magic, s;
+       uint16_t tmp;
 
        TRACE("Receiving negotation.");
 
-       if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+       if (read_sync(csock, buf, 8) != 8) {
                LOG("read failed");
                errno = EINVAL;
                return -1;
        }
 
-       magic = be64_to_cpup((uint64_t*)(buf + 8));
-       *size = be64_to_cpup((uint64_t*)(buf + 16));
-       *blocksize = 1024;
+       buf[8] = '\0';
+       if (strlen(buf) == 0) {
+               LOG("server connection closed");
+               errno = EINVAL;
+               return -1;
+       }
 
        TRACE("Magic is %c%c%c%c%c%c%c%c",
              qemu_isprint(buf[0]) ? buf[0] : '.',
@@ -323,8 +330,6 @@ int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
              qemu_isprint(buf[5]) ? buf[5] : '.',
              qemu_isprint(buf[6]) ? buf[6] : '.',
              qemu_isprint(buf[7]) ? buf[7] : '.');
-       TRACE("Magic is 0x%" PRIx64, magic);
-       TRACE("Size is %" PRIu64, *size);
 
        if (memcmp(buf, "NBDMAGIC", 8) != 0) {
                LOG("Invalid magic received");
@@ -332,10 +337,99 @@ int nbd_receive_negotiate(int csock, off_t *size, size_t *blocksize)
                return -1;
        }
 
-       TRACE("Checking magic");
+       if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+               LOG("read failed");
+               errno = EINVAL;
+               return -1;
+       }
+       magic = be64_to_cpu(magic);
+       TRACE("Magic is 0x%" PRIx64, magic);
+
+       if (name) {
+               uint32_t reserved = 0;
+               uint32_t opt;
+               uint32_t namesize;
+
+               TRACE("Checking magic (opts_magic)");
+               if (magic != 0x49484156454F5054LL) {
+                       LOG("Bad magic received");
+                       errno = EINVAL;
+                       return -1;
+               }
+               if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+                       LOG("flags read failed");
+                       errno = EINVAL;
+                       return -1;
+               }
+               *flags = be16_to_cpu(tmp) << 16;
+               /* reserved for future use */
+               if (write_sync(csock, &reserved, sizeof(reserved)) !=
+                   sizeof(reserved)) {
+                       LOG("write failed (reserved)");
+                       errno = EINVAL;
+                       return -1;
+               }
+               /* write the export name */
+               magic = cpu_to_be64(magic);
+               if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+                       LOG("write failed (magic)");
+                       errno = EINVAL;
+                       return -1;
+               }
+               opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
+               if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
+                       LOG("write failed (opt)");
+                       errno = EINVAL;
+                       return -1;
+               }
+               namesize = cpu_to_be32(strlen(name));
+               if (write_sync(csock, &namesize, sizeof(namesize)) !=
+                   sizeof(namesize)) {
+                       LOG("write failed (namesize)");
+                       errno = EINVAL;
+                       return -1;
+               }
+               if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
+                       LOG("write failed (name)");
+                       errno = EINVAL;
+                       return -1;
+               }
+       } else {
+               TRACE("Checking magic (cli_magic)");
+
+               if (magic != 0x00420281861253LL) {
+                       LOG("Bad magic received");
+                       errno = EINVAL;
+                       return -1;
+               }
+       }
+
+       if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
+               LOG("read failed");
+               errno = EINVAL;
+               return -1;
+       }
+       *size = be64_to_cpu(s);
+       *blocksize = 1024;
+       TRACE("Size is %" PRIu64, *size);
 
-       if (magic != 0x00420281861253LL) {
-               LOG("Bad magic received");
+       if (!name) {
+               if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
+                       LOG("read failed (flags)");
+                       errno = EINVAL;
+                       return -1;
+               }
+               *flags = be32_to_cpup(flags);
+       } else {
+               if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+                       LOG("read failed (tmp)");
+                       errno = EINVAL;
+                       return -1;
+               }
+               *flags |= be32_to_cpu(tmp);
+       }
+       if (read_sync(csock, &buf, 124) != 124) {
+               LOG("read failed (buf)");
                errno = EINVAL;
                return -1;
        }
@@ -354,8 +448,7 @@ int nbd_init(int fd, int csock, off_t size, size_t blocksize)
                return -1;
        }
 
-       TRACE("Setting size to %llu block(s)",
-             (unsigned long long)(size / blocksize));
+        TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
 
        if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
                int serrno = errno;
@@ -395,7 +488,7 @@ int nbd_disconnect(int fd)
        return 0;
 }
 
-int nbd_client(int fd, int csock)
+int nbd_client(int fd)
 {
        int ret;
        int serrno;
@@ -429,7 +522,7 @@ int nbd_disconnect(int fd)
     return -1;
 }
 
-int nbd_client(int fd, int csock)
+int nbd_client(int fd)
 {
     errno = ENOTSUP;
     return -1;
@@ -496,7 +589,7 @@ static int nbd_receive_request(int csock, struct nbd_request *request)
 
 int nbd_receive_reply(int csock, struct nbd_reply *reply)
 {
-       uint8_t buf[4 + 4 + 8];
+       uint8_t buf[NBD_REPLY_SIZE];
        uint32_t magic;
 
        memset(buf, 0xAA, sizeof(buf));
@@ -563,9 +656,9 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
        if (nbd_receive_request(csock, &request) == -1)
                return -1;
 
-       if (request.len > data_size) {
+       if (request.len + NBD_REPLY_SIZE > data_size) {
                LOG("len (%u) is larger than max len (%u)",
-                   request.len, data_size);
+                   request.len + NBD_REPLY_SIZE, data_size);
                errno = EINVAL;
                return -1;
        }
@@ -595,7 +688,8 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
        case NBD_CMD_READ:
                TRACE("Request type is READ");
 
-               if (bdrv_read(bs, (request.from + dev_offset) / 512, data,
+               if (bdrv_read(bs, (request.from + dev_offset) / 512,
+                             data + NBD_REPLY_SIZE,
                              request.len / 512) == -1) {
                        LOG("reading from file failed");
                        errno = EINVAL;
@@ -605,12 +699,21 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
 
                TRACE("Read %u byte(s)", request.len);
 
-               if (nbd_send_reply(csock, &reply) == -1)
-                       return -1;
+               /* Reply
+                  [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
+                  [ 4 ..  7]    error   (0 == no error)
+                  [ 7 .. 15]    handle
+                */
+
+               cpu_to_be32w((uint32_t*)data, NBD_REPLY_MAGIC);
+               cpu_to_be32w((uint32_t*)(data + 4), reply.error);
+               cpu_to_be64w((uint64_t*)(data + 8), reply.handle);
 
                TRACE("Sending data to client");
 
-               if (write_sync(csock, data, request.len) != request.len) {
+               if (write_sync(csock, data,
+                              request.len + NBD_REPLY_SIZE) !=
+                              request.len + NBD_REPLY_SIZE) {
                        LOG("writing to socket failed");
                        errno = EINVAL;
                        return -1;