Fix handling of oversized requests
authorWouter Verhelst <w@uter.be>
Fri, 28 Jan 2011 12:19:30 +0000 (13:19 +0100)
committerWouter Verhelst <w@uter.be>
Fri, 28 Jan 2011 12:21:32 +0000 (13:21 +0100)
Previously, nbd-server would not serve requests that were over 1MB in
size. This was a problem, and even a bug since the kernel does send such
requests.

Modify the server so that it loops if the request is larger than 1MB.

nbd-server.c

index b47da86..51b725c 100644 (file)
@@ -1364,7 +1364,10 @@ int mainloop(CLIENT *client) {
        reply.error = 0;
        while (go_on) {
                char buf[BUFSIZE];
+               char* p;
                size_t len;
+               size_t currlen;
+               size_t writelen;
 #ifdef DODBG
                i++;
                printf("%d: ", i);
@@ -1389,8 +1392,12 @@ int mainloop(CLIENT *client) {
 
                if (request.magic != htonl(NBD_REQUEST_MAGIC))
                        err("Not enough magic.");
-               if (len > BUFSIZE - sizeof(struct nbd_reply))
-                       err("Request too big!");
+               if (len > BUFSIZE - sizeof(struct nbd_reply)) {
+                       currlen = BUFSIZE - sizeof(struct nbd_reply);
+                       msg("INFO: oversized request (this is not a problem)");
+               } else {
+                       currlen = len;
+               }
 #ifdef DODBG
                printf("%s from %llu (%llu) len %d, ", request.type ? "WRITE" :
                                "READ", (unsigned long long)request.from,
@@ -1411,35 +1418,47 @@ int mainloop(CLIENT *client) {
 
                if (request.type==NBD_CMD_WRITE) {
                        DEBUG("wr: net->buf, ");
-                       readit(client->net, buf, len);
-                       DEBUG("buf->exp, ");
-                       if ((client->server->flags & F_READONLY) ||
-                           (client->server->flags & F_AUTOREADONLY)) {
-                               DEBUG("[WRITE to READONLY!]");
-                               ERROR(client, reply, EPERM);
-                               continue;
-                       }
-                       if (expwrite(request.from, buf, len, client)) {
-                               DEBUG("Write failed: %m" );
-                               ERROR(client, reply, errno);
-                               continue;
+                       while(len > 0) {
+                               readit(client->net, buf, currlen);
+                               DEBUG("buf->exp, ");
+                               if ((client->server->flags & F_READONLY) ||
+                                   (client->server->flags & F_AUTOREADONLY)) {
+                                       DEBUG("[WRITE to READONLY!]");
+                                       ERROR(client, reply, EPERM);
+                                       continue;
+                               }
+                               if (expwrite(request.from, buf, len, client)) {
+                                       DEBUG("Write failed: %m" );
+                                       ERROR(client, reply, errno);
+                                       continue;
+                               }
+                               SEND(client->net, reply);
+                               DEBUG("OK!\n");
+                               len -= currlen;
+                               currlen = (len < BUFSIZE) ? len : BUFSIZE;
                        }
-                       SEND(client->net, reply);
-                       DEBUG("OK!\n");
                        continue;
                }
                /* READ */
 
                DEBUG("exp->buf, ");
-               if (expread(request.from, buf + sizeof(struct nbd_reply), len, client)) {
-                       DEBUG("Read failed: %m");
-                       ERROR(client, reply, errno);
-                       continue;
-               }
-
-               DEBUG("buf->net, ");
                memcpy(buf, &reply, sizeof(struct nbd_reply));
-               writeit(client->net, buf, len + sizeof(struct nbd_reply));
+               p = buf + sizeof(struct nbd_reply);
+               writelen = currlen + sizeof(struct nbd_reply);
+               while(len > 0) {
+                       if (expread(request.from, p, currlen, client)) {
+                               DEBUG("Read failed: %m");
+                               ERROR(client, reply, errno);
+                               continue;
+                       }
+
+                       DEBUG("buf->net, ");
+                       writeit(client->net, buf, writelen);
+                       len -= currlen;
+                       currlen = (len < BUFSIZE) ? len : BUFSIZE;
+                       p = buf;
+                       writelen = currlen;
+               }
                DEBUG("OK!\n");
        }
        return 0;