summaryrefslogtreecommitdiffstats
path: root/source3/smbd
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2014-04-09 09:50:46 -0700
committerJeremy Allison <jra@samba.org>2014-04-10 19:49:07 +0200
commitf5a3d74264abb25009e73b1b35d62db34fa62343 (patch)
treecfd4920132af516deec1f33bf0e777847b7bcd15 /source3/smbd
parent88ba81140eb98494fb48ac29b9450e582ceaf10d (diff)
downloadsamba-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.c56
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) {