s3: smbd: Performance optimization for RECVFILE.
authorJeremy Allison <jra@samba.org>
Wed, 9 Apr 2014 16:50:46 +0000 (09:50 -0700)
committerJeremy Allison <jra@samba.org>
Thu, 10 Apr 2014 17:49:07 +0000 (19:49 +0200)
Based on work proposed by Jones <jones.kstw@gmail.com>.

Removes set_blocking()/set_unblocking() fcntl
calls around RECVFILE on the non-blocking socket.
Instead uses RECVFILE in a loop, and only drops
back to set_blocking()/set_unblocking() once
RECVFILE returns -1/EAGAIN/EWOULDBLOCK.

From the samba-technical list:

------------------------------------------------
The iometer 512b sequential write shows following result,
Before applying this patch: 75333 IOps
After applying this patch: 82691 IOps
------------------------------------------------

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/smbd/vfs.c

index bc9157a88719387d2db64f00e076abd158139eb3..897bf1f338e37f2ca1dec7ceb49c83853415fa6a 100644 (file)
@@ -473,24 +473,54 @@ ssize_t vfs_pwrite_data(struct smb_request *req,
 
        if (req && req->unread_bytes) {
                int sockfd = req->sconn->sock;
-               int old_flags;
                SMB_ASSERT(req->unread_bytes == N);
                /* VFS_RECVFILE must drain the socket
                 * before returning. */
                req->unread_bytes = 0;
-               /* Ensure the socket is blocking. */
-               old_flags = fcntl(sockfd, F_GETFL, 0);
-               if (set_blocking(sockfd, true) == -1) {
-                       return (ssize_t)-1;
-               }
-               ret = SMB_VFS_RECVFILE(sockfd,
-                                       fsp,
-                                       offset,
-                                       N);
-               if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
-                       return (ssize_t)-1;
+               /*
+                * Leave the socket non-blocking and
+                * use SMB_VFS_RECVFILE. If it returns
+                * EAGAIN || EWOULDBLOCK temporarily set
+                * the socket blocking and retry
+                * the RECVFILE.
+                */
+               while (total < N) {
+                       ret = SMB_VFS_RECVFILE(sockfd,
+                                               fsp,
+                                               offset + total,
+                                               N - total);
+#if defined(EWOULDBLOCK)
+                       if (ret == 0 || (ret == -1 &&
+                               (errno == EAGAIN || errno == EWOULDBLOCK))) {
+#else /* EWOULDBLOCK */
+                       if (ret == 0 || (ret == -1 && errno == EAGAIN)) {
+#endif /* EWOULDBLOCK */
+                               int old_flags;
+                               /* Ensure the socket is blocking. */
+                               old_flags = fcntl(sockfd, F_GETFL, 0);
+                               if (set_blocking(sockfd, true) == -1) {
+                                       return (ssize_t)-1;
+                               }
+                               ret = SMB_VFS_RECVFILE(sockfd,
+                                                       fsp,
+                                                       offset + total,
+                                                       N - total);
+                               if (fcntl(sockfd, F_SETFL, old_flags) == -1) {
+                                       return (ssize_t)-1;
+                               }
+                               if (ret == -1) {
+                                       return (ssize_t)-1;
+                               }
+                               total += ret;
+                               return (ssize_t)total;
+                       }
+                       /* Any other error case. */
+                       if (ret == -1) {
+                               return ret;
+                       }
+                       total += ret;
                }
-               return ret;
+               return (ssize_t)total;
        }
 
        while (total < N) {