[RFC] resource: Avoid unnecessary resource tree walking in __region_intersects()

From: Huang Ying
Date: Thu Oct 10 2024 - 02:56:42 EST


Currently, if __region_intersects() finds any overlapped but unmatched
resource, it walks the descendant resource tree to check for
overlapped and matched descendant resources. This is achieved using
for_each_resource(), which iterates not only the descent tree, but
also subsequent sibling trees in certain scenarios. While this
doesn't introduce bugs, it makes code hard to be understood and
potentially inefficient.

So, the patch renames next_resource() to __next_resource() and
modified it to return NULL after traversing all descent resources.
Test shows that this avoids unnecessary resource tree walking in
__region_intersects().

It appears even better to revise for_each_resource() to traverse the
descendant resource tree of "_root" only. But that will cause "_root"
to be evaluated twice, which I don't find a good way to eliminate.

Signed-off-by: "Huang, Ying" <ying.huang@xxxxxxxxx>
Cc: Dan Williams <dan.j.williams@xxxxxxxxx>
Cc: David Hildenbrand <david@xxxxxxxxxx>
Cc: Davidlohr Bueso <dave@xxxxxxxxxxxx>
Cc: Jonathan Cameron <jonathan.cameron@xxxxxxxxxx>
Cc: Alistair Popple <apopple@xxxxxxxxxx>
Cc: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
Cc: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
Cc: Baoquan He <bhe@xxxxxxxxxx>
Cc: Dave Jiang <dave.jiang@xxxxxxxxx>
Cc: Alison Schofield <alison.schofield@xxxxxxxxx>
---
kernel/resource.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/kernel/resource.c b/kernel/resource.c
index b730bd28b422..3ded4c5d4418 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -50,15 +50,28 @@ EXPORT_SYMBOL(iomem_resource);

static DEFINE_RWLOCK(resource_lock);

-static struct resource *next_resource(struct resource *p, bool skip_children)
+static struct resource *__next_resource(struct resource *root, struct resource *p,
+ bool skip_children)
{
if (!skip_children && p->child)
return p->child;
- while (!p->sibling && p->parent)
+ while (!p->sibling && p->parent) {
p = p->parent;
+ if (p == root)
+ return NULL;
+ }
return p->sibling;
}

+static struct resource *next_resource(struct resource *p, bool skip_children)
+{
+ return __next_resource(NULL, p, skip_children);
+}
+
+/*
+ * Traverse the whole resource tree (NOTE: not descendant tree under
+ * _root) from _root->child on.
+ */
#define for_each_resource(_root, _p, _skip_children) \
for ((_p) = (_root)->child; (_p); (_p) = next_resource(_p, _skip_children))

@@ -572,7 +585,7 @@ static int __region_intersects(struct resource *parent, resource_size_t start,
covered = false;
ostart = max(res.start, p->start);
oend = min(res.end, p->end);
- for_each_resource(p, dp, false) {
+ for (dp = p->child; dp; dp = __next_resource(p, dp, false)) {
if (!resource_overlaps(dp, &res))
continue;
is_type = (dp->flags & flags) == flags &&
--
2.39.2