svn commit: r358320 - head/sys/kern
Gleb Smirnoff
glebius at FreeBSD.org
Tue Feb 25 19:29:09 UTC 2020
Author: glebius
Date: Tue Feb 25 19:29:05 2020
New Revision: 358320
URL: https://svnweb.freebsd.org/changeset/base/358320
Log:
Generalize resources freeing in sendfile with different scenarios.
Now we execute sendfile_iodone() in all possible cases, which
guarantees that vm_object_pip_wakeup() is called and sfio structure
is freed.
At the beginning of sendfile initialize sfio->m to NULL, that would
indicate that the mbuf chain either doesn't exist, or belongs to the
syscall (not to I/O completion). Fill sfio->m only at a point when
we are positive that there are I/Os ongoing and before releasing
syscall's reference on sfio.
In sendfile_iodone() perform vm_object_pip_wakeup() once last
reference is released, then check for sfio->m. NULL pointer
indicates that we need only to free the memory.
Reviewed by: jtl, gallatin
Modified:
head/sys/kern/kern_sendfile.c
Modified: head/sys/kern/kern_sendfile.c
==============================================================================
--- head/sys/kern/kern_sendfile.c Tue Feb 25 19:26:40 2020 (r358319)
+++ head/sys/kern/kern_sendfile.c Tue Feb 25 19:29:05 2020 (r358320)
@@ -258,7 +258,7 @@ static void
sendfile_iodone(void *arg, vm_page_t *pg, int count, int error)
{
struct sf_io *sfio = arg;
- struct socket *so = sfio->so;
+ struct socket *so;
for (int i = 0; i < count; i++)
if (pg[i] != bogus_page)
@@ -272,12 +272,15 @@ sendfile_iodone(void *arg, vm_page_t *pg, int count, i
vm_object_pip_wakeup(sfio->obj);
- if (__predict_false(sfio->error && sfio->m == NULL)) {
+ if (sfio->m == NULL) {
/*
- * I/O operation failed, but pru_send hadn't been executed -
- * nothing had been sent to the socket. The syscall has
- * returned error to the user.
+ * Either I/O operation failed, or we failed to allocate
+ * buffers, or we bailed out on first busy page, or we
+ * succeeded filling the request without any I/Os. Anyway,
+ * pru_send hadn't been executed - nothing had been sent
+ * to the socket yet.
*/
+ MPASS((curthread->td_pflags & TDP_KTHREAD) == 0);
free(sfio, M_TEMP);
return;
}
@@ -291,6 +294,7 @@ sendfile_iodone(void *arg, vm_page_t *pg, int count, i
KASSERT(sfio->tls == NULL,
("non-ext_pgs mbuf with TLS session"));
#endif
+ so = sfio->so;
CURVNET_SET(so->so_vnet);
if (__predict_false(sfio->error)) {
/*
@@ -663,7 +667,7 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *h
for (off = offset; rem > 0; ) {
struct sf_io *sfio;
vm_page_t *pa;
- struct mbuf *mtail;
+ struct mbuf *m0, *mtail;
int nios, space, npages, rhpages;
mtail = NULL;
@@ -819,11 +823,9 @@ retry_space:
sfio = malloc(sizeof(struct sf_io) +
npages * sizeof(vm_page_t), M_TEMP, M_WAITOK);
refcount_init(&sfio->nios, 1);
- sfio->so = so;
sfio->obj = obj;
sfio->error = 0;
- vm_object_pip_add(obj, 1);
-
+ sfio->m = NULL;
#ifdef KERN_TLS
/*
* This doesn't use ktls_hold() because sfio->m will
@@ -832,13 +834,12 @@ retry_space:
*/
sfio->tls = tls;
#endif
-
+ vm_object_pip_add(obj, 1);
error = sendfile_swapin(obj, sfio, &nios, off, space, npages,
rhpages, flags);
if (error != 0) {
if (vp != NULL)
VOP_UNLOCK(vp);
- sfio->m = NULL;
sendfile_iodone(sfio, NULL, 0, error);
goto done;
}
@@ -876,8 +877,6 @@ retry_space:
}
for (int i = 0; i < npages; i++) {
- struct mbuf *m0;
-
/*
* If a page wasn't grabbed successfully, then
* trim the array. Can happen only with SF_NODISKIO.
@@ -922,8 +921,6 @@ retry_space:
mtx_unlock(&sfs->mtx);
}
ext_pgs = m0->m_ext.ext_pgs;
- if (i == 0)
- sfio->m = m0;
ext_pgs_idx = 0;
/* Append to mbuf chain. */
@@ -1006,9 +1003,6 @@ retry_space:
(vmoff(i, off) & PAGE_MASK);
m0->m_len = xfsize(i, npages, off, space);
- if (i == 0)
- sfio->m = m0;
-
/* Append to mbuf chain. */
if (mtail != NULL)
mtail->m_next = m0;
@@ -1024,18 +1018,22 @@ retry_space:
off += space;
rem -= space;
- /* Prepend header, if any. */
+ /*
+ * Prepend header, if any. Save pointer to first mbuf
+ * with a page.
+ */
if (hdrlen) {
prepend_header:
- mhtail->m_next = m;
+ m0 = mhtail->m_next = m;
m = mh;
mh = NULL;
- }
+ } else
+ m0 = m;
if (m == NULL) {
KASSERT(softerr, ("%s: m NULL, no error", __func__));
error = softerr;
- free(sfio, M_TEMP);
+ sendfile_iodone(sfio, NULL, 0, 0);
goto done;
}
@@ -1052,14 +1050,13 @@ prepend_header:
if (nios == 0) {
/*
* If sendfile_swapin() didn't initiate any I/Os,
- * which happens if all data is cached in VM, then
- * we can send data right now without the
- * PRUS_NOTREADY flag.
+ * which happens if all data is cached in VM, or if
+ * the header consumed all socket buffer space and
+ * sfio is NULL, then we can send data right now
+ * without the PRUS_NOTREADY flag.
*/
- if (sfio != NULL) {
- vm_object_pip_wakeup(sfio->obj);
- free(sfio, M_TEMP);
- }
+ if (sfio != NULL)
+ sendfile_iodone(sfio, NULL, 0, 0);
#ifdef KERN_TLS
if (tls != NULL && tls->mode == TCP_TLS_MODE_SW) {
error = (*so->so_proto->pr_usrreqs->pru_send)
@@ -1071,6 +1068,8 @@ prepend_header:
error = (*so->so_proto->pr_usrreqs->pru_send)
(so, 0, m, NULL, NULL, td);
} else {
+ sfio->so = so;
+ sfio->m = m0;
sfio->npages = npages;
soref(so);
error = (*so->so_proto->pr_usrreqs->pru_send)
More information about the svn-src-all
mailing list