aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Rowand <frank.rowand@sony.com>2017-10-17 19:36:26 -0400
committerRob Herring <robh@kernel.org>2017-10-17 21:47:14 -0400
commit24789c5ce5a373dd55640f9cd79117fcc3ccc46d (patch)
tree74f46e8ace25e756c8b26b9fa0b89907b21a78c6
parent61b4de4e0b384f4a22c55c3bada604da49cec4e1 (diff)
of: overlay: detect cases where device tree may become corrupt
When an attempt to apply an overlay changeset fails, an effort is made to revert any partial application of the changeset. When an attempt to remove an overlay changeset fails, an effort is made to re-apply any partial reversion of the changeset. The existing code does not check for failure to recover a failed overlay changeset application or overlay changeset revert. Add the missing checks and flag the devicetree as corrupt if the state of the devicetree can not be determined. Improve and expand the returned errors to more fully reflect the result of the effort to undo the partial effects of a failed attempt to apply or remove an overlay changeset. If the device tree might be corrupt, do not allow further attempts to apply or remove an overlay changeset. When creating an overlay changeset from an overlay device tree, add some additional warnings if the state of the overlay device tree is not as expected. Signed-off-by: Frank Rowand <frank.rowand@sony.com> Signed-off-by: Rob Herring <robh@kernel.org>
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c5
-rw-r--r--drivers/of/dynamic.c135
-rw-r--r--drivers/of/of_private.h8
-rw-r--r--drivers/of/overlay.c253
-rw-r--r--drivers/of/unittest.c57
-rw-r--r--include/linux/of.h10
6 files changed, 372 insertions, 96 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c
index 5f5b7ba35f1d..7a7be0515bfd 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c
@@ -204,7 +204,7 @@ static void __init tilcdc_convert_slave_node(void)
204 /* For all memory needed for the overlay tree. This memory can 204 /* For all memory needed for the overlay tree. This memory can
205 be freed after the overlay has been applied. */ 205 be freed after the overlay has been applied. */
206 struct kfree_table kft; 206 struct kfree_table kft;
207 int ret; 207 int ovcs_id, ret;
208 208
209 if (kfree_table_init(&kft)) 209 if (kfree_table_init(&kft))
210 return; 210 return;
@@ -247,7 +247,8 @@ static void __init tilcdc_convert_slave_node(void)
247 247
248 tilcdc_node_disable(slave); 248 tilcdc_node_disable(slave);
249 249
250 ret = of_overlay_apply(overlay); 250 ovcs_id = 0;
251 ret = of_overlay_apply(overlay, &ovcs_id);
251 if (ret) 252 if (ret)
252 pr_err("%s: Applying overlay changeset failed: %d\n", 253 pr_err("%s: Applying overlay changeset failed: %d\n",
253 __func__, ret); 254 __func__, ret);
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 4bc96af4d8e2..747d87619faf 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -491,11 +491,12 @@ static void __of_changeset_entry_invert(struct of_changeset_entry *ce,
491 } 491 }
492} 492}
493 493
494static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool revert) 494static int __of_changeset_entry_notify(struct of_changeset_entry *ce,
495 bool revert)
495{ 496{
496 struct of_reconfig_data rd; 497 struct of_reconfig_data rd;
497 struct of_changeset_entry ce_inverted; 498 struct of_changeset_entry ce_inverted;
498 int ret; 499 int ret = 0;
499 500
500 if (revert) { 501 if (revert) {
501 __of_changeset_entry_invert(ce, &ce_inverted); 502 __of_changeset_entry_invert(ce, &ce_inverted);
@@ -517,11 +518,12 @@ static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool reve
517 default: 518 default:
518 pr_err("invalid devicetree changeset action: %i\n", 519 pr_err("invalid devicetree changeset action: %i\n",
519 (int)ce->action); 520 (int)ce->action);
520 return; 521 ret = -EINVAL;
521 } 522 }
522 523
523 if (ret) 524 if (ret)
524 pr_err("changeset notifier error @%pOF\n", ce->np); 525 pr_err("changeset notifier error @%pOF\n", ce->np);
526 return ret;
525} 527}
526 528
527static int __of_changeset_entry_apply(struct of_changeset_entry *ce) 529static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
@@ -655,32 +657,82 @@ void of_changeset_destroy(struct of_changeset *ocs)
655} 657}
656EXPORT_SYMBOL_GPL(of_changeset_destroy); 658EXPORT_SYMBOL_GPL(of_changeset_destroy);
657 659
658int __of_changeset_apply(struct of_changeset *ocs) 660/*
661 * Apply the changeset entries in @ocs.
662 * If apply fails, an attempt is made to revert the entries that were
663 * successfully applied.
664 *
665 * If multiple revert errors occur then only the final revert error is reported.
666 *
667 * Returns 0 on success, a negative error value in case of an error.
668 * If a revert error occurs, it is returned in *ret_revert.
669 */
670int __of_changeset_apply_entries(struct of_changeset *ocs, int *ret_revert)
659{ 671{
660 struct of_changeset_entry *ce; 672 struct of_changeset_entry *ce;
661 int ret; 673 int ret, ret_tmp;
662 674
663 /* perform the rest of the work */
664 pr_debug("changeset: applying...\n"); 675 pr_debug("changeset: applying...\n");
665 list_for_each_entry(ce, &ocs->entries, node) { 676 list_for_each_entry(ce, &ocs->entries, node) {
666 ret = __of_changeset_entry_apply(ce); 677 ret = __of_changeset_entry_apply(ce);
667 if (ret) { 678 if (ret) {
668 pr_err("Error applying changeset (%d)\n", ret); 679 pr_err("Error applying changeset (%d)\n", ret);
669 list_for_each_entry_continue_reverse(ce, &ocs->entries, node) 680 list_for_each_entry_continue_reverse(ce, &ocs->entries,
670 __of_changeset_entry_revert(ce); 681 node) {
682 ret_tmp = __of_changeset_entry_revert(ce);
683 if (ret_tmp)
684 *ret_revert = ret_tmp;
685 }
671 return ret; 686 return ret;
672 } 687 }
673 } 688 }
674 pr_debug("changeset: applied, emitting notifiers.\n"); 689
690 return 0;
691}
692
693/*
694 * Returns 0 on success, a negative error value in case of an error.
695 *
696 * If multiple changset entry notification errors occur then only the
697 * final notification error is reported.
698 */
699int __of_changeset_apply_notify(struct of_changeset *ocs)
700{
701 struct of_changeset_entry *ce;
702 int ret = 0, ret_tmp;
703
704 pr_debug("changeset: emitting notifiers.\n");
675 705
676 /* drop the global lock while emitting notifiers */ 706 /* drop the global lock while emitting notifiers */
677 mutex_unlock(&of_mutex); 707 mutex_unlock(&of_mutex);
678 list_for_each_entry(ce, &ocs->entries, node) 708 list_for_each_entry(ce, &ocs->entries, node) {
679 __of_changeset_entry_notify(ce, 0); 709 ret_tmp = __of_changeset_entry_notify(ce, 0);
710 if (ret_tmp)
711 ret = ret_tmp;
712 }
680 mutex_lock(&of_mutex); 713 mutex_lock(&of_mutex);
681 pr_debug("changeset: notifiers sent.\n"); 714 pr_debug("changeset: notifiers sent.\n");
682 715
683 return 0; 716 return ret;
717}
718
719/*
720 * Returns 0 on success, a negative error value in case of an error.
721 *
722 * If a changeset entry apply fails, an attempt is made to revert any
723 * previous entries in the changeset. If any of the reverts fails,
724 * that failure is not reported. Thus the state of the device tree
725 * is unknown if an apply error occurs.
726 */
727static int __of_changeset_apply(struct of_changeset *ocs)
728{
729 int ret, ret_revert = 0;
730
731 ret = __of_changeset_apply_entries(ocs, &ret_revert);
732 if (!ret)
733 ret = __of_changeset_apply_notify(ocs);
734
735 return ret;
684} 736}
685 737
686/** 738/**
@@ -707,31 +759,74 @@ int of_changeset_apply(struct of_changeset *ocs)
707} 759}
708EXPORT_SYMBOL_GPL(of_changeset_apply); 760EXPORT_SYMBOL_GPL(of_changeset_apply);
709 761
710int __of_changeset_revert(struct of_changeset *ocs) 762/*
763 * Revert the changeset entries in @ocs.
764 * If revert fails, an attempt is made to re-apply the entries that were
765 * successfully removed.
766 *
767 * If multiple re-apply errors occur then only the final apply error is
768 * reported.
769 *
770 * Returns 0 on success, a negative error value in case of an error.
771 * If an apply error occurs, it is returned in *ret_apply.
772 */
773int __of_changeset_revert_entries(struct of_changeset *ocs, int *ret_apply)
711{ 774{
712 struct of_changeset_entry *ce; 775 struct of_changeset_entry *ce;
713 int ret; 776 int ret, ret_tmp;
714 777
715 pr_debug("changeset: reverting...\n"); 778 pr_debug("changeset: reverting...\n");
716 list_for_each_entry_reverse(ce, &ocs->entries, node) { 779 list_for_each_entry_reverse(ce, &ocs->entries, node) {
717 ret = __of_changeset_entry_revert(ce); 780 ret = __of_changeset_entry_revert(ce);
718 if (ret) { 781 if (ret) {
719 pr_err("Error reverting changeset (%d)\n", ret); 782 pr_err("Error reverting changeset (%d)\n", ret);
720 list_for_each_entry_continue(ce, &ocs->entries, node) 783 list_for_each_entry_continue(ce, &ocs->entries, node) {
721 __of_changeset_entry_apply(ce); 784 ret_tmp = __of_changeset_entry_apply(ce);
785 if (ret_tmp)
786 *ret_apply = ret_tmp;
787 }
722 return ret; 788 return ret;
723 } 789 }
724 } 790 }
725 pr_debug("changeset: reverted, emitting notifiers.\n"); 791
792 return 0;
793}
794
795/*
796 * If multiple changset entry notification errors occur then only the
797 * final notification error is reported.
798 */
799int __of_changeset_revert_notify(struct of_changeset *ocs)
800{
801 struct of_changeset_entry *ce;
802 int ret = 0, ret_tmp;
803
804 pr_debug("changeset: emitting notifiers.\n");
726 805
727 /* drop the global lock while emitting notifiers */ 806 /* drop the global lock while emitting notifiers */
728 mutex_unlock(&of_mutex); 807 mutex_unlock(&of_mutex);
729 list_for_each_entry_reverse(ce, &ocs->entries, node) 808 list_for_each_entry_reverse(ce, &ocs->entries, node) {
730 __of_changeset_entry_notify(ce, 1); 809 ret_tmp = __of_changeset_entry_notify(ce, 1);
810 if (ret_tmp)
811 ret = ret_tmp;
812 }
731 mutex_lock(&of_mutex); 813 mutex_lock(&of_mutex);
732 pr_debug("changeset: notifiers sent.\n"); 814 pr_debug("changeset: notifiers sent.\n");
733 815
734 return 0; 816 return ret;
817}
818
819static int __of_changeset_revert(struct of_changeset *ocs)
820{
821 int ret, ret_reply;
822
823 ret_reply = 0;
824 ret = __of_changeset_revert_entries(ocs, &ret_reply);
825
826 if (!ret)
827 ret = __of_changeset_revert_notify(ocs);
828
829 return ret;
735} 830}
736 831
737/** 832/**
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 43df14f0cbce..36357f571df2 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -39,8 +39,12 @@ extern struct kset *of_kset;
39extern int of_property_notify(int action, struct device_node *np, 39extern int of_property_notify(int action, struct device_node *np,
40 struct property *prop, struct property *old_prop); 40 struct property *prop, struct property *old_prop);
41extern void of_node_release(struct kobject *kobj); 41extern void of_node_release(struct kobject *kobj);
42extern int __of_changeset_apply(struct of_changeset *ocs); 42extern int __of_changeset_apply_entries(struct of_changeset *ocs,
43extern int __of_changeset_revert(struct of_changeset *ocs); 43 int *ret_revert);
44extern int __of_changeset_apply_notify(struct of_changeset *ocs);
45extern int __of_changeset_revert_entries(struct of_changeset *ocs,
46 int *ret_apply);
47extern int __of_changeset_revert_notify(struct of_changeset *ocs);
44#else /* CONFIG_OF_DYNAMIC */ 48#else /* CONFIG_OF_DYNAMIC */
45static inline int of_property_notify(int action, struct device_node *np, 49static inline int of_property_notify(int action, struct device_node *np,
46 struct property *prop, struct property *old_prop) 50 struct property *prop, struct property *old_prop)
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index 905916e17eec..78c50fd57750 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -50,6 +50,22 @@ struct overlay_changeset {
50 struct of_changeset cset; 50 struct of_changeset cset;
51}; 51};
52 52
53/* flags are sticky - once set, do not reset */
54static int devicetree_state_flags;
55#define DTSF_APPLY_FAIL 0x01
56#define DTSF_REVERT_FAIL 0x02
57
58/*
59 * If a changeset apply or revert encounters an error, an attempt will
60 * be made to undo partial changes, but may fail. If the undo fails
61 * we do not know the state of the devicetree.
62 */
63static int devicetree_corrupt(void)
64{
65 return devicetree_state_flags &
66 (DTSF_APPLY_FAIL | DTSF_REVERT_FAIL);
67}
68
53static int build_changeset_next_level(struct overlay_changeset *ovcs, 69static int build_changeset_next_level(struct overlay_changeset *ovcs,
54 struct device_node *target_node, 70 struct device_node *target_node,
55 const struct device_node *overlay_node, 71 const struct device_node *overlay_node,
@@ -72,6 +88,13 @@ int of_overlay_notifier_unregister(struct notifier_block *nb)
72} 88}
73EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister); 89EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister);
74 90
91static char *of_overlay_action_name[] = {
92 "pre-apply",
93 "post-apply",
94 "pre-remove",
95 "post-remove",
96};
97
75static int overlay_notify(struct overlay_changeset *ovcs, 98static int overlay_notify(struct overlay_changeset *ovcs,
76 enum of_overlay_notify_action action) 99 enum of_overlay_notify_action action)
77{ 100{
@@ -86,8 +109,14 @@ static int overlay_notify(struct overlay_changeset *ovcs,
86 109
87 ret = blocking_notifier_call_chain(&overlay_notify_chain, 110 ret = blocking_notifier_call_chain(&overlay_notify_chain,
88 action, &nd); 111 action, &nd);
89 if (ret) 112 if (ret == NOTIFY_STOP)
90 return notifier_to_errno(ret); 113 return 0;
114 if (ret) {
115 ret = notifier_to_errno(ret);
116 pr_err("overlay changeset %s notifier error %d, target: %pOF\n",
117 of_overlay_action_name[action], ret, nd.target);
118 return ret;
119 }
91 } 120 }
92 121
93 return 0; 122 return 0;
@@ -240,6 +269,14 @@ static int add_changeset_property(struct overlay_changeset *ovcs,
240 * build_changeset_next_level(). 269 * build_changeset_next_level().
241 * 270 *
242 * NOTE: Multiple mods of created nodes not supported. 271 * NOTE: Multiple mods of created nodes not supported.
272 * If more than one fragment contains a node that does not already exist
273 * in the live tree, then for each fragment of_changeset_attach_node()
274 * will add a changeset entry to add the node. When the changeset is
275 * applied, __of_attach_node() will attach the node twice (once for
276 * each fragment). At this point the device tree will be corrupted.
277 *
278 * TODO: add integrity check to ensure that multiple fragments do not
279 * create the same node.
243 * 280 *
244 * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if 281 * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
245 * invalid @overlay. 282 * invalid @overlay.
@@ -312,8 +349,8 @@ static int build_changeset_next_level(struct overlay_changeset *ovcs,
312 ret = add_changeset_property(ovcs, target_node, prop, 349 ret = add_changeset_property(ovcs, target_node, prop,
313 is_symbols_node); 350 is_symbols_node);
314 if (ret) { 351 if (ret) {
315 pr_err("Failed to apply prop @%pOF/%s\n", 352 pr_debug("Failed to apply prop @%pOF/%s, err=%d\n",
316 target_node, prop->name); 353 target_node, prop->name, ret);
317 return ret; 354 return ret;
318 } 355 }
319 } 356 }
@@ -324,8 +361,8 @@ static int build_changeset_next_level(struct overlay_changeset *ovcs,
324 for_each_child_of_node(overlay_node, child) { 361 for_each_child_of_node(overlay_node, child) {
325 ret = add_changeset_node(ovcs, target_node, child); 362 ret = add_changeset_node(ovcs, target_node, child);
326 if (ret) { 363 if (ret) {
327 pr_err("Failed to apply node @%pOF/%s\n", 364 pr_debug("Failed to apply node @%pOF/%s, err=%d\n",
328 target_node, child->name); 365 target_node, child->name, ret);
329 of_node_put(child); 366 of_node_put(child);
330 return ret; 367 return ret;
331 } 368 }
@@ -357,7 +394,7 @@ static int build_changeset(struct overlay_changeset *ovcs)
357 fragment->overlay, 394 fragment->overlay,
358 fragment->is_symbols_node); 395 fragment->is_symbols_node);
359 if (ret) { 396 if (ret) {
360 pr_err("apply failed '%pOF'\n", fragment->target); 397 pr_debug("apply failed '%pOF'\n", fragment->target);
361 return ret; 398 return ret;
362 } 399 }
363 } 400 }
@@ -412,6 +449,19 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
412 struct fragment *fragments; 449 struct fragment *fragments;
413 int cnt, ret; 450 int cnt, ret;
414 451
452 /*
453 * Warn for some issues. Can not return -EINVAL for these until
454 * of_unittest_apply_overlay() is fixed to pass these checks.
455 */
456 if (!of_node_check_flag(tree, OF_DYNAMIC))
457 pr_debug("%s() tree is not dynamic\n", __func__);
458
459 if (!of_node_check_flag(tree, OF_DETACHED))
460 pr_debug("%s() tree is not detached\n", __func__);
461
462 if (!of_node_is_root(tree))
463 pr_debug("%s() tree is not root\n", __func__);
464
415 INIT_LIST_HEAD(&ovcs->ovcs_list); 465 INIT_LIST_HEAD(&ovcs->ovcs_list);
416 466
417 of_changeset_init(&ovcs->cset); 467 of_changeset_init(&ovcs->cset);
@@ -485,12 +535,13 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs,
485 535
486 return 0; 536 return 0;
487 537
488
489err_free_fragments: 538err_free_fragments:
490 kfree(fragments); 539 kfree(fragments);
491err_free_idr: 540err_free_idr:
492 idr_remove(&ovcs_idr, ovcs->id); 541 idr_remove(&ovcs_idr, ovcs->id);
493 542
543 pr_err("%s() failed, ret = %d\n", __func__, ret);
544
494 return ret; 545 return ret;
495} 546}
496 547
@@ -517,33 +568,71 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs)
517/** 568/**
518 * of_overlay_apply() - Create and apply an overlay changeset 569 * of_overlay_apply() - Create and apply an overlay changeset
519 * @tree: Expanded overlay device tree 570 * @tree: Expanded overlay device tree
571 * @ovcs_id: Pointer to overlay changeset id
572 *
573 * Creates and applies an overlay changeset.
520 * 574 *
521 * Creates and applies an overlay changeset. If successful, the overlay 575 * If an error occurs in a pre-apply notifier, then no changes are made
522 * changeset is added to the overlay changeset list. 576 * to the device tree.
523 * 577 *
524 * Returns the id of the created overlay changeset, or a negative error number 578
579 * A non-zero return value will not have created the changeset if error is from:
580 * - parameter checks
581 * - building the changeset
582 * - overlay changset pre-apply notifier
583 *
584 * If an error is returned by an overlay changeset pre-apply notifier
585 * then no further overlay changeset pre-apply notifier will be called.
586 *
587 * A non-zero return value will have created the changeset if error is from:
588 * - overlay changeset entry notifier
589 * - overlay changset post-apply notifier
590 *
591 * If an error is returned by an overlay changeset post-apply notifier
592 * then no further overlay changeset post-apply notifier will be called.
593 *
594 * If more than one notifier returns an error, then the last notifier
595 * error to occur is returned.
596 *
597 * If an error occurred while applying the overlay changeset, then an
598 * attempt is made to revert any changes that were made to the
599 * device tree. If there were any errors during the revert attempt
600 * then the state of the device tree can not be determined, and any
601 * following attempt to apply or remove an overlay changeset will be
602 * refused.
603 *
604 * Returns 0 on success, or a negative error number. Overlay changeset
605 * id is returned to *ovcs_id.
525 */ 606 */
526int of_overlay_apply(struct device_node *tree) 607
608int of_overlay_apply(struct device_node *tree, int *ovcs_id)
527{ 609{
528 struct overlay_changeset *ovcs; 610 struct overlay_changeset *ovcs;
529 int ret; 611 int ret = 0, ret_revert, ret_tmp;
612
613 *ovcs_id = 0;
614
615 if (devicetree_corrupt()) {
616 pr_err("devicetree state suspect, refuse to apply overlay\n");
617 ret = -EBUSY;
618 goto out;
619 }
530 620
531 ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL); 621 ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL);
532 if (!ovcs) 622 if (!ovcs) {
533 return -ENOMEM; 623 ret = -ENOMEM;
624 goto out;
625 }
534 626
535 mutex_lock(&of_mutex); 627 mutex_lock(&of_mutex);
536 628
537 ret = init_overlay_changeset(ovcs, tree); 629 ret = init_overlay_changeset(ovcs, tree);
538 if (ret) { 630 if (ret)
539 pr_err("init_overlay_changeset() failed, ret = %d\n", ret);
540 goto err_free_overlay_changeset; 631 goto err_free_overlay_changeset;
541 }
542 632
543 ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY); 633 ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
544 if (ret < 0) { 634 if (ret) {
545 pr_err("%s: Pre-apply notifier failed (ret=%d)\n", 635 pr_err("overlay changeset pre-apply notify error %d\n", ret);
546 __func__, ret);
547 goto err_free_overlay_changeset; 636 goto err_free_overlay_changeset;
548 } 637 }
549 638
@@ -551,23 +640,46 @@ int of_overlay_apply(struct device_node *tree)
551 if (ret) 640 if (ret)
552 goto err_free_overlay_changeset; 641 goto err_free_overlay_changeset;
553 642
554 ret = __of_changeset_apply(&ovcs->cset); 643 ret_revert = 0;
555 if (ret) 644 ret = __of_changeset_apply_entries(&ovcs->cset, &ret_revert);
645 if (ret) {
646 if (ret_revert) {
647 pr_debug("overlay changeset revert error %d\n",
648 ret_revert);
649 devicetree_state_flags |= DTSF_APPLY_FAIL;
650 }
556 goto err_free_overlay_changeset; 651 goto err_free_overlay_changeset;
652 } else {
653 ret = __of_changeset_apply_notify(&ovcs->cset);
654 if (ret)
655 pr_err("overlay changeset entry notify error %d\n",
656 ret);
657 /* fall through */
658 }
557 659
558 list_add_tail(&ovcs->ovcs_list, &ovcs_list); 660 list_add_tail(&ovcs->ovcs_list, &ovcs_list);
559 661 *ovcs_id = ovcs->id;
560 overlay_notify(ovcs, OF_OVERLAY_POST_APPLY); 662
663 ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_APPLY);
664 if (ret_tmp) {
665 pr_err("overlay changeset post-apply notify error %d\n",
666 ret_tmp);
667 if (!ret)
668 ret = ret_tmp;
669 }
561 670
562 mutex_unlock(&of_mutex); 671 mutex_unlock(&of_mutex);
563 672
564 return ovcs->id; 673 goto out;
565 674
566err_free_overlay_changeset: 675err_free_overlay_changeset:
567 free_overlay_changeset(ovcs); 676 free_overlay_changeset(ovcs);
568 677
569 mutex_unlock(&of_mutex); 678 mutex_unlock(&of_mutex);
570 679
680out:
681 pr_debug("%s() err=%d\n", __func__, ret);
682
571 return ret; 683 return ret;
572} 684}
573EXPORT_SYMBOL_GPL(of_overlay_apply); 685EXPORT_SYMBOL_GPL(of_overlay_apply);
@@ -649,45 +761,106 @@ static int overlay_removal_is_ok(struct overlay_changeset *remove_ovcs)
649 761
650/** 762/**
651 * of_overlay_remove() - Revert and free an overlay changeset 763 * of_overlay_remove() - Revert and free an overlay changeset
652 * @ovcs_id: Overlay changeset id number 764 * @ovcs_id: Pointer to overlay changeset id
653 * 765 *
654 * Removes an overlay if it is permissible. ovcs_id was previously returned 766 * Removes an overlay if it is permissible. @ovcs_id was previously returned
655 * by of_overlay_apply(). 767 * by of_overlay_apply().
656 * 768 *
657 * Returns 0 on success, or a negative error number 769 * If an error occurred while attempting to revert the overlay changeset,
770 * then an attempt is made to re-apply any changeset entry that was
771 * reverted. If an error occurs on re-apply then the state of the device
772 * tree can not be determined, and any following attempt to apply or remove
773 * an overlay changeset will be refused.
774 *
775 * A non-zero return value will not revert the changeset if error is from:
776 * - parameter checks
777 * - overlay changset pre-remove notifier
778 * - overlay changeset entry revert
779 *
780 * If an error is returned by an overlay changeset pre-remove notifier
781 * then no further overlay changeset pre-remove notifier will be called.
782 *
783 * If more than one notifier returns an error, then the last notifier
784 * error to occur is returned.
785 *
786 * A non-zero return value will revert the changeset if error is from:
787 * - overlay changeset entry notifier
788 * - overlay changset post-remove notifier
789 *
790 * If an error is returned by an overlay changeset post-remove notifier
791 * then no further overlay changeset post-remove notifier will be called.
792 *
793 * Returns 0 on success, or a negative error number. *ovcs_id is set to
794 * zero after reverting the changeset, even if a subsequent error occurs.
658 */ 795 */
659int of_overlay_remove(int ovcs_id) 796int of_overlay_remove(int *ovcs_id)
660{ 797{
661 struct overlay_changeset *ovcs; 798 struct overlay_changeset *ovcs;
662 int ret = 0; 799 int ret, ret_apply, ret_tmp;
800
801 ret = 0;
802
803 if (devicetree_corrupt()) {
804 pr_err("suspect devicetree state, refuse to remove overlay\n");
805 ret = -EBUSY;
806 goto out;
807 }
663 808
664 mutex_lock(&of_mutex); 809 mutex_lock(&of_mutex);
665 810
666 ovcs = idr_find(&ovcs_idr, ovcs_id); 811 ovcs = idr_find(&ovcs_idr, *ovcs_id);
667 if (!ovcs) { 812 if (!ovcs) {
668 ret = -ENODEV; 813 ret = -ENODEV;
669 pr_err("remove: Could not find overlay #%d\n", ovcs_id); 814 pr_err("remove: Could not find overlay #%d\n", *ovcs_id);
670 goto out; 815 goto out_unlock;
671 } 816 }
672 817
673 if (!overlay_removal_is_ok(ovcs)) { 818 if (!overlay_removal_is_ok(ovcs)) {
674 ret = -EBUSY; 819 ret = -EBUSY;
675 goto out; 820 goto out_unlock;
676 } 821 }
677 822
678 overlay_notify(ovcs, OF_OVERLAY_PRE_REMOVE); 823 ret = overlay_notify(ovcs, OF_OVERLAY_PRE_REMOVE);
824 if (ret) {
825 pr_err("overlay changeset pre-remove notify error %d\n", ret);
826 goto out_unlock;
827 }
679 828
680 list_del(&ovcs->ovcs_list); 829 list_del(&ovcs->ovcs_list);
681 830
682 __of_changeset_revert(&ovcs->cset); 831 ret_apply = 0;
832 ret = __of_changeset_revert_entries(&ovcs->cset, &ret_apply);
833 if (ret) {
834 if (ret_apply)
835 devicetree_state_flags |= DTSF_REVERT_FAIL;
836 goto out_unlock;
837 } else {
838 ret = __of_changeset_revert_notify(&ovcs->cset);
839 if (ret) {
840 pr_err("overlay changeset entry notify error %d\n",
841 ret);
842 /* fall through - changeset was reverted */
843 }
844 }
683 845
684 overlay_notify(ovcs, OF_OVERLAY_POST_REMOVE); 846 *ovcs_id = 0;
847
848 ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_REMOVE);
849 if (ret_tmp) {
850 pr_err("overlay changeset post-remove notify error %d\n",
851 ret_tmp);
852 if (!ret)
853 ret = ret_tmp;
854 }
685 855
686 free_overlay_changeset(ovcs); 856 free_overlay_changeset(ovcs);
687 857
688out: 858out_unlock:
689 mutex_unlock(&of_mutex); 859 mutex_unlock(&of_mutex);
690 860
861out:
862 pr_debug("%s() err=%d\n", __func__, ret);
863
691 return ret; 864 return ret;
692} 865}
693EXPORT_SYMBOL_GPL(of_overlay_remove); 866EXPORT_SYMBOL_GPL(of_overlay_remove);
@@ -706,7 +879,7 @@ int of_overlay_remove_all(void)
706 879
707 /* the tail of list is guaranteed to be safe to remove */ 880 /* the tail of list is guaranteed to be safe to remove */
708 list_for_each_entry_safe_reverse(ovcs, ovcs_n, &ovcs_list, ovcs_list) { 881 list_for_each_entry_safe_reverse(ovcs, ovcs_n, &ovcs_list, ovcs_list) {
709 ret = of_overlay_remove(ovcs->id); 882 ret = of_overlay_remove(&ovcs->id);
710 if (ret) 883 if (ret)
711 return ret; 884 return ret;
712 } 885 }
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index bbdaf5606820..3640dae4b9b2 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1217,7 +1217,7 @@ static void of_unittest_untrack_overlay(int id)
1217 1217
1218static void of_unittest_destroy_tracked_overlays(void) 1218static void of_unittest_destroy_tracked_overlays(void)
1219{ 1219{
1220 int id, ret, defers; 1220 int id, ret, defers, ovcs_id;
1221 1221
1222 if (overlay_first_id < 0) 1222 if (overlay_first_id < 0)
1223 return; 1223 return;
@@ -1230,7 +1230,8 @@ static void of_unittest_destroy_tracked_overlays(void)
1230 if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id))) 1230 if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id)))
1231 continue; 1231 continue;
1232 1232
1233 ret = of_overlay_remove(id + overlay_first_id); 1233 ovcs_id = id + overlay_first_id;
1234 ret = of_overlay_remove(&ovcs_id);
1234 if (ret == -ENODEV) { 1235 if (ret == -ENODEV) {
1235 pr_warn("%s: no overlay to destroy for #%d\n", 1236 pr_warn("%s: no overlay to destroy for #%d\n",
1236 __func__, id + overlay_first_id); 1237 __func__, id + overlay_first_id);
@@ -1252,7 +1253,7 @@ static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr,
1252 int *overlay_id) 1253 int *overlay_id)
1253{ 1254{
1254 struct device_node *np = NULL; 1255 struct device_node *np = NULL;
1255 int ret, id = -1; 1256 int ret;
1256 1257
1257 np = of_find_node_by_path(overlay_path(overlay_nr)); 1258 np = of_find_node_by_path(overlay_path(overlay_nr));
1258 if (np == NULL) { 1259 if (np == NULL) {
@@ -1262,23 +1263,20 @@ static int of_unittest_apply_overlay(int overlay_nr, int unittest_nr,
1262 goto out; 1263 goto out;
1263 } 1264 }
1264 1265
1265 ret = of_overlay_apply(np); 1266 *overlay_id = 0;
1267 ret = of_overlay_apply(np, overlay_id);
1266 if (ret < 0) { 1268 if (ret < 0) {
1267 unittest(0, "could not create overlay from \"%s\"\n", 1269 unittest(0, "could not create overlay from \"%s\"\n",
1268 overlay_path(overlay_nr)); 1270 overlay_path(overlay_nr));
1269 goto out; 1271 goto out;
1270 } 1272 }
1271 id = ret; 1273 of_unittest_track_overlay(*overlay_id);
1272 of_unittest_track_overlay(id);
1273 1274
1274 ret = 0; 1275 ret = 0;
1275 1276
1276out: 1277out:
1277 of_node_put(np); 1278 of_node_put(np);
1278 1279
1279 if (overlay_id)
1280 *overlay_id = id;
1281
1282 return ret; 1280 return ret;
1283} 1281}
1284 1282
@@ -1286,7 +1284,7 @@ out:
1286static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr, 1284static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr,
1287 int before, int after, enum overlay_type ovtype) 1285 int before, int after, enum overlay_type ovtype)
1288{ 1286{
1289 int ret; 1287 int ret, ovcs_id;
1290 1288
1291 /* unittest device must not be in before state */ 1289 /* unittest device must not be in before state */
1292 if (of_unittest_device_exists(unittest_nr, ovtype) != before) { 1290 if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
@@ -1297,7 +1295,8 @@ static int of_unittest_apply_overlay_check(int overlay_nr, int unittest_nr,
1297 return -EINVAL; 1295 return -EINVAL;
1298 } 1296 }
1299 1297
1300 ret = of_unittest_apply_overlay(overlay_nr, unittest_nr, NULL); 1298 ovcs_id = 0;
1299 ret = of_unittest_apply_overlay(overlay_nr, unittest_nr, &ovcs_id);
1301 if (ret != 0) { 1300 if (ret != 0) {
1302 /* of_unittest_apply_overlay already called unittest() */ 1301 /* of_unittest_apply_overlay already called unittest() */
1303 return ret; 1302 return ret;
@@ -1320,7 +1319,7 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
1320 int unittest_nr, int before, int after, 1319 int unittest_nr, int before, int after,
1321 enum overlay_type ovtype) 1320 enum overlay_type ovtype)
1322{ 1321{
1323 int ret, ov_id; 1322 int ret, ovcs_id;
1324 1323
1325 /* unittest device must be in before state */ 1324 /* unittest device must be in before state */
1326 if (of_unittest_device_exists(unittest_nr, ovtype) != before) { 1325 if (of_unittest_device_exists(unittest_nr, ovtype) != before) {
@@ -1332,7 +1331,8 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
1332 } 1331 }
1333 1332
1334 /* apply the overlay */ 1333 /* apply the overlay */
1335 ret = of_unittest_apply_overlay(overlay_nr, unittest_nr, &ov_id); 1334 ovcs_id = 0;
1335 ret = of_unittest_apply_overlay(overlay_nr, unittest_nr, &ovcs_id);
1336 if (ret != 0) { 1336 if (ret != 0) {
1337 /* of_unittest_apply_overlay already called unittest() */ 1337 /* of_unittest_apply_overlay already called unittest() */
1338 return ret; 1338 return ret;
@@ -1347,7 +1347,7 @@ static int of_unittest_apply_revert_overlay_check(int overlay_nr,
1347 return -EINVAL; 1347 return -EINVAL;
1348 } 1348 }
1349 1349
1350 ret = of_overlay_remove(ov_id); 1350 ret = of_overlay_remove(&ovcs_id);
1351 if (ret != 0) { 1351 if (ret != 0) {
1352 unittest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n", 1352 unittest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
1353 overlay_path(overlay_nr), 1353 overlay_path(overlay_nr),
@@ -1449,7 +1449,7 @@ static void of_unittest_overlay_5(void)
1449static void of_unittest_overlay_6(void) 1449static void of_unittest_overlay_6(void)
1450{ 1450{
1451 struct device_node *np; 1451 struct device_node *np;
1452 int ret, i, ov_id[2]; 1452 int ret, i, ov_id[2], ovcs_id;
1453 int overlay_nr = 6, unittest_nr = 6; 1453 int overlay_nr = 6, unittest_nr = 6;
1454 int before = 0, after = 1; 1454 int before = 0, after = 1;
1455 1455
@@ -1476,13 +1476,14 @@ static void of_unittest_overlay_6(void)
1476 return; 1476 return;
1477 } 1477 }
1478 1478
1479 ret = of_overlay_apply(np); 1479 ovcs_id = 0;
1480 ret = of_overlay_apply(np, &ovcs_id);
1480 if (ret < 0) { 1481 if (ret < 0) {
1481 unittest(0, "could not create overlay from \"%s\"\n", 1482 unittest(0, "could not create overlay from \"%s\"\n",
1482 overlay_path(overlay_nr + i)); 1483 overlay_path(overlay_nr + i));
1483 return; 1484 return;
1484 } 1485 }
1485 ov_id[i] = ret; 1486 ov_id[i] = ovcs_id;
1486 of_unittest_track_overlay(ov_id[i]); 1487 of_unittest_track_overlay(ov_id[i]);
1487 } 1488 }
1488 1489
@@ -1500,7 +1501,8 @@ static void of_unittest_overlay_6(void)
1500 } 1501 }
1501 1502
1502 for (i = 1; i >= 0; i--) { 1503 for (i = 1; i >= 0; i--) {
1503 ret = of_overlay_remove(ov_id[i]); 1504 ovcs_id = ov_id[i];
1505 ret = of_overlay_remove(&ovcs_id);
1504 if (ret != 0) { 1506 if (ret != 0) {
1505 unittest(0, "overlay @\"%s\" failed destroy @\"%s\"\n", 1507 unittest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
1506 overlay_path(overlay_nr + i), 1508 overlay_path(overlay_nr + i),
@@ -1531,7 +1533,7 @@ static void of_unittest_overlay_6(void)
1531static void of_unittest_overlay_8(void) 1533static void of_unittest_overlay_8(void)
1532{ 1534{
1533 struct device_node *np; 1535 struct device_node *np;
1534 int ret, i, ov_id[2]; 1536 int ret, i, ov_id[2], ovcs_id;
1535 int overlay_nr = 8, unittest_nr = 8; 1537 int overlay_nr = 8, unittest_nr = 8;
1536 1538
1537 /* we don't care about device state in this test */ 1539 /* we don't care about device state in this test */
@@ -1546,18 +1548,20 @@ static void of_unittest_overlay_8(void)
1546 return; 1548 return;
1547 } 1549 }
1548 1550
1549 ret = of_overlay_apply(np); 1551 ovcs_id = 0;
1552 ret = of_overlay_apply(np, &ovcs_id);
1550 if (ret < 0) { 1553 if (ret < 0) {
1551 unittest(0, "could not create overlay from \"%s\"\n", 1554 unittest(0, "could not create overlay from \"%s\"\n",
1552 overlay_path(overlay_nr + i)); 1555 overlay_path(overlay_nr + i));
1553 return; 1556 return;
1554 } 1557 }
1555 ov_id[i] = ret; 1558 ov_id[i] = ovcs_id;
1556 of_unittest_track_overlay(ov_id[i]); 1559 of_unittest_track_overlay(ov_id[i]);
1557 } 1560 }
1558 1561
1559 /* now try to remove first overlay (it should fail) */ 1562 /* now try to remove first overlay (it should fail) */
1560 ret = of_overlay_remove(ov_id[0]); 1563 ovcs_id = ov_id[0];
1564 ret = of_overlay_remove(&ovcs_id);
1561 if (ret == 0) { 1565 if (ret == 0) {
1562 unittest(0, "overlay @\"%s\" was destroyed @\"%s\"\n", 1566 unittest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
1563 overlay_path(overlay_nr + 0), 1567 overlay_path(overlay_nr + 0),
@@ -1568,7 +1572,8 @@ static void of_unittest_overlay_8(void)
1568 1572
1569 /* removing them in order should work */ 1573 /* removing them in order should work */
1570 for (i = 1; i >= 0; i--) { 1574 for (i = 1; i >= 0; i--) {
1571 ret = of_overlay_remove(ov_id[i]); 1575 ovcs_id = ov_id[i];
1576 ret = of_overlay_remove(&ovcs_id);
1572 if (ret != 0) { 1577 if (ret != 0) {
1573 unittest(0, "overlay @\"%s\" not destroyed @\"%s\"\n", 1578 unittest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
1574 overlay_path(overlay_nr + i), 1579 overlay_path(overlay_nr + i),
@@ -2149,13 +2154,11 @@ static int __init overlay_data_add(int onum)
2149 goto out_free_np_overlay; 2154 goto out_free_np_overlay;
2150 } 2155 }
2151 2156
2152 ret = of_overlay_apply(info->np_overlay); 2157 info->overlay_id = 0;
2158 ret = of_overlay_apply(info->np_overlay, &info->overlay_id);
2153 if (ret < 0) { 2159 if (ret < 0) {
2154 pr_err("of_overlay_apply() (ret=%d), %d\n", ret, onum); 2160 pr_err("of_overlay_apply() (ret=%d), %d\n", ret, onum);
2155 goto out_free_np_overlay; 2161 goto out_free_np_overlay;
2156 } else {
2157 info->overlay_id = ret;
2158 ret = 0;
2159 } 2162 }
2160 2163
2161 pr_debug("__dtb_overlay_begin applied, overlay id %d\n", ret); 2164 pr_debug("__dtb_overlay_begin applied, overlay id %d\n", ret);
diff --git a/include/linux/of.h b/include/linux/of.h
index 7569e9cc45de..96edda95c6b0 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1298,7 +1298,7 @@ static inline bool of_device_is_system_power_controller(const struct device_node
1298 */ 1298 */
1299 1299
1300enum of_overlay_notify_action { 1300enum of_overlay_notify_action {
1301 OF_OVERLAY_PRE_APPLY, 1301 OF_OVERLAY_PRE_APPLY = 0,
1302 OF_OVERLAY_POST_APPLY, 1302 OF_OVERLAY_POST_APPLY,
1303 OF_OVERLAY_PRE_REMOVE, 1303 OF_OVERLAY_PRE_REMOVE,
1304 OF_OVERLAY_POST_REMOVE, 1304 OF_OVERLAY_POST_REMOVE,
@@ -1312,8 +1312,8 @@ struct of_overlay_notify_data {
1312#ifdef CONFIG_OF_OVERLAY 1312#ifdef CONFIG_OF_OVERLAY
1313 1313
1314/* ID based overlays; the API for external users */ 1314/* ID based overlays; the API for external users */
1315int of_overlay_apply(struct device_node *tree); 1315int of_overlay_apply(struct device_node *tree, int *ovcs_id);
1316int of_overlay_remove(int id); 1316int of_overlay_remove(int *ovcs_id);
1317int of_overlay_remove_all(void); 1317int of_overlay_remove_all(void);
1318 1318
1319int of_overlay_notifier_register(struct notifier_block *nb); 1319int of_overlay_notifier_register(struct notifier_block *nb);
@@ -1321,12 +1321,12 @@ int of_overlay_notifier_unregister(struct notifier_block *nb);
1321 1321
1322#else 1322#else
1323 1323
1324static inline int of_overlay_apply(struct device_node *tree) 1324static inline int of_overlay_apply(struct device_node *tree, int *ovcs_id)
1325{ 1325{
1326 return -ENOTSUPP; 1326 return -ENOTSUPP;
1327} 1327}
1328 1328
1329static inline int of_overlay_remove(int id) 1329static inline int of_overlay_remove(int *ovcs_id)
1330{ 1330{
1331 return -ENOTSUPP; 1331 return -ENOTSUPP;
1332} 1332}