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:
Paul Saab 2006-02-28 19:39:18 +00:00
parent 6328732d02
commit fa545f434c
4 changed files with 125 additions and 59 deletions

View File

@ -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 {

View File

@ -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, \

View File

@ -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);

View File

@ -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 *,