How to hard lock FreeBSD-5.1 generic with sl
Peter Pentchev
roam at ringlet.net
Wed Dec 31 07:29:37 PST 2003
On Tue, Dec 30, 2003 at 04:28:00PM +0200, Peter Pentchev wrote:
> On Tue, Dec 30, 2003 at 06:12:53AM -0800, Kris Kennaway wrote:
> > On Mon, Dec 29, 2003 at 06:02:45PM -0800, Chris McKenzie wrote:
> > > On three machines (PII 450, P3 450, Pentium laptop 200) with FreeBSD-5.1
> > > generic (and specific builds) I am able to completely hard lock the system
> > > by doing the following
> > >
> > > # ifconfig ppp0 create
> > > # ifconfig sl0 create
> > >
> > > Heh . . . that shouldn't happen.
> >
> > Does the problem persist with 5.2?
>
> I just tested in on a 5.2-CURRENT as of today, and yes, the system
> locked up solid - no ddb, no anything. I'll try to do some more testing
> as time permits.
[cc'd to -net for a pre-commit review / discussion]
OK, I think I've found the problem. The if_clone_attach() routine in
src/sys/net/if.c blindly adds the new cloned interface to the if_cloners
list without checking if it is already on the list. This,
understandably, leads to problems when trying to attach an interface
that already exists - such as a ppp interface.
The if_ppp code adds itself to the if_cloners list at the module
loading stage. Thus, the very first invocation of ifconfig ppp0 create
adds the ppp_cloner structure to the list *again* - and creates a loop
on the list. Any attempts to traverse the list later lead to lock-ups.
Attached is a patch that does two things: first, only adds the interface
to the list if it is not already there (the second and third chunks, at
lines 812 and 827 of if.c), and second, adds a if_check_cloners_loop()
routine to traverse the if_cloners list and panic if a loop is found.
The if_check_cloners_loop() invocations could be protected by
INVARIANTS, KASSERT, or WITNESS, but it sure helps find such problems :)
Chris, could you try this patch and see if it helps in your situation?
And.. happy New Year, everyone! (albeit a little early :)
G'luck,
Peter
--
Peter Pentchev roam at ringlet.net roam at sbnd.net roam at FreeBSD.org
PGP key: http://people.FreeBSD.org/~roam/roam.key.asc
Key fingerprint FDBA FD79 C26F 3C51 C95E DF9E ED18 B68D 1619 4553
I am not the subject of this sentence.
-------------- next part --------------
Index: src/sys/net/if.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if.c,v
retrieving revision 1.174
diff -u -r1.174 if.c
--- src/sys/net/if.c 26 Dec 2003 18:09:35 -0000 1.174
+++ src/sys/net/if.c 31 Dec 2003 15:15:25 -0000
@@ -762,6 +762,32 @@
}
/*
+ * Check the if_cloners list for loops.
+ */
+static void
+if_check_cloners_loop(void)
+{
+ struct if_clone *ifc, *ifcn, *ifct;
+
+ for (ifc = LIST_FIRST(&if_cloners); ifc != NULL; ) {
+ ifcn = LIST_NEXT(ifc, ifc_list);
+ if (ifcn == NULL)
+ return;
+ if (ifcn == ifc)
+ panic(
+ "cloners loop to self for %p / %s",
+ ifc, ifc->ifc_name);
+ for (ifct = LIST_FIRST(&if_cloners); ifct != ifc;
+ ifct = LIST_NEXT(ifct, ifc_list))
+ if (ifct == ifcn)
+ panic(
+ "cloners loop from %p / %s to %p / %s",
+ ifc, ifc->ifc_name, ifct, ifct->ifc_name);
+ ifc = ifcn;
+ }
+}
+
+/*
* Look up a network interface cloner.
*/
static struct if_clone *
@@ -771,6 +797,7 @@
const char *cp;
int i;
+ if_check_cloners_loop();
for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) {
for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) {
if (ifc->ifc_name[i] != *cp)
@@ -812,6 +839,8 @@
int err;
int len, maxclone;
int unit;
+ int found;
+ struct if_clone *ift;
KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit,
("%s: %s requested more units then allowed (%d > %d)",
@@ -827,8 +856,19 @@
ifc->ifc_units = malloc(len, M_CLONE, M_WAITOK | M_ZERO);
ifc->ifc_bmlen = len;
- LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
- if_cloners_count++;
+ if_check_cloners_loop();
+ found = 0;
+ LIST_FOREACH(ift, &if_cloners, ifc_list) {
+ if (ift == ifc) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
+ if_cloners_count++;
+ if_check_cloners_loop();
+ }
for (unit = 0; unit < ifc->ifc_minifs; unit++) {
err = (*ifc->ifc_create)(ifc, unit);
@@ -840,7 +880,9 @@
bytoff = unit >> 3;
bitoff = unit - (bytoff << 3);
ifc->ifc_units[bytoff] |= (1 << bitoff);
+ if_check_cloners_loop();
}
+ if_check_cloners_loop();
}
/*
@@ -853,6 +895,7 @@
LIST_REMOVE(ifc, ifc_list);
free(ifc->ifc_units, M_CLONE);
if_cloners_count--;
+ if_check_cloners_loop();
}
/*
@@ -877,6 +920,7 @@
count = (if_cloners_count < ifcr->ifcr_count) ?
if_cloners_count : ifcr->ifcr_count;
+ if_check_cloners_loop();
for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 187 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-net/attachments/20031231/42df306d/attachment.bin
More information about the freebsd-net
mailing list