summaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorRob Herring <robh@kernel.org>2018-11-09 16:41:10 -0500
committerRob Herring <robh@kernel.org>2018-11-09 16:43:02 -0500
commitf8274f14a9b1261bd18096c693cdd6cf7d31a06d (patch)
treee6161dc2b331bc11b7d1f557898c6747e9ddc222 /drivers/of
parent1ae367a2451e0b249074461d2d8ac76d8e929a53 (diff)
parenteeb07c573ec307c53fe2f6ac6d8d11c261f64006 (diff)
Merge tag 'kfree_validate_v7-for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/frowand/linux into dt/next
Pull overlay validation checks from Frank Rowand: "Add checks to (1) overlay apply process and (2) memory freeing triggered by overlay release. The checks are intended to detect possible memory leaks and invalid overlays. The checks revealed bugs in existing code. Fixed the bugs. While fixing bugs, noted other issues, which are fixed in separate patches." Signed-off-by: Rob Herring <robh@kernel.org>
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/dynamic.c59
-rw-r--r--drivers/of/kobj.c4
-rw-r--r--drivers/of/overlay.c292
-rw-r--r--drivers/of/unittest-data/Makefile2
-rw-r--r--drivers/of/unittest-data/overlay_bad_add_dup_node.dts28
-rw-r--r--drivers/of/unittest-data/overlay_bad_add_dup_prop.dts24
-rw-r--r--drivers/of/unittest-data/overlay_base.dts1
-rw-r--r--drivers/of/unittest.c96
8 files changed, 414 insertions, 92 deletions
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index f4f8ed9b5454..b4e5b90cb314 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -205,15 +205,24 @@ static void __of_attach_node(struct device_node *np)
205 const __be32 *phandle; 205 const __be32 *phandle;
206 int sz; 206 int sz;
207 207
208 np->name = __of_get_property(np, "name", NULL) ? : "<NULL>"; 208 if (!of_node_check_flag(np, OF_OVERLAY)) {
209 np->type = __of_get_property(np, "device_type", NULL) ? : "<NULL>"; 209 np->name = __of_get_property(np, "name", NULL);
210 210 np->type = __of_get_property(np, "device_type", NULL);
211 phandle = __of_get_property(np, "phandle", &sz); 211 if (!np->name)
212 if (!phandle) 212 np->name = "<NULL>";
213 phandle = __of_get_property(np, "linux,phandle", &sz); 213 if (!np->type)
214 if (IS_ENABLED(CONFIG_PPC_PSERIES) && !phandle) 214 np->type = "<NULL>";
215 phandle = __of_get_property(np, "ibm,phandle", &sz); 215
216 np->phandle = (phandle && (sz >= 4)) ? be32_to_cpup(phandle) : 0; 216 phandle = __of_get_property(np, "phandle", &sz);
217 if (!phandle)
218 phandle = __of_get_property(np, "linux,phandle", &sz);
219 if (IS_ENABLED(CONFIG_PPC_PSERIES) && !phandle)
220 phandle = __of_get_property(np, "ibm,phandle", &sz);
221 if (phandle && (sz >= 4))
222 np->phandle = be32_to_cpup(phandle);
223 else
224 np->phandle = 0;
225 }
217 226
218 np->child = NULL; 227 np->child = NULL;
219 np->sibling = np->parent->child; 228 np->sibling = np->parent->child;
@@ -272,9 +281,6 @@ void __of_detach_node(struct device_node *np)
272 281
273/** 282/**
274 * of_detach_node() - "Unplug" a node from the device tree. 283 * of_detach_node() - "Unplug" a node from the device tree.
275 *
276 * The caller must hold a reference to the node. The memory associated with
277 * the node is not freed until its refcount goes to zero.
278 */ 284 */
279int of_detach_node(struct device_node *np) 285int of_detach_node(struct device_node *np)
280{ 286{
@@ -330,6 +336,25 @@ void of_node_release(struct kobject *kobj)
330 if (!of_node_check_flag(node, OF_DYNAMIC)) 336 if (!of_node_check_flag(node, OF_DYNAMIC))
331 return; 337 return;
332 338
339 if (of_node_check_flag(node, OF_OVERLAY)) {
340
341 if (!of_node_check_flag(node, OF_OVERLAY_FREE_CSET)) {
342 /* premature refcount of zero, do not free memory */
343 pr_err("ERROR: memory leak before free overlay changeset, %pOF\n",
344 node);
345 return;
346 }
347
348 /*
349 * If node->properties non-empty then properties were added
350 * to this node either by different overlay that has not
351 * yet been removed, or by a non-overlay mechanism.
352 */
353 if (node->properties)
354 pr_err("ERROR: %s(), unexpected properties in %pOF\n",
355 __func__, node);
356 }
357
333 property_list_free(node->properties); 358 property_list_free(node->properties);
334 property_list_free(node->deadprops); 359 property_list_free(node->deadprops);
335 360
@@ -434,6 +459,16 @@ struct device_node *__of_node_dup(const struct device_node *np,
434 459
435static void __of_changeset_entry_destroy(struct of_changeset_entry *ce) 460static void __of_changeset_entry_destroy(struct of_changeset_entry *ce)
436{ 461{
462 if (ce->action == OF_RECONFIG_ATTACH_NODE &&
463 of_node_check_flag(ce->np, OF_OVERLAY)) {
464 if (kref_read(&ce->np->kobj.kref) > 1) {
465 pr_err("ERROR: memory leak, expected refcount 1 instead of %d, of_node_get()/of_node_put() unbalanced - destroy cset entry: attach overlay node %pOF\n",
466 kref_read(&ce->np->kobj.kref), ce->np);
467 } else {
468 of_node_set_flag(ce->np, OF_OVERLAY_FREE_CSET);
469 }
470 }
471
437 of_node_put(ce->np); 472 of_node_put(ce->np);
438 list_del(&ce->node); 473 list_del(&ce->node);
439 kfree(ce); 474 kfree(ce);
diff --git a/drivers/of/kobj.c b/drivers/of/kobj.c
index 7a0a18980b98..c72eef988041 100644
--- a/drivers/of/kobj.c
+++ b/drivers/of/kobj.c
@@ -133,6 +133,9 @@ int __of_attach_node_sysfs(struct device_node *np)
133 } 133 }
134 if (!name) 134 if (!name)
135 return -ENOMEM; 135 return -ENOMEM;
136
137 of_node_get(np);
138
136 rc = kobject_add(&np->kobj, parent, "%s", name); 139 rc = kobject_add(&np->kobj, parent, "%s", name);
137 kfree(name); 140 kfree(name);
138 if (rc) 141 if (rc)
@@ -159,6 +162,5 @@ void __of_detach_node_sysfs(struct device_node *np)
159 kobject_del(&np->kobj); 162 kobject_del(&np->kobj);
160 } 163 }
161 164
162 /* finally remove the kobj_init ref */
163 of_node_put(np); 165 of_node_put(np);
164} 166}
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 42b1f73ac5f6..2b5ac43a5690 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -24,13 +24,33 @@
24#include "of_private.h" 24#include "of_private.h"
25 25
26/** 26/**
27 * struct target - info about current target node as recursing through overlay
28 * @np: node where current level of overlay will be applied
29 * @in_livetree: @np is a node in the live devicetree
30 *
31 * Used in the algorithm to create the portion of a changeset that describes
32 * an overlay fragment, which is a devicetree subtree. Initially @np is a node
33 * in the live devicetree where the overlay subtree is targeted to be grafted
34 * into. When recursing to the next level of the overlay subtree, the target
35 * also recurses to the next level of the live devicetree, as long as overlay
36 * subtree node also exists in the live devicetree. When a node in the overlay
37 * subtree does not exist at the same level in the live devicetree, target->np
38 * points to a newly allocated node, and all subsequent targets in the subtree
39 * will be newly allocated nodes.
40 */
41struct target {
42 struct device_node *np;
43 bool in_livetree;
44};
45
46/**
27 * struct fragment - info about fragment nodes in overlay expanded device tree 47 * struct fragment - info about fragment nodes in overlay expanded device tree
28 * @target: target of the overlay operation 48 * @target: target of the overlay operation
29 * @overlay: pointer to the __overlay__ node 49 * @overlay: pointer to the __overlay__ node
30 */ 50 */
31struct fragment { 51struct fragment {
32 struct device_node *target;
33 struct device_node *overlay; 52 struct device_node *overlay;
53 struct device_node *target;
34}; 54};
35 55
36/** 56/**
@@ -72,8 +92,7 @@ static int devicetree_corrupt(void)
72} 92}
73 93
74static int build_changeset_next_level(struct overlay_changeset *ovcs, 94static int build_changeset_next_level(struct overlay_changeset *ovcs,
75 struct device_node *target_node, 95 struct target *target, const struct device_node *overlay_node);
76 const struct device_node *overlay_node);
77 96
78/* 97/*
79 * of_resolve_phandles() finds the largest phandle in the live tree. 98 * of_resolve_phandles() finds the largest phandle in the live tree.
@@ -257,15 +276,23 @@ err_free_target_path:
257/** 276/**
258 * add_changeset_property() - add @overlay_prop to overlay changeset 277 * add_changeset_property() - add @overlay_prop to overlay changeset
259 * @ovcs: overlay changeset 278 * @ovcs: overlay changeset
260 * @target_node: where to place @overlay_prop in live tree 279 * @target: where @overlay_prop will be placed
261 * @overlay_prop: property to add or update, from overlay tree 280 * @overlay_prop: property to add or update, from overlay tree
262 * @is_symbols_prop: 1 if @overlay_prop is from node "/__symbols__" 281 * @is_symbols_prop: 1 if @overlay_prop is from node "/__symbols__"
263 * 282 *
264 * If @overlay_prop does not already exist in @target_node, add changeset entry 283 * If @overlay_prop does not already exist in live devicetree, add changeset
265 * to add @overlay_prop in @target_node, else add changeset entry to update 284 * entry to add @overlay_prop in @target, else add changeset entry to update
266 * value of @overlay_prop. 285 * value of @overlay_prop.
267 * 286 *
268 * Some special properties are not updated (no error returned). 287 * @target may be either in the live devicetree or in a new subtree that
288 * is contained in the changeset.
289 *
290 * Some special properties are not added or updated (no error returned):
291 * "name", "phandle", "linux,phandle".
292 *
293 * Properties "#address-cells" and "#size-cells" are not updated if they
294 * are already in the live tree, but if present in the live tree, the values
295 * in the overlay must match the values in the live tree.
269 * 296 *
270 * Update of property in symbols node is not allowed. 297 * Update of property in symbols node is not allowed.
271 * 298 *
@@ -273,19 +300,23 @@ err_free_target_path:
273 * invalid @overlay. 300 * invalid @overlay.
274 */ 301 */
275static int add_changeset_property(struct overlay_changeset *ovcs, 302static int add_changeset_property(struct overlay_changeset *ovcs,
276 struct device_node *target_node, 303 struct target *target, struct property *overlay_prop,
277 struct property *overlay_prop,
278 bool is_symbols_prop) 304 bool is_symbols_prop)
279{ 305{
280 struct property *new_prop = NULL, *prop; 306 struct property *new_prop = NULL, *prop;
281 int ret = 0; 307 int ret = 0;
308 bool check_for_non_overlay_node = false;
282 309
283 prop = of_find_property(target_node, overlay_prop->name, NULL); 310 if (target->in_livetree)
311 if (!of_prop_cmp(overlay_prop->name, "name") ||
312 !of_prop_cmp(overlay_prop->name, "phandle") ||
313 !of_prop_cmp(overlay_prop->name, "linux,phandle"))
314 return 0;
284 315
285 if (!of_prop_cmp(overlay_prop->name, "name") || 316 if (target->in_livetree)
286 !of_prop_cmp(overlay_prop->name, "phandle") || 317 prop = of_find_property(target->np, overlay_prop->name, NULL);
287 !of_prop_cmp(overlay_prop->name, "linux,phandle")) 318 else
288 return 0; 319 prop = NULL;
289 320
290 if (is_symbols_prop) { 321 if (is_symbols_prop) {
291 if (prop) 322 if (prop)
@@ -298,12 +329,36 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
298 if (!new_prop) 329 if (!new_prop)
299 return -ENOMEM; 330 return -ENOMEM;
300 331
301 if (!prop) 332 if (!prop) {
302 ret = of_changeset_add_property(&ovcs->cset, target_node, 333 check_for_non_overlay_node = true;
334 if (!target->in_livetree) {
335 new_prop->next = target->np->deadprops;
336 target->np->deadprops = new_prop;
337 }
338 ret = of_changeset_add_property(&ovcs->cset, target->np,
303 new_prop); 339 new_prop);
304 else 340 } else if (!of_prop_cmp(prop->name, "#address-cells")) {
305 ret = of_changeset_update_property(&ovcs->cset, target_node, 341 if (!of_prop_val_eq(prop, new_prop)) {
342 pr_err("ERROR: changing value of #address-cells is not allowed in %pOF\n",
343 target->np);
344 ret = -EINVAL;
345 }
346 } else if (!of_prop_cmp(prop->name, "#size-cells")) {
347 if (!of_prop_val_eq(prop, new_prop)) {
348 pr_err("ERROR: changing value of #size-cells is not allowed in %pOF\n",
349 target->np);
350 ret = -EINVAL;
351 }
352 } else {
353 check_for_non_overlay_node = true;
354 ret = of_changeset_update_property(&ovcs->cset, target->np,
306 new_prop); 355 new_prop);
356 }
357
358 if (check_for_non_overlay_node &&
359 !of_node_check_flag(target->np, OF_OVERLAY))
360 pr_err("WARNING: memory leak will occur if overlay removed, property: %pOF/%s\n",
361 target->np, new_prop->name);
307 362
308 if (ret) { 363 if (ret) {
309 kfree(new_prop->name); 364 kfree(new_prop->name);
@@ -315,14 +370,14 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
315 370
316/** 371/**
317 * add_changeset_node() - add @node (and children) to overlay changeset 372 * add_changeset_node() - add @node (and children) to overlay changeset
318 * @ovcs: overlay changeset 373 * @ovcs: overlay changeset
319 * @target_node: where to place @node in live tree 374 * @target: where @node will be placed in live tree or changeset
320 * @node: node from within overlay device tree fragment 375 * @node: node from within overlay device tree fragment
321 * 376 *
322 * If @node does not already exist in @target_node, add changeset entry 377 * If @node does not already exist in @target, add changeset entry
323 * to add @node in @target_node. 378 * to add @node in @target.
324 * 379 *
325 * If @node already exists in @target_node, and the existing node has 380 * If @node already exists in @target, and the existing node has
326 * a phandle, the overlay node is not allowed to have a phandle. 381 * a phandle, the overlay node is not allowed to have a phandle.
327 * 382 *
328 * If @node has child nodes, add the children recursively via 383 * If @node has child nodes, add the children recursively via
@@ -342,49 +397,65 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
342 * a live devicetree created from Open Firmware. 397 * a live devicetree created from Open Firmware.
343 * 398 *
344 * NOTE_2: Multiple mods of created nodes not supported. 399 * NOTE_2: Multiple mods of created nodes not supported.
345 * If more than one fragment contains a node that does not already exist
346 * in the live tree, then for each fragment of_changeset_attach_node()
347 * will add a changeset entry to add the node. When the changeset is
348 * applied, __of_attach_node() will attach the node twice (once for
349 * each fragment). At this point the device tree will be corrupted.
350 *
351 * TODO: add integrity check to ensure that multiple fragments do not
352 * create the same node.
353 * 400 *
354 * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if 401 * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
355 * invalid @overlay. 402 * invalid @overlay.
356 */ 403 */
357static int add_changeset_node(struct overlay_changeset *ovcs, 404static int add_changeset_node(struct overlay_changeset *ovcs,
358 struct device_node *target_node, struct device_node *node) 405 struct target *target, struct device_node *node)
359{ 406{
360 const char *node_kbasename; 407 const char *node_kbasename;
408 const __be32 *phandle;
361 struct device_node *tchild; 409 struct device_node *tchild;
362 int ret = 0; 410 struct target target_child;
411 int ret = 0, size;
363 412
364 node_kbasename = kbasename(node->full_name); 413 node_kbasename = kbasename(node->full_name);
365 414
366 for_each_child_of_node(target_node, tchild) 415 for_each_child_of_node(target->np, tchild)
367 if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name))) 416 if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name)))
368 break; 417 break;
369 418
370 if (!tchild) { 419 if (!tchild) {
371 tchild = __of_node_dup(node, node_kbasename); 420 tchild = __of_node_dup(NULL, node_kbasename);
372 if (!tchild) 421 if (!tchild)
373 return -ENOMEM; 422 return -ENOMEM;
374 423
375 tchild->parent = target_node; 424 tchild->parent = target->np;
425 tchild->name = __of_get_property(node, "name", NULL);
426 tchild->type = __of_get_property(node, "device_type", NULL);
427
428 if (!tchild->name)
429 tchild->name = "<NULL>";
430 if (!tchild->type)
431 tchild->type = "<NULL>";
432
433 /* ignore obsolete "linux,phandle" */
434 phandle = __of_get_property(node, "phandle", &size);
435 if (phandle && (size == 4))
436 tchild->phandle = be32_to_cpup(phandle);
437
438 of_node_set_flag(tchild, OF_OVERLAY);
376 439
377 ret = of_changeset_attach_node(&ovcs->cset, tchild); 440 ret = of_changeset_attach_node(&ovcs->cset, tchild);
378 if (ret) 441 if (ret)
379 return ret; 442 return ret;
380 443
381 return build_changeset_next_level(ovcs, tchild, node); 444 target_child.np = tchild;
445 target_child.in_livetree = false;
446
447 ret = build_changeset_next_level(ovcs, &target_child, node);
448 of_node_put(tchild);
449 return ret;
382 } 450 }
383 451
384 if (node->phandle && tchild->phandle) 452 if (node->phandle && tchild->phandle) {
385 ret = -EINVAL; 453 ret = -EINVAL;
386 else 454 } else {
387 ret = build_changeset_next_level(ovcs, tchild, node); 455 target_child.np = tchild;
456 target_child.in_livetree = target->in_livetree;
457 ret = build_changeset_next_level(ovcs, &target_child, node);
458 }
388 of_node_put(tchild); 459 of_node_put(tchild);
389 460
390 return ret; 461 return ret;
@@ -393,7 +464,7 @@ static int add_changeset_node(struct overlay_changeset *ovcs,
393/** 464/**
394 * build_changeset_next_level() - add level of overlay changeset 465 * build_changeset_next_level() - add level of overlay changeset
395 * @ovcs: overlay changeset 466 * @ovcs: overlay changeset
396 * @target_node: where to place @overlay_node in live tree 467 * @target: where to place @overlay_node in live tree
397 * @overlay_node: node from within an overlay device tree fragment 468 * @overlay_node: node from within an overlay device tree fragment
398 * 469 *
399 * Add the properties (if any) and nodes (if any) from @overlay_node to the 470 * Add the properties (if any) and nodes (if any) from @overlay_node to the
@@ -406,27 +477,26 @@ static int add_changeset_node(struct overlay_changeset *ovcs,
406 * invalid @overlay_node. 477 * invalid @overlay_node.
407 */ 478 */
408static int build_changeset_next_level(struct overlay_changeset *ovcs, 479static int build_changeset_next_level(struct overlay_changeset *ovcs,
409 struct device_node *target_node, 480 struct target *target, const struct device_node *overlay_node)
410 const struct device_node *overlay_node)
411{ 481{
412 struct device_node *child; 482 struct device_node *child;
413 struct property *prop; 483 struct property *prop;
414 int ret; 484 int ret;
415 485
416 for_each_property_of_node(overlay_node, prop) { 486 for_each_property_of_node(overlay_node, prop) {
417 ret = add_changeset_property(ovcs, target_node, prop, 0); 487 ret = add_changeset_property(ovcs, target, prop, 0);
418 if (ret) { 488 if (ret) {
419 pr_debug("Failed to apply prop @%pOF/%s, err=%d\n", 489 pr_debug("Failed to apply prop @%pOF/%s, err=%d\n",
420 target_node, prop->name, ret); 490 target->np, prop->name, ret);
421 return ret; 491 return ret;
422 } 492 }
423 } 493 }
424 494
425 for_each_child_of_node(overlay_node, child) { 495 for_each_child_of_node(overlay_node, child) {
426 ret = add_changeset_node(ovcs, target_node, child); 496 ret = add_changeset_node(ovcs, target, child);
427 if (ret) { 497 if (ret) {
428 pr_debug("Failed to apply node @%pOF/%pOFn, err=%d\n", 498 pr_debug("Failed to apply node @%pOF/%pOFn, err=%d\n",
429 target_node, child, ret); 499 target->np, child, ret);
430 of_node_put(child); 500 of_node_put(child);
431 return ret; 501 return ret;
432 } 502 }
@@ -439,17 +509,17 @@ static int build_changeset_next_level(struct overlay_changeset *ovcs,
439 * Add the properties from __overlay__ node to the @ovcs->cset changeset. 509 * Add the properties from __overlay__ node to the @ovcs->cset changeset.
440 */ 510 */
441static int build_changeset_symbols_node(struct overlay_changeset *ovcs, 511static int build_changeset_symbols_node(struct overlay_changeset *ovcs,
442 struct device_node *target_node, 512 struct target *target,
443 const struct device_node *overlay_symbols_node) 513 const struct device_node *overlay_symbols_node)
444{ 514{
445 struct property *prop; 515 struct property *prop;
446 int ret; 516 int ret;
447 517
448 for_each_property_of_node(overlay_symbols_node, prop) { 518 for_each_property_of_node(overlay_symbols_node, prop) {
449 ret = add_changeset_property(ovcs, target_node, prop, 1); 519 ret = add_changeset_property(ovcs, target, prop, 1);
450 if (ret) { 520 if (ret) {
451 pr_debug("Failed to apply prop @%pOF/%s, err=%d\n", 521 pr_debug("Failed to apply symbols prop @%pOF/%s, err=%d\n",
452 target_node, prop->name, ret); 522 target->np, prop->name, ret);
453 return ret; 523 return ret;
454 } 524 }
455 } 525 }
@@ -457,6 +527,98 @@ static int build_changeset_symbols_node(struct overlay_changeset *ovcs,
457 return 0; 527 return 0;
458} 528}
459 529
530static int find_dup_cset_node_entry(struct overlay_changeset *ovcs,
531 struct of_changeset_entry *ce_1)
532{
533 struct of_changeset_entry *ce_2;
534 char *fn_1, *fn_2;
535 int node_path_match;
536
537 if (ce_1->action != OF_RECONFIG_ATTACH_NODE &&
538 ce_1->action != OF_RECONFIG_DETACH_NODE)
539 return 0;
540
541 ce_2 = ce_1;
542 list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) {
543 if ((ce_2->action != OF_RECONFIG_ATTACH_NODE &&
544 ce_2->action != OF_RECONFIG_DETACH_NODE) ||
545 of_node_cmp(ce_1->np->full_name, ce_2->np->full_name))
546 continue;
547
548 fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np);
549 fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np);
550 node_path_match = !strcmp(fn_1, fn_2);
551 kfree(fn_1);
552 kfree(fn_2);
553 if (node_path_match) {
554 pr_err("ERROR: multiple fragments add and/or delete node %pOF\n",
555 ce_1->np);
556 return -EINVAL;
557 }
558 }
559
560 return 0;
561}
562
563static int find_dup_cset_prop(struct overlay_changeset *ovcs,
564 struct of_changeset_entry *ce_1)
565{
566 struct of_changeset_entry *ce_2;
567 char *fn_1, *fn_2;
568 int node_path_match;
569
570 if (ce_1->action != OF_RECONFIG_ADD_PROPERTY &&
571 ce_1->action != OF_RECONFIG_REMOVE_PROPERTY &&
572 ce_1->action != OF_RECONFIG_UPDATE_PROPERTY)
573 return 0;
574
575 ce_2 = ce_1;
576 list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) {
577 if ((ce_2->action != OF_RECONFIG_ADD_PROPERTY &&
578 ce_2->action != OF_RECONFIG_REMOVE_PROPERTY &&
579 ce_2->action != OF_RECONFIG_UPDATE_PROPERTY) ||
580 of_node_cmp(ce_1->np->full_name, ce_2->np->full_name))
581 continue;
582
583 fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np);
584 fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np);
585 node_path_match = !strcmp(fn_1, fn_2);
586 kfree(fn_1);
587 kfree(fn_2);
588 if (node_path_match &&
589 !of_prop_cmp(ce_1->prop->name, ce_2->prop->name)) {
590 pr_err("ERROR: multiple fragments add, update, and/or delete property %pOF/%s\n",
591 ce_1->np, ce_1->prop->name);
592 return -EINVAL;
593 }
594 }
595
596 return 0;
597}
598
599/**
600 * changeset_dup_entry_check() - check for duplicate entries
601 * @ovcs: Overlay changeset
602 *
603 * Check changeset @ovcs->cset for multiple {add or delete} node entries for
604 * the same node or duplicate {add, delete, or update} properties entries
605 * for the same property.
606 *
607 * Returns 0 on success, or -EINVAL if duplicate changeset entry found.
608 */
609static int changeset_dup_entry_check(struct overlay_changeset *ovcs)
610{
611 struct of_changeset_entry *ce_1;
612 int dup_entry = 0;
613
614 list_for_each_entry(ce_1, &ovcs->cset.entries, node) {
615 dup_entry |= find_dup_cset_node_entry(ovcs, ce_1);
616 dup_entry |= find_dup_cset_prop(ovcs, ce_1);
617 }
618
619 return dup_entry ? -EINVAL : 0;
620}
621
460/** 622/**
461 * build_changeset() - populate overlay changeset in @ovcs from @ovcs->fragments 623 * build_changeset() - populate overlay changeset in @ovcs from @ovcs->fragments
462 * @ovcs: Overlay changeset 624 * @ovcs: Overlay changeset
@@ -472,6 +634,7 @@ static int build_changeset_symbols_node(struct overlay_changeset *ovcs,
472static int build_changeset(struct overlay_changeset *ovcs) 634static int build_changeset(struct overlay_changeset *ovcs)
473{ 635{
474 struct fragment *fragment; 636 struct fragment *fragment;
637 struct target target;
475 int fragments_count, i, ret; 638 int fragments_count, i, ret;
476 639
477 /* 640 /*
@@ -486,25 +649,32 @@ static int build_changeset(struct overlay_changeset *ovcs)
486 for (i = 0; i < fragments_count; i++) { 649 for (i = 0; i < fragments_count; i++) {
487 fragment = &ovcs->fragments[i]; 650 fragment = &ovcs->fragments[i];
488 651
489 ret = build_changeset_next_level(ovcs, fragment->target, 652 target.np = fragment->target;
653 target.in_livetree = true;
654 ret = build_changeset_next_level(ovcs, &target,
490 fragment->overlay); 655 fragment->overlay);
491 if (ret) { 656 if (ret) {
492 pr_debug("apply failed '%pOF'\n", fragment->target); 657 pr_debug("fragment apply failed '%pOF'\n",
658 fragment->target);
493 return ret; 659 return ret;
494 } 660 }
495 } 661 }
496 662
497 if (ovcs->symbols_fragment) { 663 if (ovcs->symbols_fragment) {
498 fragment = &ovcs->fragments[ovcs->count - 1]; 664 fragment = &ovcs->fragments[ovcs->count - 1];
499 ret = build_changeset_symbols_node(ovcs, fragment->target, 665
666 target.np = fragment->target;
667 target.in_livetree = true;
668 ret = build_changeset_symbols_node(ovcs, &target,
500 fragment->overlay); 669 fragment->overlay);
501 if (ret) { 670 if (ret) {
502 pr_debug("apply failed '%pOF'\n", fragment->target); 671 pr_debug("symbols fragment apply failed '%pOF'\n",
672 fragment->target);
503 return ret; 673 return ret;
504 } 674 }
505 } 675 }
506 676
507 return 0; 677 return changeset_dup_entry_check(ovcs);
508} 678}
509 679
510/* 680/*
@@ -514,7 +684,7 @@ static int build_changeset(struct overlay_changeset *ovcs)
514 * 1) "target" property containing the phandle of the target 684 * 1) "target" property containing the phandle of the target
515 * 2) "target-path" property containing the path of the target 685 * 2) "target-path" property containing the path of the target
516 */ 686 */
517static struct device_node *find_target_node(struct device_node *info_node) 687static struct device_node *find_target(struct device_node *info_node)
518{ 688{
519 struct device_node *node; 689 struct device_node *node;
520 const char *path; 690 const char *path;
@@ -620,7 +790,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
620 790
621 fragment = &fragments[cnt]; 791 fragment = &fragments[cnt];
622 fragment->overlay = overlay_node; 792 fragment->overlay = overlay_node;
623 fragment->target = find_target_node(node); 793 fragment->target = find_target(node);
624 if (!fragment->target) { 794 if (!fragment->target) {
625 of_node_put(fragment->overlay); 795 of_node_put(fragment->overlay);
626 ret = -EINVAL; 796 ret = -EINVAL;
@@ -808,7 +978,7 @@ static int of_overlay_apply(const void *fdt, struct device_node *tree,
808 978
809 ret = __of_changeset_apply_notify(&ovcs->cset); 979 ret = __of_changeset_apply_notify(&ovcs->cset);
810 if (ret) 980 if (ret)
811 pr_err("overlay changeset entry notify error %d\n", ret); 981 pr_err("overlay apply changeset entry notify error %d\n", ret);
812 /* notify failure is not fatal, continue */ 982 /* notify failure is not fatal, continue */
813 983
814 list_add_tail(&ovcs->ovcs_list, &ovcs_list); 984 list_add_tail(&ovcs->ovcs_list, &ovcs_list);
@@ -1067,7 +1237,7 @@ int of_overlay_remove(int *ovcs_id)
1067 1237
1068 ret = __of_changeset_revert_notify(&ovcs->cset); 1238 ret = __of_changeset_revert_notify(&ovcs->cset);
1069 if (ret) 1239 if (ret)
1070 pr_err("overlay changeset entry notify error %d\n", ret); 1240 pr_err("overlay remove changeset entry notify error %d\n", ret);
1071 /* notify failure is not fatal, continue */ 1241 /* notify failure is not fatal, continue */
1072 1242
1073 *ovcs_id = 0; 1243 *ovcs_id = 0;
diff --git a/drivers/of/unittest-data/Makefile b/drivers/of/unittest-data/Makefile
index 013d85e694c6..9b6807065827 100644
--- a/drivers/of/unittest-data/Makefile
+++ b/drivers/of/unittest-data/Makefile
@@ -17,6 +17,8 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \
17 overlay_12.dtb.o \ 17 overlay_12.dtb.o \
18 overlay_13.dtb.o \ 18 overlay_13.dtb.o \
19 overlay_15.dtb.o \ 19 overlay_15.dtb.o \
20 overlay_bad_add_dup_node.dtb.o \
21 overlay_bad_add_dup_prop.dtb.o \
20 overlay_bad_phandle.dtb.o \ 22 overlay_bad_phandle.dtb.o \
21 overlay_bad_symbol.dtb.o \ 23 overlay_bad_symbol.dtb.o \
22 overlay_base.dtb.o 24 overlay_base.dtb.o
diff --git a/drivers/of/unittest-data/overlay_bad_add_dup_node.dts b/drivers/of/unittest-data/overlay_bad_add_dup_node.dts
new file mode 100644
index 000000000000..145dfc3b1024
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_bad_add_dup_node.dts
@@ -0,0 +1,28 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/*
6 * &electric_1/motor-1 and &spin_ctrl_1 are the same node:
7 * /testcase-data-2/substation@100/motor-1
8 *
9 * Thus the new node "controller" in each fragment will
10 * result in an attempt to add the same node twice.
11 * This will result in an error and the overlay apply
12 * will fail.
13 */
14
15&electric_1 {
16
17 motor-1 {
18 controller {
19 power_bus = < 0x1 0x2 >;
20 };
21 };
22};
23
24&spin_ctrl_1 {
25 controller {
26 power_bus_emergency = < 0x101 0x102 >;
27 };
28};
diff --git a/drivers/of/unittest-data/overlay_bad_add_dup_prop.dts b/drivers/of/unittest-data/overlay_bad_add_dup_prop.dts
new file mode 100644
index 000000000000..c190da54f175
--- /dev/null
+++ b/drivers/of/unittest-data/overlay_bad_add_dup_prop.dts
@@ -0,0 +1,24 @@
1// SPDX-License-Identifier: GPL-2.0
2/dts-v1/;
3/plugin/;
4
5/*
6 * &electric_1/motor-1 and &spin_ctrl_1 are the same node:
7 * /testcase-data-2/substation@100/motor-1
8 *
9 * Thus the property "rpm_avail" in each fragment will
10 * result in an attempt to update the same property twice.
11 * This will result in an error and the overlay apply
12 * will fail.
13 */
14
15&electric_1 {
16
17 motor-1 {
18 rpm_avail = < 100 >;
19 };
20};
21
22&spin_ctrl_1 {
23 rpm_avail = < 100 200 >;
24};
diff --git a/drivers/of/unittest-data/overlay_base.dts b/drivers/of/unittest-data/overlay_base.dts
index 820b79ca378a..99ab9d12d00b 100644
--- a/drivers/of/unittest-data/overlay_base.dts
+++ b/drivers/of/unittest-data/overlay_base.dts
@@ -30,6 +30,7 @@
30 spin_ctrl_1: motor-1 { 30 spin_ctrl_1: motor-1 {
31 compatible = "ot,ferris-wheel-motor"; 31 compatible = "ot,ferris-wheel-motor";
32 spin = "clockwise"; 32 spin = "clockwise";
33 rpm_avail = < 50 >;
33 }; 34 };
34 35
35 spin_ctrl_2: motor-8 { 36 spin_ctrl_2: motor-8 {
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 49ae2aa744d6..9a10a48eb6a1 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -379,6 +379,7 @@ static void __init of_unittest_parse_phandle_with_args(void)
379 for (i = 0; i < 8; i++) { 379 for (i = 0; i < 8; i++) {
380 bool passed = true; 380 bool passed = true;
381 381
382 memset(&args, 0, sizeof(args));
382 rc = of_parse_phandle_with_args(np, "phandle-list", 383 rc = of_parse_phandle_with_args(np, "phandle-list",
383 "#phandle-cells", i, &args); 384 "#phandle-cells", i, &args);
384 385
@@ -432,6 +433,7 @@ static void __init of_unittest_parse_phandle_with_args(void)
432 } 433 }
433 434
434 /* Check for missing list property */ 435 /* Check for missing list property */
436 memset(&args, 0, sizeof(args));
435 rc = of_parse_phandle_with_args(np, "phandle-list-missing", 437 rc = of_parse_phandle_with_args(np, "phandle-list-missing",
436 "#phandle-cells", 0, &args); 438 "#phandle-cells", 0, &args);
437 unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc); 439 unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
@@ -440,6 +442,7 @@ static void __init of_unittest_parse_phandle_with_args(void)
440 unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc); 442 unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
441 443
442 /* Check for missing cells property */ 444 /* Check for missing cells property */
445 memset(&args, 0, sizeof(args));
443 rc = of_parse_phandle_with_args(np, "phandle-list", 446 rc = of_parse_phandle_with_args(np, "phandle-list",
444 "#phandle-cells-missing", 0, &args); 447 "#phandle-cells-missing", 0, &args);
445 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 448 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
@@ -448,6 +451,7 @@ static void __init of_unittest_parse_phandle_with_args(void)
448 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 451 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
449 452
450 /* Check for bad phandle in list */ 453 /* Check for bad phandle in list */
454 memset(&args, 0, sizeof(args));
451 rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle", 455 rc = of_parse_phandle_with_args(np, "phandle-list-bad-phandle",
452 "#phandle-cells", 0, &args); 456 "#phandle-cells", 0, &args);
453 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 457 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
@@ -456,6 +460,7 @@ static void __init of_unittest_parse_phandle_with_args(void)
456 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 460 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
457 461
458 /* Check for incorrectly formed argument list */ 462 /* Check for incorrectly formed argument list */
463 memset(&args, 0, sizeof(args));
459 rc = of_parse_phandle_with_args(np, "phandle-list-bad-args", 464 rc = of_parse_phandle_with_args(np, "phandle-list-bad-args",
460 "#phandle-cells", 1, &args); 465 "#phandle-cells", 1, &args);
461 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 466 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
@@ -506,6 +511,7 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
506 for (i = 0; i < 8; i++) { 511 for (i = 0; i < 8; i++) {
507 bool passed = true; 512 bool passed = true;
508 513
514 memset(&args, 0, sizeof(args));
509 rc = of_parse_phandle_with_args_map(np, "phandle-list", 515 rc = of_parse_phandle_with_args_map(np, "phandle-list",
510 "phandle", i, &args); 516 "phandle", i, &args);
511 517
@@ -563,21 +569,25 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
563 } 569 }
564 570
565 /* Check for missing list property */ 571 /* Check for missing list property */
572 memset(&args, 0, sizeof(args));
566 rc = of_parse_phandle_with_args_map(np, "phandle-list-missing", 573 rc = of_parse_phandle_with_args_map(np, "phandle-list-missing",
567 "phandle", 0, &args); 574 "phandle", 0, &args);
568 unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc); 575 unittest(rc == -ENOENT, "expected:%i got:%i\n", -ENOENT, rc);
569 576
570 /* Check for missing cells,map,mask property */ 577 /* Check for missing cells,map,mask property */
578 memset(&args, 0, sizeof(args));
571 rc = of_parse_phandle_with_args_map(np, "phandle-list", 579 rc = of_parse_phandle_with_args_map(np, "phandle-list",
572 "phandle-missing", 0, &args); 580 "phandle-missing", 0, &args);
573 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 581 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
574 582
575 /* Check for bad phandle in list */ 583 /* Check for bad phandle in list */
584 memset(&args, 0, sizeof(args));
576 rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-phandle", 585 rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-phandle",
577 "phandle", 0, &args); 586 "phandle", 0, &args);
578 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 587 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
579 588
580 /* Check for incorrectly formed argument list */ 589 /* Check for incorrectly formed argument list */
590 memset(&args, 0, sizeof(args));
581 rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-args", 591 rc = of_parse_phandle_with_args_map(np, "phandle-list-bad-args",
582 "phandle", 1, &args); 592 "phandle", 1, &args);
583 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); 593 unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
@@ -787,7 +797,7 @@ static void __init of_unittest_parse_interrupts(void)
787 for (i = 0; i < 4; i++) { 797 for (i = 0; i < 4; i++) {
788 bool passed = true; 798 bool passed = true;
789 799
790 args.args_count = 0; 800 memset(&args, 0, sizeof(args));
791 rc = of_irq_parse_one(np, i, &args); 801 rc = of_irq_parse_one(np, i, &args);
792 802
793 passed &= !rc; 803 passed &= !rc;
@@ -808,7 +818,7 @@ static void __init of_unittest_parse_interrupts(void)
808 for (i = 0; i < 4; i++) { 818 for (i = 0; i < 4; i++) {
809 bool passed = true; 819 bool passed = true;
810 820
811 args.args_count = 0; 821 memset(&args, 0, sizeof(args));
812 rc = of_irq_parse_one(np, i, &args); 822 rc = of_irq_parse_one(np, i, &args);
813 823
814 /* Test the values from tests-phandle.dtsi */ 824 /* Test the values from tests-phandle.dtsi */
@@ -864,6 +874,7 @@ static void __init of_unittest_parse_interrupts_extended(void)
864 for (i = 0; i < 7; i++) { 874 for (i = 0; i < 7; i++) {
865 bool passed = true; 875 bool passed = true;
866 876
877 memset(&args, 0, sizeof(args));
867 rc = of_irq_parse_one(np, i, &args); 878 rc = of_irq_parse_one(np, i, &args);
868 879
869 /* Test the values from tests-phandle.dtsi */ 880 /* Test the values from tests-phandle.dtsi */
@@ -1071,20 +1082,44 @@ static void __init of_unittest_platform_populate(void)
1071 * of np into dup node (present in live tree) and 1082 * of np into dup node (present in live tree) and
1072 * updates parent of children of np to dup. 1083 * updates parent of children of np to dup.
1073 * 1084 *
1074 * @np: node already present in live tree 1085 * @np: node whose properties are being added to the live tree
1075 * @dup: node present in live tree to be updated 1086 * @dup: node present in live tree to be updated
1076 */ 1087 */
1077static void update_node_properties(struct device_node *np, 1088static void update_node_properties(struct device_node *np,
1078 struct device_node *dup) 1089 struct device_node *dup)
1079{ 1090{
1080 struct property *prop; 1091 struct property *prop;
1092 struct property *save_next;
1081 struct device_node *child; 1093 struct device_node *child;
1082 1094 int ret;
1083 for_each_property_of_node(np, prop)
1084 of_add_property(dup, prop);
1085 1095
1086 for_each_child_of_node(np, child) 1096 for_each_child_of_node(np, child)
1087 child->parent = dup; 1097 child->parent = dup;
1098
1099 /*
1100 * "unittest internal error: unable to add testdata property"
1101 *
1102 * If this message reports a property in node '/__symbols__' then
1103 * the respective unittest overlay contains a label that has the
1104 * same name as a label in the live devicetree. The label will
1105 * be in the live devicetree only if the devicetree source was
1106 * compiled with the '-@' option. If you encounter this error,
1107 * please consider renaming __all__ of the labels in the unittest
1108 * overlay dts files with an odd prefix that is unlikely to be
1109 * used in a real devicetree.
1110 */
1111
1112 /*
1113 * open code for_each_property_of_node() because of_add_property()
1114 * sets prop->next to NULL
1115 */
1116 for (prop = np->properties; prop != NULL; prop = save_next) {
1117 save_next = prop->next;
1118 ret = of_add_property(dup, prop);
1119 if (ret)
1120 pr_err("unittest internal error: unable to add testdata property %pOF/%s",
1121 np, prop->name);
1122 }
1088} 1123}
1089 1124
1090/** 1125/**
@@ -1093,18 +1128,23 @@ static void update_node_properties(struct device_node *np,
1093 * 1128 *
1094 * @np: Node to attach to live tree 1129 * @np: Node to attach to live tree
1095 */ 1130 */
1096static int attach_node_and_children(struct device_node *np) 1131static void attach_node_and_children(struct device_node *np)
1097{ 1132{
1098 struct device_node *next, *dup, *child; 1133 struct device_node *next, *dup, *child;
1099 unsigned long flags; 1134 unsigned long flags;
1100 const char *full_name; 1135 const char *full_name;
1101 1136
1102 full_name = kasprintf(GFP_KERNEL, "%pOF", np); 1137 full_name = kasprintf(GFP_KERNEL, "%pOF", np);
1138
1139 if (!strcmp(full_name, "/__local_fixups__") ||
1140 !strcmp(full_name, "/__fixups__"))
1141 return;
1142
1103 dup = of_find_node_by_path(full_name); 1143 dup = of_find_node_by_path(full_name);
1104 kfree(full_name); 1144 kfree(full_name);
1105 if (dup) { 1145 if (dup) {
1106 update_node_properties(np, dup); 1146 update_node_properties(np, dup);
1107 return 0; 1147 return;
1108 } 1148 }
1109 1149
1110 child = np->child; 1150 child = np->child;
@@ -1125,8 +1165,6 @@ static int attach_node_and_children(struct device_node *np)
1125 attach_node_and_children(child); 1165 attach_node_and_children(child);
1126 child = next; 1166 child = next;
1127 } 1167 }
1128
1129 return 0;
1130} 1168}
1131 1169
1132/** 1170/**
@@ -1433,8 +1471,7 @@ static void of_unittest_destroy_tracked_overlays(void)
1433 } while (defers > 0); 1471 } while (defers > 0);
1434} 1472}
1435 1473
1436static int __init of_unittest_apply_overlay(int overlay_nr, int unittest_nr, 1474static int __init of_unittest_apply_overlay(int overlay_nr, int *overlay_id)
1437 int *overlay_id)
1438{ 1475{
1439 const char *overlay_name; 1476 const char *overlay_name;
1440 1477
@@ -1467,7 +1504,7 @@ static int __init of_unittest_apply_overlay_check(int overlay_nr,
1467 } 1504 }
1468 1505
1469 ovcs_id = 0; 1506 ovcs_id = 0;
1470 ret = of_unittest_apply_overlay(overlay_nr, unittest_nr, &ovcs_id); 1507 ret = of_unittest_apply_overlay(overlay_nr, &ovcs_id);
1471 if (ret != 0) { 1508 if (ret != 0) {
1472 /* of_unittest_apply_overlay already called unittest() */ 1509 /* of_unittest_apply_overlay already called unittest() */
1473 return ret; 1510 return ret;
@@ -1503,7 +1540,7 @@ static int __init of_unittest_apply_revert_overlay_check(int overlay_nr,
1503 1540
1504 /* apply the overlay */ 1541 /* apply the overlay */
1505 ovcs_id = 0; 1542 ovcs_id = 0;
1506 ret = of_unittest_apply_overlay(overlay_nr, unittest_nr, &ovcs_id); 1543 ret = of_unittest_apply_overlay(overlay_nr, &ovcs_id);
1507 if (ret != 0) { 1544 if (ret != 0) {
1508 /* of_unittest_apply_overlay already called unittest() */ 1545 /* of_unittest_apply_overlay already called unittest() */
1509 return ret; 1546 return ret;
@@ -2161,10 +2198,12 @@ OVERLAY_INFO_EXTERN(overlay_11);
2161OVERLAY_INFO_EXTERN(overlay_12); 2198OVERLAY_INFO_EXTERN(overlay_12);
2162OVERLAY_INFO_EXTERN(overlay_13); 2199OVERLAY_INFO_EXTERN(overlay_13);
2163OVERLAY_INFO_EXTERN(overlay_15); 2200OVERLAY_INFO_EXTERN(overlay_15);
2201OVERLAY_INFO_EXTERN(overlay_bad_add_dup_node);
2202OVERLAY_INFO_EXTERN(overlay_bad_add_dup_prop);
2164OVERLAY_INFO_EXTERN(overlay_bad_phandle); 2203OVERLAY_INFO_EXTERN(overlay_bad_phandle);
2165OVERLAY_INFO_EXTERN(overlay_bad_symbol); 2204OVERLAY_INFO_EXTERN(overlay_bad_symbol);
2166 2205
2167/* order of entries is hard-coded into users of overlays[] */ 2206/* entries found by name */
2168static struct overlay_info overlays[] = { 2207static struct overlay_info overlays[] = {
2169 OVERLAY_INFO(overlay_base, -9999), 2208 OVERLAY_INFO(overlay_base, -9999),
2170 OVERLAY_INFO(overlay, 0), 2209 OVERLAY_INFO(overlay, 0),
@@ -2183,9 +2222,12 @@ static struct overlay_info overlays[] = {
2183 OVERLAY_INFO(overlay_12, 0), 2222 OVERLAY_INFO(overlay_12, 0),
2184 OVERLAY_INFO(overlay_13, 0), 2223 OVERLAY_INFO(overlay_13, 0),
2185 OVERLAY_INFO(overlay_15, 0), 2224 OVERLAY_INFO(overlay_15, 0),
2225 OVERLAY_INFO(overlay_bad_add_dup_node, -EINVAL),
2226 OVERLAY_INFO(overlay_bad_add_dup_prop, -EINVAL),
2186 OVERLAY_INFO(overlay_bad_phandle, -EINVAL), 2227 OVERLAY_INFO(overlay_bad_phandle, -EINVAL),
2187 OVERLAY_INFO(overlay_bad_symbol, -EINVAL), 2228 OVERLAY_INFO(overlay_bad_symbol, -EINVAL),
2188 {} 2229 /* end marker */
2230 {.dtb_begin = NULL, .dtb_end = NULL, .expected_result = 0, .name = NULL}
2189}; 2231};
2190 2232
2191static struct device_node *overlay_base_root; 2233static struct device_node *overlay_base_root;
@@ -2215,6 +2257,19 @@ void __init unittest_unflatten_overlay_base(void)
2215 u32 data_size; 2257 u32 data_size;
2216 void *new_fdt; 2258 void *new_fdt;
2217 u32 size; 2259 u32 size;
2260 int found = 0;
2261 const char *overlay_name = "overlay_base";
2262
2263 for (info = overlays; info && info->name; info++) {
2264 if (!strcmp(overlay_name, info->name)) {
2265 found = 1;
2266 break;
2267 }
2268 }
2269 if (!found) {
2270 pr_err("no overlay data for %s\n", overlay_name);
2271 return;
2272 }
2218 2273
2219 info = &overlays[0]; 2274 info = &overlays[0];
2220 2275
@@ -2262,11 +2317,10 @@ static int __init overlay_data_apply(const char *overlay_name, int *overlay_id)
2262{ 2317{
2263 struct overlay_info *info; 2318 struct overlay_info *info;
2264 int found = 0; 2319 int found = 0;
2265 int k;
2266 int ret; 2320 int ret;
2267 u32 size; 2321 u32 size;
2268 2322
2269 for (k = 0, info = overlays; info && info->name; info++, k++) { 2323 for (info = overlays; info && info->name; info++) {
2270 if (!strcmp(overlay_name, info->name)) { 2324 if (!strcmp(overlay_name, info->name)) {
2271 found = 1; 2325 found = 1;
2272 break; 2326 break;
@@ -2430,6 +2484,12 @@ static __init void of_unittest_overlay_high_level(void)
2430 unittest(overlay_data_apply("overlay", NULL), 2484 unittest(overlay_data_apply("overlay", NULL),
2431 "Adding overlay 'overlay' failed\n"); 2485 "Adding overlay 'overlay' failed\n");
2432 2486
2487 unittest(overlay_data_apply("overlay_bad_add_dup_node", NULL),
2488 "Adding overlay 'overlay_bad_add_dup_node' failed\n");
2489
2490 unittest(overlay_data_apply("overlay_bad_add_dup_prop", NULL),
2491 "Adding overlay 'overlay_bad_add_dup_prop' failed\n");
2492
2433 unittest(overlay_data_apply("overlay_bad_phandle", NULL), 2493 unittest(overlay_data_apply("overlay_bad_phandle", NULL),
2434 "Adding overlay 'overlay_bad_phandle' failed\n"); 2494 "Adding overlay 'overlay_bad_phandle' failed\n");
2435 2495