Merge branch 'master' into extension-write-zeroes
authorAlex Bligh <alex@alex.org.uk>
Thu, 15 Dec 2016 09:40:33 +0000 (09:40 +0000)
committerAlex Bligh <alex@alex.org.uk>
Thu, 15 Dec 2016 09:40:33 +0000 (09:40 +0000)
Signed-off-by: Alex Bligh <alex@alex.org.uk>
1  2 
doc/proto.md
nbd-server.c
nbd.h

diff --cc doc/proto.md
@@@ -678,10 -683,20 +683,20 @@@ The field has the following format
    medium, and the client MAY schedule I/O accesses in a manner corresponding
    to the setting of this flag.
  - bit 5, `NBD_FLAG_SEND_TRIM`: exposes support for `NBD_CMD_TRIM`.
 -- bit 6, `NBD_FLAG_SEND_WRITE_ZEROES`: defined by the
 -  experimental `WRITE_ZEROES` [extension](https://github.com/NetworkBlockDevice/nbd/blob/extension-write-zeroes/doc/proto.md).
 +- bit 6, `NBD_FLAG_SEND_WRITE_ZEROES`: exposes support for
 +  `NBD_CMD_WRITE_ZEROES` and `NBD_CMD_FLAG_NO_HOLE`.
  - bit 7, `NBD_FLAG_SEND_DF`: defined by the experimental `STRUCTURED_REPLY`
-   [extension](https://github.com/yoe/nbd/blob/extension-structured-reply/doc/proto.md).
+   [extension](https://github.com/NetworkBlockDevice/nbd/blob/extension-structured-reply/doc/proto.md).
+ - bit 8, `NBD_FLAG_CAN_MULTI_CONN`: Indicates that the server operates
+   entirely without cache, or that the cache it uses is shared among all
+   connections to the given device. In particular, if this flag is
+   present, then the effects of `NBD_CMD_FLUSH` and `NBD_CMD_FLAG_FUA`
+   MUST be visible across all connections when the server sends its reply
+   to that command to the client. In the absense of this flag, clients
+   SHOULD NOT multiplex their commands over more than one connection to
+   the export.
+ - bit 9, `NBD_FLAG_SEND_BLOCK_STATUS`: defined by the experimental
+   `BLOCK_STATUS` [extension](https://github.com/NetworkBlockDevice/nbd/blob/extension-blockstatus/doc/proto.md).
  
  Clients SHOULD ignore unknown flags.
  
@@@ -868,14 -883,10 +883,14 @@@ valid may depend on negotiation during 
    not in fact write data (for instance on an `NBD_CMD_TRIM` in a situation
    where the command as a whole is ignored), the server MAY ignore this bit
    being set on such a command.
 -- bit 1, `NBD_CMD_FLAG_NO_HOLE`; defined by the experimental `WRITE_ZEROES`
 -  [extension](https://github.com/NetworkBlockDevice/nbd/blob/extension-write-zeroes/doc/proto.md).
 +- bit 1, `NBD_CMD_FLAG_NO_HOLE`; valid during `NBD_CMD_WRITE_ZEROES`.
 +  SHOULD be set to 1 if the client wants to ensure that the server does
 +  not create a hole. The client MAY send `NBD_CMD_FLAG_NO_HOLE` even
 +  if `NBD_FLAG_SEND_TRIM` was not set in the transmission flags field.
 +  The server MUST support the use of this flag if it advertises
 +  `NBD_FLAG_SEND_WRITE_ZEROES`.
  - bit 2, `NBD_CMD_FLAG_DF`; defined by the experimental `STRUCTURED_REPLY`
-   [extension](https://github.com/yoe/nbd/blob/extension-structured-reply/doc/proto.md).
+   [extension](https://github.com/NetworkBlockDevice/nbd/blob/extension-structured-reply/doc/proto.md).
  
  
  #### Request types
diff --cc nbd-server.c
@@@ -1185,39 -1398,6 +1400,38 @@@ int expwrite(off_t a, char *buf, size_
        return 0;
  }
  
- int expwrite_zeroes(struct nbd_request* req, CLIENT* client) {
 +
 +/**
 + * Write an amount of zeroes at a given offset to the right file.
 + * This routine could be optimised by not calling expwrite. However,
 + * this is by far the simplest way to do it.
 + *
 + * @param req the request
 + * @param client The client we're going to write for.
 + * @return 0 on success, nonzero on failure
 + **/
-       int fua = !!(req->type & NBD_CMD_FLAG_FUA);
++int expwrite_zeroes(struct nbd_request* req, CLIENT* client, int fua) {
 +      off_t a = req->from;
 +      size_t len = req->len;
 +      size_t maxsize = 64LL*1024LL*1024LL;
 +      /* use calloc() as sadly MAP_ANON is apparently not POSIX standard */
 +      char *buf = calloc (1, maxsize);
 +      int ret;
 +      while (len > 0) {
 +              size_t l = len;
 +              if (l > maxsize)
 +                      l = maxsize;
 +              ret = expwrite(a, buf, l, client, fua);
 +              if (ret) {
 +                      free(buf);
 +                      return ret;
 +              }
 +              len -= l;
 +      }
 +      free(buf);
 +      return 0;
 +}
 +
  /**
   * Flush data to a client
   *
@@@ -1417,10 -1704,9 +1738,9 @@@ hard_close
  
  void send_export_info(CLIENT* client) {
        uint64_t size_host = htonll((u64)(client->exportsize));
 -      uint16_t flags = NBD_FLAG_HAS_FLAGS;
 +      uint16_t flags = NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_WRITE_ZEROES;
  
-       if (write(client->net, &size_host, 8) < 0)
-               err("Negotiation failed/9: %m");
+       socket_write(client, &size_host, 8);
        if (client->server->flags & F_READONLY)
                flags |= NBD_FLAG_READ_ONLY;
        if (client->server->flags & F_FLUSH)
@@@ -1506,8 -1859,27 +1893,27 @@@ static void handle_normal_read(CLIENT *
        free(buf);
  }
  
- static void handle_write(CLIENT* client, struct nbd_request* req, void* data) {
+ static void handle_read(CLIENT* client, struct nbd_request* req)
+ {
+ #ifdef HAVE_SPLICE
+       /*
+        * If we have splice set we want to try that first, and if that fails
+        * for whatever reason we fall through to ye olde read.
+        */
+       if (client->server->flags & F_SPLICE)
+               if (!handle_splice_read(client, req))
+                       return;
+ #endif
+       handle_normal_read(client, req);
+ }
+ static void handle_write(struct work_package *pkg)
+ {
+       CLIENT *client = pkg->client;
+       struct nbd_request *req = pkg->req;
        struct nbd_reply rep;
 -      int fua = req->type & ~NBD_CMD_MASK_COMMAND;
++      int fua = !!(req->type & NBD_CMD_FLAG_FUA);
        DEBUG("handling write request\n");
        setup_reply(&rep, req);
  
@@@ -1552,22 -1932,6 +1966,27 @@@ static void handle_trim(CLIENT* client
        pthread_mutex_unlock(&(client->lock));
  }
  
-       if(expwrite_zeroes(req, client)) {
 +static void handle_write_zeroes(CLIENT* client, struct nbd_request* req) {
 +      struct nbd_reply rep;
 +      DEBUG("handling write_zeroes request\n");
++      int fua = !!(req->type & NBD_CMD_FLAG_FUA);
 +      setup_reply(&rep, req);
++      if ((client->server->flags & F_READONLY) ||
++          (client->server->flags & F_AUTOREADONLY)) {
++              DEBUG("[WRITE to READONLY!]");
++              rep.error = nbd_errno(EPERM);
++      } else if(expwrite_zeroes(req, client, fua)) {
 +              DEBUG("Write_zeroes failed: %m");
 +              rep.error = nbd_errno(errno);
 +      }
 +      // For now, don't trim
 +      // TODO: handle this far more efficiently with reference to the
 +      // actual backing driver
 +      pthread_mutex_lock(&(client->lock));
 +      writeit(client->net, &rep, sizeof rep);
 +      pthread_mutex_unlock(&(client->lock));
 +}
 +
  static void handle_request(gpointer data, gpointer user_data) {
        struct work_package* package = (struct work_package*) data;
        uint32_t type = package->req->type & NBD_CMD_MASK_COMMAND;
@@@ -1813,24 -2182,9 +2240,25 @@@ int mainloop(CLIENT *client) 
                                ERROR(client, reply, errno);
                                continue;
                        }
-                       SEND(client->net, reply);
+                       SEND(client, reply);
                        continue;
  
-                       if (expwrite_zeroes(&request, client)) {
 +              case NBD_CMD_WRITE_ZEROES:
 +                      if ((client->server->flags & F_READONLY) ||
 +                          (client->server->flags & F_AUTOREADONLY)) {
 +                              DEBUG("[WRITE_ZEROES to READONLY!]");
 +                              ERROR(client, reply, EPERM);
 +                              continue;
 +                      }
-                       SEND(client->net, reply);
++                      if (expwrite_zeroes(&request, client,
++                                          request.type & NBD_CMD_FLAG_FUA)) {
 +                              DEBUG("Write zeroes failed: %m");
 +                              ERROR(client, reply, errno);
 +                              continue;
 +                      }
++                      SEND(client, reply);
 +                      continue;
 +
                default:
                        DEBUG ("Ignoring unknown command\n");
                        continue;
diff --cc nbd.h
Simple merge