linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
From: Gavin Shan <gwshan@linux.vnet.ibm.com>
To: Rob Herring <robherring2@gmail.com>
Cc: Gavin Shan <gwshan@linux.vnet.ibm.com>,
	linuxppc-dev <linuxppc-dev@lists.ozlabs.org>,
	"linux-pci@vger.kernel.org" <linux-pci@vger.kernel.org>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	Benjamin Herrenschmidt <benh@kernel.crashing.org>,
	Michael Ellerman <mpe@ellerman.id.au>,
	aik@ozlabs.ru, Bjorn Helgaas <bhelgaas@google.com>,
	Grant Likely <grant.likely@linaro.org>,
	Pantelis Antoniou <panto@antoniou-consulting.com>,
	Frank Rowand <frowand.list@gmail.com>
Subject: Re: [PATCH v7 45/50] drivers/of: Avoid recursively calling unflatten_dt_node()
Date: Thu, 5 Nov 2015 10:23:15 +1100	[thread overview]
Message-ID: <20151104232315.GB9287@gwshan> (raw)
In-Reply-To: <CAL_JsqJGpV-+JYyA1g0dw_nEduhmrMEouTH03kHtuCkGSOP57Q@mail.gmail.com>

On Wed, Nov 04, 2015 at 10:07:50AM -0600, Rob Herring wrote:
>On Wed, Nov 4, 2015 at 7:12 AM, Gavin Shan <gwshan@linux.vnet.ibm.com> wrote:
>> In current implementation, unflatten_dt_node() is called recursively
>> to unflatten device nodes in FDT blob. It's stress to limited stack
>> capacity.
>
>Did you actually hit a problem?
>
>Now we have a max depth of 64. Seems like that should be plenty... Any
>idea how this compares to when we run out of stack space?
>

When I rebased last revision (v6), particular below patch, to 4.3.rc6,
the kernel won't boot in P7 and P8 boxes. On P7 boxes, the stack overruns
according to the printed kernel messages. On P8 boxes, the /bin/init in
initramfs image can't be loaded/executed properly and it's potentially
caused by memory corruption. That's why I reworked it to avoid recursive
calling to unflatten_dt_node().

The max depth "64" wasn't selected based on the stack usage. I was thinking
the device tree is converted to friendly *.dts format and it's using TAB
as the prefix for each line. If the device tree has 64 depth, Each line
in *.dts for leaf nodes have to be wrapped and spanning multiple lines.
That's why I choosed 64, maybe 32 is enough. Did you see a device-tree
that has more than 16 depth in field? :-)

>> This avoids calling the function recursively, meaning the device
>> nodes are unflattened in one call on unflatten_dt_node(): two arrays
>> are introduced to track the parent path size and the device node of
>> current level of depth, which will be used by the device node on next
>> level of depth to be unflattened. Also, the parameter "poffset" and
>> "fpsize" are unused and dropped.
>
>Yay. I'm happy to see parameters removed instead of added to this function.
>
>>
>> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
>> ---
>>  drivers/of/fdt.c | 94 +++++++++++++++++++++++++++++++++-----------------------
>>  1 file changed, 56 insertions(+), 38 deletions(-)
>>
>> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
>> index 173b036..f4793d0 100644
>> --- a/drivers/of/fdt.c
>> +++ b/drivers/of/fdt.c
>> @@ -355,61 +355,82 @@ static unsigned long populate_node(const void *blob,
>>         return fpsize;
>>  }
>>
>> +static void reverse_nodes(struct device_node *parent)
>> +{
>> +       struct device_node *child, *next;
>> +
>> +       /* In-depth first */
>> +       child = parent->child;
>> +       while (child) {
>> +               reverse_nodes(child);
>> +
>> +               child = child->sibling;
>> +       }
>> +
>> +       /* Reverse the nodes in the child list */
>> +       child = parent->child;
>> +       parent->child = NULL;
>> +       while (child) {
>> +               next = child->sibling;
>> +
>> +               child->sibling = parent->child;
>> +               parent->child = child;
>> +               child = next;
>> +       }
>> +}
>> +
>>  /**
>>   * unflatten_dt_node - Alloc and populate a device_node from the flat tree
>>   * @blob: The parent device tree blob
>>   * @mem: Memory chunk to use for allocating device nodes and properties
>> - * @poffset: pointer to node in flat tree
>>   * @dad: Parent struct device_node
>>   * @nodepp: The device_node tree created by the call
>> - * @fpsize: Size of the node path up at the current depth.
>>   * @dryrun: If true, do not allocate device nodes but still calculate needed
>>   * memory size
>>   */
>>  static void *unflatten_dt_node(const void *blob,
>>                                void *mem,
>> -                              int *poffset,
>>                                struct device_node *dad,
>>                                struct device_node **nodepp,
>> -                              unsigned long fpsize,
>>                                bool dryrun)
>
>We can probably further simplify things by returning an int with
>negative being errors and positive being the size. Also, dryrun can be
>dropped and implied by mem and/or nodepp being NULL.
>

Yeah, I think it's reasonable to return "size" from this function. "dryrun"
can be dropped and implied by NULL @mem. @nodepp can't be NULL. I perhaps
have separate patch to address it in next revision.

>>  {
>> -       struct device_node *np;
>> -       static int depth;
>> -       int old_depth;
>> -
>> -       fpsize = populate_node(blob, *poffset, &mem, dad, fpsize, &np, dryrun);
>> -       if (!fpsize)
>> -               return mem;
>> +       struct device_node *root;
>> +       int offset = 0, depth = 0;
>> +       unsigned long fpsizes[64];
>> +       struct device_node *nps[64];
>
>Use a define here.
>

Fair enough, will do in next revision. I'm not good at naming. Would
"FDT_MAX_DEPTH" is a good one?

>>
>> -       old_depth = depth;
>> -       *poffset = fdt_next_node(blob, *poffset, &depth);
>> -       if (depth < 0)
>> -               depth = 0;
>> -       while (*poffset > 0 && depth > old_depth)
>> -               mem = unflatten_dt_node(blob, mem, poffset, np, NULL,
>> -                                       fpsize, dryrun);
>> +       if (nodepp)
>> +               *nodepp = NULL;
>> +
>> +       root = dad;
>> +       fpsizes[depth] = dad ? strlen(of_node_full_name(dad)) : 0;
>> +       nps[depth++] = dad;
>> +       while (offset >= 0 && depth < 64) {
>> +               fpsizes[depth] = populate_node(blob, offset, &mem,
>> +                                              nps[depth - 1],
>> +                                              fpsizes[depth - 1],
>> +                                              &nps[depth], dryrun);
>> +               if (!fpsizes[depth])
>> +                       return mem;
>> +
>> +               if (!dryrun && nodepp && !*nodepp)
>> +                       *nodepp = nps[depth];
>> +               if (!dryrun && !root)
>> +                       root = nps[depth];
>> +
>> +               offset = fdt_next_node(blob, offset, &depth);
>> +       }
>>
>> -       if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)
>> -               pr_err("unflatten: error %d processing FDT\n", *poffset);
>> +       if (offset < 0 && offset != -FDT_ERR_NOTFOUND)
>> +               pr_err("%s: Error %d processing FDT\n",
>> +                      __func__, offset);
>
>What about depth == 64 case? I think the behavior should be a WARN and
>ignore those nodes so we at least can continue to boot and see the
>error. Of course, if there is a phandle pointing to ignored nodes, we
>have to handle that too.
>

Yeah, I'll have a WARN_ON(depth >= 64) in next revision. Sorry, I didn't
get the 2nd part of your comments: When depth > 64, the system won't work.
It might boot up. Why the phandle pointing to the ignored node has to be
dropped? 

>>
>>         /*
>>          * Reverse the child list. Some drivers assumes node order matches .dts
>>          * node order
>>          */
>> -       if (!dryrun && np->child) {
>> -               struct device_node *child = np->child;
>> -               np->child = NULL;
>> -               while (child) {
>> -                       struct device_node *next = child->sibling;
>> -                       child->sibling = np->child;
>> -                       np->child = child;
>> -                       child = next;
>> -               }
>> -       }
>> -
>> -       if (nodepp)
>> -               *nodepp = np;
>> +       if (!dryrun)
>> +               reverse_nodes(root);
>>
>>         return mem;
>>  }
>> @@ -431,7 +452,6 @@ static void __unflatten_device_tree(const void *blob,
>>                              void * (*dt_alloc)(u64 size, u64 align))
>>  {
>>         unsigned long size;
>> -       int start;
>>         void *mem;
>>
>>         pr_debug(" -> unflatten_device_tree()\n");
>> @@ -452,8 +472,7 @@ static void __unflatten_device_tree(const void *blob,
>>         }
>>
>>         /* First pass, scan for size */
>> -       start = 0;
>> -       size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0, true);
>> +       size = (unsigned long)unflatten_dt_node(blob, NULL, NULL, NULL, true);
>>         size = ALIGN(size, 4);
>>
>>         pr_debug("  size is %lx, allocating...\n", size);
>> @@ -467,8 +486,7 @@ static void __unflatten_device_tree(const void *blob,
>>         pr_debug("  unflattening %p...\n", mem);
>>
>>         /* Second pass, do actual unflattening */
>> -       start = 0;
>> -       unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false);
>> +       unflatten_dt_node(blob, mem, NULL, mynodes, false);
>>         if (be32_to_cpup(mem + size) != 0xdeadbeef)
>>                 pr_warning("End of tree marker overwritten: %08x\n",
>>                            be32_to_cpup(mem + size));

Thanks,
Gavin

  reply	other threads:[~2015-11-04 23:24 UTC|newest]

Thread overview: 157+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-04 13:12 [PATCH v7 00/50] powerpc/powernv: PCI hotplug support Gavin Shan
2015-11-04 13:12 ` [PATCH v7 01/50] PCI: Add pcibios_setup_bridge() Gavin Shan
2015-11-04 13:12 ` [PATCH v7 02/50] powerpc/pci: Override pcibios_setup_bridge() Gavin Shan
2015-11-05 22:27   ` Daniel Axtens
2015-11-05 23:44     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 03/50] powerpc/pci: Cleanup on struct pci_controller_ops Gavin Shan
2015-11-05 22:32   ` Daniel Axtens
2015-11-05 23:45     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 04/50] powerpc/powernv: Cleanup on pnv_pci_ioda_controller_ops Gavin Shan
2015-11-05 22:28   ` Daniel Axtens
2015-11-06  1:09     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 05/50] powerpc/powernv: Drop pnv_ioda_setup_dev_PE() Gavin Shan
2015-11-04 13:12 ` [PATCH v7 06/50] powerpc/powernv: Drop phb->bdfn_to_pe() Gavin Shan
2015-11-04 13:12 ` [PATCH v7 07/50] powerpc/powernv: Reorder fields in struct pnv_phb Gavin Shan
2015-11-04 13:12 ` [PATCH v7 08/50] powerpc/powernv: Rename PE# " Gavin Shan
2015-11-16  8:01   ` Alexey Kardashevskiy
2015-11-17  1:22     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 09/50] powerpc/powernv: Fix initial IO and M32 segmap Gavin Shan
2015-11-04 13:12 ` [PATCH v7 10/50] powerpc/powernv: Simplify pnv_ioda_setup_pe_seg() Gavin Shan
2015-11-05 22:56   ` Daniel Axtens
2015-11-05 23:52     ` Gavin Shan
2015-11-16  8:01       ` Alexey Kardashevskiy
2015-11-17  0:54         ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 11/50] powerpc/powernv: IO and M32 mapping based on PCI device resources Gavin Shan
2015-11-12  3:30   ` Daniel Axtens
2015-11-12  4:55     ` Gavin Shan
2015-11-16  8:01       ` Alexey Kardashevskiy
2015-11-17  1:33         ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 12/50] powerpc/powernv: Track M64 segment consumption Gavin Shan
2015-11-12  4:18   ` Daniel Axtens
2015-11-16  8:01   ` Alexey Kardashevskiy
2015-11-17  1:04     ` Gavin Shan
2015-11-19  0:10       ` Alexey Kardashevskiy
2015-11-23 22:42         ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 13/50] powerpc/powernv: Rename M64 related functions Gavin Shan
2015-11-04 13:12 ` [PATCH v7 14/50] powerpc/powernv: M64 support on P7IOC Gavin Shan
2015-11-16  8:01   ` Alexey Kardashevskiy
2015-11-17  1:37     ` Gavin Shan
2015-11-19  0:18       ` Alexey Kardashevskiy
2015-11-22 22:46         ` Gavin Shan
2015-11-16  8:02   ` Alexey Kardashevskiy
2015-11-17  1:38     ` Gavin Shan
2015-11-17  2:11       ` Alexey Kardashevskiy
2015-11-17  2:44         ` Gavin Shan
2015-11-16  8:02   ` Alexey Kardashevskiy
2015-11-17  1:42     ` Gavin Shan
2015-11-17  2:37       ` Alexey Kardashevskiy
2015-11-17  3:04         ` Gavin Shan
2015-11-17  3:40           ` Benjamin Herrenschmidt
2015-11-17  4:43           ` Alexey Kardashevskiy
2015-11-17  8:44             ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 15/50] powerpc/powernv: Rename pnv_pci_ioda_setup_dma_pe() Gavin Shan
2015-11-04 13:12 ` [PATCH v7 16/50] powerpc/powernv: Define PNV_IODA1_DMA32_SEGSIZE Gavin Shan
2015-11-04 13:12 ` [PATCH v7 17/50] powerpc/powernv: Avoid calculating DMA32 segments on PHB3 Gavin Shan
2015-11-17  1:07   ` Alexey Kardashevskiy
2015-11-17  8:48     ` Gavin Shan
2015-11-17 23:59       ` Alexey Kardashevskiy
2015-11-04 13:12 ` [PATCH v7 18/50] powerpc/powernv: Remove DMA32 PE list Gavin Shan
2015-11-17  1:54   ` Alexey Kardashevskiy
2015-11-17  2:01     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 19/50] powerpc/powernv: Track DMA32 segment consumption Gavin Shan
2015-11-17  0:28   ` Daniel Axtens
2015-11-17  1:55     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 20/50] powerpc/powernv: Improve DMA32 segment calculation Gavin Shan
2015-11-20  3:14   ` Daniel Axtens
2015-11-04 13:12 ` [PATCH v7 21/50] powerpc/powernv: Increase PE# capacity Gavin Shan
2015-11-17  0:29   ` Daniel Axtens
2015-11-17  1:56     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 22/50] powerpc/powernv: Introduce pnv_ioda_init_pe() Gavin Shan
2015-11-17  0:30   ` Daniel Axtens
2015-11-17  1:58     ` Gavin Shan
2015-11-17  2:37       ` Alexey Kardashevskiy
2015-11-17  2:53         ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 23/50] powerpc/powernv: Use PE instead of number during setup and release Gavin Shan
2015-11-17  5:08   ` Alexey Kardashevskiy
2015-11-17  9:03     ` Gavin Shan
2015-11-18  0:13       ` Alexey Kardashevskiy
2015-11-22 22:52         ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 24/50] powerpc/powernv: Allocate PE# in reverse order Gavin Shan
2015-11-04 13:12 ` [PATCH v7 25/50] powerpc/powernv: Reserve PE for root bus Gavin Shan
2015-11-17  6:04   ` Alexey Kardashevskiy
2015-11-17  9:06     ` Gavin Shan
2015-11-19  0:21       ` Alexey Kardashevskiy
2015-11-04 13:12 ` [PATCH v7 26/50] powerpc/powernv: Create PEs at PCI hot plugging time Gavin Shan
2015-11-17  7:57   ` Alexey Kardashevskiy
2015-11-17  9:12     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 27/50] powerpc/powernv: Dynamically release PEs Gavin Shan
2015-11-18  2:23   ` Alexey Kardashevskiy
2015-11-23 23:06     ` Gavin Shan
2015-11-24  0:22       ` Alexey Kardashevskiy
2015-11-04 13:12 ` [PATCH v7 28/50] powerpc/pci: Rename pcibios_{add, remove}_pci_devices() Gavin Shan
2015-11-18  2:43   ` [PATCH v7 28/50] powerpc/pci: Rename pcibios_{add,remove}_pci_devices() Alexey Kardashevskiy
2015-11-23 23:08     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 29/50] powerpc/pci: Rename pcibios_find_pci_bus() Gavin Shan
2015-11-18  3:59   ` Alexey Kardashevskiy
2015-11-23 23:11     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 30/50] powerpc/pci: Move pci_find_bus_by_node() around Gavin Shan
2015-11-04 13:12 ` [PATCH v7 31/50] powerpc/pci: Export pci_add_device_node_info() Gavin Shan
2015-11-04 13:12 ` [PATCH v7 32/50] powerpc/pci: Introduce pci_remove_device_node_info() Gavin Shan
2015-11-04 13:12 ` [PATCH v7 33/50] powerpc/pci: Export pci_traverse_device_nodes() Gavin Shan
2015-11-18  3:14   ` Alexey Kardashevskiy
2015-11-23 23:23     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 34/50] powerpc/pci: Delay populating pdn Gavin Shan
2015-11-18  4:24   ` Alexey Kardashevskiy
2015-11-23 23:42     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 35/50] powerpc/pci: Don't scan empty slot Gavin Shan
2015-11-04 13:12 ` [PATCH v7 36/50] powerpc/pci: Update bridge windows on PCI plug Gavin Shan
2015-11-04 13:12 ` [PATCH v7 37/50] powerpc/powernv: Simplify pnv_eeh_reset() Gavin Shan
2015-11-12  5:11   ` Daniel Axtens
2015-11-12  6:11     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 38/50] powerpc/powernv: Exclude root bus in pnv_pci_reset_secondary_bus() Gavin Shan
2015-11-12 22:59   ` Daniel Axtens
2015-11-12 23:25     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 39/50] powerpc/powernv: Fundamental reset " Gavin Shan
2015-11-12  6:15   ` Gavin Shan
2015-11-13  0:08   ` Daniel Axtens
2015-11-13  0:20     ` Gavin Shan
2015-11-13  0:23     ` Benjamin Herrenschmidt
2015-11-13  0:23   ` Daniel Axtens
2015-11-04 13:12 ` [PATCH v7 40/50] powerpc/powernv: Support PCI slot ID Gavin Shan
2015-11-04 13:12 ` [PATCH v7 41/50] powerpc/powernv: Use firmware PCI slot reset infrastructure Gavin Shan
2015-11-04 13:12 ` [PATCH v7 42/50] powerpc/powernv: Functions to get/set PCI slot status Gavin Shan
2015-11-04 13:12 ` [PATCH v7 43/50] powerpc/powernv: Select OF_DYNAMIC Gavin Shan
2015-11-04 13:12 ` [PATCH v7 44/50] drivers/of: Split unflatten_dt_node() Gavin Shan
2015-11-04 18:43   ` Rob Herring
2015-11-04 23:05     ` Gavin Shan
2015-11-04 13:12 ` [PATCH v7 45/50] drivers/of: Avoid recursively calling unflatten_dt_node() Gavin Shan
2015-11-04 16:07   ` Rob Herring
2015-11-04 23:23     ` Gavin Shan [this message]
2015-11-04 23:26       ` Gavin Shan
2016-05-13  7:16     ` Geert Uytterhoeven
2016-05-13 11:31       ` [PATCH] drivers/of: Fix build warning in populate_node() Gavin Shan
2016-05-16 14:11         ` Rob Herring
2015-12-06 20:28   ` [PATCH v7 45/50] drivers/of: Avoid recursively calling unflatten_dt_node() Rob Herring
2015-12-06 21:49     ` Guenter Roeck
2015-12-06 23:54     ` Benjamin Herrenschmidt
2015-12-07  2:21       ` Guenter Roeck
2015-12-07  2:33         ` Rob Herring
2015-12-07  3:40           ` Guenter Roeck
2015-11-04 13:12 ` [PATCH v7 46/50] drivers/of: Rename unflatten_dt_node() Gavin Shan
2015-11-04 13:12 ` [PATCH v7 47/50] drivers/of: Specify parent node in of_fdt_unflatten_tree() Gavin Shan
2015-11-04 13:12 ` [PATCH v7 48/50] drivers/of: Return allocated memory from of_fdt_unflatten_tree() Gavin Shan
2015-11-04 13:12 ` [PATCH v7 49/50] drivers/of: Export OF changeset functions Gavin Shan
2015-11-04 16:12   ` Rob Herring
2015-11-04 23:23     ` Gavin Shan
2016-01-13 13:54   ` [v7,49/50] " Wolfram Sang
2016-01-13 21:18     ` Michael Ellerman
2016-01-13 21:20       ` Wolfram Sang
2016-01-13 23:53         ` Rob Herring
2016-01-14  7:28           ` Wolfram Sang
2015-11-04 13:12 ` [PATCH v7 50/50] PCI/hotplug: PowerPC PowerNV PCI hotplug driver Gavin Shan
2015-11-18  7:33   ` Alexey Kardashevskiy
2015-11-23 23:16     ` Gavin Shan
2015-11-09  3:09 ` [PATCH v7 00/50] powerpc/powernv: PCI hotplug support Gavin Shan
2015-11-09  4:24   ` Pramod Sudheendra
2015-11-09  4:29     ` Gavin Shan
2015-11-09  6:43       ` Benjamin Herrenschmidt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20151104232315.GB9287@gwshan \
    --to=gwshan@linux.vnet.ibm.com \
    --cc=aik@ozlabs.ru \
    --cc=benh@kernel.crashing.org \
    --cc=bhelgaas@google.com \
    --cc=devicetree@vger.kernel.org \
    --cc=frowand.list@gmail.com \
    --cc=grant.likely@linaro.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=mpe@ellerman.id.au \
    --cc=panto@antoniou-consulting.com \
    --cc=robherring2@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).