acpi panics - potential fix

From: Nate Lawson <nate_at_root.org>
Date: Sun, 11 May 2003 10:38:15 -0700 (PDT)
If you are having acpi panics, please try the attached patch.

-Nate

---------- Forwarded message ----------
Date: Wed, 07 May 2003 11:23:31 +0900
From: Takayoshi Kochi <kochi_at_netbsd.org>
Reply-To: acpi-jp_at_jp.FreeBSD.org
To: acpi-jp_at_jp.FreeBSD.org
Subject: [acpi-jp 2182] Re: Outstanding ACPI issues for 5.1-RELEASE

(please ignore my last posting, sorry)

Hello Nate and all,

While tracking NetBSD PR/17872, Takashi Yamamoto found
a bug in nsalloc.c.  In AcpiNsDeleteNode(), it was possible
to make parent-child loop.  Robert Moore admitted this is
a bug and will be fixed in the next release.

And I found another problem about reference counting of
ACPI_NAMESPACE_NODE objects.  Under a certain condition
(for my laptop, repeated evaluation of _BST method of
battery) reference count goes up to wrap UINT16 and may
cause unexpected object free.  I reported this
to Robert also, but I haven't got official fix.
It seems to me that reference counting of ACPI_NAMESPACE_NODE
is unnecessary but I'm not sure.  I attached my
fix (which also includes Yamamoto-san's fix), but
please take this as an experimetntal patch.

The acpi_thermal panic problem might be related to this one.

For more info about the NetBSD PR/17872, plase refer to the url:
http://www.netbsd.org/cgi-bin/query-pr-single.pl?number=17872

From: Nate Lawson <nate_at_root.org>
Subject: [acpi-jp 2177] Outstanding ACPI issues for 5.1-RELEASE
Date: Tue, 6 May 2003 14:28:21 -0700

> Here is a list of the current problems.  We would like to fix as many as
> possible before the release.  If anyone has time to tackle these issues,
> please let me know.  The reporters listed below should open a PR and send
> me the number as I do not want to replicate GNATS in email.
>
> --------------------------------------------------------------
> Problem:  acpi_thermal causes a panic
> Reporter: ru_at_freebsd.org
> Information:
> This looks like referencing a freed or uninitialized data member.
>
> The below was produces with the latest 0228 ACPI diff in-tree, and acpi
> device compiled directly into a kernel.  Loading it as a module gave me
> some lines offset in the source file, and the faulting address was
> 0xdeadc0de.

---
Takayoshi Kochi
--- nsalloc.c.orig	2003-03-05 02:33:38.000000000 +0900
+++ nsalloc.c	2003-04-25 20:11:13.000000000 +0900
_at__at_ -210,7 +210,14 _at__at_
     }
     else
     {
-        ParentNode->Child = NextNode->Peer;
+	if (NextNode->Flags & ANOBJ_END_OF_PEER_LIST)
+	{
+	    ParentNode->Child = NULL;
+	}
+	else
+	{
+             ParentNode->Child = NextNode->Peer;
+	}
     }
 
 
_at__at_ -517,6 +524,62 _at__at_
 
 /*******************************************************************************
  *
+ * FUNCTION:    AcpiNsRemoveReference
+ *
+ * PARAMETERS:  Node           - Named node whose reference count is to be
+ *                               decremented
+ *
+ * RETURN:      None.
+ *
+ * DESCRIPTION: Remove a Node reference.  Decrements the reference count
+ *              of all parent Nodes up to the root.  Any node along
+ *              the way that reaches zero references is freed.
+ *
+ ******************************************************************************/
+
+static void
+AcpiNsRemoveReference (
+    ACPI_NAMESPACE_NODE     *Node)
+{
+    ACPI_NAMESPACE_NODE     *ParentNode;
+    ACPI_NAMESPACE_NODE     *ThisNode;
+
+
+    ACPI_FUNCTION_ENTRY ();
+
+
+    /*
+     * Decrement the reference count(s) of this node and all
+     * nodes up to the root,  Delete anything with zero remaining references.
+     */
+    ThisNode = Node;
+    while (ThisNode)
+    {
+        /* Prepare to move up to parent */
+
+        ParentNode = AcpiNsGetParentNode (ThisNode);
+
+        /* Decrement the reference count on this node */
+
+        ThisNode->ReferenceCount--;
+
+        /* Delete the node if no more references */
+
+        if (!ThisNode->ReferenceCount)
+        {
+            /* Delete all children and delete the node */
+
+            AcpiNsDeleteChildren (ThisNode);
+            AcpiNsDeleteNode (ThisNode);
+        }
+
+        ThisNode = ParentNode;
+    }
+}
+
+
+/*******************************************************************************
+ *
  * FUNCTION:    AcpiNsDeleteNamespaceSubtree
  *
  * PARAMETERS:  ParentNode      - Root of the subtree to be deleted
_at__at_ -532,8 +595,9 _at__at_
 AcpiNsDeleteNamespaceSubtree (
     ACPI_NAMESPACE_NODE     *ParentNode)
 {
-    ACPI_NAMESPACE_NODE     *ChildNode = NULL;
-    UINT32                  Level = 1;
+    ACPI_NAMESPACE_NODE     *ChildNode;
+    ACPI_NAMESPACE_NODE     *DeletionNode;
+    UINT32                  Level;
 
 
     ACPI_FUNCTION_TRACE ("NsDeleteNamespaceSubtree");
_at__at_ -544,6 +608,10 _at__at_
         return_VOID;
     }
 
+    ChildNode = NULL;
+    DeletionNode = NULL;
+    Level = 1;
+
     /*
      * Traverse the tree of objects until we bubble back up
      * to where we started.
_at__at_ -554,6 +622,12 _at__at_
 
         ChildNode = AcpiNsGetNextNode (ACPI_TYPE_ANY, ParentNode,
                                             ChildNode);
+        if (DeletionNode)
+        {
+            AcpiNsRemoveReference (DeletionNode);
+            DeletionNode = NULL;
+        }
+
         if (ChildNode)
         {
             /* Found a child node - detach any attached object */
_at__at_ -572,6 +646,10 _at__at_
                 ParentNode    = ChildNode;
                 ChildNode     = 0;
             }
+	    else
+	    {
+                DeletionNode = ChildNode;
+	    }
         }
         else
         {
_at__at_ -585,7 +663,10 _at__at_
              * Now delete all of the children of this parent
              * all at the same time.
              */
-            AcpiNsDeleteChildren (ParentNode);
+	    if (Level != 0)
+	    {
+		DeletionNode = ParentNode;
+	    }
 
             /* New "last child" is this parent node */
 
_at__at_ -603,62 +684,6 _at__at_
 
 /*******************************************************************************
  *
- * FUNCTION:    AcpiNsRemoveReference
- *
- * PARAMETERS:  Node           - Named node whose reference count is to be
- *                               decremented
- *
- * RETURN:      None.
- *
- * DESCRIPTION: Remove a Node reference.  Decrements the reference count
- *              of all parent Nodes up to the root.  Any node along
- *              the way that reaches zero references is freed.
- *
- ******************************************************************************/
-
-static void
-AcpiNsRemoveReference (
-    ACPI_NAMESPACE_NODE     *Node)
-{
-    ACPI_NAMESPACE_NODE     *ParentNode;
-    ACPI_NAMESPACE_NODE     *ThisNode;
-
-
-    ACPI_FUNCTION_ENTRY ();
-
-
-    /*
-     * Decrement the reference count(s) of this node and all
-     * nodes up to the root,  Delete anything with zero remaining references.
-     */
-    ThisNode = Node;
-    while (ThisNode)
-    {
-        /* Prepare to move up to parent */
-
-        ParentNode = AcpiNsGetParentNode (ThisNode);
-
-        /* Decrement the reference count on this node */
-
-        ThisNode->ReferenceCount--;
-
-        /* Delete the node if no more references */
-
-        if (!ThisNode->ReferenceCount)
-        {
-            /* Delete all children and delete the node */
-
-            AcpiNsDeleteChildren (ThisNode);
-            AcpiNsDeleteNode (ThisNode);
-        }
-
-        ThisNode = ParentNode;
-    }
-}
-
-
-/*******************************************************************************
- *
  * FUNCTION:    AcpiNsDeleteNamespaceByOwner
  *
  * PARAMETERS:  OwnerId     - All nodes with this owner will be deleted
Received on Sun May 11 2003 - 08:38:15 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:37:07 UTC