Message ID | 1539563070-12969-14-git-send-email-frowand.list@gmail.com (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | of: overlay: validation checks, subsequent fixes | expand |
On Sun, 2018-10-14 at 17:24 -0700, frowand.list@gmail.com wrote: > From: Frank Rowand <frank.rowand@sony.com> > > Add test case of two fragments updating the same property. After > adding the test case, the system hangs at end of boot, after > after slub stack dumps from kfree() in crypto modprobe code. [] > -static int check_changeset_dup_add_node(struct overlay_changeset *ovcs) > +static int changeset_dup_entry_check(struct overlay_changeset *ovcs) > { > - struct of_changeset_entry *ce_1, *ce_2; > - char *fn_1, *fn_2; > - int name_match; > + struct of_changeset_entry *ce_1; > + int dup_entry = 0; > > list_for_each_entry(ce_1, &ovcs->cset.entries, node) { > - > - if (ce_1->action == OF_RECONFIG_ATTACH_NODE || > - ce_1->action == OF_RECONFIG_DETACH_NODE) { > - > - ce_2 = ce_1; > - list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) { > - if (ce_2->action == OF_RECONFIG_ATTACH_NODE || > - ce_2->action == OF_RECONFIG_DETACH_NODE) { > - /* inexpensive name compare */ > - if (!of_node_cmp(ce_1->np->full_name, > - ce_2->np->full_name)) { > - /* expensive full path name compare */ > - fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np); > - fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np); > - name_match = !strcmp(fn_1, fn_2); > - kfree(fn_1); > - kfree(fn_2); > - if (name_match) { > - pr_err("ERROR: multiple overlay fragments add and/or delete node %pOF\n", > - ce_1->np); > - return -EINVAL; > - } > - } > - } > - } > - } > + dup_entry |= find_dup_cset_node_entry(ovcs, ce_1); > + dup_entry |= find_dup_cset_prop(ovcs, ce_1); I think this is worse performance than before. This now walks all entries when before it would return -EINVAL directly when it found a match.
On 10/14/18 18:06, Joe Perches wrote: > On Sun, 2018-10-14 at 17:24 -0700, frowand.list@gmail.com wrote: >> From: Frank Rowand <frank.rowand@sony.com> >> >> Add test case of two fragments updating the same property. After >> adding the test case, the system hangs at end of boot, after >> after slub stack dumps from kfree() in crypto modprobe code. > [] >> -static int check_changeset_dup_add_node(struct overlay_changeset *ovcs) >> +static int changeset_dup_entry_check(struct overlay_changeset *ovcs) >> { >> - struct of_changeset_entry *ce_1, *ce_2; >> - char *fn_1, *fn_2; >> - int name_match; >> + struct of_changeset_entry *ce_1; >> + int dup_entry = 0; >> >> list_for_each_entry(ce_1, &ovcs->cset.entries, node) { >> - >> - if (ce_1->action == OF_RECONFIG_ATTACH_NODE || >> - ce_1->action == OF_RECONFIG_DETACH_NODE) { >> - >> - ce_2 = ce_1; >> - list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) { >> - if (ce_2->action == OF_RECONFIG_ATTACH_NODE || >> - ce_2->action == OF_RECONFIG_DETACH_NODE) { >> - /* inexpensive name compare */ >> - if (!of_node_cmp(ce_1->np->full_name, >> - ce_2->np->full_name)) { >> - /* expensive full path name compare */ >> - fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np); >> - fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np); >> - name_match = !strcmp(fn_1, fn_2); >> - kfree(fn_1); >> - kfree(fn_2); >> - if (name_match) { >> - pr_err("ERROR: multiple overlay fragments add and/or delete node %pOF\n", >> - ce_1->np); >> - return -EINVAL; >> - } >> - } >> - } >> - } >> - } >> + dup_entry |= find_dup_cset_node_entry(ovcs, ce_1); >> + dup_entry |= find_dup_cset_prop(ovcs, ce_1); > > I think this is worse performance than before. > > This now walks all entries when before it would > return -EINVAL directly when it found a match. Yes, it is worse performance, but that is OK. This is a check that is done when a devicetree overlay is applied. If an error occurs then that means that the overlay was incorrectly specified. The file drivers/of/unittest-data/overlay_bad_add_dup_prop.dts in this patch provides an example of how a bad overlay can be created. Once an error was detected, the check could return immediately, or it could continue to give a complete list of detected errors. I chose to give the complete list of detected errors. -Frank
On Sun, 2018-10-14 at 18:52 -0700, Frank Rowand wrote: > On 10/14/18 18:06, Joe Perches wrote: > > On Sun, 2018-10-14 at 17:24 -0700, frowand.list@gmail.com wrote: > > > From: Frank Rowand <frank.rowand@sony.com> > > > > > > Add test case of two fragments updating the same property. After > > > adding the test case, the system hangs at end of boot, after > > > after slub stack dumps from kfree() in crypto modprobe code. [] > > I think this is worse performance than before. > > > > This now walks all entries when before it would > > return -EINVAL directly when it found a match. > > Yes, it is worse performance, but that is OK. > > This is a check that is done when a devicetree overlay is applied. > If an error occurs then that means that the overlay was incorrectly > specified. The file drivers/of/unittest-data/overlay_bad_add_dup_prop.dts > in this patch provides an example of how a bad overlay can be created. > > Once an error was detected, the check could return immediately, or it > could continue to give a complete list of detected errors. I chose to > give the complete list of detected errors. Swell. Please describe that in the commit message.
On 10/14/18 18:55, Joe Perches wrote: > On Sun, 2018-10-14 at 18:52 -0700, Frank Rowand wrote: >> On 10/14/18 18:06, Joe Perches wrote: >>> On Sun, 2018-10-14 at 17:24 -0700, frowand.list@gmail.com wrote: >>>> From: Frank Rowand <frank.rowand@sony.com> >>>> >>>> Add test case of two fragments updating the same property. After >>>> adding the test case, the system hangs at end of boot, after >>>> after slub stack dumps from kfree() in crypto modprobe code. > [] >>> I think this is worse performance than before. >>> >>> This now walks all entries when before it would >>> return -EINVAL directly when it found a match. >> >> Yes, it is worse performance, but that is OK. >> >> This is a check that is done when a devicetree overlay is applied. >> If an error occurs then that means that the overlay was incorrectly >> specified. The file drivers/of/unittest-data/overlay_bad_add_dup_prop.dts >> in this patch provides an example of how a bad overlay can be created. >> >> Once an error was detected, the check could return immediately, or it >> could continue to give a complete list of detected errors. I chose to >> give the complete list of detected errors. > > Swell. Please describe that in the commit message. If a version 4 of the series is created I will update the commit message. As a stand alone item I do not think it is worth a new version. -Frank
On 10/14/18 20:21, Frank Rowand wrote: > On 10/14/18 18:55, Joe Perches wrote: >> On Sun, 2018-10-14 at 18:52 -0700, Frank Rowand wrote: >>> On 10/14/18 18:06, Joe Perches wrote: >>>> On Sun, 2018-10-14 at 17:24 -0700, frowand.list@gmail.com wrote: >>>>> From: Frank Rowand <frank.rowand@sony.com> >>>>> >>>>> Add test case of two fragments updating the same property. After >>>>> adding the test case, the system hangs at end of boot, after >>>>> after slub stack dumps from kfree() in crypto modprobe code. >> [] >>>> I think this is worse performance than before. >>>> >>>> This now walks all entries when before it would >>>> return -EINVAL directly when it found a match. >>> >>> Yes, it is worse performance, but that is OK. >>> >>> This is a check that is done when a devicetree overlay is applied. >>> If an error occurs then that means that the overlay was incorrectly >>> specified. The file drivers/of/unittest-data/overlay_bad_add_dup_prop.dts >>> in this patch provides an example of how a bad overlay can be created. >>> >>> Once an error was detected, the check could return immediately, or it >>> could continue to give a complete list of detected errors. I chose to >>> give the complete list of detected errors. >> >> Swell. Please describe that in the commit message. > > If a version 4 of the series is created I will update the commit > message. As a stand alone item I do not think it is worth a > new version. And there will be a version 4, so I will update the commit message. -Frank
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index b0a0dafb6a13..908bcc62019b 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -514,52 +514,96 @@ static int build_changeset_symbols_node(struct overlay_changeset *ovcs, return 0; } +static int find_dup_cset_node_entry(struct overlay_changeset *ovcs, + struct of_changeset_entry *ce_1) +{ + struct of_changeset_entry *ce_2; + char *fn_1, *fn_2; + int node_path_match; + + if (ce_1->action != OF_RECONFIG_ATTACH_NODE && + ce_1->action != OF_RECONFIG_DETACH_NODE) + return 0; + + ce_2 = ce_1; + list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) { + if ((ce_2->action != OF_RECONFIG_ATTACH_NODE && + ce_2->action != OF_RECONFIG_DETACH_NODE) || + of_node_cmp(ce_1->np->full_name, ce_2->np->full_name)) + continue; + + fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np); + fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np); + node_path_match = !strcmp(fn_1, fn_2); + kfree(fn_1); + kfree(fn_2); + if (node_path_match) { + pr_err("ERROR: multiple overlay fragments add and/or delete node %pOF\n", + ce_1->np); + return -EINVAL; + } + } + + return 0; +} + +static int find_dup_cset_prop(struct overlay_changeset *ovcs, + struct of_changeset_entry *ce_1) +{ + struct of_changeset_entry *ce_2; + char *fn_1, *fn_2; + int node_path_match; + + if (ce_1->action != OF_RECONFIG_ADD_PROPERTY && + ce_1->action != OF_RECONFIG_REMOVE_PROPERTY && + ce_1->action != OF_RECONFIG_UPDATE_PROPERTY) + return 0; + + ce_2 = ce_1; + list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) { + if ((ce_2->action != OF_RECONFIG_ADD_PROPERTY && + ce_2->action != OF_RECONFIG_REMOVE_PROPERTY && + ce_2->action != OF_RECONFIG_UPDATE_PROPERTY) || + of_node_cmp(ce_1->np->full_name, ce_2->np->full_name)) + continue; + + fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np); + fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np); + node_path_match = !strcmp(fn_1, fn_2); + kfree(fn_1); + kfree(fn_2); + if (node_path_match && + !of_prop_cmp(ce_1->prop->name, ce_2->prop->name)) { + pr_err("ERROR: multiple overlay fragments add, update, and/or delete property %pOF/%s\n", + ce_1->np, ce_1->prop->name); + return -EINVAL; + } + } + + return 0; +} + /** - * check_changeset_dup_add_node() - changeset validation: duplicate add node + * changeset_dup_entry_check() - check for duplicate entries * @ovcs: Overlay changeset * - * Check changeset @ovcs->cset for multiple add node entries for the same - * node. + * Check changeset @ovcs->cset for multiple {add or delete} node entries for + * the same node or duplicate {add, delete, or update} properties entries + * for the same property. * - * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if - * invalid overlay in @ovcs->fragments[]. + * Returns 0 on success, or -EINVAL if duplicate changeset entry found. */ -static int check_changeset_dup_add_node(struct overlay_changeset *ovcs) +static int changeset_dup_entry_check(struct overlay_changeset *ovcs) { - struct of_changeset_entry *ce_1, *ce_2; - char *fn_1, *fn_2; - int name_match; + struct of_changeset_entry *ce_1; + int dup_entry = 0; list_for_each_entry(ce_1, &ovcs->cset.entries, node) { - - if (ce_1->action == OF_RECONFIG_ATTACH_NODE || - ce_1->action == OF_RECONFIG_DETACH_NODE) { - - ce_2 = ce_1; - list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) { - if (ce_2->action == OF_RECONFIG_ATTACH_NODE || - ce_2->action == OF_RECONFIG_DETACH_NODE) { - /* inexpensive name compare */ - if (!of_node_cmp(ce_1->np->full_name, - ce_2->np->full_name)) { - /* expensive full path name compare */ - fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np); - fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np); - name_match = !strcmp(fn_1, fn_2); - kfree(fn_1); - kfree(fn_2); - if (name_match) { - pr_err("ERROR: multiple overlay fragments add and/or delete node %pOF\n", - ce_1->np); - return -EINVAL; - } - } - } - } - } + dup_entry |= find_dup_cset_node_entry(ovcs, ce_1); + dup_entry |= find_dup_cset_prop(ovcs, ce_1); } - return 0; + return dup_entry ? -EINVAL : 0; } /** @@ -617,7 +661,7 @@ static int build_changeset(struct overlay_changeset *ovcs) } } - return check_changeset_dup_add_node(ovcs); + return changeset_dup_entry_check(ovcs); } /* diff --git a/drivers/of/unittest-data/Makefile b/drivers/of/unittest-data/Makefile index 166dbdbfd1c5..9b6807065827 100644 --- a/drivers/of/unittest-data/Makefile +++ b/drivers/of/unittest-data/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \ overlay_13.dtb.o \ overlay_15.dtb.o \ overlay_bad_add_dup_node.dtb.o \ + overlay_bad_add_dup_prop.dtb.o \ overlay_bad_phandle.dtb.o \ overlay_bad_symbol.dtb.o \ overlay_base.dtb.o 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 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +/* + * &electric_1/motor-1 and &spin_ctrl_1 are the same node: + * /testcase-data-2/substation@100/motor-1 + * + * Thus the property "rpm_avail" in each fragment will + * result in an attempt to update the same property twice. + * This will result in an error and the overlay apply + * will fail. + */ + +&electric_1 { + + motor-1 { + rpm_avail = < 100 >; + }; +}; + +&spin_ctrl_1 { + rpm_avail = < 100 200 >; +}; 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 @@ spin_ctrl_1: motor-1 { compatible = "ot,ferris-wheel-motor"; spin = "clockwise"; + rpm_avail = < 50 >; }; spin_ctrl_2: motor-8 { diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 471b8eb6e842..efd9c947f192 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -2148,6 +2148,7 @@ struct overlay_info { OVERLAY_INFO_EXTERN(overlay_13); OVERLAY_INFO_EXTERN(overlay_15); OVERLAY_INFO_EXTERN(overlay_bad_add_dup_node); +OVERLAY_INFO_EXTERN(overlay_bad_add_dup_prop); OVERLAY_INFO_EXTERN(overlay_bad_phandle); OVERLAY_INFO_EXTERN(overlay_bad_symbol); @@ -2171,6 +2172,7 @@ struct overlay_info { OVERLAY_INFO(overlay_13, 0), OVERLAY_INFO(overlay_15, 0), OVERLAY_INFO(overlay_bad_add_dup_node, -EINVAL), + OVERLAY_INFO(overlay_bad_add_dup_prop, -EINVAL), OVERLAY_INFO(overlay_bad_phandle, -EINVAL), OVERLAY_INFO(overlay_bad_symbol, -EINVAL), {} @@ -2418,6 +2420,9 @@ static __init void of_unittest_overlay_high_level(void) unittest(overlay_data_apply("overlay_bad_add_dup_node", NULL), "Adding overlay 'overlay_bad_add_dup_node' failed\n"); + unittest(overlay_data_apply("overlay_bad_add_dup_prop", NULL), + "Adding overlay 'overlay_bad_add_dup_prop' failed\n"); + unittest(overlay_data_apply("overlay_bad_phandle", NULL), "Adding overlay 'overlay_bad_phandle' failed\n");