diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 4c00a205f69e..cb05ceb9d95f 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -1427,37 +1427,83 @@ freebsd32_ftruncate(struct thread *td, struct freebsd32_ftruncate_args *uap) return (ftruncate(td, &ap)); } +struct sf_hdtr32 { + uint32_t headers; + int hdr_cnt; + uint32_t trailers; + int trl_cnt; +}; + +static int +freebsd32_do_sendfile(struct thread *td, + struct freebsd32_sendfile_args *uap, int compat) +{ + struct sendfile_args ap; + struct sf_hdtr32 hdtr32; + struct sf_hdtr hdtr; + struct uio *hdr_uio, *trl_uio; + struct iovec32 *iov32; + int error; + + hdr_uio = trl_uio = NULL; + + ap.fd = uap->fd; + ap.s = uap->s; + ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32)); + ap.nbytes = uap->nbytes; + ap.hdtr = (struct sf_hdtr *)uap->hdtr; /* XXX not used */ + ap.sbytes = uap->sbytes; + ap.flags = uap->flags; + + if (uap->hdtr != NULL) { + error = copyin(uap->hdtr, &hdtr32, sizeof(hdtr32)); + if (error) + goto out; + PTRIN_CP(hdtr32, hdtr, headers); + CP(hdtr32, hdtr, hdr_cnt); + PTRIN_CP(hdtr32, hdtr, trailers); + CP(hdtr32, hdtr, trl_cnt); + + if (hdtr.headers != NULL) { + iov32 = (struct iovec32 *)(uintptr_t)hdtr32.headers; + error = freebsd32_copyinuio(iov32, + hdtr32.hdr_cnt, &hdr_uio); + if (error) + goto out; + } + if (hdtr.trailers != NULL) { + iov32 = (struct iovec32 *)(uintptr_t)hdtr32.trailers; + error = freebsd32_copyinuio(iov32, + hdtr32.trl_cnt, &trl_uio); + if (error) + goto out; + } + } + + error = kern_sendfile(td, &ap, hdr_uio, trl_uio, compat); +out: + if (hdr_uio) + free(hdr_uio, M_IOV); + if (trl_uio) + free(trl_uio, M_IOV); + return (error); +} + #ifdef COMPAT_FREEBSD4 int freebsd4_freebsd32_sendfile(struct thread *td, struct freebsd4_freebsd32_sendfile_args *uap) { - struct freebsd4_sendfile_args ap; - - ap.fd = uap->fd; - ap.s = uap->s; - ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32)); - ap.nbytes = uap->nbytes; /* XXX check */ - ap.hdtr = uap->hdtr; /* XXX check */ - ap.sbytes = uap->sbytes; /* XXX FIXME!! */ - ap.flags = uap->flags; - return (freebsd4_sendfile(td, &ap)); + return (freebsd32_do_sendfile(td, + (struct freebsd32_sendfile_args *)uap, 1)); } #endif int freebsd32_sendfile(struct thread *td, struct freebsd32_sendfile_args *uap) { - struct sendfile_args ap; - ap.fd = uap->fd; - ap.s = uap->s; - ap.offset = (uap->offsetlo | ((off_t)uap->offsethi << 32)); - ap.nbytes = uap->nbytes; /* XXX check */ - ap.hdtr = uap->hdtr; /* XXX check */ - ap.sbytes = uap->sbytes; /* XXX FIXME!! */ - ap.flags = uap->flags; - return (sendfile(td, &ap)); + return (freebsd32_do_sendfile(td, uap, 0)); } struct stat32 { diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 05c6a3774ad6..d6797c281ff0 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -566,7 +566,7 @@ ; XXX note - bigendian is different 336 AUE_SENDFILE MCOMPAT4 { int freebsd32_sendfile(int fd, int s, \ u_int32_t offsetlo, u_int32_t offsethi, \ - size_t nbytes, struct sf_hdtr *hdtr, \ + size_t nbytes, struct sf_hdtr32 *hdtr, \ off_t *sbytes, int flags); } 337 AUE_NULL MNOPROTO { int kldsym(int fileid, int cmd, \ void *data); } @@ -666,7 +666,7 @@ int count); } 393 AUE_NULL MSTD { int freebsd32_sendfile(int fd, int s, \ u_int32_t offsetlo, u_int32_t offsethi, \ - size_t nbytes, struct sf_hdtr *hdtr, \ + size_t nbytes, struct sf_hdtr32 *hdtr, \ off_t *sbytes, int flags); } 394 AUE_NULL UNIMPL mac_syscall 395 AUE_GETFSSTAT MNOPROTO { int getfsstat(struct statfs *buf, \ diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 6afc60a62c61..7f93068f2468 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -1741,6 +1741,41 @@ 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) +{ + struct sf_hdtr hdtr; + struct uio *hdr_uio, *trl_uio; + int error; + + hdr_uio = trl_uio = NULL; + + if (uap->hdtr != NULL) { + error = copyin(uap->hdtr, &hdtr, sizeof(hdtr)); + if (error) + goto out; + if (hdtr.headers != NULL) { + error = copyinuio(hdtr.headers, hdtr.hdr_cnt, &hdr_uio); + if (error) + goto out; + } + if (hdtr.trailers != NULL) { + error = copyinuio(hdtr.trailers, hdtr.trl_cnt, &trl_uio); + if (error) + goto out; + + } + } + + error = kern_sendfile(td, uap, hdr_uio, trl_uio, compat); +out: + if (hdr_uio) + free(hdr_uio, M_IOV); + if (trl_uio) + free(trl_uio, M_IOV); + return (error); +} + #ifdef COMPAT_FREEBSD4 int freebsd4_sendfile(struct thread *td, struct freebsd4_sendfile_args *uap) @@ -1759,8 +1794,9 @@ freebsd4_sendfile(struct thread *td, struct freebsd4_sendfile_args *uap) } #endif /* COMPAT_FREEBSD4 */ -static int -do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) +int +kern_sendfile(struct thread *td, struct sendfile_args *uap, + struct uio *hdr_uio, struct uio *trl_uio, int compat) { struct vnode *vp; struct vm_object *obj; @@ -1768,9 +1804,6 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) struct mbuf *m, *m_header = NULL; struct sf_buf *sf; struct vm_page *pg; - struct writev_args nuap; - struct sf_hdtr hdtr; - struct uio *hdr_uio = NULL; off_t off, xfsize, hdtr_size, sbytes = 0; int error, headersize = 0, headersent = 0; @@ -1817,27 +1850,16 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) * 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. - */ - if (hdtr.headers != NULL) { - error = copyinuio(hdtr.headers, hdtr.hdr_cnt, &hdr_uio); - if (error) + if (hdr_uio != NULL) { + hdr_uio->uio_td = td; + hdr_uio->uio_rw = UIO_WRITE; + if (hdr_uio->uio_resid > 0) { + m_header = m_uiotombuf(hdr_uio, M_DONTWAIT, 0, 0); + if (m_header == NULL) goto done; - hdr_uio->uio_td = td; - hdr_uio->uio_rw = UIO_WRITE; - if (hdr_uio->uio_resid > 0) { - m_header = m_uiotombuf(hdr_uio, M_DONTWAIT, 0, 0); - if (m_header == NULL) - goto done; - headersize = m_header->m_pkthdr.len; - if (compat) - sbytes += headersize; - } + headersize = m_header->m_pkthdr.len; + if (compat) + sbytes += headersize; } } @@ -2112,17 +2134,14 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) /* * 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(td, &nuap); - if (error) - goto done; - if (compat) - sbytes += td->td_retval[0]; - else - hdtr_size += td->td_retval[0]; + if (trl_uio != NULL) { + error = kern_writev(td, uap->s, trl_uio); + if (error) + goto done; + if (compat) + sbytes += td->td_retval[0]; + else + hdtr_size += td->td_retval[0]; } done: @@ -2149,8 +2168,6 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat) vrele(vp); if (so) fputsock(so); - if (hdr_uio != NULL) - free(hdr_uio, M_IOV); if (m_header) m_freem(m_header); diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index 546434244f3c..e6a228f72e4f 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -45,6 +45,7 @@ struct sockaddr; struct stat; struct kevent; struct kevent_copyops; +struct sendfile_args; int kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg, u_int buflen); @@ -122,6 +123,8 @@ int kern_sched_rr_get_interval(struct thread *td, pid_t pid, struct timespec *ts); int kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou, fd_set *fd_ex, struct timeval *tvp); +int kern_sendfile(struct thread *td, struct sendfile_args *uap, + struct uio *hdr_uio, struct uio *trl_uio, int compat); int kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags, struct mbuf *control, enum uio_seg segflg); int kern_setitimer(struct thread *, u_int, struct itimerval *,