[PATCH] Fix bug 9412 - SMB2 server doesn't support recvfile.

Jeremy Allison jra at samba.org
Mon Apr 7 16:24:15 MDT 2014


On Mon, Apr 07, 2014 at 06:43:35PM +0800, Jones wrote:
> 2014-04-03 18:11 GMT+08:00 Jones <jones.kstw at gmail.com>:
> 
>           2014-04-03 2:06 GMT+08:00 Stefan (metze)
>           Metzmacher <metze at samba.org>:
> 
>           And turn the socket into blocking mode once we get EAGAIN?
> 
>      Add poll_one_fd() and infinite waiting for socket fd is ready to
>      read.
> 
> 
> Hello Jeremy, Metze,
> 
> After lookup the BUGS section in man page select/poll,
> it seems not a good idea to select/poll a fd with O_NONBLOCK,
> my modification may cause undefined behavior which is platform dependent.
> 
> After checking sys_sendfile(),
> a preliminary thought prompt to handle the EAGAIN in sys_recvfile(),
> please kindly help comment,
> thanks.

Jones, can you test the following ?

If it works for you in reducing CPU usage
I'll add your name to it and propose it
for mater.

Cheers,

	Jeremy.
-------------- next part --------------
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index bc9157a..897bf1f3 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) {


More information about the samba-technical mailing list