svn commit: r254356 - in head/sys: compat/freebsd32 kern ofed/include/linux opencrypto sys

Gleb Smirnoff glebius at FreeBSD.org
Thu Aug 15 07:54:34 UTC 2013


Author: glebius
Date: Thu Aug 15 07:54:31 2013
New Revision: 254356
URL: http://svnweb.freebsd.org/changeset/base/254356

Log:
  Make sendfile() a method in the struct fileops.  Currently only
  vnode backed file descriptors have this method implemented.
  
  Reviewed by:	kib
  Sponsored by:	Nginx, Inc.
  Sponsored by:	Netflix

Modified:
  head/sys/compat/freebsd32/freebsd32_misc.c
  head/sys/kern/kern_descrip.c
  head/sys/kern/kern_event.c
  head/sys/kern/sys_pipe.c
  head/sys/kern/sys_socket.c
  head/sys/kern/tty_pts.c
  head/sys/kern/uipc_mqueue.c
  head/sys/kern/uipc_sem.c
  head/sys/kern/uipc_shm.c
  head/sys/kern/uipc_syscalls.c
  head/sys/kern/vfs_vnops.c
  head/sys/ofed/include/linux/linux_compat.c
  head/sys/opencrypto/cryptodev.c
  head/sys/sys/file.h
  head/sys/sys/socket.h

Modified: head/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_misc.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/compat/freebsd32/freebsd32_misc.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/bus.h>
+#include <sys/capability.h>
 #include <sys/clock.h>
 #include <sys/exec.h>
 #include <sys/fcntl.h>
@@ -1653,22 +1654,19 @@ 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;
+	struct file *fp;
+	off_t offset;
 	int error;
 
-	hdr_uio = trl_uio = NULL;
+	offset = PAIR32TO64(off_t, uap->offset);
+	if (offset < 0)
+		return (EINVAL);
 
-	ap.fd = uap->fd;
-	ap.s = uap->s;
-	ap.offset = PAIR32TO64(off_t,uap->offset);
-	ap.nbytes = uap->nbytes;
-	ap.hdtr = (struct sf_hdtr *)uap->hdtr;		/* XXX not used */
-	ap.sbytes = uap->sbytes;
-	ap.flags = uap->flags;
+	hdr_uio = trl_uio = NULL;
 
 	if (uap->hdtr != NULL) {
 		error = copyin(uap->hdtr, &hdtr32, sizeof(hdtr32));
@@ -1695,7 +1693,15 @@ freebsd32_do_sendfile(struct thread *td,
 		}
 	}
 
-	error = kern_sendfile(td, &ap, hdr_uio, trl_uio, compat);
+	AUDIT_ARG_FD(uap->fd);
+
+	if ((error = fget_read(td, uap->fd, CAP_PREAD, &fp)) != 0)
+		goto out;
+
+	error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, offset,
+	    uap->nbytes, uap->sbytes, uap->flags, compat ? SFK_COMPAT : 0, td);
+	fdrop(fp, td);
+
 out:
 	if (hdr_uio)
 		free(hdr_uio, M_IOV);

Modified: head/sys/kern/kern_descrip.c
==============================================================================
--- head/sys/kern/kern_descrip.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/kern/kern_descrip.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -3887,6 +3887,15 @@ badfo_chown(struct file *fp, uid_t uid, 
 	return (EBADF);
 }
 
+static int
+badfo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
+    struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags,
+    int kflags, struct thread *td)
+{
+
+	return (EBADF);
+}
+
 struct fileops badfileops = {
 	.fo_read = badfo_readwrite,
 	.fo_write = badfo_readwrite,
@@ -3898,6 +3907,7 @@ struct fileops badfileops = {
 	.fo_close = badfo_close,
 	.fo_chmod = badfo_chmod,
 	.fo_chown = badfo_chown,
+	.fo_sendfile = badfo_sendfile,
 };
 
 int
@@ -3916,6 +3926,15 @@ invfo_chown(struct file *fp, uid_t uid, 
 	return (EINVAL);
 }
 
+int
+invfo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
+    struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags,
+    int kflags, struct thread *td)
+{
+
+	return (EINVAL);
+}
+
 /*-------------------------------------------------------------------*/
 
 /*

Modified: head/sys/kern/kern_event.c
==============================================================================
--- head/sys/kern/kern_event.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/kern/kern_event.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -127,6 +127,7 @@ static struct fileops kqueueops = {
 	.fo_close = kqueue_close,
 	.fo_chmod = invfo_chmod,
 	.fo_chown = invfo_chown,
+	.fo_sendfile = invfo_sendfile,
 };
 
 static int 	knote_attach(struct knote *kn, struct kqueue *kq);

Modified: head/sys/kern/sys_pipe.c
==============================================================================
--- head/sys/kern/sys_pipe.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/kern/sys_pipe.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -164,6 +164,7 @@ struct fileops pipeops = {
 	.fo_close = pipe_close,
 	.fo_chmod = pipe_chmod,
 	.fo_chown = pipe_chown,
+	.fo_sendfile = invfo_sendfile,
 	.fo_flags = DFLAG_PASSABLE
 };
 

Modified: head/sys/kern/sys_socket.c
==============================================================================
--- head/sys/kern/sys_socket.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/kern/sys_socket.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -66,6 +66,7 @@ struct fileops	socketops = {
 	.fo_close = soo_close,
 	.fo_chmod = invfo_chmod,
 	.fo_chown = invfo_chown,
+	.fo_sendfile = invfo_sendfile,
 	.fo_flags = DFLAG_PASSABLE
 };
 

Modified: head/sys/kern/tty_pts.c
==============================================================================
--- head/sys/kern/tty_pts.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/kern/tty_pts.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -599,6 +599,7 @@ static struct fileops ptsdev_ops = {
 	.fo_close	= ptsdev_close,
 	.fo_chmod	= invfo_chmod,
 	.fo_chown	= invfo_chown,
+	.fo_sendfile	= invfo_sendfile,
 	.fo_flags	= DFLAG_PASSABLE,
 };
 

Modified: head/sys/kern/uipc_mqueue.c
==============================================================================
--- head/sys/kern/uipc_mqueue.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/kern/uipc_mqueue.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -2597,7 +2597,8 @@ static struct fileops mqueueops = {
 	.fo_stat		= mqf_stat,
 	.fo_chmod		= mqf_chmod,
 	.fo_chown		= mqf_chown,
-	.fo_close		= mqf_close
+	.fo_close		= mqf_close,
+	.fo_sendfile		= invfo_sendfile,
 };
 
 static struct vop_vector mqfs_vnodeops = {

Modified: head/sys/kern/uipc_sem.c
==============================================================================
--- head/sys/kern/uipc_sem.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/kern/uipc_sem.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -149,6 +149,7 @@ static struct fileops ksem_ops = {
 	.fo_close = ksem_closef,
 	.fo_chmod = ksem_chmod,
 	.fo_chown = ksem_chown,
+	.fo_sendfile = invfo_sendfile,
 	.fo_flags = DFLAG_PASSABLE
 };
 

Modified: head/sys/kern/uipc_shm.c
==============================================================================
--- head/sys/kern/uipc_shm.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/kern/uipc_shm.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -132,6 +132,7 @@ static struct fileops shm_ops = {
 	.fo_close = shm_close,
 	.fo_chmod = shm_chmod,
 	.fo_chown = shm_chown,
+	.fo_sendfile = invfo_sendfile,
 	.fo_flags = DFLAG_PASSABLE
 };
 

Modified: head/sys/kern/uipc_syscalls.c
==============================================================================
--- head/sys/kern/uipc_syscalls.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/kern/uipc_syscalls.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -157,6 +157,9 @@ sfstat_sysctl(SYSCTL_HANDLER_ARGS)
 }
 SYSCTL_PROC(_kern_ipc, OID_AUTO, sfstat, CTLTYPE_OPAQUE | CTLFLAG_RW,
     NULL, 0, sfstat_sysctl, "I", "sendfile statistics");
+
+fo_sendfile_t vn_sendfile;
+
 /*
  * Convert a user file descriptor to a kernel file entry and check if required
  * capability rights are present.
@@ -1904,8 +1907,12 @@ do_sendfile(struct thread *td, struct se
 {
 	struct sf_hdtr hdtr;
 	struct uio *hdr_uio, *trl_uio;
+	struct file *fp;
 	int error;
 
+	if (uap->offset < 0)
+		return (EINVAL);
+
 	hdr_uio = trl_uio = NULL;
 
 	if (uap->hdtr != NULL) {
@@ -1925,7 +1932,19 @@ do_sendfile(struct thread *td, struct se
 		}
 	}
 
-	error = kern_sendfile(td, uap, hdr_uio, trl_uio, compat);
+	AUDIT_ARG_FD(uap->fd);
+
+	/*
+	 * sendfile(2) can start at any offset within a file so we require
+	 * CAP_READ+CAP_SEEK = CAP_PREAD.
+	 */
+	if ((error = fget_read(td, uap->fd, CAP_PREAD, &fp)) != 0)
+		goto out;
+
+	error = fo_sendfile(fp, uap->s, hdr_uio, trl_uio, uap->offset,
+	    uap->nbytes, uap->sbytes, uap->flags, compat ? SFK_COMPAT : 0, td);
+	fdrop(fp, td);
+
 out:
 	if (hdr_uio)
 		free(hdr_uio, M_IOV);
@@ -1953,11 +1972,12 @@ freebsd4_sendfile(struct thread *td, str
 #endif /* COMPAT_FREEBSD4 */
 
 int
-kern_sendfile(struct thread *td, struct sendfile_args *uap,
-    struct uio *hdr_uio, struct uio *trl_uio, int compat)
+vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
+    struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags,
+    int kflags, struct thread *td)
 {
+	struct vnode *vp = fp->f_vnode;
 	struct file *sock_fp;
-	struct vnode *vp;
 	struct vm_object *obj = NULL;
 	struct socket *so = NULL;
 	struct mbuf *m = NULL;
@@ -1969,23 +1989,10 @@ kern_sendfile(struct thread *td, struct 
 	int bsize;
 	struct sendfile_sync *sfs = NULL;
 
-	/*
-	 * The file descriptor must be a regular file and have a
-	 * backing VM object.
-	 * File offset must be positive.  If it goes beyond EOF
-	 * we send only the header/trailer and no payload data.
-	 */
-	AUDIT_ARG_FD(uap->fd);
-	/*
-	 * sendfile(2) can start at any offset within a file so we require
-	 * CAP_READ+CAP_SEEK = CAP_PREAD.
-	 */
-	if ((error = fgetvp_read(td, uap->fd, CAP_PREAD, &vp)) != 0)
-		goto out;
 	vn_lock(vp, LK_SHARED | LK_RETRY);
 	if (vp->v_type == VREG) {
 		bsize = vp->v_mount->mnt_stat.f_iosize;
-		if (uap->nbytes == 0) {
+		if (nbytes == 0) {
 			error = VOP_GETATTR(vp, &va, td->td_ucred);
 			if (error != 0) {
 				VOP_UNLOCK(vp, 0);
@@ -1994,7 +2001,7 @@ kern_sendfile(struct thread *td, struct 
 			}
 			rem = va.va_size;
 		} else
-			rem = uap->nbytes;
+			rem = nbytes;
 		obj = vp->v_object;
 		if (obj != NULL) {
 			/*
@@ -2019,16 +2026,12 @@ kern_sendfile(struct thread *td, struct 
 		error = EINVAL;
 		goto out;
 	}
-	if (uap->offset < 0) {
-		error = EINVAL;
-		goto out;
-	}
 
 	/*
 	 * The socket must be a stream socket and connected.
 	 * Remember if it a blocking or non-blocking socket.
 	 */
-	if ((error = getsock_cap(td->td_proc->p_fd, uap->s, CAP_SEND,
+	if ((error = getsock_cap(td->td_proc->p_fd, sockfd, CAP_SEND,
 	    &sock_fp, NULL)) != 0)
 		goto out;
 	so = sock_fp->f_data;
@@ -2045,10 +2048,10 @@ kern_sendfile(struct thread *td, struct 
 	 * caller to retry later.
 	 * XXX: Experimental.
 	 */
-	if (uap->flags & SF_MNOWAIT)
+	if (flags & SF_MNOWAIT)
 		mnw = 1;
 
-	if (uap->flags & SF_SYNC) {
+	if (flags & SF_SYNC) {
 		sfs = malloc(sizeof *sfs, M_TEMP, M_WAITOK | M_ZERO);
 		mtx_init(&sfs->mtx, "sendfile", NULL, MTX_DEF);
 		cv_init(&sfs->cv, "sendfile");
@@ -2070,11 +2073,11 @@ kern_sendfile(struct thread *td, struct 
 			 * the header.  If compat is specified subtract the
 			 * header size from nbytes.
 			 */
-			if (compat) {
-				if (uap->nbytes > hdr_uio->uio_resid)
-					uap->nbytes -= hdr_uio->uio_resid;
+			if (kflags & SFK_COMPAT) {
+				if (nbytes > hdr_uio->uio_resid)
+					nbytes -= hdr_uio->uio_resid;
 				else
-					uap->nbytes = 0;
+					nbytes = 0;
 			}
 			m = m_uiotombuf(hdr_uio, (mnw ? M_NOWAIT : M_WAITOK),
 			    0, 0, 0);
@@ -2105,14 +2108,14 @@ kern_sendfile(struct thread *td, struct 
 	 * The outer loop checks the state and available space of the socket
 	 * and takes care of the overall progress.
 	 */
-	for (off = uap->offset; ; ) {
+	for (off = offset; ; ) {
 		struct mbuf *mtail;
 		int loopbytes;
 		int space;
 		int done;
 
-		if ((uap->nbytes != 0 && uap->nbytes == fsbytes) ||
-		    (uap->nbytes == 0 && va.va_size == fsbytes))
+		if ((nbytes != 0 && nbytes == fsbytes) ||
+		    (nbytes == 0 && va.va_size == fsbytes))
 			break;
 
 		mtail = NULL;
@@ -2210,11 +2213,11 @@ retry_space:
 			 * or the passed in nbytes.
 			 */
 			pgoff = (vm_offset_t)(off & PAGE_MASK);
-			if (uap->nbytes)
-				rem = (uap->nbytes - fsbytes - loopbytes);
+			if (nbytes)
+				rem = (nbytes - fsbytes - loopbytes);
 			else
 				rem = va.va_size -
-				    uap->offset - fsbytes - loopbytes;
+				    offset - fsbytes - loopbytes;
 			xfsize = omin(PAGE_SIZE - pgoff, rem);
 			xfsize = omin(space - loopbytes, xfsize);
 			if (xfsize <= 0) {
@@ -2242,7 +2245,7 @@ retry_space:
 				VM_OBJECT_WUNLOCK(obj);
 			else if (m != NULL)
 				error = EAGAIN;	/* send what we already got */
-			else if (uap->flags & SF_NODISKIO)
+			else if (flags & SF_NODISKIO)
 				error = EBUSY;
 			else {
 				ssize_t resid;
@@ -2299,7 +2302,7 @@ retry_space:
 				vm_page_lock(pg);
 				vm_page_unwire(pg, 0);
 				KASSERT(pg->object != NULL,
-				    ("kern_sendfile: object disappeared"));
+				    ("%s: object disappeared", __func__));
 				vm_page_unlock(pg);
 				if (m == NULL)
 					error = (mnw ? EAGAIN : EINTR);
@@ -2399,7 +2402,7 @@ retry_space:
 	 */
 	if (trl_uio != NULL) {
 		sbunlock(&so->so_snd);
-		error = kern_writev(td, uap->s, trl_uio);
+		error = kern_writev(td, sockfd, trl_uio);
 		if (error == 0)
 			sbytes += td->td_retval[0];
 		goto out;
@@ -2415,13 +2418,11 @@ out:
 	if (error == 0) {
 		td->td_retval[0] = 0;
 	}
-	if (uap->sbytes != NULL) {
-		copyout(&sbytes, uap->sbytes, sizeof(off_t));
+	if (sent != NULL) {
+		copyout(&sbytes, sent, sizeof(off_t));
 	}
 	if (obj != NULL)
 		vm_object_deallocate(obj);
-	if (vp != NULL)
-		vrele(vp);
 	if (so)
 		fdrop(sock_fp, td);
 	if (m)

Modified: head/sys/kern/vfs_vnops.c
==============================================================================
--- head/sys/kern/vfs_vnops.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/kern/vfs_vnops.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -88,6 +88,7 @@ static fo_poll_t	vn_poll;
 static fo_kqfilter_t	vn_kqfilter;
 static fo_stat_t	vn_statfile;
 static fo_close_t	vn_closefile;
+extern fo_sendfile_t	vn_sendfile;
 
 struct 	fileops vnops = {
 	.fo_read = vn_io_fault,
@@ -100,6 +101,7 @@ struct 	fileops vnops = {
 	.fo_close = vn_closefile,
 	.fo_chmod = vn_chmod,
 	.fo_chown = vn_chown,
+	.fo_sendfile = vn_sendfile,
 	.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
 };
 

Modified: head/sys/ofed/include/linux/linux_compat.c
==============================================================================
--- head/sys/ofed/include/linux/linux_compat.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/ofed/include/linux/linux_compat.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -565,6 +565,7 @@ struct fileops linuxfileops = {
 	.fo_ioctl = linux_file_ioctl,
 	.fo_chmod = invfo_chmod,
 	.fo_chown = invfo_chown,
+	.fo_sendfile = invfo_sendfile,
 };
 
 /*

Modified: head/sys/opencrypto/cryptodev.c
==============================================================================
--- head/sys/opencrypto/cryptodev.c	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/opencrypto/cryptodev.c	Thu Aug 15 07:54:31 2013	(r254356)
@@ -304,6 +304,7 @@ static struct fileops cryptofops = {
     .fo_close = cryptof_close,
     .fo_chmod = invfo_chmod,
     .fo_chown = invfo_chown,
+    .fo_sendfile = invfo_sendfile,
 };
 
 static struct csession *csefind(struct fcrypt *, u_int);

Modified: head/sys/sys/file.h
==============================================================================
--- head/sys/sys/file.h	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/sys/file.h	Thu Aug 15 07:54:31 2013	(r254356)
@@ -105,6 +105,9 @@ typedef	int fo_chmod_t(struct file *fp, 
 		    struct ucred *active_cred, struct thread *td);
 typedef	int fo_chown_t(struct file *fp, uid_t uid, gid_t gid,
 		    struct ucred *active_cred, struct thread *td);
+typedef int fo_sendfile_t(struct file *fp, int sockfd, struct uio *hdr_uio,
+		    struct uio *trl_uio, off_t offset, size_t nbytes,
+		    off_t *sent, int flags, int kflags, struct thread *td);
 typedef	int fo_flags_t;
 
 struct fileops {
@@ -118,6 +121,7 @@ struct fileops {
 	fo_close_t	*fo_close;
 	fo_chmod_t	*fo_chmod;
 	fo_chown_t	*fo_chown;
+	fo_sendfile_t	*fo_sendfile;
 	fo_flags_t	fo_flags;	/* DFLAG_* below */
 };
 
@@ -235,6 +239,7 @@ fo_close_t	soo_close;
 
 fo_chmod_t	invfo_chmod;
 fo_chown_t	invfo_chown;
+fo_sendfile_t	invfo_sendfile;
 
 void finit(struct file *, u_int, short, void *, struct fileops *);
 int fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp);
@@ -273,6 +278,7 @@ static __inline fo_stat_t	fo_stat;
 static __inline fo_close_t	fo_close;
 static __inline fo_chmod_t	fo_chmod;
 static __inline fo_chown_t	fo_chown;
+static __inline fo_sendfile_t	fo_sendfile;
 
 static __inline int
 fo_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
@@ -352,6 +358,16 @@ fo_chown(struct file *fp, uid_t uid, gid
 	return ((*fp->f_ops->fo_chown)(fp, uid, gid, active_cred, td));
 }
 
+static __inline int
+fo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
+    struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags,
+    int kflags, struct thread *td)
+{
+
+	return ((*fp->f_ops->fo_sendfile)(fp, sockfd, hdr_uio, trl_uio, offset,
+	    nbytes, sent, flags, kflags, td));
+}
+
 #endif /* _KERNEL */
 
 #endif /* !SYS_FILE_H */

Modified: head/sys/sys/socket.h
==============================================================================
--- head/sys/sys/socket.h	Thu Aug 15 05:14:20 2013	(r254355)
+++ head/sys/sys/socket.h	Thu Aug 15 07:54:31 2013	(r254356)
@@ -628,7 +628,11 @@ struct sf_hdtr {
 #define	SF_NODISKIO     0x00000001
 #define	SF_MNOWAIT	0x00000002
 #define	SF_SYNC		0x00000004
-#endif
+
+#ifdef _KERNEL
+#define	SFK_COMPAT	0x00000001
+#endif /* _KERNEL */
+#endif /* __BSD_VISIBLE */
 
 #ifndef	_KERNEL
 


More information about the svn-src-all mailing list