summaryrefslogtreecommitdiffstats
path: root/sys/kern/uipc_syscalls.c
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2013-03-28 14:14:28 +0000
committerscottl <scottl@FreeBSD.org>2013-03-28 14:14:28 +0000
commit84ae5b84bb4c87e71b9e80c17fd03a8499aae847 (patch)
treeacd2b86f2021d4b53cb86e95ca60833e2467f52a /sys/kern/uipc_syscalls.c
parent08624e38f4a313eef84f0267a519509c7cbd873f (diff)
downloadFreeBSD-src-84ae5b84bb4c87e71b9e80c17fd03a8499aae847.zip
FreeBSD-src-84ae5b84bb4c87e71b9e80c17fd03a8499aae847.tar.gz
Several fixes and improvements to sendfile()
1. If we wanted to send exactly as many bytes as the socket buffer is sized for, the inner loop of kern_sendfile() would see that the socket is full before seeing that it had no more bytes left to send. This would cause it to return EAGAIN to the caller instead of success. Fix by changing the order that these conditions are tested. 2. Simplify the calculation for the bytes to send in each iteration of the inner loop of kern_sendfile() 3. Fix some calls with bogus arguments to sf_buf_ext(). These would only trigger on mbuf allocation failure, but would be hilariously bad if they did trigger. Submitted by: gibbs(3), andre(2) Reviewed by: emax, andre Obtained from: Netflix MFC after: 1 week
Diffstat (limited to 'sys/kern/uipc_syscalls.c')
-rw-r--r--sys/kern/uipc_syscalls.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index 42a1ff1..3ee48c8 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -2115,7 +2115,7 @@ retry_space:
* Loop and construct maximum sized mbuf chain to be bulk
* dumped into socket buffer.
*/
- while (space > loopbytes) {
+ while (1) {
vm_pindex_t pindex;
vm_offset_t pgoff;
struct mbuf *m0;
@@ -2127,15 +2127,12 @@ retry_space:
* or the passed in nbytes.
*/
pgoff = (vm_offset_t)(off & PAGE_MASK);
- xfsize = omin(PAGE_SIZE - pgoff,
- obj->un_pager.vnp.vnp_size - uap->offset -
- fsbytes - loopbytes);
if (uap->nbytes)
rem = (uap->nbytes - fsbytes - loopbytes);
else
rem = obj->un_pager.vnp.vnp_size -
uap->offset - fsbytes - loopbytes;
- xfsize = omin(rem, xfsize);
+ xfsize = omin(PAGE_SIZE - pgoff, rem);
xfsize = omin(space - loopbytes, xfsize);
if (xfsize <= 0) {
VM_OBJECT_WUNLOCK(obj);
@@ -2144,6 +2141,16 @@ retry_space:
}
/*
+ * We've already overfilled the socket.
+ * Let the outer loop figure out how to handle it.
+ */
+ if (space <= loopbytes) {
+ VM_OBJECT_WUNLOCK(obj);
+ done = 0;
+ break;
+ }
+
+ /*
* Attempt to look up the page. Allocate
* if not found or wait and loop if busy.
*/
@@ -2249,14 +2256,14 @@ retry_space:
m0 = m_get((mnw ? M_NOWAIT : M_WAITOK), MT_DATA);
if (m0 == NULL) {
error = (mnw ? EAGAIN : ENOBUFS);
- sf_buf_mext((void *)sf_buf_kva(sf), sf);
+ sf_buf_mext(NULL, sf);
break;
}
if (m_extadd(m0, (caddr_t )sf_buf_kva(sf), PAGE_SIZE,
sf_buf_mext, sfs, sf, M_RDONLY, EXT_SFBUF,
(mnw ? M_NOWAIT : M_WAITOK)) != 0) {
error = (mnw ? EAGAIN : ENOBUFS);
- sf_buf_mext((void *)sf_buf_kva(sf), sf);
+ sf_buf_mext(NULL, sf);
m_freem(m0);
break;
}
OpenPOWER on IntegriCloud