From a43caef195168afbe03d1d4a962e643322322c40 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Thu, 9 Jan 2014 00:11:14 +0000 Subject: [PATCH] Refactor out the common sendfile code from the do_sendfile() and the compat32 sendfile syscall. Sponsored by: Netflix, Inc. --- sys/compat/freebsd32/freebsd32_misc.c | 27 +------- sys/kern/uipc_syscalls.c | 93 +++++++++++++++------------ sys/sys/sf_base.h | 36 +++++++++++ 3 files changed, 92 insertions(+), 64 deletions(-) create mode 100644 sys/sys/sf_base.h diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 3b267456229..c8681c6e3f8 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -86,6 +86,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #ifdef INET #include @@ -1651,8 +1652,6 @@ freebsd32_do_sendfile(struct thread *td, struct sf_hdtr hdtr; struct uio *hdr_uio, *trl_uio; struct iovec32 *iov32; - struct file *fp; - cap_rights_t rights; off_t offset; int error; off_t sbytes; @@ -1690,29 +1689,9 @@ freebsd32_do_sendfile(struct thread *td, } } - AUDIT_ARG_FD(uap->fd); + error = _do_sendfile(td, uap->fd, uap->s, uap->flags, compat, + offset, uap->nbytes, &sbytes, hdr_uio, trl_uio); - if ((error = fget_read(td, uap->fd, - cap_rights_init(&rights, CAP_PREAD), &fp)) != 0) { - goto out; - } - - /* - * If we need to wait for completion, initialise the sfsync - * state here. - */ - if (uap->flags & SF_SYNC) - sfs = sf_sync_alloc(uap->flags & SF_SYNC); - - error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, offset, - uap->nbytes, &sbytes, uap->flags, compat ? SFK_COMPAT : 0, - sfs, td); - if (sfs != NULL) { - sf_sync_syscall_wait(sfs); - sf_sync_free(sfs); - } - - fdrop(fp, td); if (uap->sbytes != NULL) copyout(&sbytes, uap->sbytes, sizeof(off_t)); diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 3243f562787..6dbdd522a2d 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -1988,51 +1989,23 @@ sys_sendfile(struct thread *td, struct sendfile_args *uap) return (do_sendfile(td, uap, 0)); } -static int -do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) +int +_do_sendfile(struct thread *td, int src_fd, int sock_fd, int flags, + int compat, off_t offset, size_t nbytes, off_t *sbytes, + struct uio *hdr_uio, struct uio *trl_uio) { - struct sf_hdtr hdtr; - struct uio *hdr_uio, *trl_uio; - struct file *fp; cap_rights_t rights; + struct sendfile_sync *sfs = NULL; + struct file *fp; int error; - off_t sbytes; - struct sendfile_sync *sfs; - /* - * File offset must be positive. If it goes beyond EOF - * we send only the header/trailer and no payload data. - */ - if (uap->offset < 0) - return (EINVAL); - - hdr_uio = trl_uio = NULL; - sfs = NULL; - - if (uap->hdtr != NULL) { - error = copyin(uap->hdtr, &hdtr, sizeof(hdtr)); - if (error != 0) - goto out; - if (hdtr.headers != NULL) { - error = copyinuio(hdtr.headers, hdtr.hdr_cnt, &hdr_uio); - if (error != 0) - goto out; - } - if (hdtr.trailers != NULL) { - error = copyinuio(hdtr.trailers, hdtr.trl_cnt, &trl_uio); - if (error != 0) - goto out; - - } - } - - AUDIT_ARG_FD(uap->fd); + AUDIT_ARG_FD(src_fd); /* * sendfile(2) can start at any offset within a file so we require * CAP_READ+CAP_SEEK = CAP_PREAD. */ - if ((error = fget_read(td, uap->fd, + if ((error = fget_read(td, src_fd, cap_rights_init(&rights, CAP_PREAD), &fp)) != 0) { goto out; } @@ -2041,11 +2014,11 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) * If we need to wait for completion, initialise the sfsync * state here. */ - if (uap->flags & SF_SYNC) - sfs = sf_sync_alloc(uap->flags & SF_SYNC); + if (flags & SF_SYNC) + sfs = sf_sync_alloc(flags & SF_SYNC); - error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, uap->offset, - uap->nbytes, &sbytes, uap->flags, compat ? SFK_COMPAT : 0, sfs, td); + error = fo_sendfile(fp, sock_fd, hdr_uio, trl_uio, offset, + nbytes, sbytes, flags, compat ? SFK_COMPAT : 0, sfs, td); /* * If appropriate, do the wait and free here. @@ -2062,6 +2035,46 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) */ fdrop(fp, td); +out: + return (error); +} + +static int +do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) +{ + struct sf_hdtr hdtr; + struct uio *hdr_uio, *trl_uio; + int error; + off_t sbytes; + + /* + * File offset must be positive. If it goes beyond EOF + * we send only the header/trailer and no payload data. + */ + if (uap->offset < 0) + return (EINVAL); + + hdr_uio = trl_uio = NULL; + + if (uap->hdtr != NULL) { + error = copyin(uap->hdtr, &hdtr, sizeof(hdtr)); + if (error != 0) + goto out; + if (hdtr.headers != NULL) { + error = copyinuio(hdtr.headers, hdtr.hdr_cnt, &hdr_uio); + if (error != 0) + goto out; + } + if (hdtr.trailers != NULL) { + error = copyinuio(hdtr.trailers, hdtr.trl_cnt, &trl_uio); + if (error != 0) + goto out; + } + } + + error = _do_sendfile(td, uap->fd, uap->s, uap->flags, compat, + uap->offset, uap->nbytes, &sbytes, hdr_uio, trl_uio); + if (uap->sbytes != NULL) { copyout(&sbytes, uap->sbytes, sizeof(off_t)); } diff --git a/sys/sys/sf_base.h b/sys/sys/sf_base.h new file mode 100644 index 00000000000..1c03ef44725 --- /dev/null +++ b/sys/sys/sf_base.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2013 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_SF_BASE_H_ +#define _SYS_SF_BASE_H_ + +extern int _do_sendfile(struct thread *, int src_fd, int sock_fd, int flags, + int compat, off_t offset, size_t nbytes, off_t *sbytes, + struct uio *hdr_uio, struct uio *trl_uio); + +#endif /* _SYS_SF_BASE_H_ */