mbox series

[0/4] DT printf format specifiers

Message ID 20170614203025.7581-1-robh@kernel.org
Headers show
Series DT printf format specifiers | expand

Message

Rob Herring June 14, 2017, 8:30 p.m. UTC
This resurrects an old patch[1] from Pantelis adding printf format 
specifiers for DT nodes. The previous versions didn't get applied after 
debate about the what character(s) to use. Grant suggested %pO for 
base kobject and %pOF for struct device_node. Everyone agreed, but no 
new version was posted.

I ended up re-writing the core implementation to be more inline with how 
other format specifiers are written which allowed removing #define code 
fragments. The other 3 patches convert the core DT code to use %pOF and 
prepare for changing device_node.full_name to stop storing the full path 
for every node.

My plan is to merge this series for v4.13 and post follow-up patches to 
convert all arches and subsystems to %pOF for v4.14. The full series is 
available here[2]. I tested this on QEMU running the DT unittests.

Rob

[1] https://patchwork.kernel.org/patch/6127521/
[2] git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git dt-printf

Pantelis Antoniou (1):
  of: Custom printk format specifier for device node

Rob Herring (3):
  of: use kbasename instead of open coding
  of: find_node_by_full_name rewrite to compare each level
  of: Convert to using %pOF instead of full_name

 Documentation/printk-formats.txt |  31 +++++++++
 drivers/of/address.c             |  21 +++---
 drivers/of/base.c                |  76 ++++++++++++----------
 drivers/of/device.c              |   2 +-
 drivers/of/dynamic.c             |  33 +++++-----
 drivers/of/irq.c                 |  10 +--
 drivers/of/of_mdio.c             |  10 +--
 drivers/of/of_pci.c              |  29 ++++-----
 drivers/of/of_private.h          |   3 +
 drivers/of/overlay.c             |  21 +++---
 drivers/of/platform.c            |  34 +++++-----
 drivers/of/resolver.c            |  34 ++--------
 drivers/of/unittest.c            |  66 +++++++++++--------
 lib/vsprintf.c                   | 135 ++++++++++++++++++++++++++++++++++++++-
 scripts/checkpatch.pl            |   2 +-
 15 files changed, 331 insertions(+), 176 deletions(-)

-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Joe Perches June 14, 2017, 8:56 p.m. UTC | #1
On Wed, 2017-06-14 at 15:30 -0500, Rob Herring wrote:
> From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>


I think the commit subject is wrong.
It adds an "of" specific bit to vsprintf.c.
The subject should be
'vsprintf:  Add %p extension "%pO" for device tree'

> 90% of the usage of device node's full_name is printing it out

> in a kernel message. Preparing for the eventual delayed allocation

> introduce a custom printk format specifier that is both more

> compact and more pleasant to the eye.

> 

> For instance typical use is:

> 	pr_info("Frobbing node %s\n", node->full_name);

> 

> Which can be written now as:

> 	pr_info("Frobbing node %pOF\n", node);


Somehow I think this example is poor as node->full_name
is a pretty obvious to read use.  %pOF requires you to
look up or know what the output is going to be.

> More fine-grained control of formatting includes printing the name,

> flag, path-spec name, reference count and others, explained in the

> documentation entry.

> 

> Originally written by Pantelis, but pretty much rewrote the core

> function using existing string/number functions. The 2 passes were

> unnecessary and have been removed. Also, updated the checkpatch.pl

> check.


Some comments about the code.

> diff --git a/lib/vsprintf.c b/lib/vsprintf.c

> []

> @@ -1470,6 +1471,123 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)

>  	return format_flags(buf, end, flags, names);

>  }

>  

> +static noinline_for_stack

> +char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)

> +{

> +	int len, ret;

> +

> +	if (!np || !np->parent)

> +		return buf;

> +

> +	buf = device_node_gen_full_name(np->parent, buf, end);


This is recursive.  How many levels of parents could there be?
Perhaps there should be a recursion limit.

> +

> +	if (buf < end)

> +		len = end - buf;

> +	else

> +		len = 0;

> +	ret = snprintf(buf, len, "/%s", kbasename(np->full_name));

> +	if (ret <= 0)

> +		return buf;

> +	else if (len == 0 || ret < len)

> +		return buf + ret;

> +	return buf + len;

> +}


Does this work with %p<len>OF for a right justified or padded
length string?  Perhaps widen_string should be added.

> +static noinline_for_stack

> +char *device_node_string(char *buf, char *end, struct device_node *dn,

> +			 struct printf_spec spec, const char *fmt)

> +{

> +	char tbuf[sizeof("xxxxxxxxxx") + 1];

> +	const char *fmtp, *p;

> +	int ret;

> +	char *buf_start = buf;

> +	struct property *prop;

> +	bool has_mult, pass;

> +	const struct printf_spec num_spec = {

> +		.flags = SMALL,

> +		.field_width = -1,

> +		.precision = -1,

> +		.base = 10,

> +	};

> +

> +	struct printf_spec str_spec = spec;

> +	str_spec.field_width = -1;

> +

> +	if (!IS_ENABLED(CONFIG_OF))

> +		return string(buf, end, "(!OF)", spec);

> +

> +	if ((unsigned long)dn < PAGE_SIZE)

> +		return string(buf, end, "(null)", spec);

> +

> +	/* simple case without anything any more format specifiers */

> +	if (fmt[1] == '\0' || strcspn(fmt + 1,"fnpPFcCr") > 0)

> +		fmt = "Ff";

> +

> +	for (fmtp = fmt + 1, pass = false; strspn(fmtp,"fnpPFcCr"); fmtp++, pass = true) {


why not
	while (isalpha(*++fmt))
like ip6 or isalnum like FORMAT_TYPE_PTR uses?

> +		if (pass && (*fmtp != 'f')) {

> +			if (buf < end)

> +				*buf = '|';

> +			buf++;

> +		}

> +

> +		switch (*fmtp) {

> +		case 'f':	/* full_name */

> +			if (pass) {

> +				if (buf < end)

> +					*buf = ':';

> +				buf++;

> +			}

> +			buf = device_node_gen_full_name(dn, buf, end);

> +			break;

> +		case 'n':	/* name */

> +			buf = string(buf, end, dn->name, str_spec);

> +			break;

> +		case 'p':	/* phandle */

> +			buf = number(buf, end, (unsigned int)dn->phandle, num_spec);

> +			break;

> +		case 'P':	/* path-spec */

> +			buf = string(buf, end, kbasename(of_node_full_name(dn)), str_spec);

> +			break;

> +		case 'F':	/* flags */

> +			snprintf(tbuf, sizeof(tbuf), "%c%c%c%c",

> +				of_node_check_flag(dn, OF_DYNAMIC) ?

> +					'D' : '-',

> +				of_node_check_flag(dn, OF_DETACHED) ?

> +					'd' : '-',

> +				of_node_check_flag(dn, OF_POPULATED) ?

> +					'P' : '-',

> +				of_node_check_flag(dn,

> +					OF_POPULATED_BUS) ?  'B' : '-');


I'd try to avoid all uses of snprintf as it's effectively
another fairly
large stack frame.

It's probably better to avoid more recursion stack depth use
and just use *buf++ as appropriate.

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joe Perches June 14, 2017, 8:58 p.m. UTC | #2
On Wed, 2017-06-14 at 15:30 -0500, Rob Herring wrote:
> Now that we have a custom printf format specifier, convert users of

> full_name to use %pOF instead. This is preparation to remove storing

> of the full path string for each node.


Well, a full_name removal makes my reply in 2/4 less sensible.
Maybe 2/4 should say that full_name is going away.

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring June 15, 2017, 12:30 p.m. UTC | #3
On Wed, Jun 14, 2017 at 3:56 PM, Joe Perches <joe@perches.com> wrote:
> On Wed, 2017-06-14 at 15:30 -0500, Rob Herring wrote:

>> From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>

>

> I think the commit subject is wrong.

> It adds an "of" specific bit to vsprintf.c.

> The subject should be

> 'vsprintf:  Add %p extension "%pO" for device tree'


Okay, but it was good enough for the 2-3 versions Pantelis did before...

>> 90% of the usage of device node's full_name is printing it out

>> in a kernel message. Preparing for the eventual delayed allocation

>> introduce a custom printk format specifier that is both more

>> compact and more pleasant to the eye.

>>

>> For instance typical use is:

>>       pr_info("Frobbing node %s\n", node->full_name);

>>

>> Which can be written now as:

>>       pr_info("Frobbing node %pOF\n", node);

>

> Somehow I think this example is poor as node->full_name

> is a pretty obvious to read use.  %pOF requires you to

> look up or know what the output is going to be.


So %pOFfullname? We've beat this one to death IMO.

>

>> More fine-grained control of formatting includes printing the name,

>> flag, path-spec name, reference count and others, explained in the

>> documentation entry.

>>

>> Originally written by Pantelis, but pretty much rewrote the core

>> function using existing string/number functions. The 2 passes were

>> unnecessary and have been removed. Also, updated the checkpatch.pl

>> check.

>

> Some comments about the code.

>

>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c

>> []

>> @@ -1470,6 +1471,123 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)

>>       return format_flags(buf, end, flags, names);

>>  }

>>

>> +static noinline_for_stack

>> +char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)

>> +{

>> +     int len, ret;

>> +

>> +     if (!np || !np->parent)

>> +             return buf;

>> +

>> +     buf = device_node_gen_full_name(np->parent, buf, end);

>

> This is recursive.  How many levels of parents could there be?

> Perhaps there should be a recursion limit.


2-6 I'd say is typical. The FDT unflattening code limits things to 64
(which is probably way more than needed).

I could re-write it to be non-recursive, but then I'll just have the
max sized array of pointers on the stack.

>

>> +

>> +     if (buf < end)

>> +             len = end - buf;

>> +     else

>> +             len = 0;

>> +     ret = snprintf(buf, len, "/%s", kbasename(np->full_name));


I can replace this one too with a strcat and save some stack space.

>> +     if (ret <= 0)

>> +             return buf;

>> +     else if (len == 0 || ret < len)

>> +             return buf + ret;

>> +     return buf + len;

>> +}

>

> Does this work with %p<len>OF for a right justified or padded

> length string?  Perhaps widen_string should be added.


widen_string is called at the end of device_node_string.

>> +static noinline_for_stack

>> +char *device_node_string(char *buf, char *end, struct device_node *dn,

>> +                      struct printf_spec spec, const char *fmt)

>> +{

>> +     char tbuf[sizeof("xxxxxxxxxx") + 1];

>> +     const char *fmtp, *p;

>> +     int ret;

>> +     char *buf_start = buf;

>> +     struct property *prop;

>> +     bool has_mult, pass;

>> +     const struct printf_spec num_spec = {

>> +             .flags = SMALL,

>> +             .field_width = -1,

>> +             .precision = -1,

>> +             .base = 10,

>> +     };

>> +

>> +     struct printf_spec str_spec = spec;

>> +     str_spec.field_width = -1;

>> +

>> +     if (!IS_ENABLED(CONFIG_OF))

>> +             return string(buf, end, "(!OF)", spec);

>> +

>> +     if ((unsigned long)dn < PAGE_SIZE)

>> +             return string(buf, end, "(null)", spec);

>> +

>> +     /* simple case without anything any more format specifiers */

>> +     if (fmt[1] == '\0' || strcspn(fmt + 1,"fnpPFcCr") > 0)

>> +             fmt = "Ff";

>> +

>> +     for (fmtp = fmt + 1, pass = false; strspn(fmtp,"fnpPFcCr"); fmtp++, pass = true) {

>

> why not

>         while (isalpha(*++fmt))

> like ip6 or isalnum like FORMAT_TYPE_PTR uses?


Okay.

>

>> +             if (pass && (*fmtp != 'f')) {

>> +                     if (buf < end)

>> +                             *buf = '|';

>> +                     buf++;

>> +             }

>> +

>> +             switch (*fmtp) {

>> +             case 'f':       /* full_name */

>> +                     if (pass) {

>> +                             if (buf < end)

>> +                                     *buf = ':';

>> +                             buf++;

>> +                     }

>> +                     buf = device_node_gen_full_name(dn, buf, end);

>> +                     break;

>> +             case 'n':       /* name */

>> +                     buf = string(buf, end, dn->name, str_spec);

>> +                     break;

>> +             case 'p':       /* phandle */

>> +                     buf = number(buf, end, (unsigned int)dn->phandle, num_spec);

>> +                     break;

>> +             case 'P':       /* path-spec */

>> +                     buf = string(buf, end, kbasename(of_node_full_name(dn)), str_spec);

>> +                     break;

>> +             case 'F':       /* flags */

>> +                     snprintf(tbuf, sizeof(tbuf), "%c%c%c%c",

>> +                             of_node_check_flag(dn, OF_DYNAMIC) ?

>> +                                     'D' : '-',

>> +                             of_node_check_flag(dn, OF_DETACHED) ?

>> +                                     'd' : '-',

>> +                             of_node_check_flag(dn, OF_POPULATED) ?

>> +                                     'P' : '-',

>> +                             of_node_check_flag(dn,

>> +                                     OF_POPULATED_BUS) ?  'B' : '-');

>

> I'd try to avoid all uses of snprintf as it's effectively

> another fairly

> large stack frame.


Okay.

> It's probably better to avoid more recursion stack depth use

> and just use *buf++ as appropriate.


You can't use *buf++ as this code must work and increment buf even
when buf is NULL.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joe Perches June 15, 2017, 4:51 p.m. UTC | #4
On Thu, 2017-06-15 at 07:30 -0500, Rob Herring wrote:
> On Wed, Jun 14, 2017 at 3:56 PM, Joe Perches <joe@perches.com> wrote:

> > On Wed, 2017-06-14 at 15:30 -0500, Rob Herring wrote:

> > > From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>

> > 

> > I think the commit subject is wrong.

> > It adds an "of" specific bit to vsprintf.c.

> > The subject should be

> > 'vsprintf:  Add %p extension "%pO" for device tree'

> 

> Okay, but it was good enough for the 2-3 versions Pantelis did before...


Which were not applied.

> > > 90% of the usage of device node's full_name is printing it out

> > > in a kernel message. Preparing for the eventual delayed allocation


The "eventual delayed allocation" bit doesn't
mean anything to me.

> > > introduce a custom printk format specifier that is both more

> > > compact and more pleasant to the eye.

> > > 

> > > For instance typical use is:

> > >       pr_info("Frobbing node %s\n", node->full_name);

> > > 

> > > Which can be written now as:

> > >       pr_info("Frobbing node %pOF\n", node);

> > 

> > Somehow I think this example is poor as node->full_name

> > is a pretty obvious to read use.  %pOF requires you to

> > look up or know what the output is going to be.

> 

> So %pOFfullname? We've beat this one to death IMO.


I don't doubt the utility, just the example.
Just mention that full_name is going away.

> > > More fine-grained control of formatting includes printing the name,

> > > flag, path-spec name, reference count and others, explained in the

> > > documentation entry.

> > > 

> > > Originally written by Pantelis, but pretty much rewrote the core

> > > function using existing string/number functions. The 2 passes were

> > > unnecessary and have been removed. Also, updated the checkpatch.pl

> > > check.

> > 

> > Some comments about the code.

> > 

> > > diff --git a/lib/vsprintf.c b/lib/vsprintf.c

> > > []

> > > @@ -1470,6 +1471,123 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)

> > >       return format_flags(buf, end, flags, names);

> > >  }

> > > 

> > > +static noinline_for_stack

> > > +char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)

> > > +{

> > > +     int len, ret;

> > > +

> > > +     if (!np || !np->parent)

> > > +             return buf;

> > > +

> > > +     buf = device_node_gen_full_name(np->parent, buf, end);

> > 

> > This is recursive.  How many levels of parents could there be?

> > Perhaps there should be a recursion limit.

> 

> 2-6 I'd say is typical. The FDT unflattening code limits things to 64

> (which is probably way more than needed).

> 

> I could re-write it to be non-recursive, but then I'll just have the

> max sized array of pointers on the stack.


Which would be less stack than how many recursive calls?  5?

In any case, 64 * 8 for pointers or 5+ stack
frames is a fair amount of stack.

Maybe too much.

> > > +             case 'F':       /* flags */

> > > +                     snprintf(tbuf, sizeof(tbuf), "%c%c%c%c",

> > > +                             of_node_check_flag(dn, OF_DYNAMIC) ?

> > > +                                     'D' : '-',

> > > +                             of_node_check_flag(dn, OF_DETACHED) ?

> > > +                                     'd' : '-',

> > > +                             of_node_check_flag(dn, OF_POPULATED) ?

> > > +                                     'P' : '-',

> > > +                             of_node_check_flag(dn,

> > > +                                     OF_POPULATED_BUS) ?  'B' : '-');

> > 

> > I'd try to avoid all uses of snprintf as it's effectively

> > another fairly large stack frame.

> 

> Okay.

> 

> > It's probably better to avoid more recursion stack depth use

> > and just use *buf++ as appropriate.

> 

> You can't use *buf++ as this code must work and increment buf even

> when buf is NULL.


tbuf then.

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring June 15, 2017, 9:26 p.m. UTC | #5
On Wed, Jun 14, 2017 at 01:56:48PM -0700, Joe Perches wrote:
> On Wed, 2017-06-14 at 15:30 -0500, Rob Herring wrote:

> > From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>

> 

> I think the commit subject is wrong.

> It adds an "of" specific bit to vsprintf.c.

> The subject should be

> 'vsprintf:  Add %p extension "%pO" for device tree'

> 

> > 90% of the usage of device node's full_name is printing it out

> > in a kernel message. Preparing for the eventual delayed allocation

> > introduce a custom printk format specifier that is both more

> > compact and more pleasant to the eye.

> > 

> > For instance typical use is:

> > 	pr_info("Frobbing node %s\n", node->full_name);

> > 

> > Which can be written now as:

> > 	pr_info("Frobbing node %pOF\n", node);

> 

> Somehow I think this example is poor as node->full_name

> is a pretty obvious to read use.  %pOF requires you to

> look up or know what the output is going to be.

> 

> > More fine-grained control of formatting includes printing the name,

> > flag, path-spec name, reference count and others, explained in the

> > documentation entry.

> > 

> > Originally written by Pantelis, but pretty much rewrote the core

> > function using existing string/number functions. The 2 passes were

> > unnecessary and have been removed. Also, updated the checkpatch.pl

> > check.

> 

> Some comments about the code.

> 

> > diff --git a/lib/vsprintf.c b/lib/vsprintf.c

> > []

> > @@ -1470,6 +1471,123 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)

> >  	return format_flags(buf, end, flags, names);

> >  }

> >  

> > +static noinline_for_stack

> > +char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)

> > +{

> > +	int len, ret;

> > +

> > +	if (!np || !np->parent)

> > +		return buf;

> > +

> > +	buf = device_node_gen_full_name(np->parent, buf, end);

> 

> This is recursive.  How many levels of parents could there be?

> Perhaps there should be a recursion limit.


Okay, unlike unflattening code, we can easily calculate the depth and 
then allocate an array on the stack. So this is what I've ended up 
with:

static int device_node_calc_depth(const struct device_node *np)
{
	int d;

	for (d = 0; np; d++)
		np = np->parent;

	return d;
}

static noinline_for_stack
char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)
{
	int i;
	int depth = device_node_calc_depth(np);
	const struct device_node *nodes[depth];
	const struct printf_spec strspec = {
		.field_width = -1,
		.precision = -1,
	};

	if (!depth)
		return buf;
	/* special case for root node */
	if (depth == 1)
		return string(buf, end, "/", strspec);

	depth--;
	for (i = depth - 1; i >= 0; i--) {
		nodes[i] = np;
		np = np->parent;
	}
	for (i = 0; i < depth; i++) {
		buf = string(buf, end, "/", strspec);
		buf = string(buf, end, kbasename(nodes[i]->full_name), strspec);
	}
	return buf;
}


> > +	/* simple case without anything any more format specifiers */

> > +	if (fmt[1] == '\0' || strcspn(fmt + 1,"fnpPFcCr") > 0)

> > +		fmt = "Ff";

> > +

> > +	for (fmtp = fmt + 1, pass = false; strspn(fmtp,"fnpPFcCr"); fmtp++, pass = true) {

> 

> why not

> 	while (isalpha(*++fmt))

> like ip6 or isalnum like FORMAT_TYPE_PTR uses?


This case is more complicated with the field separators. If we have 
something like %pOFfxyz where xyz are not valid format specifiers, we'd 
end up with extra field separators.

I did simplify things a bit and got rid of fmtp and just use fmt 
instead.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joe Perches June 15, 2017, 9:50 p.m. UTC | #6
On Thu, 2017-06-15 at 16:26 -0500, Rob Herring wrote:
> On Wed, Jun 14, 2017 at 01:56:48PM -0700, Joe Perches wrote:

> > On Wed, 2017-06-14 at 15:30 -0500, Rob Herring wrote:

> > > From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>

[]
> > > diff --git a/lib/vsprintf.c b/lib/vsprintf.c

> > > []

> > > @@ -1470,6 +1471,123 @@ char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)

> > >  	return format_flags(buf, end, flags, names);

> > >  }

> > >  

> > > +static noinline_for_stack

> > > +char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)

> > > +{

> > > +	int len, ret;

> > > +

> > > +	if (!np || !np->parent)

> > > +		return buf;

> > > +

> > > +	buf = device_node_gen_full_name(np->parent, buf, end);

> > 

> > This is recursive.  How many levels of parents could there be?

> > Perhaps there should be a recursion limit.

> 

> Okay, unlike unflattening code, we can easily calculate the depth and 

> then allocate an array on the stack. So this is what I've ended up 

> with:

> 

> static int device_node_calc_depth(const struct device_node *np)

> {

> 	int d;

> 

> 	for (d = 0; np; d++)

> 		np = np->parent;

> 

> 	return d;

> }

> 

> static noinline_for_stack

> char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end)

> {

> 	int i;

> 	int depth = device_node_calc_depth(np);

> 	const struct device_node *nodes[depth];

> 	const struct printf_spec strspec = {

> 		.field_width = -1,

> 		.precision = -1,

> 	};


static const struct printf_spec strspec = { etc...
and please move strspec above *nodes

> 

> 	if (!depth)

> 		return buf;

> 	/* special case for root node */

> 	if (depth == 1)

> 		return string(buf, end, "/", strspec);

> 

> 	depth--;

> 	for (i = depth - 1; i >= 0; i--) {

> 		nodes[i] = np;

> 		np = np->parent;

> 	}

> 	for (i = 0; i < depth; i++) {

> 		buf = string(buf, end, "/", strspec);

> 		buf = string(buf, end, kbasename(nodes[i]->full_name), strspec);

> 	}

> 	return buf;

> }


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html