svn commit: r247740 - head/sys/kern

Pawel Jakub Dawidek pjd at FreeBSD.org
Sun Mar 3 23:39:31 UTC 2013


Author: pjd
Date: Sun Mar  3 23:39:30 2013
New Revision: 247740
URL: http://svnweb.freebsd.org/changeset/base/247740

Log:
  For some reason when I started to pass filedescent structures instead of
  pointers to the file structure receiving descriptors stopped to work when also
  at least few kilobytes of data is being send. In the kernel the
  soreceive_generic() function doesn't see control mbuf as the first mbuf and
  unp_externalize() is never called, first 6(?) kilobytes of data is missing as
  well on receiving end.
  
  This breaks for example tmux.
  
  I don't know yet why going from 8 bytes to sizeof(struct filedescent) per
  descriptor (or even to 16 bytes per descriptor) breaks things, but to
  work-around it for now use 8 bytes per file descriptor at the cost of memory
  allocation.
  
  Reported by:	flo, Diane Bruce, Jan Beich <jbeich at tormail.org>
  Simple testcase provided by:	mjg

Modified:
  head/sys/kern/uipc_usrreq.c

Modified: head/sys/kern/uipc_usrreq.c
==============================================================================
--- head/sys/kern/uipc_usrreq.c	Sun Mar  3 23:27:21 2013	(r247739)
+++ head/sys/kern/uipc_usrreq.c	Sun Mar  3 23:39:30 2013	(r247740)
@@ -102,6 +102,8 @@ __FBSDID("$FreeBSD$");
 
 #include <vm/uma.h>
 
+MALLOC_DECLARE(M_FILECAPS);
+
 /*
  * Locking key:
  * (l)	Locked using list lock
@@ -282,7 +284,7 @@ static void	unp_drop(struct unpcb *, int
 static void	unp_gc(__unused void *, int);
 static void	unp_scan(struct mbuf *, void (*)(struct file *));
 static void	unp_discard(struct file *);
-static void	unp_freerights(struct filedescent *, int);
+static void	unp_freerights(struct filedescent **, int);
 static void	unp_init(void);
 static int	unp_internalize(struct mbuf **, struct thread *);
 static void	unp_internalize_fp(struct file *);
@@ -1679,17 +1681,17 @@ unp_drop(struct unpcb *unp, int errno)
 }
 
 static void
-unp_freerights(struct filedescent *fde, int fdcount)
+unp_freerights(struct filedescent **fdep, int fdcount)
 {
 	struct file *fp;
 	int i;
 
-	for (i = 0; i < fdcount; i++, fde++) {
-		fp = fde->fde_file;
-		filecaps_free(&fdep->fde_caps);
-		bzero(fde, sizeof(*fde));
+	for (i = 0; i < fdcount; i++) {
+		fp = fdep[i]->fde_file;
+		filecaps_free(&fdep[i]->fde_caps);
 		unp_discard(fp);
 	}
+	free(fdep[0], M_FILECAPS);
 }
 
 static int
@@ -1700,7 +1702,7 @@ unp_externalize(struct mbuf *control, st
 	int i;
 	int *fdp;
 	struct filedesc *fdesc = td->td_proc->p_fd;
-	struct filedescent *fde, *fdep;
+	struct filedescent *fde, **fdep;
 	void *data;
 	socklen_t clen = control->m_len, datalen;
 	int error, newfds;
@@ -1756,16 +1758,18 @@ unp_externalize(struct mbuf *control, st
 
 			fdp = (int *)
 			    CMSG_DATA(mtod(*controlp, struct cmsghdr *));
-			for (i = 0; i < newfds; i++, fdep++, fdp++) {
+			for (i = 0; i < newfds; i++, fdp++) {
 				if (fdalloc(td, 0, &f))
 					panic("unp_externalize fdalloc failed");
 				fde = &fdesc->fd_ofiles[f];
-				fde->fde_file = fdep->fde_file;
-				filecaps_move(&fdep->fde_caps, &fde->fde_caps);
+				fde->fde_file = fdep[0]->fde_file;
+				filecaps_move(&fdep[0]->fde_caps,
+				    &fde->fde_caps);
 				unp_externalize_fp(fde->fde_file);
 				*fdp = f;
 			}
 			FILEDESC_XUNLOCK(fdesc);
+			free(fdep[0], M_FILECAPS);
 		} else {
 			/* We can just copy anything else across. */
 			if (error || controlp == NULL)
@@ -1840,7 +1844,7 @@ unp_internalize(struct mbuf **controlp, 
 	struct bintime *bt;
 	struct cmsghdr *cm = mtod(control, struct cmsghdr *);
 	struct cmsgcred *cmcred;
-	struct filedescent *fde, *fdep;
+	struct filedescent *fde, **fdep, *fdev;
 	struct file *fp;
 	struct timeval *tv;
 	int i, fd, *fdp;
@@ -1914,7 +1918,7 @@ unp_internalize(struct mbuf **controlp, 
 			 * Now replace the integer FDs with pointers to the
 			 * file structure and capability rights.
 			 */
-			newlen = oldfds * sizeof(*fdep);
+			newlen = oldfds * sizeof(fdep[0]);
 			*controlp = sbcreatecontrol(NULL, newlen,
 			    SCM_RIGHTS, SOL_SOCKET);
 			if (*controlp == NULL) {
@@ -1923,13 +1927,17 @@ unp_internalize(struct mbuf **controlp, 
 				goto out;
 			}
 			fdp = data;
-			fdep = (struct filedescent *)
+			fdep = (struct filedescent **)
 			    CMSG_DATA(mtod(*controlp, struct cmsghdr *));
-			for (i = 0; i < oldfds; i++, fdep++, fdp++) {
+			fdev = malloc(sizeof(*fdev) * oldfds, M_FILECAPS,
+			    M_WAITOK);
+			for (i = 0; i < oldfds; i++, fdev++, fdp++) {
 				fde = &fdesc->fd_ofiles[*fdp];
-				fdep->fde_file = fde->fde_file;
-				filecaps_copy(&fde->fde_caps, &fdep->fde_caps);
-				unp_internalize_fp(fdep->fde_file);
+				fdep[i] = fdev;
+				fdep[i]->fde_file = fde->fde_file;
+				filecaps_copy(&fde->fde_caps,
+				    &fdep[i]->fde_caps);
+				unp_internalize_fp(fdep[i]->fde_file);
 			}
 			FILEDESC_SUNLOCK(fdesc);
 			break;
@@ -2291,7 +2299,7 @@ static void
 unp_scan(struct mbuf *m0, void (*op)(struct file *))
 {
 	struct mbuf *m;
-	struct filedescent *fdep;
+	struct filedescent **fdep;
 	struct cmsghdr *cm;
 	void *data;
 	int i;
@@ -2318,8 +2326,8 @@ unp_scan(struct mbuf *m0, void (*op)(str
 				    cm->cmsg_type == SCM_RIGHTS) {
 					qfds = datalen / sizeof(*fdep);
 					fdep = data;
-					for (i = 0; i < qfds; i++, fdep++)
-						(*op)(fdep->fde_file);
+					for (i = 0; i < qfds; i++)
+						(*op)(fdep[i]->fde_file);
 				}
 
 				if (CMSG_SPACE(datalen) < clen) {


More information about the svn-src-all mailing list