Skip to content

Commit d7ce9c7

Browse files
yhuang-intelakpm00
authored andcommitted
resource: avoid unnecessary resource tree walking in __region_intersects()
Currently, if __region_intersects() finds any overlapped but unmatched resource, it walks the descendant resource tree to check for overlapped and matched descendant resources using for_each_resource(). However, in current kernel, for_each_resource() iterates not only the descendant 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 revises next_resource() and for_each_resource() and makes for_each_resource() traverse the subtree under the specified subtree root only. Test shows that this avoids unnecessary resource tree walking in __region_intersects(). For the example resource tree as follows, X | A----D----E | B--C if 'A' is the overlapped but unmatched resource, original kernel iterates 'B', 'C', 'D', 'E' when it walks the descendant tree. While the patched kernel iterates only 'B', 'C'. Thanks David Hildenbrand for providing a good resource tree example. Link: https://lkml.kernel.org/r/20241029122735.79164-1-ying.huang@intel.com Signed-off-by: "Huang, Ying" <ying.huang@intel.com> Acked-by: Dan Williams <dan.j.williams@intel.com> Cc: David Hildenbrand <david@redhat.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Jonathan Cameron <jonathan.cameron@huawei.com> Cc: Alistair Popple <apopple@nvidia.com> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Baoquan He <bhe@redhat.com> Cc: Dave Jiang <dave.jiang@intel.com> Cc: Alison Schofield <alison.schofield@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 77e94b0 commit d7ce9c7

File tree

1 file changed

+22
-4
lines changed

1 file changed

+22
-4
lines changed

kernel/resource.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,35 @@ EXPORT_SYMBOL(iomem_resource);
5050

5151
static DEFINE_RWLOCK(resource_lock);
5252

53-
static struct resource *next_resource(struct resource *p, bool skip_children)
53+
/*
54+
* Return the next node of @p in pre-order tree traversal. If
55+
* @skip_children is true, skip the descendant nodes of @p in
56+
* traversal. If @p is a descendant of @subtree_root, only traverse
57+
* the subtree under @subtree_root.
58+
*/
59+
static struct resource *next_resource(struct resource *p, bool skip_children,
60+
struct resource *subtree_root)
5461
{
5562
if (!skip_children && p->child)
5663
return p->child;
57-
while (!p->sibling && p->parent)
64+
while (!p->sibling && p->parent) {
5865
p = p->parent;
66+
if (p == subtree_root)
67+
return NULL;
68+
}
5969
return p->sibling;
6070
}
6171

72+
/*
73+
* Traverse the resource subtree under @_root in pre-order, excluding
74+
* @_root itself.
75+
*
76+
* NOTE: '__p' is introduced to avoid shadowing '_p' outside of loop.
77+
* And it is referenced to avoid unused variable warning.
78+
*/
6279
#define for_each_resource(_root, _p, _skip_children) \
63-
for ((_p) = (_root)->child; (_p); (_p) = next_resource(_p, _skip_children))
80+
for (typeof(_root) __root = (_root), __p = _p = __root->child; \
81+
__p && _p; _p = next_resource(_p, _skip_children, __root))
6482

6583
#ifdef CONFIG_PROC_FS
6684

@@ -88,7 +106,7 @@ static void *r_next(struct seq_file *m, void *v, loff_t *pos)
88106

89107
(*pos)++;
90108

91-
return (void *)next_resource(p, false);
109+
return (void *)next_resource(p, false, NULL);
92110
}
93111

94112
static void r_stop(struct seq_file *m, void *v)

0 commit comments

Comments
 (0)