]> git.proxmox.com Git - qemu.git/blobdiff - nbd.c
fix spelling in libcacard sub directory
[qemu.git] / nbd.c
diff --git a/nbd.c b/nbd.c
index 0dcd86b52fba3d963a67ef873243c8b3c78d21d0..e6c931c5ceed95387dd7455bfb2110a23a96caf7 100644 (file)
--- a/nbd.c
+++ b/nbd.c
@@ -17,6 +17,7 @@
  */
 
 #include "nbd.h"
+#include "block.h"
 
 #include <errno.h>
 #include <string.h>
 #include <ctype.h>
 #include <inttypes.h>
 
+#ifdef __linux__
+#include <linux/fs.h>
+#endif
+
 #include "qemu_socket.h"
 
 //#define DEBUG_NBD
@@ -62,6 +67,8 @@
 #define NBD_PRINT_DEBUG         _IO(0xab, 6)
 #define NBD_SET_SIZE_BLOCKS     _IO(0xab, 7)
 #define NBD_DISCONNECT          _IO(0xab, 8)
+#define NBD_SET_TIMEOUT         _IO(0xab, 9)
+#define NBD_SET_FLAGS           _IO(0xab, 10)
 
 #define NBD_OPT_EXPORT_NAME     (1 << 0)
 
@@ -78,7 +85,7 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
         ssize_t len;
 
         if (do_read) {
-            len = recv(fd, buffer + offset, size - offset, 0);
+            len = qemu_recv(fd, buffer + offset, size - offset, 0);
         } else {
             len = send(fd, buffer + offset, size - offset, 0);
         }
@@ -171,7 +178,7 @@ int unix_socket_outgoing(const char *path)
                   Request (type == 2)
 */
 
-int nbd_negotiate(int csock, off_t size)
+int nbd_negotiate(int csock, off_t size, uint32_t flags)
 {
     char buf[8 + 8 + 8 + 128];
 
@@ -179,14 +186,16 @@ int nbd_negotiate(int csock, off_t size)
         [ 0 ..   7]   passwd   ("NBDMAGIC")
         [ 8 ..  15]   magic    (0x00420281861253)
         [16 ..  23]   size
-        [24 .. 151]   reserved (0)
+        [24 ..  27]   flags
+        [28 .. 151]   reserved (0)
      */
 
     TRACE("Beginning negotiation.");
     memcpy(buf, "NBDMAGIC", 8);
     cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
     cpu_to_be64w((uint64_t*)(buf + 16), size);
-    memset(buf + 24, 0, 128);
+    cpu_to_be32w((uint32_t*)(buf + 24), flags | NBD_FLAG_HAS_FLAGS);
+    memset(buf + 28, 0, 124);
 
     if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
         LOG("write failed");
@@ -336,8 +345,8 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
         return 0;
 }
 
-#ifndef _WIN32
-int nbd_init(int fd, int csock, off_t size, size_t blocksize)
+#ifdef __linux__
+int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
 {
     TRACE("Setting block size to %lu", (unsigned long)blocksize);
 
@@ -357,6 +366,26 @@ int nbd_init(int fd, int csock, off_t size, size_t blocksize)
         return -1;
     }
 
+    if (flags & NBD_FLAG_READ_ONLY) {
+        int read_only = 1;
+        TRACE("Setting readonly attribute");
+
+        if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
+            int serrno = errno;
+            LOG("Failed setting read-only attribute");
+            errno = serrno;
+            return -1;
+        }
+    }
+
+    if (ioctl(fd, NBD_SET_FLAGS, flags) < 0
+        && errno != ENOTTY) {
+        int serrno = errno;
+        LOG("Failed setting flags");
+        errno = serrno;
+        return -1;
+    }
+
     TRACE("Clearing NBD socket");
 
     if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
@@ -396,6 +425,13 @@ int nbd_client(int fd)
     TRACE("Doing NBD loop");
 
     ret = ioctl(fd, NBD_DO_IT);
+    if (ret == -1 && errno == EPIPE) {
+        /* NBD_DO_IT normally returns EPIPE when someone has disconnected
+         * the socket via NBD_DISCONNECT.  We do not want to return 1 in
+         * that case.
+         */
+        ret = 0;
+    }
     serrno = errno;
 
     TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
@@ -410,7 +446,7 @@ int nbd_client(int fd)
     return ret;
 }
 #else
-int nbd_init(int fd, int csock, off_t size, size_t blocksize)
+int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
 {
     errno = ENOTSUP;
     return -1;
@@ -547,7 +583,7 @@ static int nbd_send_reply(int csock, struct nbd_reply *reply)
 }
 
 int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
-             off_t *offset, bool readonly, uint8_t *data, int data_size)
+             off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size)
 {
     struct nbd_request request;
     struct nbd_reply reply;
@@ -631,7 +667,7 @@ int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
             return -1;
         }
 
-        if (readonly) {
+        if (nbdflags & NBD_FLAG_READ_ONLY) {
             TRACE("Server is read-only, return error");
             reply.error = 1;
         } else {