[PATCH] Eliminate witness warning in linux_ioctl.c

Craig Rodrigues rodrigc at crodrigues.org
Fri Aug 26 04:35:23 GMT 2005


Hi,

If I run the following test:

(1)  Make sure that the linux_base-8 port is installed.
(2)  kldload linux.ko
(3)  Download and run the ifconfig program from Fedora:
      http://people.freebsd.org/~rodrigc/linux-test/ifconfig.bz2

I get this following WITNESS warning (not a LOR!!):

Calling uiomove() with the following non-sleepable locks held:
exclusive sleep mutex ifnet r = 0 (0xc096dd60) locked @ /usr/src/sys/modules/lin
ux/../../compat/linux/linux_ioctl.c:2170
KDB: stack backtrace:
kdb_backtrace(1,c17fe900,400,d165bc50,d165bbfc) at kdb_backtrace+0x29
witness_warn(5,0,c0856813,c064b97d,0) at witness_warn+0x18e
uiomove(d165bc70,20,d165bc50,1,bfbfddb0) at uiomove+0x56
linux_ioctl_socket(c1b94000,d165bd04,c181e120,0,c1b94000) at linux_ioctl_socket+
0x7dc
linux_ioctl(c1b94000,d165bd04,3,3,246) at linux_ioctl+0x99
syscall(3b,3b,3b,b,bfbfe208) at syscall+0x22f
Xint0x80_syscall() at Xint0x80_syscall+0x1f
--- syscall (54, Linux ELF, linux_ioctl), eip = 0x283252a4, esp = 0xbfbfdd90, eb
p = 0xbfbfe1e0 ---


In order to eliminate this WITNESS warning,
I modified linux_ifconf() to not use uiomove().  I
based my changes on the logic used in ifconf() in net/if.c.

Can someone provide feedback on this patch?

Thanks.

-- 
Craig Rodrigues        
rodrigc at crodrigues.org
-------------- next part --------------
Index: linux_ioctl.c
===================================================================
RCS file: /home/ncvs/src/sys/compat/linux/linux_ioctl.c,v
retrieving revision 1.128
diff -u -u -r1.128 linux_ioctl.c
--- linux_ioctl.c	9 Aug 2005 10:19:41 -0000	1.128
+++ linux_ioctl.c	26 Aug 2005 04:33:38 -0000
@@ -46,6 +46,7 @@
 #include <sys/linker_set.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
+#include <sys/sbuf.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/soundcard.h>
@@ -2130,14 +2131,15 @@
 	struct l_ifreq ifr;
 	struct ifnet *ifp;
 	struct ifaddr *ifa;
-	struct iovec iov;
-	struct uio uio;
-	int error, ethno;
+	struct sbuf *sb;
+	int error, ethno, full = 0, valid_len, max_len;
 
 	error = copyin(uifc, &ifc, sizeof(ifc));
 	if (error != 0)
 		return (error);
 
+	max_len = MAXPHYS - 1;
+
 	/* handle the 'request buffer size' case */
 	if (ifc.ifc_buf == PTROUT(NULL)) {
 		ifc.ifc_len = 0;
@@ -2152,25 +2154,24 @@
 		return (error);
 	}
 
-	/* much easier to use uiomove than keep track ourselves */
-	iov.iov_base = PTRIN(ifc.ifc_buf);
-	iov.iov_len = ifc.ifc_len;
-	uio.uio_iov = &iov;
-	uio.uio_iovcnt = 1;
-	uio.uio_offset = 0;
-	uio.uio_resid = ifc.ifc_len;
-	uio.uio_segflg = UIO_USERSPACE;
-	uio.uio_rw = UIO_READ;
-	uio.uio_td = td;
+	if (ifc.ifc_len <= 0)
+		return (EINVAL);
 
+again:
 	/* Keep track of eth interfaces */
 	ethno = 0;
+	if (ifc.ifc_len <= max_len) {
+		max_len = ifc.ifc_len;
+		full = 1;
+	}
+	sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
+	max_len = 0;
+	valid_len = 0;
 
 	/* Return all AF_INET addresses of all interfaces */
 	IFNET_RLOCK();		/* could sleep XXX */
 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
-		if (uio.uio_resid <= 0)
-			break;
+		int addrs = 0;
 
 		bzero(&ifr, sizeof(ifr));
 		if (IFP_IS_ETH(ifp))
@@ -2183,26 +2184,39 @@
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			struct sockaddr *sa = ifa->ifa_addr;
 
-			if (uio.uio_resid <= 0)
-				break;
-
 			if (sa->sa_family == AF_INET) {
 				ifr.ifr_addr.sa_family = LINUX_AF_INET;
 				memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
 				    sizeof(ifr.ifr_addr.sa_data));
-
-				error = uiomove(&ifr, sizeof(ifr), &uio);
-				if (error != 0) {
-					IFNET_RUNLOCK();
-					return (error);
-				}
+				sbuf_bcat(sb, &ifr, sizeof(ifr));
+				max_len += sizeof(ifr);
+				addrs++;
 			}
+
+			if (!sbuf_overflowed(sb))
+				valid_len = sbuf_len(sb);
+		}
+		if (addrs == 0) {
+			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
+			sbuf_bcat(sb, &ifr, sizeof(ifr));
+			max_len += sizeof(ifr);
+
+			if (!sbuf_overflowed(sb))
+				valid_len = sbuf_len(sb);
 		}
 	}
 	IFNET_RUNLOCK();
 
-	ifc.ifc_len -= uio.uio_resid;
+	if (valid_len != max_len && !full) {
+		sbuf_delete(sb);
+		goto again;
+	}
+
+	ifc.ifc_len = valid_len; 
+	sbuf_finish(sb);
+	memcpy(ifc.ifc_buf, sbuf_data(sb), ifc.ifc_len);
 	error = copyout(&ifc, uifc, sizeof(ifc));
+	sbuf_delete(sb);
 
 	return (error);
 }


More information about the freebsd-current mailing list