From c6efc78b2882500d1a2fd6581e7040063d5fceb5 Mon Sep 17 00:00:00 2001 From: Wouter Verhelst Date: Fri, 28 Jan 2011 13:19:30 +0100 Subject: [PATCH] Fix handling of oversized requests 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 | 67 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/nbd-server.c b/nbd-server.c index b47da86..51b725c 100644 --- a/nbd-server.c +++ b/nbd-server.c @@ -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; -- 1.7.10.4