From owner-svn-src-all@FreeBSD.ORG Thu May 9 16:05:52 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 52088621; Thu, 9 May 2013 16:05:52 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 3362EF57; Thu, 9 May 2013 16:05:52 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.6/8.14.6) with ESMTP id r49G5qo4032339; Thu, 9 May 2013 16:05:52 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.6/8.14.5/Submit) id r49G5q8M032338; Thu, 9 May 2013 16:05:52 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201305091605.r49G5q8M032338@svn.freebsd.org> From: Konstantin Belousov Date: Thu, 9 May 2013 16:05:52 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r250409 - head/sys/kern X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 09 May 2013 16:05:52 -0000 Author: kib Date: Thu May 9 16:05:51 2013 New Revision: 250409 URL: http://svnweb.freebsd.org/changeset/base/250409 Log: Item 1 in r248830 causes earlier exits from the sendfile(2), before all requested data was sent. The reason is that xfsize <= 0 condition must not be tested at all if space == loopbytes. Otherwise, the done is set to 1, and sendfile(2) is aborted too early. Instead of moving the condition to exiting the inner loop after the xfersize check, directly check for the completed transfer before the testing of the available space in the socket buffer, and revert item 1 of r248830. It is arguably another bug to sleep waiting for socket buffer space (or return EAGAIN for non-blocking socket) if all bytes are already transferred. Reported by: pho Discussed with: scottl, gibbs Tested by: scottl (stable/9 backport), pho Modified: head/sys/kern/uipc_syscalls.c Modified: head/sys/kern/uipc_syscalls.c ============================================================================== --- head/sys/kern/uipc_syscalls.c Thu May 9 15:57:55 2013 (r250408) +++ head/sys/kern/uipc_syscalls.c Thu May 9 16:05:51 2013 (r250409) @@ -1956,6 +1956,17 @@ kern_sendfile(struct thread *td, struct goto out; vn_lock(vp, LK_SHARED | LK_RETRY); if (vp->v_type == VREG) { + bsize = vp->v_mount->mnt_stat.f_iosize; + if (uap->nbytes == 0) { + error = VOP_GETATTR(vp, &va, td->td_ucred); + if (error != 0) { + VOP_UNLOCK(vp, 0); + obj = NULL; + goto out; + } + rem = va.va_size; + } else + rem = uap->nbytes; obj = vp->v_object; if (obj != NULL) { /* @@ -1973,7 +1984,8 @@ kern_sendfile(struct thread *td, struct obj = NULL; } } - } + } else + bsize = 0; /* silence gcc */ VOP_UNLOCK(vp, 0); if (obj == NULL) { error = EINVAL; @@ -2065,11 +2077,20 @@ kern_sendfile(struct thread *td, struct * The outer loop checks the state and available space of the socket * and takes care of the overall progress. */ - for (off = uap->offset, rem = uap->nbytes; ; ) { - struct mbuf *mtail = NULL; - int loopbytes = 0; - int space = 0; - int done = 0; + for (off = uap->offset; ; ) { + struct mbuf *mtail; + int loopbytes; + int space; + int done; + + if ((uap->nbytes != 0 && uap->nbytes == fsbytes) || + (uap->nbytes == 0 && va.va_size == fsbytes)) + break; + + mtail = NULL; + loopbytes = 0; + space = 0; + done = 0; /* * Check the socket state for ongoing connection, @@ -2141,17 +2162,16 @@ retry_space: if (error != 0) goto done; error = VOP_GETATTR(vp, &va, td->td_ucred); - if (error != 0) { + if (error != 0 || off >= va.va_size) { VOP_UNLOCK(vp, 0); goto done; } - bsize = vp->v_mount->mnt_stat.f_iosize; /* * Loop and construct maximum sized mbuf chain to be bulk * dumped into socket buffer. */ - while (1) { + while (space > loopbytes) { vm_pindex_t pindex; vm_offset_t pgoff; struct mbuf *m0; @@ -2175,15 +2195,6 @@ retry_space: } /* - * We've already overfilled the socket. - * Let the outer loop figure out how to handle it. - */ - if (space <= loopbytes) { - done = 0; - break; - } - - /* * Attempt to look up the page. Allocate * if not found or wait and loop if busy. */