From 3627dcf262d0a35af458e0c84d770346daf9d8e4 Mon Sep 17 00:00:00 2001 From: rodrigc Date: Sat, 27 Aug 2005 14:44:10 +0000 Subject: Rewrite linux_ifconf() to be more like ifconf() in net/if.c so that we do not call uiomove() while IFNET_RLOCK() is held. This eliminates the witness warning: Calling uiomove() with the following non-sleepable locks held: exclusive sleep mutex ifnet r = 0 (0xc096dd60) locked @ /usr/src/sys/modules/linux/../../compat/linux/linux_ioctl.c:2170 MFC after: 2 days --- sys/compat/linux/linux_ioctl.c | 64 +++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 25 deletions(-) (limited to 'sys/compat') diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index 8cfd3d2..50d3029 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -2130,14 +2131,15 @@ linux_ifconf(struct thread *td, struct ifconf *uifc) 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 @@ linux_ifconf(struct thread *td, struct ifconf *uifc) 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 @@ linux_ifconf(struct thread *td, struct ifconf *uifc) 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); } -- cgit v1.1