svn commit: r191423 - head/sys/net
Robert Watson
rwatson at FreeBSD.org
Thu Apr 23 13:08:48 UTC 2009
Author: rwatson
Date: Thu Apr 23 13:08:47 2009
New Revision: 191423
URL: http://svn.freebsd.org/changeset/base/191423
Log:
Add ifunit_ref(), a version of ifunit(), that returns not just an
interface pointer, but also a reference to it.
Modify ifioctl() to use ifunit_ref(), holding the reference until
all ioctls, etc, have completed.
This closes a class of reader-writer races in which interfaces
could be removed during long-running ioctls, leading to crashes.
Many other consumers of ifunit() should now use ifunit_ref() to
avoid similar races.
MFC after: 3 weeks
Modified:
head/sys/net/if.c
head/sys/net/if_var.h
Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c Thu Apr 23 12:09:49 2009 (r191422)
+++ head/sys/net/if.c Thu Apr 23 13:08:47 2009 (r191423)
@@ -1788,10 +1788,27 @@ if_slowtimo(void *arg)
}
/*
- * Map interface name to
- * interface structure pointer.
+ * Map interface name to interface structure pointer, with or without
+ * returning a reference.
*/
struct ifnet *
+ifunit_ref(const char *name)
+{
+ INIT_VNET_NET(curvnet);
+ struct ifnet *ifp;
+
+ IFNET_RLOCK();
+ TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+ if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0)
+ break;
+ }
+ if (ifp != NULL)
+ if_ref(ifp);
+ IFNET_RUNLOCK();
+ return (ifp);
+}
+
+struct ifnet *
ifunit(const char *name)
{
INIT_VNET_NET(curvnet);
@@ -2167,17 +2184,21 @@ ifioctl(struct socket *so, u_long cmd, c
return (if_getgroupmembers((struct ifgroupreq *)data));
}
- ifp = ifunit(ifr->ifr_name);
- if (ifp == 0)
+ ifp = ifunit_ref(ifr->ifr_name);
+ if (ifp == NULL)
return (ENXIO);
error = ifhwioctl(cmd, ifp, data, td);
- if (error != ENOIOCTL)
+ if (error != ENOIOCTL) {
+ if_rele(ifp);
return (error);
+ }
oif_flags = ifp->if_flags;
- if (so->so_proto == 0)
+ if (so->so_proto == NULL) {
+ if_rele(ifp);
return (EOPNOTSUPP);
+ }
#ifndef COMPAT_43
error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
data,
@@ -2250,6 +2271,7 @@ ifioctl(struct socket *so, u_long cmd, c
}
#endif
}
+ if_rele(ifp);
return (error);
}
Modified: head/sys/net/if_var.h
==============================================================================
--- head/sys/net/if_var.h Thu Apr 23 12:09:49 2009 (r191422)
+++ head/sys/net/if_var.h Thu Apr 23 13:08:47 2009 (r191423)
@@ -776,6 +776,7 @@ void if_up(struct ifnet *);
int ifioctl(struct socket *, u_long, caddr_t, struct thread *);
int ifpromisc(struct ifnet *, int);
struct ifnet *ifunit(const char *);
+struct ifnet *ifunit_ref(const char *);
void ifq_attach(struct ifaltq *, struct ifnet *ifp);
void ifq_detach(struct ifaltq *);
More information about the svn-src-head
mailing list