Re: [PATCH] livetree: Add only new data to fixup nodes instead of complete regeneration

David Gibson <[email protected]>
Newsgroups org.kernel.vger.devicetree-compiler
Message-ID <aJ6zI_mOB21fKja6@zatzit>
On Thu, Aug 14, 2025 at 11:28:05AM +0200, Uwe Kleine-König wrote:
> On Thu, Aug 14, 2025 at 11:05:02AM +0200, Uwe Kleine-König wrote:
> > Hello David,
> > 
> > On Thu, Aug 14, 2025 at 05:36:08PM +1000, David Gibson wrote:
> > > On Fri, Aug 01, 2025 at 06:00:31PM +0200, Uwe Kleine-König wrote:
> > > >  livetree.c              | 75 +++++++++++++++++++++++++++++++----------
> > > >  tests/retain-fixups.dts | 29 ++++++++++++++++
> > > >  tests/run_tests.sh      |  5 +++
> > > >  3 files changed, 92 insertions(+), 17 deletions(-)
> > > >  create mode 100644 tests/retain-fixups.dts
> > > > 
> > > > diff --git a/livetree.c b/livetree.c
> > > > index d51d05830b18..24f7c561d77e 100644
> > > > --- a/livetree.c
> > > > +++ b/livetree.c
> > > > @@ -356,6 +356,60 @@ void append_to_property(struct node *node,
> > > >  	}
> > > >  }
> > > >  
> > > > +static void append_unique_str_to_property(struct node *node,
> > > > +					  char *name, const char *data, int len)
> > > > +{
> > > > +	struct data d;
> > > > +	struct property *p;
> > > > +
> > > > +	p = get_property(node, name);
> > > > +	if (p) {
> > > > +		const char *s;
> > > > +
> > > > +		for (s = p->val.val; s < p->val.val + p->val.len; s = strchr(s, '\0') + 1) {
> > > 
> > > This isn't quite safe.  You check s is within bounds on each
> > > iteration, but if the property is malformed and doesn't end with a \0,
> > > the strchr() itself could read beyond the property's bounds.
> > > 
> > > strnchr() could work, but is awkward: it would return NULL if there
> > > are no further \0 within the property, and on most systems NULL <
> > > p->val.val + p->val.len would return true, so you'd have to check for
> > > that case separately.  You could use strnlen() instead, but that's
> > > also a bit awkward - it doesn't include the \0, so you'd need to add
> > > +1 - but in the malformed case that would put you one beyond the end
> > > of the buffer.  That would probably work in practice, but creating
> > > pointers beyond the buffer they're within is technically UB.
> > 
> > fair, my approach would be to check p->val.val[p->val.len - 1] == '\0'
> > once before the loop.
> > 
> > > > +			if (strcmp(data, s) == 0)
> > > 
> > > This also relies on the \0 being there.  Any fix for the above, will
> > > probably result in being able to get the length of each string segment
> > > fairly naturally, so it would make sense to use memcmp() instead.
> > > 
> > > > +				/* data already contained in node.name */
> > > > +				return;
> > > > +		}
> > > > +
> > > > +		d = data_add_marker(p->val, TYPE_STRING, name);
> > > > +		d = data_append_data(d, data, len);
> > > > +		p->val = d;
> > > > +	} else {
> > > > +		d = data_add_marker(empty_data, TYPE_STRING, name);
> > > > +		d = data_append_data(d, data, len);
> > > > +		p = build_property(name, d, NULL);
> > > > +		add_property(node, p);
> > > 
> > > You can add the property first, then share the data_append_data()
> > > logic with the previous case.
> > 
> > This is mostly taken from append_to_property(), I will check if your
> > suggested improvement will apply to that one, too.
> 
> I think that would be:

Looks good.

> diff --git a/livetree.c b/livetree.c
> index d51d05830b18..2ccdc9d9c2a7 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -344,16 +344,14 @@ void append_to_property(struct node *node,
>  	struct property *p;
>  
>  	p = get_property(node, name);
> -	if (p) {
> -		d = data_add_marker(p->val, type, name);
> -		d = data_append_data(d, data, len);
> -		p->val = d;
> -	} else {
> -		d = data_add_marker(empty_data, type, name);
> -		d = data_append_data(d, data, len);
> -		p = build_property(name, d, NULL);
> +	if (!p) {
> +		p = build_property(name, empty_data, NULL);
>  		add_property(node, p);
>  	}
> +
> +	d = data_add_marker(p->val, type, name);
> +	d = data_append_data(d, data, len);
> +	p->val = d;

You could even do this in place in p->val, avoiding the temporary.

>  }
>  
>  struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
> 
> The test suite is happy with it. I will include that with the next
> revision of my fix patch.
> 
> Best regards
> Uwe



-- 
David Gibson (he or they)	| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you, not the other way
				| around.
http://www.ozlabs.org/~dgibson
signature.asc (application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmiesyIACgkQzQJF27ox
2GdqkA//Q70UAGXmiz1MiRz0ZLnW7m/6OLQT69hifQmxHrpBiV2Npa0ucbZDMbVC
j4vSg2pOnNxGVI1wPwYnKsDTHAG3y0mZcLjhAyaX+eYIzNGc7pjv6vwlHHdZPcIv
QknB9E4Y7fEy3mUT7KY81wduGlfpaIr19jHp9cNAGkn91xcw/dgGVYFYulHsFYzM
7aURWCrStVWQX+ytcB9HcaubZji6KxujO3h1yYoqwH+fecM9gHIA90jO80wrDhaZ
jaSsf8eoeYyE2v2nHGoIEFdSkBXVV4Iw6G8PmdzMjunNtz/pX4WqEMrl0MtffUW+
jY53uvCsRoWwgALEWWkcPUDNFKZ+iZd3g5Ohh/xcwgYbE8/WVciQ3KOQnUnv57VD
uija556xymkiHSBFjmKdPBmU+Z/4SWtBBN4ukD/3gvuKPEXi5SkAwRPHhiLgo0GN
6/tFHmAWmdGQeZ6+zlyy7kW/QDBZNFpM1upumi3AXi2gZxtPH2Qy2nK6WxUUHSj+
t0WCL388Z3x2xmKYB0DcFLF9XWWbQ4GfYZQxl8amke6e48EOExahXRbZD2aViypI
gES3+G4K8V4eMlxuiHI6Eqb7+yZoiM7qUEr13Tx/2HlVjL0Vo+1Rd1bUsuo3usJO
VL4hmeHt8Q1NUzv7f7e0XVVLbd90ouSaImOn4YI+IfuM9U3Yx3w=
=4mBX
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.