Date: Sun, 23 Feb 2014 08:22:31 +0000 (UTC) From: Gleb Smirnoff <glebius@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r262357 - projects/sendfile/sys/kern Message-ID: <201402230822.s1N8MVCN019741@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: glebius Date: Sun Feb 23 08:22:31 2014 New Revision: 262357 URL: http://svnweb.freebsd.org/changeset/base/262357 Log: Fixes to new sendfile: - Add function fixspace() that subtracts from space amount of bytes, contained in pages that failed. Use this function on failures, otherwise space won't match actual space sent to socket. - Do not leak mh mbuf chain on failures. - Do not leak vnode lock on malloc failure. - Do not leak wirings on m_get() failure. Sponsored by: Netflix Sponsored by: Nginx, Inc. Modified: projects/sendfile/sys/kern/uipc_syscalls.c Modified: projects/sendfile/sys/kern/uipc_syscalls.c ============================================================================== --- projects/sendfile/sys/kern/uipc_syscalls.c Sun Feb 23 07:26:58 2014 (r262356) +++ projects/sendfile/sys/kern/uipc_syscalls.c Sun Feb 23 08:22:31 2014 (r262357) @@ -2648,6 +2648,36 @@ vmoff(int i, off_t off) return (trunc_page(off + i * PAGE_SIZE)); } +/* + * Pretend as if we don't have enough space, subtract xfsize() of + * all pages that failed. + */ +static inline void +fixspace(int old, int new, off_t off, int *space) +{ + + KASSERT(old > new, ("%s: old %d new %d", __func__, old, new)); + + /* Subtract last one. */ + *space -= xfsize(old - 1, old, off, *space); + old--; + + if (new == old) + /* There was only one page. */ + return; + + /* Subtract first one. */ + if (new == 0) { + *space -= xfsize(0, old, off, *space); + new++; + } + + /* Rest of pages are full sized. */ + *space -= (old - new) * PAGE_SIZE; + + KASSERT(*space >= 0, ("%s: space went backwards", __func__)); +} + struct sf_io { u_int nios; int npages; @@ -2862,7 +2892,7 @@ vn_sendfile(struct file *fp, int sockfd, obj = NULL; so = NULL; - m = NULL; + m = mh = NULL; sbytes = 0; error = sendfile_getobj(td, fp, &obj, &vp, &shmfd, &obj_size, &bsize); @@ -2915,10 +2945,8 @@ vn_sendfile(struct file *fp, int sockfd, goto out; } hdrlen = m_length(mh, &mhtail); - } else { - mh = NULL; + } else hdrlen = 0; - } rem = nbytes ? omin(nbytes, obj_size - offset) : obj_size - offset; @@ -3043,6 +3071,8 @@ retry_space: sfio = malloc(sizeof(struct sf_io) + npages * sizeof(vm_page_t), M_TEMP, mwait); if (sfio == NULL) { + if (vp != NULL) + VOP_UNLOCK(vp, 0); error = merror; goto done; } @@ -3079,6 +3109,7 @@ retry_space: } if (m == NULL) error = merror; + fixspace(npages, i, off, &space); break; } @@ -3088,21 +3119,28 @@ retry_space: */ m0 = m_get(mwait, MT_DATA); if (m0 == NULL) { - error = merror; + for (int j = i; j < npages; j++) { + vm_page_lock(pa[j]); + vm_page_unwire(pa[j], 0); + vm_page_unlock(pa[j]); + } (void)sf_buf_mext(NULL, NULL, sf); + error = merror; + fixspace(npages, i, off, &space); break; } if (m_extadd(m0, (caddr_t )sf_buf_kva(sf), PAGE_SIZE, sf_buf_mext, sfs, sf, M_RDONLY, EXT_SFBUF, mwait) != 0) { - for (int j = i + 1; j < npages; j++) { + for (int j = i; j < npages; j++) { vm_page_lock(pa[j]); vm_page_unwire(pa[j], 0); vm_page_unlock(pa[j]); } - error = merror; (void)sf_buf_mext(NULL, NULL, sf); m_freem(m0); + error = merror; + fixspace(npages, i, off, &space); break; } m0->m_data = (char *)sf_buf_kva(sf) + @@ -3139,6 +3177,7 @@ retry_space: if (hdrlen) { mhtail->m_next = m; m = mh; + mh = NULL; } if (error) { @@ -3208,6 +3247,8 @@ out: fdrop(sock_fp, td); if (m) m_freem(m); + if (mh) + m_freem(mh); if (error == ERESTART) error = EINTR;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201402230822.s1N8MVCN019741>