From peterjeremy@optushome.com.au  Sat Jan 21 10:33:03 2006
Return-Path: <peterjeremy@optushome.com.au>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id C491416A420
	for <FreeBSD-gnats-submit@freebsd.org>; Sat, 21 Jan 2006 10:33:03 +0000 (GMT)
	(envelope-from peterjeremy@optushome.com.au)
Received: from mail27.syd.optusnet.com.au (mail27.syd.optusnet.com.au [211.29.133.168])
	by mx1.FreeBSD.org (Postfix) with ESMTP id D674843D49
	for <FreeBSD-gnats-submit@freebsd.org>; Sat, 21 Jan 2006 10:33:02 +0000 (GMT)
	(envelope-from peterjeremy@optushome.com.au)
Received: from server.vk2pj.dyndns.org (c220-239-19-236.belrs4.nsw.optusnet.com.au [220.239.19.236])
	by mail27.syd.optusnet.com.au (8.12.11/8.12.11) with ESMTP id k0LAX0Cg022883
	(version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NO)
	for <FreeBSD-gnats-submit@freebsd.org>; Sat, 21 Jan 2006 21:33:01 +1100
Received: from server.vk2pj.dyndns.org (localhost.vk2pj.dyndns.org [127.0.0.1])
	by server.vk2pj.dyndns.org (8.13.4/8.13.4) with ESMTP id k0LAX0ck000866;
	Sat, 21 Jan 2006 21:33:00 +1100 (EST)
	(envelope-from peter@server.vk2pj.dyndns.org)
Received: (from peter@localhost)
	by server.vk2pj.dyndns.org (8.13.4/8.13.1/Submit) id k0LAX0Wf000865;
	Sat, 21 Jan 2006 21:33:00 +1100 (EST)
	(envelope-from peter)
Message-Id: <200601211033.k0LAX0Wf000865@server.vk2pj.dyndns.org>
Date: Sat, 21 Jan 2006 21:33:00 +1100 (EST)
From: Peter Jeremy <peterjeremy@optushome.com.au>
Reply-To: Peter Jeremy <peterjeremy@optushome.com.au>
To: FreeBSD-gnats-submit@freebsd.org
Subject: [PATCH] Panic if device with iicbus child is detached
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         92092
>Category:       kern
>Synopsis:       [iicbus] [patch] Panic if device with iicbus child is detached
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Jan 21 10:40:07 GMT 2006
>Closed-Date:    Wed Mar 21 16:00:11 UTC 2012
>Last-Modified:  Wed Mar 21 16:00:11 UTC 2012
>Originator:     Peter Jeremy
>Release:        FreeBSD 7.0-CURRENT i386
>Organization:
n/a
>Environment:
System: FreeBSD server.vk2pj.dyndns.org 7.0-CURRENT FreeBSD 7.0-CURRENT #24: Sat Jan 21 20:55:05 EST 2006 root@server.vk2pj.dyndns.org:/var/obj/k7/usr/src/sys/server i386

>Description:

When deleting a device (using device_delete_child()), all its child
devices are recursively deleted and then device_detach() is called.

In the case of iicsmb, this causes a panic because iicsmb_detach()
also calls device_delete_child() on the smbus child it has cached in
its softc.  By this time that child has been destroyed.

Looking at device_detach(), it appears that the solution is to create
a bus_child_detached method to inform the parent that a child is being
destroyed so it can invalidate cached pointers to that child.

Looking at the iicsmb code, it appears that iicbb and iicsmb both
cache and explicitly delete child devices and therefore both need
bus_child_detached methods.

Looking at the number of different devices attached as children,
together with the paucity of bus_child_detached methods (only isa, ed,
pccard, cbb and usb exist), there are likely to be other similar
issues elsewhere.

>How-To-Repeat:
	Create a device that does
		child = device_add_child(dev, "iicbus", -1);
	on attach and
		device_delete_child(dev, child);
	on detach.  Attach and detach the device (eg load/unload it as a kld)
	with UMA memory debugging enabled (0xdeadc0de fill on free).
	You should get a panic that looks similar to:

--- trap 0xc, eip = 0xc056229a, esp = 0xd6b9cae4, ebp = 0xd6b9caf0 ---
device_delete_child(c32e6900,deadc0de,c3379610,d6b9cb1c,c04a1fb6) at device_delete_child+0xa
device_delete_child(c3350100,c32e6900,c3350100,c3350100,d6b9cb40) at device_delete_child+0x1d
iicsmb_detach(c3350100,c3321050,c0748228,965,c3350100) at iicsmb_detach+0x36
device_detach(c3350100,c32e6900,c336e100,d6b9cb68,c05622ad) at device_detach+0x8e
device_delete_child(c336e100,c3350100,c338f000,d6b9cb88,c087fd7f) at device_delete_child+0x30
device_delete_child(c3371180,c336e100,0,c33a2e00,c3371180) at device_delete_child+0x1d
release_resources(c338f000,c0886928,c3371180,c3371180,d6b9cbc4) at release_resources+0xdf
saa_detach(c3371180,c3331850,c0748228,965,c331e9a0) at saa_detach+0x84
device_detach(c3371180,c0885188,c3371180,c32f0380,c0886940) at device_detach+0x8e
devclass_delete_driver(c32f0380,c0886928,1,c3281c80,c3281c80) at devclass_delete_driver+0x95
driver_module_handler(c3281c80,1,c0886940) at driver_module_handler+0xf3
module_unload(c3281c80,0,1fb,0,0) at module_unload+0x60
linker_file_unload(c32a2e00,0,c0707925,327,2) at linker_file_unload+0x87
kern_kldunload(c3a30600,2,0,d6b9cd30,c06c3d63) at kern_kldunload+0x94
kldunloadf(c3a30600,d6b9cd04,8,440,c3b6b318) at kldunloadf+0x2c

>Fix:

Index: sys/dev/iicbus/iicbb.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/iicbus/iicbb.c,v
retrieving revision 1.13
diff -u -r1.13 iicbb.c
--- sys/dev/iicbus/iicbb.c	24 Aug 2003 17:49:13 -0000	1.13
+++ sys/dev/iicbus/iicbb.c	21 Jan 2006 10:15:38 -0000
@@ -67,6 +67,7 @@
 static int iicbb_attach(device_t);
 static int iicbb_detach(device_t);
 static int iicbb_print_child(device_t, device_t);
+static void iicbb_child_detached(device_t dev, device_t child);
 
 static int iicbb_callback(device_t, int, caddr_t);
 static int iicbb_start(device_t, u_char, int);
@@ -83,6 +84,7 @@
 
 	/* bus interface */
 	DEVMETHOD(bus_print_child,	iicbb_print_child),
+	DEVMETHOD(bus_child_detached,	iicbb_child_detached),
 
 	/* iicbus interface */
 	DEVMETHOD(iicbus_callback,	iicbb_callback),
@@ -139,6 +141,16 @@
 	return (0);
 }
 
+static void
+iicbb_child_detached(device_t dev, device_t child)
+{
+	struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev);
+
+	if (child == sc->iicbus)
+		sc->iicbus = NULL;
+	/* need to abort any operation in progress as well */
+}
+
 static int
 iicbb_print_child(device_t bus, device_t dev)
 {
Index: sys/dev/iicbus/iicsmb.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/iicbus/iicsmb.c,v
retrieving revision 1.12
diff -u -r1.12 iicsmb.c
--- sys/dev/iicbus/iicsmb.c	10 Aug 2003 14:28:24 -0000	1.12
+++ sys/dev/iicbus/iicsmb.c	21 Jan 2006 10:15:53 -0000
@@ -81,6 +81,7 @@
 static int iicsmb_attach(device_t);
 static int iicsmb_detach(device_t);
 static void iicsmb_identify(driver_t *driver, device_t parent);
+static void iicsmb_child_detached(device_t dev, device_t child);
 
 static void iicsmb_intr(device_t dev, int event, char *buf);
 static int iicsmb_callback(device_t dev, int index, caddr_t data);
@@ -107,6 +108,7 @@
 	/* bus interface */
 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
+	DEVMETHOD(bus_child_detached,	iicsmb_child_detached),
 
 	/* iicbus interface */
 	DEVMETHOD(iicbus_intr,		iicsmb_intr),
@@ -176,6 +178,16 @@
 	return (0);
 }
 
+static void
+iicsmb_child_detached(device_t dev, device_t child)
+{
+	struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
+
+	if (child == sc->smbus)
+		sc->smbus = NULL;
+	/* need to abort any operation in progress as well */
+}
+
 /*
  * iicsmb_intr()
  *


>Release-Note:
>Audit-Trail:

From: Peter Jeremy <PeterJeremy@optushome.com.au>
To: FreeBSD-gnats-submit@freebsd.org, freebsd-bugs@freebsd.org
Cc:  
Subject: Re: kern/92092: [PATCH] Panic if device with iicbus child is detached
Date: Wed, 25 Jan 2006 15:52:10 +1100

 --9amGYk9869ThD9tj
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 Following further investigating and comments from jhb@, I believe that
 my previous patch was overly complicated: Both detach methods already
 use bus_generic_detach() and this includes device_delete_child(),
 making the device_delete_child() calls superfluous.  This makes both
 detach methods collapse down to bus_generic_detach().  The iicbb softc
 is now also superfluous since it was only used to cache the child
 device.
 
 The iicbus part of the following patch has been tested by detaching
 and re-attaching an iicbus parent device.  Unfortunately, I don't
 think I've got anything that uses iicbb so I can't easily test that.
 
 An updated patch is attached.
 
 -- 
 Peter Jeremy
 
 --9amGYk9869ThD9tj
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename="iic.patch"
 
 Index: iicbb.c
 ===================================================================
 RCS file: /usr/ncvs/src/sys/dev/iicbus/iicbb.c,v
 retrieving revision 1.13
 diff -u -r1.13 iicbb.c
 --- iicbb.c	24 Aug 2003 17:49:13 -0000	1.13
 +++ iicbb.c	24 Jan 2006 08:36:10 -0000
 @@ -59,13 +59,8 @@
  #include "iicbus_if.h"
  #include "iicbb_if.h"
  
 -struct iicbb_softc {
 -	device_t iicbus;
 -};
 -
  static int iicbb_probe(device_t);
  static int iicbb_attach(device_t);
 -static int iicbb_detach(device_t);
  static int iicbb_print_child(device_t, device_t);
  
  static int iicbb_callback(device_t, int, caddr_t);
 @@ -79,7 +74,7 @@
  	/* device interface */
  	DEVMETHOD(device_probe,		iicbb_probe),
  	DEVMETHOD(device_attach,	iicbb_attach),
 -	DEVMETHOD(device_detach,	iicbb_detach),
 +	DEVMETHOD(device_detach,	bus_generic_detach),
  
  	/* bus interface */
  	DEVMETHOD(bus_print_child,	iicbb_print_child),
 @@ -99,7 +94,7 @@
  driver_t iicbb_driver = {
  	"iicbb",
  	iicbb_methods,
 -	sizeof(struct iicbb_softc),
 +	0,
  };
  
  devclass_t iicbb_devclass;
 @@ -113,13 +108,7 @@
  
  static int iicbb_attach(device_t dev)
  {
 -	struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev);
 -
 -	bzero(sc, sizeof(struct iicbb_softc));
 -
 -	sc->iicbus = device_add_child(dev, "iicbus", -1);
 -
 -	if (!sc->iicbus)
 +	if (device_add_child(dev, "iicbus", -1) == NULL)
  		return (ENXIO);
  
  	bus_generic_attach(dev);
 @@ -127,18 +116,6 @@
  	return (0);
  }
  
 -static int iicbb_detach(device_t dev)
 -{
 -	struct iicbb_softc *sc = (struct iicbb_softc *)device_get_softc(dev);
 -
 -	if (sc->iicbus) {
 -		bus_generic_detach(dev);
 -		device_delete_child(dev, sc->iicbus);
 -	}
 -
 -	return (0);
 -}
 -
  static int
  iicbb_print_child(device_t bus, device_t dev)
  {
 Index: iicsmb.c
 ===================================================================
 RCS file: /usr/ncvs/src/sys/dev/iicbus/iicsmb.c,v
 retrieving revision 1.12
 diff -u -r1.12 iicsmb.c
 --- iicsmb.c	10 Aug 2003 14:28:24 -0000	1.12
 +++ iicsmb.c	24 Jan 2006 08:36:10 -0000
 @@ -79,7 +79,6 @@
  
  static int iicsmb_probe(device_t);
  static int iicsmb_attach(device_t);
 -static int iicsmb_detach(device_t);
  static void iicsmb_identify(driver_t *driver, device_t parent);
  
  static void iicsmb_intr(device_t dev, int event, char *buf);
 @@ -102,7 +101,7 @@
  	DEVMETHOD(device_identify,	iicsmb_identify),
  	DEVMETHOD(device_probe,		iicsmb_probe),
  	DEVMETHOD(device_attach,	iicsmb_attach),
 -	DEVMETHOD(device_detach,	iicsmb_detach),
 +	DEVMETHOD(device_detach,	bus_generic_detach),
  
  	/* bus interface */
  	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
 @@ -163,19 +162,6 @@
  	return (0);
  }
  
 -static int
 -iicsmb_detach(device_t dev)
 -{
 -	struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
 -	
 -	bus_generic_detach(dev);
 -	if (sc->smbus) {
 -		device_delete_child(dev, sc->smbus);
 -	}
 -
 -	return (0);
 -}
 -
  /*
   * iicsmb_intr()
   *
 
 --9amGYk9869ThD9tj--
State-Changed-From-To: open->feedback 
State-Changed-By: jh 
State-Changed-When: Sat Mar 10 08:51:53 UTC 2012 
State-Changed-Why:  
Is this still a problem? 

http://www.freebsd.org/cgi/query-pr.cgi?pr=92092 
State-Changed-From-To: feedback->closed 
State-Changed-By: jh 
State-Changed-When: Wed Mar 21 15:56:41 UTC 2012 
State-Changed-Why:  
Hardware is no more available for testing. This has been possibly fixed 
in r164900. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=92092 
>Unformatted:
