Home | History | Annotate | Line # | Download | only in namespace
nsalloc.c revision 1.1.1.2.20.1
      1 /*******************************************************************************
      2  *
      3  * Module Name: nsalloc - Namespace allocation and deletion utilities
      4  *
      5  ******************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2013, Intel Corp.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions, and the following disclaimer,
     16  *    without modification.
     17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     18  *    substantially similar to the "NO WARRANTY" disclaimer below
     19  *    ("Disclaimer") and any redistribution must be conditioned upon
     20  *    including a substantially similar Disclaimer requirement for further
     21  *    binary redistribution.
     22  * 3. Neither the names of the above-listed copyright holders nor the names
     23  *    of any contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * Alternatively, this software may be distributed under the terms of the
     27  * GNU General Public License ("GPL") version 2 as published by the Free
     28  * Software Foundation.
     29  *
     30  * NO WARRANTY
     31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     41  * POSSIBILITY OF SUCH DAMAGES.
     42  */
     43 
     44 
     45 #define __NSALLOC_C__
     46 
     47 #include "acpi.h"
     48 #include "accommon.h"
     49 #include "acnamesp.h"
     50 
     51 
     52 #define _COMPONENT          ACPI_NAMESPACE
     53         ACPI_MODULE_NAME    ("nsalloc")
     54 
     55 
     56 /*******************************************************************************
     57  *
     58  * FUNCTION:    AcpiNsCreateNode
     59  *
     60  * PARAMETERS:  Name            - Name of the new node (4 char ACPI name)
     61  *
     62  * RETURN:      New namespace node (Null on failure)
     63  *
     64  * DESCRIPTION: Create a namespace node
     65  *
     66  ******************************************************************************/
     67 
     68 ACPI_NAMESPACE_NODE *
     69 AcpiNsCreateNode (
     70     UINT32                  Name)
     71 {
     72     ACPI_NAMESPACE_NODE     *Node;
     73 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
     74     UINT32                  Temp;
     75 #endif
     76 
     77 
     78     ACPI_FUNCTION_TRACE (NsCreateNode);
     79 
     80 
     81     Node = AcpiOsAcquireObject (AcpiGbl_NamespaceCache);
     82     if (!Node)
     83     {
     84         return_PTR (NULL);
     85     }
     86 
     87     ACPI_MEM_TRACKING (AcpiGbl_NsNodeList->TotalAllocated++);
     88 
     89 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
     90         Temp = AcpiGbl_NsNodeList->TotalAllocated -
     91                 AcpiGbl_NsNodeList->TotalFreed;
     92         if (Temp > AcpiGbl_NsNodeList->MaxOccupied)
     93         {
     94             AcpiGbl_NsNodeList->MaxOccupied = Temp;
     95         }
     96 #endif
     97 
     98     Node->Name.Integer = Name;
     99     ACPI_SET_DESCRIPTOR_TYPE (Node, ACPI_DESC_TYPE_NAMED);
    100     return_PTR (Node);
    101 }
    102 
    103 
    104 /*******************************************************************************
    105  *
    106  * FUNCTION:    AcpiNsDeleteNode
    107  *
    108  * PARAMETERS:  Node            - Node to be deleted
    109  *
    110  * RETURN:      None
    111  *
    112  * DESCRIPTION: Delete a namespace node. All node deletions must come through
    113  *              here. Detaches any attached objects, including any attached
    114  *              data. If a handler is associated with attached data, it is
    115  *              invoked before the node is deleted.
    116  *
    117  ******************************************************************************/
    118 
    119 void
    120 AcpiNsDeleteNode (
    121     ACPI_NAMESPACE_NODE     *Node)
    122 {
    123     ACPI_OPERAND_OBJECT     *ObjDesc;
    124     ACPI_OPERAND_OBJECT     *NextDesc;
    125 
    126 
    127     ACPI_FUNCTION_NAME (NsDeleteNode);
    128 
    129 
    130     /* Detach an object if there is one */
    131 
    132     AcpiNsDetachObject (Node);
    133 
    134     /*
    135      * Delete an attached data object list if present (objects that were
    136      * attached via AcpiAttachData). Note: After any normal object is
    137      * detached above, the only possible remaining object(s) are data
    138      * objects, in a linked list.
    139      */
    140     ObjDesc = Node->Object;
    141     while (ObjDesc &&
    142         (ObjDesc->Common.Type == ACPI_TYPE_LOCAL_DATA))
    143     {
    144         /* Invoke the attached data deletion handler if present */
    145 
    146         if (ObjDesc->Data.Handler)
    147         {
    148             ObjDesc->Data.Handler (Node, ObjDesc->Data.Pointer);
    149         }
    150 
    151         NextDesc = ObjDesc->Common.NextObject;
    152         AcpiUtRemoveReference (ObjDesc);
    153         ObjDesc = NextDesc;
    154     }
    155 
    156     /* Special case for the statically allocated root node */
    157 
    158     if (Node == AcpiGbl_RootNode)
    159     {
    160         return;
    161     }
    162 
    163     /* Now we can delete the node */
    164 
    165     (void) AcpiOsReleaseObject (AcpiGbl_NamespaceCache, Node);
    166 
    167     ACPI_MEM_TRACKING (AcpiGbl_NsNodeList->TotalFreed++);
    168     ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n",
    169         Node, AcpiGbl_CurrentNodeCount));
    170 }
    171 
    172 
    173 /*******************************************************************************
    174  *
    175  * FUNCTION:    AcpiNsRemoveNode
    176  *
    177  * PARAMETERS:  Node            - Node to be removed/deleted
    178  *
    179  * RETURN:      None
    180  *
    181  * DESCRIPTION: Remove (unlink) and delete a namespace node
    182  *
    183  ******************************************************************************/
    184 
    185 void
    186 AcpiNsRemoveNode (
    187     ACPI_NAMESPACE_NODE     *Node)
    188 {
    189     ACPI_NAMESPACE_NODE     *ParentNode;
    190     ACPI_NAMESPACE_NODE     *PrevNode;
    191     ACPI_NAMESPACE_NODE     *NextNode;
    192 
    193 
    194     ACPI_FUNCTION_TRACE_PTR (NsRemoveNode, Node);
    195 
    196 
    197     ParentNode = Node->Parent;
    198 
    199     PrevNode = NULL;
    200     NextNode = ParentNode->Child;
    201 
    202     /* Find the node that is the previous peer in the parent's child list */
    203 
    204     while (NextNode != Node)
    205     {
    206         PrevNode = NextNode;
    207         NextNode = NextNode->Peer;
    208     }
    209 
    210     if (PrevNode)
    211     {
    212         /* Node is not first child, unlink it */
    213 
    214         PrevNode->Peer = Node->Peer;
    215     }
    216     else
    217     {
    218         /*
    219          * Node is first child (has no previous peer).
    220          * Link peer list to parent
    221          */
    222         ParentNode->Child = Node->Peer;
    223     }
    224 
    225     /* Delete the node and any attached objects */
    226 
    227     AcpiNsDeleteNode (Node);
    228     return_VOID;
    229 }
    230 
    231 
    232 /*******************************************************************************
    233  *
    234  * FUNCTION:    AcpiNsInstallNode
    235  *
    236  * PARAMETERS:  WalkState       - Current state of the walk
    237  *              ParentNode      - The parent of the new Node
    238  *              Node            - The new Node to install
    239  *              Type            - ACPI object type of the new Node
    240  *
    241  * RETURN:      None
    242  *
    243  * DESCRIPTION: Initialize a new namespace node and install it amongst
    244  *              its peers.
    245  *
    246  *              Note: Current namespace lookup is linear search. This appears
    247  *              to be sufficient as namespace searches consume only a small
    248  *              fraction of the execution time of the ACPI subsystem.
    249  *
    250  ******************************************************************************/
    251 
    252 void
    253 AcpiNsInstallNode (
    254     ACPI_WALK_STATE         *WalkState,
    255     ACPI_NAMESPACE_NODE     *ParentNode,    /* Parent */
    256     ACPI_NAMESPACE_NODE     *Node,          /* New Child*/
    257     ACPI_OBJECT_TYPE        Type)
    258 {
    259     ACPI_OWNER_ID           OwnerId = 0;
    260     ACPI_NAMESPACE_NODE     *ChildNode;
    261 
    262 
    263     ACPI_FUNCTION_TRACE (NsInstallNode);
    264 
    265 
    266     if (WalkState)
    267     {
    268         /*
    269          * Get the owner ID from the Walk state. The owner ID is used to
    270          * track table deletion and deletion of objects created by methods.
    271          */
    272         OwnerId = WalkState->OwnerId;
    273 
    274         if ((WalkState->MethodDesc) &&
    275             (ParentNode != WalkState->MethodNode))
    276         {
    277             /*
    278              * A method is creating a new node that is not a child of the
    279              * method (it is non-local). Mark the executing method as having
    280              * modified the namespace. This is used for cleanup when the
    281              * method exits.
    282              */
    283             WalkState->MethodDesc->Method.InfoFlags |= ACPI_METHOD_MODIFIED_NAMESPACE;
    284         }
    285     }
    286 
    287     /* Link the new entry into the parent and existing children */
    288 
    289     Node->Peer = NULL;
    290     Node->Parent = ParentNode;
    291     ChildNode = ParentNode->Child;
    292 
    293     if (!ChildNode)
    294     {
    295         ParentNode->Child = Node;
    296     }
    297     else
    298     {
    299         /* Add node to the end of the peer list */
    300 
    301         while (ChildNode->Peer)
    302         {
    303             ChildNode = ChildNode->Peer;
    304         }
    305 
    306         ChildNode->Peer = Node;
    307     }
    308 
    309     /* Init the new entry */
    310 
    311     Node->OwnerId = OwnerId;
    312     Node->Type = (UINT8) Type;
    313 
    314     ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
    315         "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n",
    316         AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Node->Type), Node, OwnerId,
    317         AcpiUtGetNodeName (ParentNode), AcpiUtGetTypeName (ParentNode->Type),
    318         ParentNode));
    319 
    320     return_VOID;
    321 }
    322 
    323 
    324 /*******************************************************************************
    325  *
    326  * FUNCTION:    AcpiNsDeleteChildren
    327  *
    328  * PARAMETERS:  ParentNode      - Delete this objects children
    329  *
    330  * RETURN:      None.
    331  *
    332  * DESCRIPTION: Delete all children of the parent object. In other words,
    333  *              deletes a "scope".
    334  *
    335  ******************************************************************************/
    336 
    337 void
    338 AcpiNsDeleteChildren (
    339     ACPI_NAMESPACE_NODE     *ParentNode)
    340 {
    341     ACPI_NAMESPACE_NODE     *NextNode;
    342     ACPI_NAMESPACE_NODE     *NodeToDelete;
    343 
    344 
    345     ACPI_FUNCTION_TRACE_PTR (NsDeleteChildren, ParentNode);
    346 
    347 
    348     if (!ParentNode)
    349     {
    350         return_VOID;
    351     }
    352 
    353     /* Deallocate all children at this level */
    354 
    355     NextNode = ParentNode->Child;
    356     while (NextNode)
    357     {
    358         /* Grandchildren should have all been deleted already */
    359 
    360         if (NextNode->Child)
    361         {
    362             ACPI_ERROR ((AE_INFO, "Found a grandchild! P=%p C=%p",
    363                 ParentNode, NextNode));
    364         }
    365 
    366         /*
    367          * Delete this child node and move on to the next child in the list.
    368          * No need to unlink the node since we are deleting the entire branch.
    369          */
    370         NodeToDelete = NextNode;
    371         NextNode = NextNode->Peer;
    372         AcpiNsDeleteNode (NodeToDelete);
    373     };
    374 
    375     /* Clear the parent's child pointer */
    376 
    377     ParentNode->Child = NULL;
    378     return_VOID;
    379 }
    380 
    381 
    382 /*******************************************************************************
    383  *
    384  * FUNCTION:    AcpiNsDeleteNamespaceSubtree
    385  *
    386  * PARAMETERS:  ParentNode      - Root of the subtree to be deleted
    387  *
    388  * RETURN:      None.
    389  *
    390  * DESCRIPTION: Delete a subtree of the namespace. This includes all objects
    391  *              stored within the subtree.
    392  *
    393  ******************************************************************************/
    394 
    395 void
    396 AcpiNsDeleteNamespaceSubtree (
    397     ACPI_NAMESPACE_NODE     *ParentNode)
    398 {
    399     ACPI_NAMESPACE_NODE     *ChildNode = NULL;
    400     UINT32                  Level = 1;
    401     ACPI_STATUS             Status;
    402 
    403 
    404     ACPI_FUNCTION_TRACE (NsDeleteNamespaceSubtree);
    405 
    406 
    407     if (!ParentNode)
    408     {
    409         return_VOID;
    410     }
    411 
    412     /* Lock namespace for possible update */
    413 
    414     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
    415     if (ACPI_FAILURE (Status))
    416     {
    417         return_VOID;
    418     }
    419 
    420     /*
    421      * Traverse the tree of objects until we bubble back up
    422      * to where we started.
    423      */
    424     while (Level > 0)
    425     {
    426         /* Get the next node in this scope (NULL if none) */
    427 
    428         ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode);
    429         if (ChildNode)
    430         {
    431             /* Found a child node - detach any attached object */
    432 
    433             AcpiNsDetachObject (ChildNode);
    434 
    435             /* Check if this node has any children */
    436 
    437             if (ChildNode->Child)
    438             {
    439                 /*
    440                  * There is at least one child of this node,
    441                  * visit the node
    442                  */
    443                 Level++;
    444                 ParentNode = ChildNode;
    445                 ChildNode  = NULL;
    446             }
    447         }
    448         else
    449         {
    450             /*
    451              * No more children of this parent node.
    452              * Move up to the grandparent.
    453              */
    454             Level--;
    455 
    456             /*
    457              * Now delete all of the children of this parent
    458              * all at the same time.
    459              */
    460             AcpiNsDeleteChildren (ParentNode);
    461 
    462             /* New "last child" is this parent node */
    463 
    464             ChildNode = ParentNode;
    465 
    466             /* Move up the tree to the grandparent */
    467 
    468             ParentNode = ParentNode->Parent;
    469         }
    470     }
    471 
    472     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
    473     return_VOID;
    474 }
    475 
    476 
    477 /*******************************************************************************
    478  *
    479  * FUNCTION:    AcpiNsDeleteNamespaceByOwner
    480  *
    481  * PARAMETERS:  OwnerId     - All nodes with this owner will be deleted
    482  *
    483  * RETURN:      Status
    484  *
    485  * DESCRIPTION: Delete entries within the namespace that are owned by a
    486  *              specific ID. Used to delete entire ACPI tables. All
    487  *              reference counts are updated.
    488  *
    489  * MUTEX:       Locks namespace during deletion walk.
    490  *
    491  ******************************************************************************/
    492 
    493 void
    494 AcpiNsDeleteNamespaceByOwner (
    495     ACPI_OWNER_ID            OwnerId)
    496 {
    497     ACPI_NAMESPACE_NODE     *ChildNode;
    498     ACPI_NAMESPACE_NODE     *DeletionNode;
    499     ACPI_NAMESPACE_NODE     *ParentNode;
    500     UINT32                  Level;
    501     ACPI_STATUS             Status;
    502 
    503 
    504     ACPI_FUNCTION_TRACE_U32 (NsDeleteNamespaceByOwner, OwnerId);
    505 
    506 
    507     if (OwnerId == 0)
    508     {
    509         return_VOID;
    510     }
    511 
    512     /* Lock namespace for possible update */
    513 
    514     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
    515     if (ACPI_FAILURE (Status))
    516     {
    517         return_VOID;
    518     }
    519 
    520     DeletionNode = NULL;
    521     ParentNode = AcpiGbl_RootNode;
    522     ChildNode = NULL;
    523     Level = 1;
    524 
    525     /*
    526      * Traverse the tree of nodes until we bubble back up
    527      * to where we started.
    528      */
    529     while (Level > 0)
    530     {
    531         /*
    532          * Get the next child of this parent node. When ChildNode is NULL,
    533          * the first child of the parent is returned
    534          */
    535         ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode);
    536 
    537         if (DeletionNode)
    538         {
    539             AcpiNsDeleteChildren (DeletionNode);
    540             AcpiNsRemoveNode (DeletionNode);
    541             DeletionNode = NULL;
    542         }
    543 
    544         if (ChildNode)
    545         {
    546             if (ChildNode->OwnerId == OwnerId)
    547             {
    548                 /* Found a matching child node - detach any attached object */
    549 
    550                 AcpiNsDetachObject (ChildNode);
    551             }
    552 
    553             /* Check if this node has any children */
    554 
    555             if (ChildNode->Child)
    556             {
    557                 /*
    558                  * There is at least one child of this node,
    559                  * visit the node
    560                  */
    561                 Level++;
    562                 ParentNode = ChildNode;
    563                 ChildNode  = NULL;
    564             }
    565             else if (ChildNode->OwnerId == OwnerId)
    566             {
    567                 DeletionNode = ChildNode;
    568             }
    569         }
    570         else
    571         {
    572             /*
    573              * No more children of this parent node.
    574              * Move up to the grandparent.
    575              */
    576             Level--;
    577             if (Level != 0)
    578             {
    579                 if (ParentNode->OwnerId == OwnerId)
    580                 {
    581                     DeletionNode = ParentNode;
    582                 }
    583             }
    584 
    585             /* New "last child" is this parent node */
    586 
    587             ChildNode = ParentNode;
    588 
    589             /* Move up the tree to the grandparent */
    590 
    591             ParentNode = ParentNode->Parent;
    592         }
    593     }
    594 
    595     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
    596     return_VOID;
    597 }
    598