From 75a872f8ed371753ba566e42103f22a16b8d4097 Mon Sep 17 00:00:00 2001 From: "David P. Reese, Jr." Date: Wed, 8 Oct 2003 01:30:32 +0000 Subject: [PATCH] Introduce the function iovec_copyin() and it's friend iovec_free(). These remove a great deal of duplicate code in the syscall functions. For those who like numbers, this patch uses iovec_copyin() four times in uipc_syscalls.c, two times in linux_socket.c and two times in 43bsd_socket.c. Would somebody please comment on the inclusion of sys/malloc.h in sys/uio.h? Remove sockargs() which was used once in the svr4 emulation code. It is replaced with a small piece of code that gets an mbuf and copyin()'s to it's data region. Remove the osendfile() syscall which was inapropriately named and placed in the COMPAT_43 code where it doesn't belong. Split the socket(), shutdown() and sendfile() syscalls. All of the syscalls in kern/uipc_syscalls.c are now split. Prevent a panic due to m_freem()'ing a dangling pointer in recvmsg(), orecvmsg(), linux_recvmsg(). This patch completely removes COMPAT_43 from kern/uipc_syscalls.c. --- sys/emulation/43bsd/43bsd_socket.c | 61 ++--- sys/emulation/linux/linux_socket.c | 60 ++--- sys/emulation/svr4/svr4_stream.c | 16 +- sys/kern/init_sysent.c | 4 +- sys/kern/kern_subr.c | 40 +++- sys/kern/syscalls.c | 4 +- sys/kern/syscalls.master | 5 +- sys/kern/uipc_syscalls.c | 347 ++++++++++++----------------- sys/sys/kern_syscall.h | 9 +- sys/sys/socketvar.h | 3 +- sys/sys/syscall-hide.h | 3 +- sys/sys/syscall.h | 4 +- sys/sys/syscall.mk | 2 +- sys/sys/sysproto.h | 16 +- sys/sys/sysunion.h | 5 +- sys/sys/uio.h | 15 +- 16 files changed, 260 insertions(+), 334 deletions(-) diff --git a/sys/emulation/43bsd/43bsd_socket.c b/sys/emulation/43bsd/43bsd_socket.c index f02e4de128..4fe5661690 100644 --- a/sys/emulation/43bsd/43bsd_socket.c +++ b/sys/emulation/43bsd/43bsd_socket.c @@ -32,7 +32,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/emulation/43bsd/43bsd_socket.c,v 1.3 2003/10/03 00:04:04 daver Exp $ + * $DragonFly: src/sys/emulation/43bsd/43bsd_socket.c,v 1.4 2003/10/08 01:30:32 daver Exp $ * from: DragonFly kern/uipc_syscalls.c,v 1.13 * * The original versions of these syscalls used to live in @@ -207,11 +207,11 @@ osendmsg(struct osendmsg_args *uap) struct thread *td = curthread; struct msghdr msg; struct uio auio; - struct iovec aiov[UIO_SMALLIOV], *iov = NULL, *iovp; + struct iovec aiov[UIO_SMALLIOV], *iov = NULL; struct sockaddr *sa = NULL; struct mbuf *control = NULL; struct cmsghdr *cm; - int error, i; + int error; error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg)); if (error) @@ -230,31 +230,13 @@ osendmsg(struct osendmsg_args *uap) /* * Populate auio. */ - if (msg.msg_iovlen >= UIO_MAXIOV) { - error = EMSGSIZE; - goto cleanup; - } - if (msg.msg_iovlen >= UIO_SMALLIOV) { - MALLOC(iov, struct iovec *, - sizeof(struct iovec) * msg.msg_iovlen, M_IOV, - M_WAITOK); - } else { - iov = aiov; - } - error = copyin(msg.msg_iov, iov, msg.msg_iovlen * sizeof(struct iovec)); + error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen, + &auio.uio_resid); if (error) goto cleanup; auio.uio_iov = iov; auio.uio_iovcnt = msg.msg_iovlen; auio.uio_offset = 0; - auio.uio_resid = 0; - for (i = 0, iovp = auio.uio_iov; i < msg.msg_iovlen; i++, iovp++) { - auio.uio_resid += iovp->iov_len; - if (auio.uio_resid < 0) { - error = EINVAL; - goto cleanup; - } - } auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_WRITE; auio.uio_td = td; @@ -304,8 +286,7 @@ osendmsg(struct osendmsg_args *uap) cleanup: if (sa) FREE(sa, M_SONAME); - if (iov != aiov) - FREE(iov, M_IOV); + iovec_free(&iov, aiov); return (error); } @@ -386,12 +367,12 @@ orecvmsg(struct orecvmsg_args *uap) struct thread *td = curthread; struct msghdr msg; struct uio auio; - struct iovec aiov[UIO_SMALLIOV], *iov = NULL, *iovp; - struct mbuf *m, *control; + struct iovec aiov[UIO_SMALLIOV], *iov = NULL; + struct mbuf *m, *control = NULL; struct sockaddr *sa = NULL; caddr_t ctlbuf; socklen_t *ufromlenp, *ucontrollenp; - int error, fromlen, controllen, len, i, flags, *uflagsp; + int error, fromlen, controllen, len, flags, *uflagsp; /* * This copyin handles everything except the iovec. @@ -415,28 +396,13 @@ orecvmsg(struct orecvmsg_args *uap) /* * Populate auio. */ - if (msg.msg_iovlen >= UIO_MAXIOV) - return (EMSGSIZE); - if (msg.msg_iovlen >= UIO_SMALLIOV) { - MALLOC(iov, struct iovec *, - sizeof(struct iovec) * msg.msg_iovlen, M_IOV, M_WAITOK); - } else { - iov = aiov; - } - error = copyin(msg.msg_iov, iov, msg.msg_iovlen * sizeof(struct iovec)); + error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen, + &auio.uio_resid); if (error) - goto cleanup; + return (error); auio.uio_iov = iov; auio.uio_iovcnt = msg.msg_iovlen; auio.uio_offset = 0; - auio.uio_resid = 0; - for (i = 0, iovp = auio.uio_iov; i < msg.msg_iovlen; i++, iovp++) { - auio.uio_resid += iovp->iov_len; - if (auio.uio_resid < 0) { - error = EINVAL; - goto cleanup; - } - } auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_READ; auio.uio_td = td; @@ -516,8 +482,7 @@ orecvmsg(struct orecvmsg_args *uap) cleanup: if (sa) FREE(sa, M_SONAME); - if (iov != aiov) - FREE(iov, M_IOV); + iovec_free(&iov, aiov); if (control) m_freem(control); return (error); diff --git a/sys/emulation/linux/linux_socket.c b/sys/emulation/linux/linux_socket.c index 21d0297e86..f06dcbc119 100644 --- a/sys/emulation/linux/linux_socket.c +++ b/sys/emulation/linux/linux_socket.c @@ -26,7 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/compat/linux/linux_socket.c,v 1.19.2.8 2001/11/07 20:33:55 marcel Exp $ - * $DragonFly: src/sys/emulation/linux/linux_socket.c,v 1.12 2003/10/04 02:12:51 daver Exp $ + * $DragonFly: src/sys/emulation/linux/linux_socket.c,v 1.13 2003/10/08 01:30:32 daver Exp $ */ /* XXX we use functions that might not exist. */ @@ -839,10 +839,10 @@ linux_sendmsg(struct linux_sendmsg_args *args, int *res) struct thread *td = curthread; struct msghdr msg; struct uio auio; - struct iovec aiov[UIO_SMALLIOV], *iov = NULL, *iovp; + struct iovec aiov[UIO_SMALLIOV], *iov = NULL; struct sockaddr *sa = NULL; struct mbuf *control = NULL; - int error, i; + int error; error = copyin(args, &linux_args, sizeof(linux_args)); if (error) @@ -864,30 +864,13 @@ linux_sendmsg(struct linux_sendmsg_args *args, int *res) /* * Populate auio. */ - if (msg.msg_iovlen >= UIO_MAXIOV) { - error = EMSGSIZE; - goto cleanup; - } - if (msg.msg_iovlen >= UIO_SMALLIOV) { - MALLOC(iov, struct iovec *, - sizeof(struct iovec) * msg.msg_iovlen, M_IOV, M_WAITOK); - } else { - iov = aiov; - } - error = copyin(msg.msg_iov, iov, msg.msg_iovlen * sizeof(struct iovec)); + error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen, + &auio.uio_resid); if (error) goto cleanup; auio.uio_iov = iov; auio.uio_iovcnt = msg.msg_iovlen; auio.uio_offset = 0; - auio.uio_resid = 0; - for (i = 0, iovp = auio.uio_iov; i < msg.msg_iovlen; i++, iovp++) { - auio.uio_resid += iovp->iov_len; - if (auio.uio_resid < 0) { - error = EINVAL; - goto cleanup; - } - } auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_WRITE; auio.uio_td = td; @@ -934,8 +917,7 @@ linux_sendmsg(struct linux_sendmsg_args *args, int *res) cleanup: if (sa) FREE(sa, M_SONAME); - if (iov != aiov) - FREE(iov, M_IOV); + iovec_free(&iov, aiov); return (error); } @@ -952,12 +934,12 @@ linux_recvmsg(struct linux_recvmsg_args *args, int *res) struct thread *td = curthread; struct msghdr msg; struct uio auio; - struct iovec aiov[UIO_SMALLIOV], *iov = NULL, *iovp; - struct mbuf *m, *control; + struct iovec aiov[UIO_SMALLIOV], *iov = NULL; + struct mbuf *m, *control = NULL; struct sockaddr *sa = NULL; caddr_t ctlbuf; socklen_t *ufromlenp, *ucontrollenp; - int error, fromlen, controllen, len, i, flags, *uflagsp; + int error, fromlen, controllen, len, flags, *uflagsp; error = copyin(args, &linux_args, sizeof(linux_args)); if (error) @@ -982,28 +964,13 @@ linux_recvmsg(struct linux_recvmsg_args *args, int *res) /* * Populate auio. */ - if (msg.msg_iovlen >= UIO_MAXIOV) - return (EMSGSIZE); - if (msg.msg_iovlen >= UIO_SMALLIOV) { - MALLOC(iov, struct iovec *, - sizeof(struct iovec) * msg.msg_iovlen, M_IOV, M_WAITOK); - } else { - iov = aiov; - } - error = copyin(msg.msg_iov, iov, msg.msg_iovlen * sizeof(struct iovec)); + error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen, + &auio.uio_resid); if (error) - goto cleanup; + return (error); auio.uio_iov = iov; auio.uio_iovcnt = msg.msg_iovlen; auio.uio_offset = 0; - auio.uio_resid = 0; - for (i = 0, iovp = auio.uio_iov; i < msg.msg_iovlen; i++, iovp++) { - auio.uio_resid += iovp->iov_len; - if (auio.uio_resid < 0) { - error = EINVAL; - goto cleanup; - } - } auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_READ; auio.uio_td = td; @@ -1075,8 +1042,7 @@ linux_recvmsg(struct linux_recvmsg_args *args, int *res) cleanup: if (sa) FREE(sa, M_SONAME); - if (iov != aiov) - FREE(iov, M_IOV); + iovec_free(&iov, aiov); if (control) m_freem(control); return (error); diff --git a/sys/emulation/svr4/svr4_stream.c b/sys/emulation/svr4/svr4_stream.c index d299325a25..3e5d17e044 100644 --- a/sys/emulation/svr4/svr4_stream.c +++ b/sys/emulation/svr4/svr4_stream.c @@ -28,7 +28,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/svr4/svr4_stream.c,v 1.12.2.2 2000/11/26 04:42:27 dillon Exp $ - * $DragonFly: src/sys/emulation/svr4/Attic/svr4_stream.c,v 1.9 2003/08/27 06:07:10 rob Exp $ + * $DragonFly: src/sys/emulation/svr4/Attic/svr4_stream.c,v 1.10 2003/10/08 01:30:32 daver Exp $ */ /* @@ -201,10 +201,18 @@ svr4_sendit(td, s, mp, flags, retval) error = EINVAL; goto bad; } - error = sockargs(&control, mp->msg_control, - mp->msg_controllen, MT_CONTROL); - if (error) + control = m_get(M_WAIT, MT_CONTROL); + if (control == NULL) { + error = ENOBUFS; goto bad; + } + control->m_len = mp->msg_controllen; + error = copyin(mp->msg_control, mtod(control, caddr_t), + mp->msg_controllen); + if (error) { + m_free(control); + goto bad; + } } else { control = 0; } diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 9f71a2a15c..3be78f3195 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -2,7 +2,7 @@ * System call switch table. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/kern/init_sysent.c,v 1.7 2003/08/12 02:36:15 dillon Exp $ + * $DragonFly: src/sys/kern/init_sysent.c,v 1.8 2003/10/08 01:30:32 daver Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.2 2003/06/17 04:28:41 dillon Exp */ @@ -358,7 +358,7 @@ struct sysent sysent[] = { { AS(sched_get_priority_min_args), (sy_call_t *)sched_get_priority_min }, /* 333 = sched_get_priority_min */ { AS(sched_rr_get_interval_args), (sy_call_t *)sched_rr_get_interval }, /* 334 = sched_rr_get_interval */ { AS(utrace_args), (sy_call_t *)utrace }, /* 335 = utrace */ - { compat(AS(osendfile_args),sendfile) }, /* 336 = old sendfile */ + { 0, (sy_call_t *)nosys }, /* 336 = obsolete freebsd4_sendfile */ { AS(kldsym_args), (sy_call_t *)kldsym }, /* 337 = kldsym */ { AS(jail_args), (sy_call_t *)jail }, /* 338 = jail */ { 0, (sy_call_t *)nosys }, /* 339 = pioctl */ diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c index 864549a380..4d55a70aac 100644 --- a/sys/kern/kern_subr.c +++ b/sys/kern/kern_subr.c @@ -37,7 +37,7 @@ * * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94 * $FreeBSD: src/sys/kern/kern_subr.c,v 1.31.2.2 2002/04/21 08:09:37 bde Exp $ - * $DragonFly: src/sys/kern/kern_subr.c,v 1.11 2003/10/02 19:21:06 drhodus Exp $ + * $DragonFly: src/sys/kern/kern_subr.c,v 1.12 2003/10/08 01:30:32 daver Exp $ */ #include "opt_ddb.h" @@ -446,3 +446,41 @@ phashinit(elements, type, nentries) *nentries = hashsize; return (hashtbl); } + +/* + * Copyin an iovec. If the iovec array fits, use the preallocated small + * iovec structure. If it is too big, dynamically allocate an iovec array + * of sufficient size. + */ +int +iovec_copyin(struct iovec *uiov, struct iovec **kiov, struct iovec *siov, + size_t iov_cnt, size_t *iov_len) +{ + struct iovec *iovp; + int error, i; + + if (iov_cnt >= UIO_MAXIOV) + return EMSGSIZE; + if (iov_cnt >= UIO_SMALLIOV) { + MALLOC(*kiov, struct iovec *, sizeof(struct iovec) * iov_cnt, + M_IOV, M_WAITOK); + } else { + *kiov = siov; + } + error = copyin(uiov, *kiov, iov_cnt * sizeof(struct iovec)); + if (error) + goto cleanup; + *iov_len = 0; + for (i = 0, iovp = *kiov; i < iov_cnt; i++, iovp++) { + *iov_len += iovp->iov_len; + if (iov_len < 0) { + error = EINVAL; + goto cleanup; + } + } + +cleanup: + if (error) + iovec_free(kiov, siov); + return (error); +} diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index fb8c01241c..3cccce9c7e 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -2,7 +2,7 @@ * System call names. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/kern/syscalls.c,v 1.7 2003/08/12 02:36:15 dillon Exp $ + * $DragonFly: src/sys/kern/syscalls.c,v 1.8 2003/10/08 01:30:32 daver Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.2 2003/06/17 04:28:41 dillon Exp */ @@ -343,7 +343,7 @@ char *syscallnames[] = { "sched_get_priority_min", /* 333 = sched_get_priority_min */ "sched_rr_get_interval", /* 334 = sched_rr_get_interval */ "utrace", /* 335 = utrace */ - "old.sendfile", /* 336 = old sendfile */ + "obs_freebsd4_sendfile", /* 336 = obsolete freebsd4_sendfile */ "kldsym", /* 337 = kldsym */ "jail", /* 338 = jail */ "#339", /* 339 = pioctl */ diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 3f22492a58..9b36dd768e 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ - $DragonFly: src/sys/kern/syscalls.master,v 1.2 2003/06/17 04:28:41 dillon Exp $ + $DragonFly: src/sys/kern/syscalls.master,v 1.3 2003/10/08 01:30:32 daver Exp $ ; @(#)syscalls.master 8.2 (Berkeley) 1/13/94 ; $FreeBSD: src/sys/kern/syscalls.master,v 1.72.2.10 2002/07/12 08:22:46 alfred Exp $ @@ -474,8 +474,7 @@ 333 STD POSIX { int sched_get_priority_min (int policy); } 334 STD POSIX { int sched_rr_get_interval (pid_t pid, struct timespec *interval); } 335 STD BSD { int utrace(const void *addr, size_t len); } -336 COMPAT BSD { int sendfile(int fd, int s, off_t offset, size_t nbytes, \ - struct sf_hdtr *hdtr, off_t *sbytes, int flags); } +336 OBSOL NOHIDE freebsd4_sendfile 337 STD BSD { int kldsym(int fileid, int cmd, void *data); } 338 STD BSD { int jail(struct jail *jail); } 339 UNIMPL BSD pioctl diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 09da715a4a..b5345276f9 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -35,10 +35,9 @@ * * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94 * $FreeBSD: src/sys/kern/uipc_syscalls.c,v 1.65.2.17 2003/04/04 17:11:16 tegge Exp $ - * $DragonFly: src/sys/kern/uipc_syscalls.c,v 1.17 2003/10/03 00:04:04 daver Exp $ + * $DragonFly: src/sys/kern/uipc_syscalls.c,v 1.18 2003/10/08 01:30:32 daver Exp $ */ -#include "opt_compat.h" #include "opt_ktrace.h" #include @@ -73,15 +72,8 @@ #include #include -#if defined(COMPAT_43) -#include -#endif /* COMPAT_43 */ - static void sf_buf_init(void *arg); SYSINIT(sock_sf, SI_SUB_MBUF, SI_ORDER_ANY, sf_buf_init, NULL) - -static int do_sendfile(struct sendfile_args *uap, int compat); - static SLIST_HEAD(, sf_buf) sf_freelist; static vm_offset_t sf_base; static struct sf_buf *sf_bufs; @@ -90,9 +82,6 @@ static int sf_buf_alloc_want; /* * System call interface to the socket abstraction. */ -#if defined(COMPAT_43) || defined(COMPAT_SUNOS) -#define COMPAT_OLDSOCK -#endif extern struct fileops socketops; @@ -100,7 +89,7 @@ extern struct fileops socketops; * socket_args(int domain, int type, int protocol) */ int -socket(struct socket_args *uap) +kern_socket(int domain, int type, int protocol, int *res) { struct thread *td = curthread; struct proc *p = td->td_proc; @@ -116,7 +105,7 @@ socket(struct socket_args *uap) if (error) return (error); fhold(fp); - error = socreate(uap->domain, &so, uap->type, uap->protocol, td); + error = socreate(domain, &so, type, protocol, td); if (error) { if (fdp->fd_ofiles[fd] == fp) { fdp->fd_ofiles[fd] = NULL; @@ -127,12 +116,22 @@ socket(struct socket_args *uap) fp->f_flag = FREAD|FWRITE; fp->f_ops = &socketops; fp->f_type = DTYPE_SOCKET; - uap->sysmsg_result = fd; + *res = fd; } fdrop(fp, td); return (error); } +int +socket(struct socket_args *uap) +{ + int error; + + error = kern_socket(uap->domain, uap->type, uap->protocol, + &uap->sysmsg_result); + + return (error); +} int kern_bind(int s, struct sockaddr *sa) { @@ -615,10 +614,10 @@ sendmsg(struct sendmsg_args *uap) struct thread *td = curthread; struct msghdr msg; struct uio auio; - struct iovec aiov[UIO_SMALLIOV], *iov = NULL, *iovp; + struct iovec aiov[UIO_SMALLIOV], *iov = NULL; struct sockaddr *sa = NULL; struct mbuf *control = NULL; - int error, i; + int error; error = copyin(uap->msg, (caddr_t)&msg, sizeof(msg)); if (error) @@ -636,30 +635,13 @@ sendmsg(struct sendmsg_args *uap) /* * Populate auio. */ - if (msg.msg_iovlen >= UIO_MAXIOV) { - error = EMSGSIZE; - goto cleanup; - } - if (msg.msg_iovlen >= UIO_SMALLIOV) { - MALLOC(iov, struct iovec *, - sizeof(struct iovec) * msg.msg_iovlen, M_IOV, M_WAITOK); - } else { - iov = aiov; - } - error = copyin(msg.msg_iov, iov, msg.msg_iovlen * sizeof(struct iovec)); + error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen, + &auio.uio_resid); if (error) goto cleanup; auio.uio_iov = iov; auio.uio_iovcnt = msg.msg_iovlen; auio.uio_offset = 0; - auio.uio_resid = 0; - for (i = 0, iovp = auio.uio_iov; i < msg.msg_iovlen; i++, iovp++) { - auio.uio_resid += iovp->iov_len; - if (auio.uio_resid < 0) { - error = EINVAL; - goto cleanup; - } - } auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_WRITE; auio.uio_td = td; @@ -693,8 +675,7 @@ sendmsg(struct sendmsg_args *uap) cleanup: if (sa) FREE(sa, M_SONAME); - if (iov != aiov) - FREE(iov, M_IOV); + iovec_free(&iov, aiov); return (error); } @@ -811,12 +792,12 @@ recvmsg(struct recvmsg_args *uap) struct thread *td = curthread; struct msghdr msg; struct uio auio; - struct iovec aiov[UIO_SMALLIOV], *iov = NULL, *iovp; - struct mbuf *m, *control; + struct iovec aiov[UIO_SMALLIOV], *iov = NULL; + struct mbuf *m, *control = NULL; struct sockaddr *sa = NULL; caddr_t ctlbuf; socklen_t *ufromlenp, *ucontrollenp; - int error, fromlen, controllen, len, i, flags, *uflagsp; + int error, fromlen, controllen, len, flags, *uflagsp; /* * This copyin handles everything except the iovec. @@ -840,28 +821,13 @@ recvmsg(struct recvmsg_args *uap) /* * Populate auio. */ - if (msg.msg_iovlen >= UIO_MAXIOV) - return (EMSGSIZE); - if (msg.msg_iovlen >= UIO_SMALLIOV) { - MALLOC(iov, struct iovec *, - sizeof(struct iovec) * msg.msg_iovlen, M_IOV, M_WAITOK); - } else { - iov = aiov; - } - error = copyin(msg.msg_iov, iov, msg.msg_iovlen * sizeof(struct iovec)); + error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen, + &auio.uio_resid); if (error) - goto cleanup; + return (error); auio.uio_iov = iov; auio.uio_iovcnt = msg.msg_iovlen; auio.uio_offset = 0; - auio.uio_resid = 0; - for (i = 0, iovp = auio.uio_iov; i < msg.msg_iovlen; i++, iovp++) { - auio.uio_resid += iovp->iov_len; - if (auio.uio_resid < 0) { - error = EINVAL; - goto cleanup; - } - } auio.uio_segflg = UIO_USERSPACE; auio.uio_rw = UIO_READ; auio.uio_td = td; @@ -919,8 +885,7 @@ recvmsg(struct recvmsg_args *uap) cleanup: if (sa) FREE(sa, M_SONAME); - if (iov != aiov) - FREE(iov, M_IOV); + iovec_free(&iov, aiov); if (control) m_freem(control); return (error); @@ -929,9 +894,8 @@ cleanup: /* * shutdown_args(int s, int how) */ -/* ARGSUSED */ int -shutdown(struct shutdown_args *uap) +kern_shutdown(int s, int how) { struct thread *td = curthread; struct proc *p = td->td_proc; @@ -939,14 +903,24 @@ shutdown(struct shutdown_args *uap) int error; KKASSERT(p); - error = holdsock(p->p_fd, uap->s, &fp); + error = holdsock(p->p_fd, s, &fp); if (error) return (error); - error = soshutdown((struct socket *)fp->f_data, uap->how); + error = soshutdown((struct socket *)fp->f_data, how); fdrop(fp, td); return(error); } +int +shutdown(struct shutdown_args *uap) +{ + int error; + + error = kern_shutdown(uap->s, uap->how); + + return (error); +} + /* * If sopt->sopt_td == NULL, then sopt->sopt_val is treated as an * in kernel pointer instead of a userland pointer. This allows us @@ -1189,50 +1163,6 @@ getpeername(struct getpeername_args *uap) return (error); } -/* - * sockargs() will be removed soon. It is currently only called from the - * emulation code. - */ -int -sockargs(mp, buf, buflen, type) - struct mbuf **mp; - caddr_t buf; - int buflen, type; -{ - struct sockaddr *sa; - struct mbuf *m; - int error; - - if ((u_int)buflen > MLEN) { -#ifdef COMPAT_OLDSOCK - if (type == MT_SONAME && (u_int)buflen <= 112) - buflen = MLEN; /* unix domain compat. hack */ - else -#endif - return (EINVAL); - } - m = m_get(M_WAIT, type); - if (m == NULL) - return (ENOBUFS); - m->m_len = buflen; - error = copyin(buf, mtod(m, caddr_t), (u_int)buflen); - if (error) - (void) m_free(m); - else { - *mp = m; - if (type == MT_SONAME) { - sa = mtod(m, struct sockaddr *); - -#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN - if (sa->sa_family == 0 && sa->sa_len < AF_MAX) - sa->sa_family = sa->sa_len; -#endif - sa->sa_len = buflen; - } - } - return (error); -} - int getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len) { @@ -1249,7 +1179,11 @@ getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len) if (error) { FREE(sa, M_SONAME); } else { -#if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN +#if BYTE_ORDER != BIG_ENDIAN + /* + * The bind(), connect(), and sendto() syscalls were not + * versioned for COMPAT_43. Thus, this check must stay. + */ if (sa->sa_family == 0 && sa->sa_len < AF_MAX) sa->sa_family = sa->sa_len; #endif @@ -1389,54 +1323,29 @@ sf_buf_free(caddr_t addr, u_int size) * specified by 's'. Send only 'nbytes' of the file or until EOF if * nbytes == 0. Optionally add a header and/or trailer to the socket * output. If specified, write the total number of bytes sent into *sbytes. + * + * In FreeBSD kern/uipc_syscalls.c,v 1.103, a bug was fixed that caused + * the headers to count against the remaining bytes to be sent from + * the file descriptor. We may wish to implement a compatibility syscall + * in the future. */ int sendfile(struct sendfile_args *uap) -{ - return (do_sendfile(uap, 0)); -} - -#ifdef COMPAT_43 -int -osendfile(struct osendfile_args *uap) -{ - struct sendfile_args args; - - args.fd = uap->fd; - args.s = uap->s; - args.offset = uap->offset; - args.nbytes = uap->nbytes; - args.hdtr = uap->hdtr; - args.sbytes = uap->sbytes; - args.flags = uap->flags; - - return (do_sendfile(&args, 1)); -} -#endif - -int -do_sendfile(struct sendfile_args *uap, int compat) { struct thread *td = curthread; struct proc *p = td->td_proc; struct file *fp; struct filedesc *fdp; - struct vnode *vp; - struct vm_object *obj; - struct socket *so; - struct mbuf *m; - struct sf_buf *sf; - struct vm_page *pg; - struct writev_args nuap; + struct vnode *vp = NULL; struct sf_hdtr hdtr; - off_t off, xfsize, hdtr_size, sbytes = 0; - int error = 0, s; + struct iovec aiov[UIO_SMALLIOV], *iov = NULL; + struct uio auio; + off_t hdtr_size = 0, sbytes; + int error, res; KKASSERT(p); fdp = p->p_fd; - vp = NULL; - hdtr_size = 0; /* * Do argument checking. Must be a regular file in, stream * type and connected socket out, positive offset. @@ -1452,12 +1361,99 @@ do_sendfile(struct sendfile_args *uap, int compat) } vp = (struct vnode *)fp->f_data; vref(vp); + fdrop(fp, td); + + /* + * If specified, get the pointer to the sf_hdtr struct for + * any headers/trailers. + */ + if (uap->hdtr) { + error = copyin(uap->hdtr, &hdtr, sizeof(hdtr)); + if (error) + goto done; + /* + * Send any headers. + */ + if (hdtr.headers) { + error = iovec_copyin(hdtr.headers, &iov, aiov, + hdtr.hdr_cnt, &auio.uio_resid); + if (error) + goto done; + auio.uio_iov = iov; + auio.uio_iovcnt = hdtr.hdr_cnt; + auio.uio_offset = 0; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_td = td; + + error = kern_sendmsg(uap->s, NULL, &auio, NULL, 0, + &res); + + iovec_free(&iov, aiov); + if (error) + goto done; + hdtr_size += res; + } + } + + error = kern_sendfile(vp, uap->s, uap->offset, uap->nbytes, + &sbytes, uap->flags); + if (error) + goto done; + + /* + * Send trailers. Wimp out and use writev(2). + */ + if (uap->hdtr != NULL && hdtr.trailers != NULL) { + error = iovec_copyin(hdtr.trailers, &iov, aiov, + hdtr.trl_cnt, &auio.uio_resid); + if (error) + goto done; + auio.uio_iov = iov; + auio.uio_iovcnt = hdtr.trl_cnt; + auio.uio_offset = 0; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_td = td; + + error = kern_sendmsg(uap->s, NULL, &auio, NULL, 0, &res); + + iovec_free(&iov, aiov); + if (error) + goto done; + hdtr_size += res; + } + +done: + if (uap->sbytes != NULL) { + sbytes += hdtr_size; + copyout(&sbytes, uap->sbytes, sizeof(off_t)); + } + if (vp) + vrele(vp); + return (error); +} + +int +kern_sendfile(struct vnode *vp, int s, off_t offset, size_t nbytes, + off_t *sbytes, int flags) +{ + struct thread *td = curthread; + struct proc *p = td->td_proc; + struct vm_object *obj; + struct socket *so; + struct file *fp; + struct mbuf *m; + struct sf_buf *sf; + struct vm_page *pg; + off_t off, xfsize; + int error = 0; + if (vp->v_type != VREG || VOP_GETVOBJECT(vp, &obj) != 0) { error = EINVAL; goto done; } - fdrop(fp, td); - error = holdsock(p->p_fd, uap->s, &fp); + error = holdsock(p->p_fd, s, &fp); if (error) goto done; so = (struct socket *)fp->f_data; @@ -1469,36 +1465,12 @@ do_sendfile(struct sendfile_args *uap, int compat) error = ENOTCONN; goto done; } - if (uap->offset < 0) { + if (offset < 0) { error = EINVAL; goto done; } - /* - * If specified, get the pointer to the sf_hdtr struct for - * any headers/trailers. - */ - if (uap->hdtr != NULL) { - error = copyin(uap->hdtr, &hdtr, sizeof(hdtr)); - if (error) - goto done; - /* - * Send any headers. Wimp out and use writev(2). - */ - if (hdtr.headers != NULL) { - nuap.fd = uap->s; - nuap.iovp = hdtr.headers; - nuap.iovcnt = hdtr.hdr_cnt; - error = writev(&nuap); - if (error) - goto done; - if (compat) - sbytes += nuap.sysmsg_result; - else - hdtr_size += nuap.sysmsg_result; - } - } - + *sbytes = 0; /* * Protect against multiple writers to the socket. */ @@ -1510,7 +1482,7 @@ do_sendfile(struct sendfile_args *uap, int compat) * into an sf_buf, attach an mbuf header to the sf_buf, and queue * it on the socket. */ - for (off = uap->offset; ; off += xfsize, sbytes += xfsize) { + for (off = offset; ; off += xfsize, *sbytes += xfsize) { vm_pindex_t pindex; vm_offset_t pgoff; @@ -1526,8 +1498,8 @@ retry_lookup: pgoff = (vm_offset_t)(off & PAGE_MASK); if (PAGE_SIZE - pgoff < xfsize) xfsize = PAGE_SIZE - pgoff; - if (uap->nbytes && xfsize > (uap->nbytes - sbytes)) - xfsize = uap->nbytes - sbytes; + if (nbytes && xfsize > (nbytes - *sbytes)) + xfsize = nbytes - *sbytes; if (xfsize <= 0) break; /* @@ -1727,30 +1699,7 @@ retry_space: } sbunlock(&so->so_snd); - /* - * Send trailers. Wimp out and use writev(2). - */ - if (uap->hdtr != NULL && hdtr.trailers != NULL) { - nuap.fd = uap->s; - nuap.iovp = hdtr.trailers; - nuap.iovcnt = hdtr.trl_cnt; - error = writev(&nuap); - if (error) - goto done; - if (compat) - sbytes += nuap.sysmsg_result; - else - hdtr_size += nuap.sysmsg_result; - } - done: - if (uap->sbytes != NULL) { - if (compat == 0) - sbytes += hdtr_size; - copyout(&sbytes, uap->sbytes, sizeof(off_t)); - } - if (vp) - vrele(vp); if (fp) fdrop(fp, td); return (error); diff --git a/sys/sys/kern_syscall.h b/sys/sys/kern_syscall.h index 6cfa86602f..8132640cab 100644 --- a/sys/sys/kern_syscall.h +++ b/sys/sys/kern_syscall.h @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/sys/kern_syscall.h,v 1.4 2003/10/03 00:04:04 daver Exp $ + * $DragonFly: src/sys/sys/kern_syscall.h,v 1.5 2003/10/08 01:30:32 daver Exp $ */ #ifndef _SYS_KERN_SYSCALL_H_ @@ -33,8 +33,11 @@ struct mbuf; struct msghdr; +struct sf_hdtr; struct sockaddr; +struct socket; struct sockopt; +struct vnode; int kern_accept(int s, struct sockaddr **name, int *namelen, int *res); int kern_bind(int s, struct sockaddr *sa); @@ -45,9 +48,13 @@ int kern_getsockopt(int s, struct sockopt *sopt); int kern_getsockname(int s, struct sockaddr **name, int *namelen); int kern_recvmsg(int s, struct sockaddr **sa, struct uio *auio, struct mbuf **control, int *flags, int *res); +int kern_shutdown(int s, int how); +int kern_sendfile(struct vnode *vp, int s, off_t offset, size_t nbytes, + off_t *sbytes, int flags); int kern_sendmsg(int s, struct sockaddr *sa, struct uio *auio, struct mbuf *control, int flags, int *res); int kern_setsockopt(int s, struct sockopt *sopt); +int kern_socket(int domain, int type, int protocol, int *res); int kern_socketpair(int domain, int type, int protocol, int *sockv); #endif /* !_SYS_KERN_SYSCALL_H_ */ diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index 977af38e24..fb727b02ed 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -32,7 +32,7 @@ * * @(#)socketvar.h 8.3 (Berkeley) 2/19/95 * $FreeBSD: src/sys/sys/socketvar.h,v 1.46.2.10 2003/08/24 08:24:39 hsu Exp $ - * $DragonFly: src/sys/sys/socketvar.h,v 1.5 2003/08/24 23:07:08 hsu Exp $ + * $DragonFly: src/sys/sys/socketvar.h,v 1.6 2003/10/08 01:30:32 daver Exp $ */ #ifndef _SYS_SOCKETVAR_H_ @@ -328,7 +328,6 @@ int sokqfilter (struct file *fp, struct knote *kn); */ struct sockaddr *dup_sockaddr (struct sockaddr *sa, int canwait); int holdsock (struct filedesc *fdp, int fdes, struct file **fpp); -int sockargs (struct mbuf **mp, caddr_t buf, int buflen, int type); int getsockaddr (struct sockaddr **namp, caddr_t uaddr, size_t len); void sbappend (struct sockbuf *sb, struct mbuf *m); int sbappendaddr (struct sockbuf *sb, struct sockaddr *asa, diff --git a/sys/sys/syscall-hide.h b/sys/sys/syscall-hide.h index eb554c63c9..8ec08b4df2 100644 --- a/sys/sys/syscall-hide.h +++ b/sys/sys/syscall-hide.h @@ -2,7 +2,7 @@ * System call hiders. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/sys/syscall-hide.h,v 1.8 2003/08/20 07:31:21 rob Exp $ + * $DragonFly: src/sys/sys/syscall-hide.h,v 1.9 2003/10/08 01:30:32 daver Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.2 2003/06/17 04:28:41 dillon Exp */ @@ -254,7 +254,6 @@ HIDE_POSIX(sched_get_priority_max) HIDE_POSIX(sched_get_priority_min) HIDE_POSIX(sched_rr_get_interval) HIDE_BSD(utrace) -HIDE_BSD(sendfile) HIDE_BSD(kldsym) HIDE_BSD(jail) HIDE_BSD(pioctl) diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index 332c5ede4e..6b0934d5dd 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -2,7 +2,7 @@ * System call numbers. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/sys/syscall.h,v 1.8 2003/08/20 07:31:21 rob Exp $ + * $DragonFly: src/sys/sys/syscall.h,v 1.9 2003/10/08 01:30:32 daver Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.2 2003/06/17 04:28:41 dillon Exp */ @@ -260,7 +260,7 @@ #define SYS_sched_get_priority_min 333 #define SYS_sched_rr_get_interval 334 #define SYS_utrace 335 - /* 336 is old sendfile */ + /* 336 is obsolete freebsd4_sendfile */ #define SYS_kldsym 337 #define SYS_jail 338 #define SYS_sigprocmask 340 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index 55e993c0c5..00a1dc83b6 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -1,6 +1,6 @@ # DragonFly system call names. # DO NOT EDIT-- this file is automatically generated. -# $DragonFly: src/sys/sys/syscall.mk,v 1.8 2003/08/20 07:31:21 rob Exp $ +# $DragonFly: src/sys/sys/syscall.mk,v 1.9 2003/10/08 01:30:32 daver Exp $ # created from DragonFly: src/sys/kern/syscalls.master,v 1.2 2003/06/17 04:28:41 dillon Exp MIASM = \ syscall.o \ diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index c7152f8b76..e7aee857f2 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -2,7 +2,7 @@ * System call prototypes. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/sys/sysproto.h,v 1.8 2003/08/20 07:31:21 rob Exp $ + * $DragonFly: src/sys/sys/sysproto.h,v 1.9 2003/10/08 01:30:32 daver Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.2 2003/06/17 04:28:41 dillon Exp */ @@ -2447,19 +2447,6 @@ struct ogetdirentries_args { u_int count; char count_[PAD_(u_int)]; long * basep; char basep_[PAD_(long *)]; }; -struct osendfile_args { -#ifdef _KERNEL - union sysmsg sysmsg; -#endif - union usrmsg usrmsg; - int fd; char fd_[PAD_(int)]; - int s; char s_[PAD_(int)]; - off_t offset; char offset_[PAD_(off_t)]; - size_t nbytes; char nbytes_[PAD_(size_t)]; - struct sf_hdtr * hdtr; char hdtr_[PAD_(struct sf_hdtr *)]; - off_t * sbytes; char sbytes_[PAD_(off_t *)]; - int flags; char flags_[PAD_(int)]; -}; #ifdef _KERNEL @@ -2500,7 +2487,6 @@ int okillpg (struct okillpg_args *); int oquota (struct oquota_args *); int ogetsockname (struct getsockname_args *); int ogetdirentries (struct ogetdirentries_args *); -int osendfile (struct osendfile_args *); #endif /* _KERNEL */ diff --git a/sys/sys/sysunion.h b/sys/sys/sysunion.h index 3709e14154..fbe6779f6e 100644 --- a/sys/sys/sysunion.h +++ b/sys/sys/sysunion.h @@ -2,7 +2,7 @@ * Union of syscall args for messaging. * * DO NOT EDIT-- this file is automatically generated. - * $DragonFly: src/sys/sys/sysunion.h,v 1.5 2003/08/20 07:31:21 rob Exp $ + * $DragonFly: src/sys/sys/sysunion.h,v 1.6 2003/10/08 01:30:32 daver Exp $ * created from DragonFly: src/sys/kern/syscalls.master,v 1.2 2003/06/17 04:28:41 dillon Exp */ @@ -308,9 +308,6 @@ union sysunion { struct sched_get_priority_min_args sched_get_priority_min; struct sched_rr_get_interval_args sched_rr_get_interval; struct utrace_args utrace; -#ifdef COMPAT_43 - struct osendfile_args osendfile; -#endif struct kldsym_args kldsym; struct jail_args jail; struct sigprocmask_args sigprocmask; diff --git a/sys/sys/uio.h b/sys/sys/uio.h index d6dfe3834c..876fee6242 100644 --- a/sys/sys/uio.h +++ b/sys/sys/uio.h @@ -32,12 +32,14 @@ * * @(#)uio.h 8.5 (Berkeley) 2/22/94 * $FreeBSD: src/sys/sys/uio.h,v 1.11.2.1 2001/09/28 16:58:35 dillon Exp $ - * $DragonFly: src/sys/sys/uio.h,v 1.5 2003/10/02 19:21:06 drhodus Exp $ + * $DragonFly: src/sys/sys/uio.h,v 1.6 2003/10/08 01:30:32 daver Exp $ */ #ifndef _SYS_UIO_H_ #define _SYS_UIO_H_ +#include /* Needed to inline iovec_free(). */ + /* * XXX * iov_base should be a void *. @@ -86,6 +88,17 @@ int uiomove (caddr_t, int, struct uio *); int uiomove_frombuf (void *buf, int buflen, struct uio *uio); int uiomoveco (caddr_t, int, struct uio *, struct vm_object *); int uioread (int, struct uio *, struct vm_object *, int *); +int iovec_copyin(struct iovec *, struct iovec **, struct iovec *, + size_t, size_t *); + +static __inline void +iovec_free(struct iovec **kiov, struct iovec *siov) +{ + if (*kiov != siov) { + FREE(*kiov, M_IOV); + *kiov = NULL; + } +} #else /* !_KERNEL */ -- 2.41.0