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
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to