Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 2 Oct 2009 20:15:48 +0000 (UTC)
From:      Kip Macy <kmacy@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r197718 - in user/kmacy/releng_8_fcs/sys: kern sys
Message-ID:  <200910022015.n92KFm0m012048@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kmacy
Date: Fri Oct  2 20:15:47 2009
New Revision: 197718
URL: http://svn.freebsd.org/changeset/base/197718

Log:
  Add background sendfile for asynchrounous completion of non-blocking requests.
  Disable by default.

Modified:
  user/kmacy/releng_8_fcs/sys/kern/uipc_sockbuf.c
  user/kmacy/releng_8_fcs/sys/kern/uipc_socket.c
  user/kmacy/releng_8_fcs/sys/kern/uipc_syscalls.c
  user/kmacy/releng_8_fcs/sys/sys/file.h
  user/kmacy/releng_8_fcs/sys/sys/sockbuf.h
  user/kmacy/releng_8_fcs/sys/sys/socket.h
  user/kmacy/releng_8_fcs/sys/sys/socketvar.h
  user/kmacy/releng_8_fcs/sys/sys/sockstate.h
  user/kmacy/releng_8_fcs/sys/sys/syscallsubr.h

Modified: user/kmacy/releng_8_fcs/sys/kern/uipc_sockbuf.c
==============================================================================
--- user/kmacy/releng_8_fcs/sys/kern/uipc_sockbuf.c	Fri Oct  2 19:51:03 2009	(r197717)
+++ user/kmacy/releng_8_fcs/sys/kern/uipc_sockbuf.c	Fri Oct  2 20:15:47 2009	(r197718)
@@ -133,7 +133,7 @@ sbwait(struct sockbuf *sb)
 }
 
 int
-sblock(struct sockbuf *sb, int flags)
+_sblock(struct sockbuf *sb, int flags, const char *file, int line)
 {
 
 	KASSERT((flags & SBL_VALID) == flags,
@@ -142,12 +142,12 @@ sblock(struct sockbuf *sb, int flags)
 	if (flags & SBL_WAIT) {
 		if ((sb->sb_flags & SB_NOINTR) ||
 		    (flags & SBL_NOINTR)) {
-			sx_xlock(&sb->sb_sx);
+			_sx_xlock(&sb->sb_sx, 0, file, line);
 			return (0);
 		}
-		return (sx_xlock_sig(&sb->sb_sx));
+		return (_sx_xlock(&sb->sb_sx, SX_INTERRUPTIBLE, file, line));
 	} else {
-		if (sx_try_xlock(&sb->sb_sx) == 0)
+		if (_sx_try_xlock(&sb->sb_sx, file, line) == 0)
 			return (EWOULDBLOCK);
 		return (0);
 	}
@@ -178,7 +178,10 @@ sowakeup(struct socket *so, struct sockb
 	int ret;
 
 	SOCKBUF_LOCK_ASSERT(sb);
-
+	if (sb->sb_flags & SB_SENDING) {
+	        SOCKBUF_UNLOCK(sb);
+		return;
+	}
 	selwakeuppri(&sb->sb_sel, PSOCK);
 	if (!SEL_WAITING(&sb->sb_sel))
 		sb->sb_flags &= ~SB_SEL;
@@ -906,6 +909,8 @@ sbdrop_locked(struct sockbuf *sb, int le
 	SOCKBUF_LOCK_ASSERT(sb);
 
 	sbdrop_internal(sb, len);
+	if (sb->sb_flags & SB_SENDING)
+		sosendingwakeup(sb);
 }
 
 void

Modified: user/kmacy/releng_8_fcs/sys/kern/uipc_socket.c
==============================================================================
--- user/kmacy/releng_8_fcs/sys/kern/uipc_socket.c	Fri Oct  2 19:51:03 2009	(r197717)
+++ user/kmacy/releng_8_fcs/sys/kern/uipc_socket.c	Fri Oct  2 20:15:47 2009	(r197718)
@@ -124,10 +124,15 @@ __FBSDID("$FreeBSD$");
 #include <sys/resourcevar.h>
 #include <net/route.h>
 #include <sys/signalvar.h>
+#include <sys/smp.h>
 #include <sys/stat.h>
 #include <sys/sx.h>
+#include <sys/syscallsubr.h>
 #include <sys/sysctl.h>
+#include <sys/sysproto.h>
+#include <sys/taskqueue.h>
 #include <sys/uio.h>
+#include <sys/vnode.h>
 #include <sys/jail.h>
 
 #include <net/vnet.h>
@@ -3329,6 +3334,345 @@ soisdisconnected(struct socket *so)
 	wakeup(&so->so_timeo);
 }
 
+struct socketref {
+	struct proc *sr_proc;
+	struct ucred *sr_ucred;
+	struct file *sr_sock_fp;
+	struct file *sr_fp;
+	struct socket *sr_so;
+	struct sendfile_args sr_uap;
+	struct uio sr_hdr_uio;
+	struct uio sr_trl_uio;
+	short sr_compat;
+	int sr_magic;
+	off_t sr_vnp_size;
+	struct task sr_task;
+	TAILQ_ENTRY(socketref) entry;
+
+};
+TAILQ_HEAD(srq, socketref);
+
+struct srq *sendfile_bg_queue;
+struct mtx sendfile_bg_lock;
+struct callout *sendfile_callout;
+struct taskqueue *sendfile_tq;
+extern int getsock(struct filedesc *fdp, int fd,
+    struct file **fpp, u_int *fflagp);
+static void sendfile_task_func(void *context, int pending __unused);
+static int srsendingwakeup(struct socketref *sr);
+
+MALLOC_DEFINE(M_SOCKREF, "sockref", "socket reference memory");
+
+#define SOCKBUF_LOCK_COND(sb, lockflag) do {	\
+		if ((lockflag))			\
+			SOCKBUF_LOCK((sb));	\
+} while (0)
+
+#define SOCKBUF_UNLOCK_COND(sb, lockflag) do {	\
+		if ((lockflag))			\
+			SOCKBUF_UNLOCK((sb));	\
+} while (0)
+
+
+static void
+socketref_free(struct socketref *sr)
+{
+	struct file *fp = sr->sr_fp;
+	struct file *sock_fp = sr->sr_sock_fp;
+	struct proc *p = sr->sr_proc;
+	struct ucred *cred = sr->sr_ucred;
+
+	if (cred != NULL)
+		crfree(cred);
+	vrele(fp->f_vnode);
+	fdrop(fp, NULL);
+	fdrop(sock_fp, NULL);
+	PRELE(p);
+#ifdef INVARIANTS
+	bzero(sr, sizeof(*sr));
+#endif	
+	free(sr, M_SOCKREF);
+}
+
+void
+soissending(struct socket *so, struct thread *td,
+    struct sendfile_args *uap, struct uio *hdr_uio,
+    struct uio *trl_uio, int compat, off_t sbytes,
+    off_t vnp_size)
+{
+	struct socketref *ref;
+	int error;
+	struct socket *refso;
+	struct vnode *vp;
+	
+	SOCKBUF_LOCK_ASSERT(&so->so_snd);
+	ref = malloc(sizeof(struct socketref), 
+	    M_SOCKREF, M_NOWAIT|M_ZERO);
+	if (ref == NULL)
+		return;
+	/*
+	 * Obtain reference to socket :-/
+	 * drop when done sending
+	 */
+	so->so_snd.sb_flags |= SB_SENDING;
+	PROC_LOCK(td->td_proc);
+	td->td_proc->p_lock++;
+	PROC_UNLOCK(td->td_proc);
+
+	ref->sr_proc = td->td_proc;
+
+	if ((error = getsock(td->td_proc->p_fd, uap->s, &ref->sr_sock_fp,
+		    NULL)) != 0) {
+		goto error;
+	}
+	if (ref->sr_sock_fp->f_type != DTYPE_SOCKET) {
+		printf("socket descriptor s=%d is not socket", uap->s);
+		goto error;
+	}
+
+	refso = ref->sr_sock_fp->f_data;
+	if (refso != so) {
+		printf("socket mismatch between refso: %p so: %p\n",
+		    refso, so);
+		goto error_sock_fp;
+	}
+	ref->sr_so = refso;
+
+	if ((error = fget(td, uap->fd, &ref->sr_fp)) != 0) {
+		goto error_sock_fp;
+	} else if (ref->sr_fp->f_vnode != NULL) {
+		vp = ref->sr_fp->f_vnode;
+		vref(vp);
+	} else {
+		goto error_fp;
+	}
+
+	bcopy(uap, &ref->sr_uap, sizeof(*uap));
+	ref->sr_uap.sbytes = NULL;
+	ref->sr_sock_fp->f_sfbytes = 0;
+	CTR4(KTR_SPARE1, "sock %p off %ld sbytes %ld total_sbytes %ld",
+	    so, ref->sr_uap.offset, sbytes, ref->sr_fp->f_sfbytes);
+	ref->sr_uap.offset += sbytes;
+	if (uap->nbytes)
+		ref->sr_uap.nbytes -= sbytes;
+	/*
+	 * XXX 
+	 * We have to malloc memory for the uio data
+	 */
+	if (hdr_uio != NULL)
+		bcopy(hdr_uio, &ref->sr_hdr_uio, 
+		      sizeof(*hdr_uio));
+	if (trl_uio != NULL)
+		bcopy(trl_uio, &ref->sr_trl_uio, 
+		      sizeof(*trl_uio));
+	ref->sr_compat = compat;
+	ref->sr_magic = 0xCAFEBABE;
+	ref->sr_vnp_size = vnp_size;
+	TASK_INIT(&ref->sr_task, 0, sendfile_task_func, ref);
+
+	CTR3(KTR_SPARE2, "enqueueing socket %p sock_fp %p s %d", so, ref->sr_sock_fp, uap->s);
+	mtx_lock(&sendfile_bg_lock);
+	TAILQ_INSERT_TAIL(sendfile_bg_queue, ref, entry);
+	mtx_unlock(&sendfile_bg_lock);
+	return;
+error_fp:
+	fdrop(ref->sr_fp, td);
+error_sock_fp:
+	fdrop(ref->sr_sock_fp, td);
+error:
+	free(ref, M_DEVBUF);
+}
+
+static void
+sendfile_task_func(void *context, int pending __unused)
+{
+	struct socketref *sr;
+	struct socket *so;
+	struct sockbuf *sb;
+	struct file *sock_fp, *fp;
+	int error = EAGAIN;
+	struct uio *hdr_uio = NULL, *trl_uio = NULL;
+	off_t sbytes = 0;
+
+	sr = context;
+	CTR0(KTR_SPARE2, "task_func running");
+	if (sr->sr_magic != 0xCAFEBABE) {
+		printf("bad magic! 0x%x\n", sr->sr_magic);
+		/* XXX memory leak */
+		return;
+	}
+
+	sock_fp = sr->sr_sock_fp;
+	fp = sr->sr_fp;
+	CTR2(KTR_SPARE2, "processing sr %p sock_fp %p", sr, sock_fp);
+	if (sock_fp->f_type != DTYPE_SOCKET)
+		goto done;
+		
+	so = sock_fp->f_data;
+	CTR1(KTR_SPARE2, "task processing socket %p", so);
+		
+	if ((so->so_state & SS_ISCONNECTED) == 0)
+		goto done;
+
+	if (sr->sr_ucred == NULL &&
+	    (sr->sr_ucred = crdup(sr->sr_proc->p_ucred)) == NULL)
+		goto done;
+
+	sb = &so->so_snd;
+	SOCKBUF_UNLOCK_ASSERT(sb);
+	SOCKBUF_LOCK(sb);
+	sb->sb_flags &= ~SB_SENDING;
+	if (sb->sb_state & SBS_CANTSENDMORE) {
+		CTR1(KTR_SPARE2, "SBS_CANTSENDMORE - socket %p", so);
+		sowwakeup_locked(so);
+		goto done;
+	} else if (sowriteable(so)) {
+		sb->sb_flags |= SB_SENDING;
+		SOCKBUF_UNLOCK(sb);
+		if (sr->sr_hdr_uio.uio_td != NULL)
+			hdr_uio = &sr->sr_hdr_uio;
+		if (sr->sr_trl_uio.uio_td != NULL)
+			trl_uio = &sr->sr_trl_uio;
+
+		sr->sr_uap.sbytes = &sbytes;
+		sr->sr_uap.flags |= SF_TASKQ;
+		CTR1(KTR_SPARE2, "task sending on socket %p", so);
+		
+		error = kern_sendfile(curthread, &sr->sr_uap,
+		    hdr_uio, trl_uio,
+		    sr->sr_compat, fp, so, sr->sr_ucred);
+		CTR4(KTR_SPARE1, "sock %p off %ld sbytes %ld total_sbytes %ld",
+		    so, sr->sr_uap.offset, sbytes, fp->f_sfbytes);
+		atomic_add_long(&fp->f_sfbytes, sbytes);
+		sr->sr_uap.offset += sbytes;
+		if (sr->sr_uap.nbytes)
+			sr->sr_uap.nbytes -= sbytes;
+		if (error == EAGAIN &&
+		    (sr->sr_uap.offset + sbytes == sr->sr_vnp_size)) {
+			CTR0(KTR_SPARE1, "EAGAIN on full send");
+			error = 0;
+		}
+		SOCKBUF_LOCK(sb);
+	}
+#ifdef KTR
+	else
+		CTR2(KTR_SPARE1, "sock %p off %ld - not writeable in task_func",
+		    so, sr->sr_uap.offset);
+#endif		
+	if (error == EAGAIN && srsendingwakeup(sr) != ENOTCONN) {
+		SOCKBUF_UNLOCK(sb);
+		return;
+	}
+#ifdef KTR
+	if (error && error != EAGAIN && error != EPIPE) 
+		CTR1(KTR_SPARE1, "error %d", error); 
+#endif
+	
+	sb->sb_flags &= ~SB_SENDING;
+	sowwakeup_locked(so);
+done:
+	SOCKBUF_UNLOCK_ASSERT(sb);
+	socketref_free(sr);
+}
+
+static int
+srsendingwakeup(struct socketref *sr) 
+{
+	struct socket *so;
+	struct file *fp;
+	struct sockbuf *sb;
+
+	if (sr->sr_magic != 0xCAFEBABE) {
+		printf("bad magic! sr: %p magic : 0x%x in %s\n",
+		    sr, sr->sr_magic, __FUNCTION__);
+		/*
+		 * XXX leak - should be assert perhaps
+		 * 
+		 */
+		return (0);
+	}
+
+	fp = sr->sr_sock_fp;
+	CTR2(KTR_SPARE2, "processing s %d sock_fp %p", sr->sr_uap.s, fp);
+	if (fp->f_type != DTYPE_SOCKET) {
+		CTR1(KTR_SPARE1, "not socket - type %d", fp->f_type);
+		goto error;
+	}
+	so = fp->f_data;
+	if ((so->so_state & SS_ISCONNECTED) == 0) {
+		CTR1(KTR_SPARE1, "not connected %p", so);
+		goto error;
+	}
+
+	CTR1(KTR_SPARE2, "processing socket %p", so);
+	sb = &so->so_snd;
+	SOCKBUF_LOCK_ASSERT(sb);
+	sb->sb_flags &= ~SB_SENDING;
+	if (sb->sb_state & SBS_CANTSENDMORE) {
+		CTR1(KTR_SPARE1, "SBS_CANTSENDMORE %p", so);
+	} else if (sowriteable(so)) {
+		CTR2(KTR_SPARE2, "enqueue socket to task %p sr %p", so, sr);
+		sb->sb_flags |= SB_SENDING;
+		taskqueue_enqueue(sendfile_tq, &sr->sr_task);
+	} else {
+		CTR2(KTR_SPARE1, "sock %p off %ld - not writeable in srsendingwakeup",
+		    so, sr->sr_uap.offset);
+		sb->sb_flags |= SB_SENDING;
+		mtx_lock(&sendfile_bg_lock);
+		TAILQ_INSERT_TAIL(sendfile_bg_queue, sr, entry);
+		mtx_unlock(&sendfile_bg_lock);
+	}
+	return (0);
+error:
+	return (ENOTCONN);
+}
+
+void
+sosendingwakeup(struct sockbuf *sb)
+{
+	struct socketref *sr = NULL;
+
+	SOCKBUF_LOCK_ASSERT(sb);
+	mtx_lock(&sendfile_bg_lock);
+	if (!TAILQ_EMPTY(sendfile_bg_queue)) {
+		TAILQ_FOREACH(sr, sendfile_bg_queue, entry) {
+			if (sb == &sr->sr_so->so_snd) {
+				sb->sb_flags &= ~SB_SENDING;
+				TAILQ_REMOVE(sendfile_bg_queue, sr, entry);
+				break;
+			}
+		}
+
+	}
+	mtx_unlock(&sendfile_bg_lock);
+	
+	/*
+	 * Buffer in flight
+	 */
+	if (sr != NULL && srsendingwakeup(sr) == ENOTCONN) {
+		CTR2(KTR_SPARE2, "freeing expired socket %p ref %p",
+		    sr->sr_so, sr);
+		socketref_free(sr);
+	}
+}
+
+static void
+init_bgsend(void *unused __unused)
+{	
+
+	sendfile_tq = taskqueue_create("sendfile background taskq",  M_NOWAIT,
+	    taskqueue_thread_enqueue, &sendfile_tq);
+	taskqueue_start_threads(&sendfile_tq, mp_ncpus, PI_SOFT,
+	    "sendfile background taskq");
+
+	mtx_init(&sendfile_bg_lock, "sendfile bg", NULL, MTX_DEF);
+	sendfile_bg_queue = malloc(sizeof(struct srq),
+	    M_DEVBUF, M_NOWAIT);
+	TAILQ_INIT(sendfile_bg_queue);
+}
+
+SYSINIT(init_bgsend, SI_SUB_SMP, SI_ORDER_ANY, init_bgsend, NULL);
+
 /*
  * Make a copy of a sockaddr in a malloced buffer of type M_SONAME.
  */

Modified: user/kmacy/releng_8_fcs/sys/kern/uipc_syscalls.c
==============================================================================
--- user/kmacy/releng_8_fcs/sys/kern/uipc_syscalls.c	Fri Oct  2 19:51:03 2009	(r197717)
+++ user/kmacy/releng_8_fcs/sys/kern/uipc_syscalls.c	Fri Oct  2 20:15:47 2009	(r197718)
@@ -112,6 +112,14 @@ SYSCTL_INT(_kern_ipc, OID_AUTO, nsfbufsp
 SYSCTL_INT(_kern_ipc, OID_AUTO, nsfbufsused, CTLFLAG_RD, &nsfbufsused, 0,
     "Number of sendfile(2) sf_bufs in use");
 
+
+/* XXX move to header */
+int getsock(struct filedesc *fdp, int fd, struct file **fpp, u_int *fflagp);
+
+static int bg_sendfile_enable = 0;
+SYSCTL_INT(_kern_ipc, OID_AUTO, bg_sendfile_enable, CTLFLAG_RW,
+    &bg_sendfile_enable, 0, "Enable background sendfile");
+
 /*
  * Convert a user file descriptor to a kernel file entry.  A reference on the
  * file entry is held upon returning.  This is lighter weight than
@@ -120,7 +128,7 @@ SYSCTL_INT(_kern_ipc, OID_AUTO, nsfbufsu
  * associated with the additional reference count.  If requested, return the
  * open file flags.
  */
-static int
+int
 getsock(struct filedesc *fdp, int fd, struct file **fpp, u_int *fflagp)
 {
 	struct file *fp;
@@ -1774,7 +1782,8 @@ do_sendfile(struct thread *td, struct se
 		}
 	}
 
-	error = kern_sendfile(td, uap, hdr_uio, trl_uio, compat);
+	error = kern_sendfile(td, uap, hdr_uio, trl_uio, compat,
+	    NULL, NULL, NULL);
 out:
 	if (hdr_uio)
 		free(hdr_uio, M_IOV);
@@ -1803,20 +1812,27 @@ freebsd4_sendfile(struct thread *td, str
 
 int
 kern_sendfile(struct thread *td, struct sendfile_args *uap,
-    struct uio *hdr_uio, struct uio *trl_uio, int compat)
+    struct uio *hdr_uio, struct uio *trl_uio, int compat,
+    struct file *bgfp, struct socket *bgso, struct ucred *bgcred)
 {
-	struct file *sock_fp;
-	struct vnode *vp;
+	struct file *sock_fp, *fp = NULL;
+	struct vnode *vp = NULL;
 	struct vm_object *obj = NULL;
 	struct socket *so = NULL;
 	struct mbuf *m = NULL;
 	struct sf_buf *sf;
 	struct vm_page *pg;
-	off_t off, xfsize, fsbytes = 0, sbytes = 0, rem = 0;
+	struct ucred *cred;
+	off_t off, xfsize, fsbytes = 0, sbytes = 0, rem = 0, vnp_size = 0;
 	int error, hdrlen = 0, mnw = 0;
 	int vfslocked;
 	struct sendfile_sync *sfs = NULL;
 
+	if (bgcred != NULL)
+		cred = bgcred;
+	else
+		cred = td->td_ucred;
+
 	/*
 	 * The file descriptor must be a regular file and have a
 	 * backing VM object.
@@ -1824,8 +1840,23 @@ kern_sendfile(struct thread *td, struct 
 	 * we send only the header/trailer and no payload data.
 	 */
 	AUDIT_ARG_FD(uap->fd);
-	if ((error = fgetvp_read(td, uap->fd, &vp)) != 0)
-		goto out;
+	if  ((uap->flags & SF_TASKQ) == 0) {
+		if ((error = fget_read(td, uap->fd, &fp)) != 0)
+			goto out;
+		else {
+			if (fp->f_vnode == NULL) {
+				fdrop(fp, td);
+				error = EINVAL;
+				goto out;
+			} else {
+				vp = fp->f_vnode;
+				vref(vp);
+			}
+		}
+	} else {
+		vp = bgfp->f_vnode;
+	}
+
 	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	vn_lock(vp, LK_SHARED | LK_RETRY);
 	if (vp->v_type == VREG) {
@@ -1858,22 +1889,39 @@ kern_sendfile(struct thread *td, struct 
 		goto out;
 	}
 
-	/*
-	 * The socket must be a stream socket and connected.
-	 * Remember if it a blocking or non-blocking socket.
-	 */
-	if ((error = getsock(td->td_proc->p_fd, uap->s, &sock_fp,
-	    NULL)) != 0)
-		goto out;
-	so = sock_fp->f_data;
-	if (so->so_type != SOCK_STREAM) {
-		error = EINVAL;
-		goto out;
+	if  ((uap->flags & SF_TASKQ) == 0) {
+		/*
+		 * The socket must be a stream socket and connected.
+		 * Remember if it a blocking or non-blocking socket.
+		 */
+		if ((error = getsock(td->td_proc->p_fd, uap->s, &sock_fp,
+			    NULL)) != 0)
+			goto out;
+		so = sock_fp->f_data;
+		if (so->so_type != SOCK_STREAM) {
+			error = EINVAL;
+			goto out;
+		}
+		if ((so->so_state & SS_ISCONNECTED) == 0) {
+			error = ENOTCONN;
+			goto out;
+		}
+	} else {
+		so = bgso;
 	}
-	if ((so->so_state & SS_ISCONNECTED) == 0) {
-		error = ENOTCONN;
+
+	if ((uap->flags & SF_TASKQ) == 0 &&
+	    sock_fp->f_sfbytes != 0) {
+		SOCKBUF_UNLOCK(&so->so_snd);
+		if (uap->sbytes != NULL) {
+			copyout(&sbytes, uap->sbytes, sizeof(off_t));
+			sock_fp->f_sfbytes = 0;
+		}
+		error = 0;
 		goto out;
 	}
+
+	
 	/*
 	 * Do not wait on memory allocations but return ENOMEM for
 	 * caller to retry later.
@@ -1890,7 +1938,7 @@ kern_sendfile(struct thread *td, struct 
 	}
 
 #ifdef MAC
-	error = mac_socket_check_send(td->td_ucred, so);
+	error = mac_socket_check_send(cred, so);
 	if (error)
 		goto out;
 #endif
@@ -1980,6 +2028,9 @@ retry_space:
 		    (space <= 0 ||
 		     space < so->so_snd.sb_lowat)) {
 			if (so->so_state & SS_NBIO) {
+				if (bg_sendfile_enable &&
+				    (so->so_snd.sb_flags & SB_SENDING) == 0)
+					soissending(so, td, uap, hdr_uio, trl_uio, compat, sbytes, vnp_size);
 				SOCKBUF_UNLOCK(&so->so_snd);
 				error = EAGAIN;
 				goto done;
@@ -2041,6 +2092,7 @@ retry_space:
 				done = 1;		/* all data sent */
 				break;
 			}
+			vnp_size = obj->un_pager.vnp.vnp_size;
 			/*
 			 * Don't overflow the send buffer.
 			 * Stop here and send out what we've
@@ -2098,7 +2150,7 @@ retry_space:
 				error = vn_rdwr(UIO_READ, vp, NULL, MAXBSIZE,
 				    trunc_page(off), UIO_NOCOPY, IO_NODELOCKED |
 				    IO_VMIO | ((MAXBSIZE / bsize) << IO_SEQSHIFT),
-				    td->td_ucred, NOCRED, &resid, td);
+				    cred, NOCRED, &resid, td);
 				VOP_UNLOCK(vp, 0);
 				VFS_UNLOCK_GIANT(vfslocked);
 				VM_OBJECT_LOCK(obj);
@@ -2245,17 +2297,24 @@ out:
 		td->td_retval[0] = 0;
 	}
 	if (uap->sbytes != NULL) {
-		copyout(&sbytes, uap->sbytes, sizeof(off_t));
+		if ((uap->flags & SF_TASKQ) == 0)
+			copyout(&sbytes, uap->sbytes, sizeof(off_t));
+		else
+			*(uap->sbytes) = sbytes;
 	}
 	if (obj != NULL)
 		vm_object_deallocate(obj);
-	if (vp != NULL) {
-		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
-		vrele(vp);
-		VFS_UNLOCK_GIANT(vfslocked);
+	if ((uap->flags & SF_TASKQ) == 0) {
+		if (vp != NULL) {
+			vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+			vrele(vp);
+			VFS_UNLOCK_GIANT(vfslocked);
+		}
+		if (so)
+			fdrop(sock_fp, td);
+		if (fp)
+			fdrop(fp, td);
 	}
-	if (so)
-		fdrop(sock_fp, td);
 	if (m)
 		m_freem(m);
 

Modified: user/kmacy/releng_8_fcs/sys/sys/file.h
==============================================================================
--- user/kmacy/releng_8_fcs/sys/sys/file.h	Fri Oct  2 19:51:03 2009	(r197717)
+++ user/kmacy/releng_8_fcs/sys/sys/file.h	Fri Oct  2 20:15:47 2009	(r197718)
@@ -132,6 +132,7 @@ struct file {
 	 *  DFLAG_SEEKABLE specific fields
 	 */
 	off_t		f_offset;
+	off_t		f_sfbytes;
 	/*
 	 * Mandatory Access control information.
 	 */

Modified: user/kmacy/releng_8_fcs/sys/sys/sockbuf.h
==============================================================================
--- user/kmacy/releng_8_fcs/sys/sys/sockbuf.h	Fri Oct  2 19:51:03 2009	(r197717)
+++ user/kmacy/releng_8_fcs/sys/sys/sockbuf.h	Fri Oct  2 20:15:47 2009	(r197718)
@@ -52,6 +52,7 @@
 #define	SB_NOCOALESCE	0x200		/* don't coalesce new data into existing mbufs */
 #define	SB_IN_TOE	0x400		/* socket buffer is in the middle of an operation */
 #define	SB_AUTOSIZE	0x800		/* automatically size socket buffer */
+#define	SB_SENDING	0x1000		/* socket is owned by sendfile thread */
 
 #define	SBS_CANTSENDMORE	0x0010	/* can't send more data to peer */
 #define	SBS_CANTRCVMORE		0x0020	/* can't receive more data from peer */
@@ -155,9 +156,12 @@ struct mbuf *
 	sbsndptr(struct sockbuf *sb, u_int off, u_int len, u_int *moff);
 void	sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb);
 int	sbwait(struct sockbuf *sb);
-int	sblock(struct sockbuf *sb, int flags);
+int	_sblock(struct sockbuf *sb, int flags, const char *file, int line);
 void	sbunlock(struct sockbuf *sb);
 
+#define sblock(sb, flags) \
+	_sblock((sb), (flags), __FILE__, __LINE__)
+
 /*
  * How much space is there in a socket buffer (so->so_snd or so->so_rcv)?
  * This is problematical if the fields are unsigned, as the space might

Modified: user/kmacy/releng_8_fcs/sys/sys/socket.h
==============================================================================
--- user/kmacy/releng_8_fcs/sys/sys/socket.h	Fri Oct  2 19:51:03 2009	(r197717)
+++ user/kmacy/releng_8_fcs/sys/sys/socket.h	Fri Oct  2 20:15:47 2009	(r197718)
@@ -617,6 +617,7 @@ struct sf_hdtr {
 #define	SF_NODISKIO     0x00000001
 #define	SF_MNOWAIT	0x00000002
 #define	SF_SYNC		0x00000004
+#define	SF_TASKQ	0x00000008
 #endif
 
 #ifndef	_KERNEL

Modified: user/kmacy/releng_8_fcs/sys/sys/socketvar.h
==============================================================================
--- user/kmacy/releng_8_fcs/sys/sys/socketvar.h	Fri Oct  2 19:51:03 2009	(r197717)
+++ user/kmacy/releng_8_fcs/sys/sys/socketvar.h	Fri Oct  2 20:15:47 2009	(r197718)
@@ -206,7 +206,8 @@ struct xsocket {
 /* can we write something to so? */
 #define	sowriteable(so) \
     ((sbspace(&(so)->so_snd) >= (so)->so_snd.sb_lowat && \
-	(((so)->so_state&SS_ISCONNECTED) || \
+	!((so)->so_snd.sb_flags & SB_SENDING) &&	 \
+	(((so)->so_state&SS_ISCONNECTED) ||		     \
 	  ((so)->so_proto->pr_flags&PR_CONNREQUIRED)==0)) || \
      ((so)->so_snd.sb_state & SBS_CANTSENDMORE) || \
      (so)->so_error)

Modified: user/kmacy/releng_8_fcs/sys/sys/sockstate.h
==============================================================================
--- user/kmacy/releng_8_fcs/sys/sys/sockstate.h	Fri Oct  2 19:51:03 2009	(r197717)
+++ user/kmacy/releng_8_fcs/sys/sys/sockstate.h	Fri Oct  2 20:15:47 2009	(r197718)
@@ -71,11 +71,18 @@
 #define	SBS_RCVATMARK		0x0040	/* at mark on input */
 
 struct socket;
+struct sendfile_args;
+struct uio;
 
 void	soisconnected(struct socket *so);
 void	soisconnecting(struct socket *so);
 void	soisdisconnected(struct socket *so);
 void	soisdisconnecting(struct socket *so);
+void	soissending(struct socket *so,
+    struct thread *td, struct sendfile_args *uap,
+    struct uio *hdr_uio, struct uio *trl_uio,
+    int compat, off_t sbytes, off_t vnp_size);
+void	sosendingwakeup(struct sockbuf *sb);
 void	socantrcvmore(struct socket *so);
 void	socantrcvmore_locked(struct socket *so);
 void	socantsendmore(struct socket *so);

Modified: user/kmacy/releng_8_fcs/sys/sys/syscallsubr.h
==============================================================================
--- user/kmacy/releng_8_fcs/sys/sys/syscallsubr.h	Fri Oct  2 19:51:03 2009	(r197717)
+++ user/kmacy/releng_8_fcs/sys/sys/syscallsubr.h	Fri Oct  2 20:15:47 2009	(r197718)
@@ -172,7 +172,8 @@ int	kern_semctl(struct thread *td, int s
 int	kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
 	    fd_set *fd_ex, struct timeval *tvp, int abi_nfdbits);
 int	kern_sendfile(struct thread *td, struct sendfile_args *uap,
-	    struct uio *hdr_uio, struct uio *trl_uio, int compat);
+	    struct uio *hdr_uio, struct uio *trl_uio, int compat,
+    struct file *bgfp, struct socket *bgso, struct ucred *bgcred);
 int	kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
 	    struct mbuf *control, enum uio_seg segflg);
 int	kern_setgroups(struct thread *td, u_int ngrp, gid_t *groups);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200910022015.n92KFm0m012048>