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
This commit is contained in:
parent
87272c821c
commit
6014145f38
@ -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 {
|
||||
|
@ -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, \
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 *,
|
||||
|
Loading…
Reference in New Issue
Block a user