summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorps <ps@FreeBSD.org>2006-02-28 19:39:18 +0000
committerps <ps@FreeBSD.org>2006-02-28 19:39:18 +0000
commit6014145f3878ae927ab23d37d89490e33addf743 (patch)
tree8d194756dd94e282324cd9c351ff45ebed818cb0
parent87272c821ca130738fc0299198dfa74e4ed95086 (diff)
downloadFreeBSD-src-6014145f3878ae927ab23d37d89490e33addf743.zip
FreeBSD-src-6014145f3878ae927ab23d37d89490e33addf743.tar.gz
Fix 32bit sendfile by implementing kern_sendfile so that it takes
the header and trailers as iovec arguments instead of copying them in inside of sendfile. Reviewed by: jhb MFC after: 3 weeks
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c82
-rw-r--r--sys/compat/freebsd32/syscalls.master4
-rw-r--r--sys/kern/uipc_syscalls.c93
-rw-r--r--sys/sys/syscallsubr.h3
4 files changed, 124 insertions, 58 deletions
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 4c00a20..cb05ceb 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));
}
-#ifdef COMPAT_FREEBSD4
-int
-freebsd4_freebsd32_sendfile(struct thread *td,
- struct freebsd4_freebsd32_sendfile_args *uap)
+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 freebsd4_sendfile_args ap;
+ 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; /* XXX check */
- ap.hdtr = uap->hdtr; /* XXX check */
- ap.sbytes = uap->sbytes; /* XXX FIXME!! */
+ ap.nbytes = uap->nbytes;
+ ap.hdtr = (struct sf_hdtr *)uap->hdtr; /* XXX not used */
+ ap.sbytes = uap->sbytes;
ap.flags = uap->flags;
- return (freebsd4_sendfile(td, &ap));
+
+ 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)
+{
+ 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 05c6a37..d6797c2 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 6afc60a..7f93068 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 @@ retry_space:
/*
* 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 @@ done:
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 5464342..e6a228f 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 *,
OpenPOWER on IntegriCloud