Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

of: overlay: Stop leaking resources on overlay removal

Only the overlay notifier callbacks have a chance to potentially get
hold of references to those two resources, but they are not supposed to
store them beyond OF_OVERLAY_POST_REMOVE.

Document the overlay notifier API, its constraint regarding pointer
lifetime, and then remove intentional leaks of ovcs->overlay_tree and
ovcs->fdt from free_overlay_changeset.

See also https://lkml.org/lkml/2018/4/23/1063 and following.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Reviewed-by: Frank Rowand <frowand.list@gmail.com>
Signed-off-by: Rob Herring <robh@kernel.org>

authored by

Jan Kiszka and committed by
Rob Herring
83ef4777 970f04c8

+29 -9
+8
Documentation/devicetree/overlay-notes.txt
··· 98 98 of_overlay_remove_all() which will remove every single one in the correct 99 99 order. 100 100 101 + In addition, there is the option to register notifiers that get called on 102 + overlay operations. See of_overlay_notifier_register/unregister and 103 + enum of_overlay_notify_action for details. 104 + 105 + Note that a notifier callback is not supposed to store pointers to a device 106 + tree node or its content beyond OF_OVERLAY_POST_REMOVE corresponding to the 107 + respective node it received. 108 + 101 109 Overlay DTS Format 102 110 ------------------ 103 111
+21 -9
drivers/of/overlay.c
··· 102 102 103 103 static BLOCKING_NOTIFIER_HEAD(overlay_notify_chain); 104 104 105 + /** 106 + * of_overlay_notifier_register() - Register notifier for overlay operations 107 + * @nb: Notifier block to register 108 + * 109 + * Register for notification on overlay operations on device tree nodes. The 110 + * reported actions definied by @of_reconfig_change. The notifier callback 111 + * furthermore receives a pointer to the affected device tree node. 112 + * 113 + * Note that a notifier callback is not supposed to store pointers to a device 114 + * tree node or its content beyond @OF_OVERLAY_POST_REMOVE corresponding to the 115 + * respective node it received. 116 + */ 105 117 int of_overlay_notifier_register(struct notifier_block *nb) 106 118 { 107 119 return blocking_notifier_chain_register(&overlay_notify_chain, nb); 108 120 } 109 121 EXPORT_SYMBOL_GPL(of_overlay_notifier_register); 110 122 123 + /** 124 + * of_overlay_notifier_register() - Unregister notifier for overlay operations 125 + * @nb: Notifier block to unregister 126 + */ 111 127 int of_overlay_notifier_unregister(struct notifier_block *nb) 112 128 { 113 129 return blocking_notifier_chain_unregister(&overlay_notify_chain, nb); ··· 687 671 of_node_put(ovcs->fragments[i].overlay); 688 672 } 689 673 kfree(ovcs->fragments); 690 - 691 674 /* 692 - * TODO 693 - * 694 - * would like to: kfree(ovcs->overlay_tree); 695 - * but can not since drivers may have pointers into this data 696 - * 697 - * would like to: kfree(ovcs->fdt); 698 - * but can not since drivers may have pointers into this data 675 + * There should be no live pointers into ovcs->overlay_tree and 676 + * ovcs->fdt due to the policy that overlay notifiers are not allowed 677 + * to retain pointers into the overlay devicetree. 699 678 */ 700 - 679 + kfree(ovcs->overlay_tree); 680 + kfree(ovcs->fdt); 701 681 kfree(ovcs); 702 682 } 703 683