On Mon, May 14, 2018 at 10:24:09AM +0200, Martin Pieuchot wrote:
> On 14/05/18(Mon) 10:17, Theo Buehler wrote:
> > This was pointed out to me by mpi a while ago.
> >
> > The if_clone_list() function accesses &if_cloners, which is only
> > modified via if_clone_attach() and if_clone_detach().
> >
> > The latter function is never called, as far as I can tell, while
> > if_clone_attach() is only called at boot time via the pdevinit[]
> > mechanism in ioconf.c.
> >
> > So, for the purposes of the NET_LOCK(), &if_cloners is immutable, hence
> > if_clone_list() does not need the NET_RLOCK().
>
> Please add a KERNEL_ASSERT_LOCKED() in if_clone_list(), with that ok
> mpi@.
[...]
> Another (better) alternative would be to introduce a rwlock to protect
> those two globals and use it where required.
Here's an updated diff that implements an rwlock to protect if_cloners
and if_clone_count.
Note that there are two uses for SIOCIFGCLONERS, one that just asks for
a count of cloners and the other that asks for the entire list (compare
with the two ioctl calls in list_cloners() in ifconfig.c). I decided to
split the paths more clearly which also has the benefit of keeping the
diff smaller.
While here, replace a ternary operator with a MIN for readability.
Index: sys/net/if.c
===================================================================
RCS file: /var/cvs/src/sys/net/if.c,v
retrieving revision 1.551
diff -u -p -r1.551 if.c
--- sys/net/if.c 28 Apr 2018 15:44:59 -0000 1.551
+++ sys/net/if.c 14 May 2018 12:32:28 -0000
@@ -217,6 +217,9 @@ void if_idxmap_insert(struct ifnet *);
void if_idxmap_remove(struct ifnet *);
TAILQ_HEAD(, ifg_group) ifg_head = TAILQ_HEAD_INITIALIZER(ifg_head);
+
+/* Serialize access to &if_cloners and if_cloners_count */
+struct rwlock if_cloners_lock = RWLOCK_INITIALIZER("ifclonerslk");
LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
int if_cloners_count;
@@ -1243,11 +1246,13 @@ if_clone_lookup(const char *name, int *u
if (cp - name < IFNAMSIZ-1 && *cp == '0' && cp[1] != '\0')
return (NULL); /* unit number 0 padded */
+ rw_enter_read(&if_cloners_lock);
LIST_FOREACH(ifc, &if_cloners, ifc_list) {
if (strlen(ifc->ifc_name) == cp - name &&
!strncmp(name, ifc->ifc_name, cp - name))
break;
}
+ rw_exit_read(&if_cloners_lock);
if (ifc == NULL)
return (NULL);
@@ -1273,8 +1278,10 @@ if_clone_lookup(const char *name, int *u
void
if_clone_attach(struct if_clone *ifc)
{
+ rw_enter_write(&if_cloners_lock);
LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
if_cloners_count++;
+ rw_exit_write(&if_cloners_lock);
}
/*
@@ -1283,9 +1290,10 @@ if_clone_attach(struct if_clone *ifc)
void
if_clone_detach(struct if_clone *ifc)
{
-
+ rw_enter_write(&if_cloners_lock);
LIST_REMOVE(ifc, ifc_list);
if_cloners_count--;
+ rw_exit_write(&if_cloners_lock);
}
/*
@@ -1298,17 +1306,21 @@ if_clone_list(struct if_clonereq *ifcr)
struct if_clone *ifc;
int count, error = 0;
- ifcr->ifcr_total = if_cloners_count;
if ((dst = ifcr->ifcr_buffer) == NULL) {
/* Just asking how many there are. */
+ rw_enter_read(&if_cloners_lock);
+ ifcr->ifcr_total = if_cloners_count;
+ rw_exit_read(&if_cloners_lock);
return (0);
}
if (ifcr->ifcr_count < 0)
return (EINVAL);
- count = (if_cloners_count < ifcr->ifcr_count) ?
- if_cloners_count : ifcr->ifcr_count;
+ rw_enter_read(&if_cloners_lock);
+
+ ifcr->ifcr_total = if_cloners_count;
+ count = MIN(if_cloners_count, ifcr->ifcr_count);
LIST_FOREACH(ifc, &if_cloners, ifc_list) {
if (count == 0)
@@ -1322,6 +1334,7 @@ if_clone_list(struct if_clonereq *ifcr)
dst += IFNAMSIZ;
}
+ rw_exit_read(&if_cloners_lock);
return (error);
}
@@ -2164,9 +2177,7 @@ ifioctl_get(u_long cmd, caddr_t data)
NET_RUNLOCK();
return (error);
case SIOCIFGCLONERS:
- NET_RLOCK();
error = if_clone_list((struct if_clonereq *)data);
- NET_RUNLOCK();
return (error);
case SIOCGIFGMEMB:
NET_RLOCK();