Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp701387imu; Mon, 5 Nov 2018 07:31:53 -0800 (PST) X-Google-Smtp-Source: AJdET5eSeOPD+9U5yLSI7NRTHc6bJnjAa6M62qmZ39JMGed4OGNoMLh5TE7K1KsfK5t1oK/pjGW4 X-Received: by 2002:a63:ee0e:: with SMTP id e14mr20080494pgi.8.1541431913111; Mon, 05 Nov 2018 07:31:53 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541431912; cv=none; d=google.com; s=arc-20160816; b=hY4yZ3vmCHsnysBPW+DO45rpgutlWXcLkYKuMVzD8fdh4d5mnQgWRkuChxLEvcWAye urGCS7pzru8n1OhxLWkEFxqM/zHiTTng1eBzx7eQl+XCt9SHlRksJW0AVzyiN5Zk4x/H WOibHKVQuVfeIZI2mKZqnXWnPaL18RanTMZRWg+sFNJ8SRenfcxCx9x5qnIaqy6phLH5 NF2EBXKSjPzAu498rY5MEQQxeSDKFfgtvLNFx/1dNVnpY0NXGzZSNpWR2PXOmafb7/kb VoZ2aTzzWx49xH5pmcJrWo8bW/zhWWTYcb3tJzZ7KgUUBKU6wscB2TfQGmodnG2FUp5P e75g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature; bh=D3FT5lRIYH6zQDYcowRpU+vLMnNgl8P6Y/UgX4wXgbo=; b=I6ajcovEc675p24gjfnt8MXqVnkeeSYJMMj6PTrX+p+LMP5/HThTqwCnmqd8IfN2Tn t9t0fkzOSWp/dBXIVJPYn34xBbA9ccs41hxhhoG1fCEhfza6SnU8TqXYlIQIOy8G3Jyv soFIi337SI5SH5ZFgo8NExrrBsASV9aRWVLlKty6OGYljTlzybcEFPtf6ZydNe3S9GN0 Un2iDGNgUo/JwBVmCzqSLB6SpjBJ85So/wKmMhQ7zK7ULEuJv2lCJAyPoKCc3zgkawNd gKv7Ss1zzCgViQKpwBBfTE/npuEMGUecjfo0DoyJ9NeJPgmqq76JYF43kToV+B0a++b8 n4iQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b="k/D/sEw4"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a17-v6si14216927pls.302.2018.11.05.07.31.37; Mon, 05 Nov 2018 07:31:52 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b="k/D/sEw4"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730269AbeKFArN (ORCPT + 99 others); Mon, 5 Nov 2018 19:47:13 -0500 Received: from mail-pf1-f195.google.com ([209.85.210.195]:46175 "EHLO mail-pf1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730234AbeKFArM (ORCPT ); Mon, 5 Nov 2018 19:47:12 -0500 Received: by mail-pf1-f195.google.com with SMTP id r64-v6so4575642pfb.13; Mon, 05 Nov 2018 07:26:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=D3FT5lRIYH6zQDYcowRpU+vLMnNgl8P6Y/UgX4wXgbo=; b=k/D/sEw4twBiPsmxDINj4PMFEOjySngc8xKsjFLUfqk3ALfGAMDgg1nf4q7FJdCzY4 /NsLHx5vMBQlLRWHIFJg8ayRZhG4OzyezzmQGVasJbh2NqgiVRgNRwafxLbpLZFUFcDX G8Tgy4rj+HQF2dt0MVtGUgE0z9UU1nadAietye5uHWpBIkmZMIGVTb7A0uR/t75LeuQk rcnDZJcK4RPKniiV7Mt7iAsFRdkNAumfmT4t/4GuXgPJV1qJKOrUwOSQtjDlsbk2rvCp sQDRfo7YLL4wuFveLbjHCG4I3CBwC0Iukh0nY4J0r+2DNKDrtFzuFR9x5KIhZHk93yRq GOag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=D3FT5lRIYH6zQDYcowRpU+vLMnNgl8P6Y/UgX4wXgbo=; b=WMeoSAaGLB8GNGsQR71rVIkPZQwZF6h3L7LXom2sqN97tqTmfZCU33aMupFIJ8sq+2 UHBk0XEtg4Nuqa5b2VYJsoP27uOlQshCNaleUdOUXl0LieQDkaC2f3OhyMG5u4BYz6W+ ll9Jn4ydQhOPRvD04NQpSqsr19Mnbm8vuqISwAiYhe6U9ALJbOmePpKJh3jfqXfvY0X9 f9hvgvPK057uYm0J6In4y/iKK85dh5g4sQfFMnXb1O0xZTuonMys6HJvno4lGm68EJJQ Ho6Te57Pvh5QtPQeZixyCmyQ3uw2qvQe57eztKNS1hevYfDWimzu60mZIy5DRlpL2kWS 41cQ== X-Gm-Message-State: AGRZ1gKAChR3nYrYnCaacO35yPcT1lSFXYEYNHehn2HHIEJfZuPZSBe/ gVUKRuPukqlsUCVq6Pv55AU= X-Received: by 2002:a62:507:: with SMTP id 7-v6mr22540125pff.80.1541431618937; Mon, 05 Nov 2018 07:26:58 -0800 (PST) Received: from localhost.localdomain (c-24-6-192-50.hsd1.ca.comcast.net. [24.6.192.50]) by smtp.gmail.com with ESMTPSA id u76-v6sm37260578pfa.176.2018.11.05.07.26.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 05 Nov 2018 07:26:58 -0800 (PST) From: frowand.list@gmail.com To: Rob Herring , Pantelis Antoniou , Michael Ellerman , Benjamin Herrenschmidt , Paul Mackerras , Alan Tull , Moritz Fischer Cc: linux-kernel@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-fpga@vger.kernel.org Subject: [PATCH v6 05/18] of: overlay: use prop add changeset entry for property in new nodes Date: Mon, 5 Nov 2018 07:25:02 -0800 Message-Id: <1541431515-25197-6-git-send-email-frowand.list@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1541431515-25197-1-git-send-email-frowand.list@gmail.com> References: <1541431515-25197-1-git-send-email-frowand.list@gmail.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Frank Rowand The changeset entry 'update property' was used for new properties in an overlay instead of 'add property'. The decision of whether to use 'update property' was based on whether the property already exists in the subtree where the node is being spliced into. At the top level of creating a changeset describing the overlay, the target node is in the live devicetree, so checking whether the property exists in the target node returns the correct result. As soon as the changeset creation algorithm recurses into a new node, the target is no longer in the live devicetree, but is instead in the detached overlay tree, thus all properties are incorrectly found to already exist in the target. This fix will expose another devicetree bug that will be fixed in the following patch in the series. When this patch is applied the errors reported by the devictree unittest will change, and the unittest results will change from: ### dt-test ### end of unittest - 210 passed, 0 failed to ### dt-test ### end of unittest - 203 passed, 7 failed Tested-by: Alan Tull Signed-off-by: Frank Rowand --- Changes since v5: - update for context change from a613b26a50136 "of: Convert to using %pOFn instead of device_node.name" drivers/of/overlay.c | 112 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 7613f7d680c7..6fd8e6145e10 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -24,6 +24,26 @@ #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 * @overlay: pointer to the __overlay__ node @@ -72,8 +92,7 @@ static int devicetree_corrupt(void) } 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. @@ -257,14 +276,17 @@ static struct property *dup_and_fixup_symbol_prop( /** * 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. @@ -273,20 +295,22 @@ static struct property *dup_and_fixup_symbol_prop( * 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; @@ -299,10 +323,10 @@ static int add_changeset_property(struct overlay_changeset *ovcs, 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) { @@ -315,14 +339,14 @@ static int add_changeset_property(struct overlay_changeset *ovcs, /** * 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 @@ -355,15 +379,16 @@ static int add_changeset_property(struct overlay_changeset *ovcs, * 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; @@ -372,22 +397,28 @@ static int add_changeset_node(struct overlay_changeset *ovcs, 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; @@ -396,7 +427,7 @@ static int add_changeset_node(struct overlay_changeset *ovcs, /** * 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 @@ -409,27 +440,26 @@ static int add_changeset_node(struct overlay_changeset *ovcs, * 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; } @@ -442,17 +472,17 @@ static int build_changeset_next_level(struct overlay_changeset *ovcs, * 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; } } @@ -475,6 +505,7 @@ static int build_changeset_symbols_node(struct overlay_changeset *ovcs, static int build_changeset(struct overlay_changeset *ovcs) { struct fragment *fragment; + struct target target; int fragments_count, i, ret; /* @@ -489,7 +520,9 @@ static int build_changeset(struct overlay_changeset *ovcs) 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); @@ -499,7 +532,10 @@ static int build_changeset(struct overlay_changeset *ovcs) 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); @@ -517,7 +553,7 @@ static int build_changeset(struct overlay_changeset *ovcs) * 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; @@ -623,7 +659,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs, 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; -- Frank Rowand