On Mon, Jun 29, 2020 at 04:27:50PM +0200, Hrvoje Popovski wrote: > On 29.6.2020. 10:59, Vitaliy Makkoveev wrote: > > I reworked tool for reproduce. Now I avoided fork()/exec() route and it > > takes couple of minutes to take panic on 4 cores. Also some screenshots > > attached. > > > > I hope anyone else will try it. > > Hi, > > i'm getting panic quite fast :) > i will leave box in ddb if more information is needed >
Thanks. Right now it takes seconds to catch panic at least with switch(4), bridge(4), pflog(4), vether(4) and etherip(4). So you can leave ddb(4). I like to someone will try my solution for this issue. And reviews are welcomed :) The latest diff below. If the `unit' was obtained it's guaranteed that there is no pseudo interface with `name' is system. ifunit() now useless here and can be dropped. Index: sys/net/if.c =================================================================== RCS file: /cvs/src/sys/net/if.c,v retrieving revision 1.610 diff -u -p -r1.610 if.c --- sys/net/if.c 22 Jun 2020 09:45:13 -0000 1.610 +++ sys/net/if.c 29 Jun 2020 13:54:29 -0000 @@ -157,6 +157,8 @@ void if_linkstate_task(void *); int if_clone_list(struct if_clonereq *); struct if_clone *if_clone_lookup(const char *, int *); +int if_clone_alloc_unit(struct if_clone *, int); +void if_clone_rele_unit(struct if_clone *, int); int if_group_egress_build(void); @@ -1244,19 +1246,18 @@ if_clone_create(const char *name, int rd { struct if_clone *ifc; struct ifnet *ifp; - int unit, ret; + int unit, error; ifc = if_clone_lookup(name, &unit); if (ifc == NULL) return (EINVAL); + error = if_clone_alloc_unit(ifc, unit); + if (error != 0) + return (error); - if (ifunit(name) != NULL) - return (EEXIST); - - ret = (*ifc->ifc_create)(ifc, unit); - - if (ret != 0 || (ifp = ifunit(name)) == NULL) - return (ret); + error = (*ifc->ifc_create)(ifc, unit); + if (error != 0 || (ifp = ifunit(name)) == NULL) + return (error); NET_LOCK(); if_addgroup(ifp, ifc->ifc_name); @@ -1264,7 +1265,7 @@ if_clone_create(const char *name, int rd if_setrdomain(ifp, rdomain); NET_UNLOCK(); - return (ret); + return (0); } /* @@ -1275,9 +1276,9 @@ if_clone_destroy(const char *name) { struct if_clone *ifc; struct ifnet *ifp; - int ret; + int ret, unit; - ifc = if_clone_lookup(name, NULL); + ifc = if_clone_lookup(name, &unit); if (ifc == NULL) return (EINVAL); @@ -1297,6 +1298,7 @@ if_clone_destroy(const char *name) } NET_UNLOCK(); ret = (*ifc->ifc_destroy)(ifp); + if_clone_rele_unit(ifc, unit); return (ret); } @@ -1342,12 +1344,95 @@ if_clone_lookup(const char *name, int *u unit = (unit * 10) + (*cp++ - '0'); } - if (unitp != NULL) - *unitp = unit; + *unitp = unit; return (ifc); } /* + * Allocate unit for cloned network interface. + */ +int if_clone_alloc_unit(struct if_clone *ifc, int unit) +{ + int word, bit, ret; + + word = unit / (sizeof(*ifc->ifc_map) * 8); + bit = unit % (sizeof(*ifc->ifc_map) * 8); + + rw_enter_write(&ifc->ifc_lock); + + if(word >= ifc->ifc_map_size) { + u_long *map; + int size; + + size = word + 1; + map = mallocarray(size, sizeof(*map), M_TEMP, M_WAITOK | + M_ZERO); + + if (ifc->ifc_map != NULL) { + memcpy(map, ifc->ifc_map, ifc->ifc_map_size); + free(ifc->ifc_map, M_TEMP, + ifc->ifc_map_size * sizeof(*map)); + } + + ifc->ifc_map = map; + ifc->ifc_map_size = size; + } + + if (ifc->ifc_map[word] & (1UL << bit)) + ret = EEXIST; + else { + ifc->ifc_map[word] |= (1UL << bit); + ret = 0; + } + + rw_exit_write(&ifc->ifc_lock); + + return ret; +} + +/* + * Release allocated unit for cloned network interface. + */ +void if_clone_rele_unit(struct if_clone *ifc, int unit) +{ + int word, bit; + + word = unit / (sizeof(*ifc->ifc_map) * 8); + bit = unit % (sizeof(*ifc->ifc_map) * 8); + + rw_enter_write(&ifc->ifc_lock); + KASSERT(word < ifc->ifc_map_size); + + ifc->ifc_map[word] &= ~(1UL << bit); + + if (ifc->ifc_map[word] == 0) { + u_long *map; + int size; + + size = ifc->ifc_map_size - 2; + while (size>=0) { + if (ifc->ifc_map[size] != 0) + break; + --size; + } + if (size<0) { + size = 0; + map = NULL; + } else { + size += 1; + map = mallocarray(size, sizeof(*map), M_TEMP, + M_WAITOK); + memcpy(map, ifc->ifc_map, size); + } + + free(ifc->ifc_map, M_TEMP, ifc->ifc_map_size * sizeof(*map)); + ifc->ifc_map = map; + ifc->ifc_map_size = size; + } + rw_exit_write(&ifc->ifc_lock); +} + +/* * Register a network interface cloner. */ void @@ -1360,6 +1445,7 @@ if_clone_attach(struct if_clone *ifc) * initialization, the if_cloners becomes immutable. */ KASSERT(pdevinit_done == 0); + rw_init(&ifc->ifc_lock, "icflck"); LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); if_cloners_count++; } Index: sys/net/if_var.h =================================================================== RCS file: /cvs/src/sys/net/if_var.h,v retrieving revision 1.105 diff -u -p -r1.105 if_var.h --- sys/net/if_var.h 12 May 2020 08:49:54 -0000 1.105 +++ sys/net/if_var.h 29 Jun 2020 13:54:29 -0000 @@ -45,6 +45,7 @@ #include <sys/task.h> #include <sys/time.h> #include <sys/timeout.h> +#include <sys/rwlock.h> #include <net/ifq.h> @@ -86,6 +87,10 @@ struct if_clone { const char *ifc_name; /* name of device, e.g. `gif' */ size_t ifc_namelen; /* length of name */ + struct rwlock ifc_lock; /* lock for map */ + u_long *ifc_map; /* units map */ + int ifc_map_size; /* units map size */ + int (*ifc_create)(struct if_clone *, int); int (*ifc_destroy)(struct ifnet *); }; @@ -95,6 +100,8 @@ struct if_clone { .ifc_list = { NULL, NULL }, \ .ifc_name = name, \ .ifc_namelen = sizeof(name) - 1, \ + .ifc_map = NULL, \ + .ifc_map_size = 0, \ .ifc_create = create, \ .ifc_destroy = destroy, \ }