diff options
author | Jeremy Allison <jra@samba.org> | 2014-04-09 09:50:46 -0700 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2014-04-10 19:49:07 +0200 |
commit | f5a3d74264abb25009e73b1b35d62db34fa62343 (patch) | |
tree | cfd4920132af516deec1f33bf0e777847b7bcd15 /source3/smbd | |
parent | 88ba81140eb98494fb48ac29b9450e582ceaf10d (diff) | |
download | samba-f5a3d74264abb25009e73b1b35d62db34fa62343.tar.gz samba-f5a3d74264abb25009e73b1b35d62db34fa62343.tar.xz samba-f5a3d74264abb25009e73b1b35d62db34fa62343.zip |
s3: smbd: Performance optimization for RECVFILE.
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>
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/vfs.c | 56 |
1 files changed, 43 insertions, 13 deletions
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index bc9157a8871..897bf1f338e 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -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) { |