#include "of_private.h"
 
+/**
+ * struct target - info about current target node as recursing through overlay
+ * @np:                        node where current level of overlay will be applied
+ * @in_livetree:       @np is a node in the live devicetree
+ *
+ * Used in the algorithm to create the portion of a changeset that describes
+ * an overlay fragment, which is a devicetree subtree.  Initially @np is a node
+ * in the live devicetree where the overlay subtree is targeted to be grafted
+ * into.  When recursing to the next level of the overlay subtree, the target
+ * also recurses to the next level of the live devicetree, as long as overlay
+ * subtree node also exists in the live devicetree.  When a node in the overlay
+ * subtree does not exist at the same level in the live devicetree, target->np
+ * points to a newly allocated node, and all subsequent targets in the subtree
+ * will be newly allocated nodes.
+ */
+struct target {
+       struct device_node *np;
+       bool in_livetree;
+};
+
 /**
  * struct fragment - info about fragment nodes in overlay expanded device tree
  * @target:    target of the overlay operation
 }
 
 static int build_changeset_next_level(struct overlay_changeset *ovcs,
-               struct device_node *target_node,
-               const struct device_node *overlay_node);
+               struct target *target, const struct device_node *overlay_node);
 
 /*
  * of_resolve_phandles() finds the largest phandle in the live tree.
 /**
  * add_changeset_property() - add @overlay_prop to overlay changeset
  * @ovcs:              overlay changeset
- * @target_node:       where to place @overlay_prop in live tree
+ * @target:            where @overlay_prop will be placed
  * @overlay_prop:      property to add or update, from overlay tree
  * @is_symbols_prop:   1 if @overlay_prop is from node "/__symbols__"
  *
- * If @overlay_prop does not already exist in @target_node, add changeset entry
- * to add @overlay_prop in @target_node, else add changeset entry to update
+ * If @overlay_prop does not already exist in live devicetree, add changeset
+ * entry to add @overlay_prop in @target, else add changeset entry to update
  * value of @overlay_prop.
  *
+ * @target may be either in the live devicetree or in a new subtree that
+ * is contained in the changeset.
+ *
  * Some special properties are not updated (no error returned).
  *
  * Update of property in symbols node is not allowed.
  * invalid @overlay.
  */
 static int add_changeset_property(struct overlay_changeset *ovcs,
-               struct device_node *target_node,
-               struct property *overlay_prop,
+               struct target *target, struct property *overlay_prop,
                bool is_symbols_prop)
 {
        struct property *new_prop = NULL, *prop;
        int ret = 0;
 
-       prop = of_find_property(target_node, overlay_prop->name, NULL);
-
        if (!of_prop_cmp(overlay_prop->name, "name") ||
            !of_prop_cmp(overlay_prop->name, "phandle") ||
            !of_prop_cmp(overlay_prop->name, "linux,phandle"))
                return 0;
 
+       if (target->in_livetree)
+               prop = of_find_property(target->np, overlay_prop->name, NULL);
+       else
+               prop = NULL;
+
        if (is_symbols_prop) {
                if (prop)
                        return -EINVAL;
                return -ENOMEM;
 
        if (!prop)
-               ret = of_changeset_add_property(&ovcs->cset, target_node,
+               ret = of_changeset_add_property(&ovcs->cset, target->np,
                                                new_prop);
        else
-               ret = of_changeset_update_property(&ovcs->cset, target_node,
+               ret = of_changeset_update_property(&ovcs->cset, target->np,
                                                   new_prop);
 
        if (ret) {
 
 /**
  * add_changeset_node() - add @node (and children) to overlay changeset
- * @ovcs:              overlay changeset
- * @target_node:       where to place @node in live tree
- * @node:              node from within overlay device tree fragment
+ * @ovcs:      overlay changeset
+ * @target:    where @node will be placed in live tree or changeset
+ * @node:      node from within overlay device tree fragment
  *
- * If @node does not already exist in @target_node, add changeset entry
- * to add @node in @target_node.
+ * If @node does not already exist in @target, add changeset entry
+ * to add @node in @target.
  *
- * If @node already exists in @target_node, and the existing node has
+ * If @node already exists in @target, and the existing node has
  * a phandle, the overlay node is not allowed to have a phandle.
  *
  * If @node has child nodes, add the children recursively via
  * invalid @overlay.
  */
 static int add_changeset_node(struct overlay_changeset *ovcs,
-               struct device_node *target_node, struct device_node *node)
+               struct target *target, struct device_node *node)
 {
        const char *node_kbasename;
        struct device_node *tchild;
+       struct target target_child;
        int ret = 0;
 
        node_kbasename = kbasename(node->full_name);
 
-       for_each_child_of_node(target_node, tchild)
+       for_each_child_of_node(target->np, tchild)
                if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name)))
                        break;
 
                if (!tchild)
                        return -ENOMEM;
 
-               tchild->parent = target_node;
+               tchild->parent = target->np;
                of_node_set_flag(tchild, OF_OVERLAY);
 
                ret = of_changeset_attach_node(&ovcs->cset, tchild);
                if (ret)
                        return ret;
 
-               ret = build_changeset_next_level(ovcs, tchild, node);
+               target_child.np = tchild;
+               target_child.in_livetree = false;
+
+               ret = build_changeset_next_level(ovcs, &target_child, node);
                of_node_put(tchild);
                return ret;
        }
 
-       if (node->phandle && tchild->phandle)
+       if (node->phandle && tchild->phandle) {
                ret = -EINVAL;
-       else
-               ret = build_changeset_next_level(ovcs, tchild, node);
+       } else {
+               target_child.np = tchild;
+               target_child.in_livetree = target->in_livetree;
+               ret = build_changeset_next_level(ovcs, &target_child, node);
+       }
        of_node_put(tchild);
 
        return ret;
 /**
  * build_changeset_next_level() - add level of overlay changeset
  * @ovcs:              overlay changeset
- * @target_node:       where to place @overlay_node in live tree
+ * @target:            where to place @overlay_node in live tree
  * @overlay_node:      node from within an overlay device tree fragment
  *
  * Add the properties (if any) and nodes (if any) from @overlay_node to the
  * invalid @overlay_node.
  */
 static int build_changeset_next_level(struct overlay_changeset *ovcs,
-               struct device_node *target_node,
-               const struct device_node *overlay_node)
+               struct target *target, const struct device_node *overlay_node)
 {
        struct device_node *child;
        struct property *prop;
        int ret;
 
        for_each_property_of_node(overlay_node, prop) {
-               ret = add_changeset_property(ovcs, target_node, prop, 0);
+               ret = add_changeset_property(ovcs, target, prop, 0);
                if (ret) {
                        pr_debug("Failed to apply prop @%pOF/%s, err=%d\n",
-                                target_node, prop->name, ret);
+                                target->np, prop->name, ret);
                        return ret;
                }
        }
 
        for_each_child_of_node(overlay_node, child) {
-               ret = add_changeset_node(ovcs, target_node, child);
+               ret = add_changeset_node(ovcs, target, child);
                if (ret) {
                        pr_debug("Failed to apply node @%pOF/%pOFn, err=%d\n",
-                                target_node, child, ret);
+                                target->np, child, ret);
                        of_node_put(child);
                        return ret;
                }
  * Add the properties from __overlay__ node to the @ovcs->cset changeset.
  */
 static int build_changeset_symbols_node(struct overlay_changeset *ovcs,
-               struct device_node *target_node,
+               struct target *target,
                const struct device_node *overlay_symbols_node)
 {
        struct property *prop;
        int ret;
 
        for_each_property_of_node(overlay_symbols_node, prop) {
-               ret = add_changeset_property(ovcs, target_node, prop, 1);
+               ret = add_changeset_property(ovcs, target, prop, 1);
                if (ret) {
                        pr_debug("Failed to apply prop @%pOF/%s, err=%d\n",
-                                target_node, prop->name, ret);
+                                target->np, prop->name, ret);
                        return ret;
                }
        }
 static int build_changeset(struct overlay_changeset *ovcs)
 {
        struct fragment *fragment;
+       struct target target;
        int fragments_count, i, ret;
 
        /*
        for (i = 0; i < fragments_count; i++) {
                fragment = &ovcs->fragments[i];
 
-               ret = build_changeset_next_level(ovcs, fragment->target,
+               target.np = fragment->target;
+               target.in_livetree = true;
+               ret = build_changeset_next_level(ovcs, &target,
                                                 fragment->overlay);
                if (ret) {
                        pr_debug("apply failed '%pOF'\n", fragment->target);
 
        if (ovcs->symbols_fragment) {
                fragment = &ovcs->fragments[ovcs->count - 1];
-               ret = build_changeset_symbols_node(ovcs, fragment->target,
+
+               target.np = fragment->target;
+               target.in_livetree = true;
+               ret = build_changeset_symbols_node(ovcs, &target,
                                                   fragment->overlay);
                if (ret) {
                        pr_debug("apply failed '%pOF'\n", fragment->target);
  * 1) "target" property containing the phandle of the target
  * 2) "target-path" property containing the path of the target
  */
-static struct device_node *find_target_node(struct device_node *info_node)
+static struct device_node *find_target(struct device_node *info_node)
 {
        struct device_node *node;
        const char *path;
 
                fragment = &fragments[cnt];
                fragment->overlay = overlay_node;
-               fragment->target = find_target_node(node);
+               fragment->target = find_target(node);
                if (!fragment->target) {
                        of_node_put(fragment->overlay);
                        ret = -EINVAL;