Skip to content

Commit 55e329d

Browse files
author
Danilo Krummrich
committed
devres: add free_node callback to struct devres_node
Currently, there are three "subclasses" of struct devres_node, which are struct devres, struct devres_group, struct devres_action. release_nodes(), which only knows about the base struct devres_node, assumes that for all "subclasses" struct devres_node is the first member in the structure and calls kfree() on struct devres_node. While this technically works, we can still improve semantical correctness and type safety with a corresponding free_node() callback. Additionally, we will need this callback soon in the Rust Devres code, to allocate and free the required memory on the Rust side. Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Link: https://patch.msgid.link/20260202235210.55176-6-dakr@kernel.org Signed-off-by: Danilo Krummrich <dakr@kernel.org>
1 parent 2b5c6a1 commit 55e329d

1 file changed

Lines changed: 45 additions & 12 deletions

File tree

drivers/base/devres.c

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818

1919
struct devres_node;
2020
typedef void (*dr_node_release_t)(struct device *dev, struct devres_node *node);
21+
typedef void (*dr_node_free_t)(struct devres_node *node);
2122

2223
struct devres_node {
2324
struct list_head entry;
2425
dr_node_release_t release;
26+
dr_node_free_t free_node;
2527
const char *name;
2628
size_t size;
2729
};
@@ -46,10 +48,18 @@ struct devres_group {
4648
/* -- 8 pointers */
4749
};
4850

49-
static void devres_node_init(struct devres_node *node, dr_node_release_t release)
51+
static void devres_node_init(struct devres_node *node,
52+
dr_node_release_t release,
53+
dr_node_free_t free_node)
5054
{
5155
INIT_LIST_HEAD(&node->entry);
5256
node->release = release;
57+
node->free_node = free_node;
58+
}
59+
60+
static inline void free_node(struct devres_node *node)
61+
{
62+
node->free_node(node);
5363
}
5464

5565
static void set_node_dbginfo(struct devres_node *node, const char *name,
@@ -124,6 +134,13 @@ static void dr_node_release(struct device *dev, struct devres_node *node)
124134
dr->release(dev, dr->data);
125135
}
126136

137+
static void dr_node_free(struct devres_node *node)
138+
{
139+
struct devres *dr = container_of(node, struct devres, node);
140+
141+
kfree(dr);
142+
}
143+
127144
static __always_inline struct devres *alloc_dr(dr_release_t release,
128145
size_t size, gfp_t gfp, int nid)
129146
{
@@ -141,7 +158,7 @@ static __always_inline struct devres *alloc_dr(dr_release_t release,
141158
if (!(gfp & __GFP_ZERO))
142159
memset(dr, 0, offsetof(struct devres, data));
143160

144-
devres_node_init(&dr->node, dr_node_release);
161+
devres_node_init(&dr->node, dr_node_release, dr_node_free);
145162
dr->release = release;
146163
return dr;
147164
}
@@ -233,6 +250,11 @@ void devres_for_each_res(struct device *dev, dr_release_t release,
233250
}
234251
EXPORT_SYMBOL_GPL(devres_for_each_res);
235252

253+
static inline void free_dr(struct devres *dr)
254+
{
255+
free_node(&dr->node);
256+
}
257+
236258
/**
237259
* devres_free - Free device resource data
238260
* @res: Pointer to devres data to free
@@ -245,7 +267,7 @@ void devres_free(void *res)
245267
struct devres *dr = container_of(res, struct devres, data);
246268

247269
BUG_ON(!list_empty(&dr->node.entry));
248-
kfree(dr);
270+
free_dr(dr);
249271
}
250272
}
251273
EXPORT_SYMBOL_GPL(devres_free);
@@ -522,13 +544,10 @@ static void release_nodes(struct device *dev, struct list_head *todo)
522544
{
523545
struct devres_node *node, *tmp;
524546

525-
/* Release. Note that devres, devres_action and devres_group are
526-
* handled as devres_node in the following loop. This is safe.
527-
*/
528547
list_for_each_entry_safe_reverse(node, tmp, todo, entry) {
529548
devres_log(dev, node, "REL");
530549
node->release(dev, node);
531-
kfree(node);
550+
free_node(node);
532551
}
533552
}
534553

@@ -561,6 +580,13 @@ int devres_release_all(struct device *dev)
561580
return cnt;
562581
}
563582

583+
static void devres_group_free(struct devres_node *node)
584+
{
585+
struct devres_group *grp = container_of(node, struct devres_group, node[0]);
586+
587+
kfree(grp);
588+
}
589+
564590
/**
565591
* devres_open_group - Open a new devres group
566592
* @dev: Device to open devres group for
@@ -582,8 +608,8 @@ void *devres_open_group(struct device *dev, void *id, gfp_t gfp)
582608
if (unlikely(!grp))
583609
return NULL;
584610

585-
devres_node_init(&grp->node[0], &group_open_release);
586-
devres_node_init(&grp->node[1], &group_close_release);
611+
devres_node_init(&grp->node[0], &group_open_release, devres_group_free);
612+
devres_node_init(&grp->node[1], &group_close_release, NULL);
587613
set_node_dbginfo(&grp->node[0], "grp<", 0);
588614
set_node_dbginfo(&grp->node[1], "grp>", 0);
589615
grp->id = grp;
@@ -754,6 +780,13 @@ static void devm_action_release(struct device *dev, struct devres_node *node)
754780
devres->action.action(devres->action.data);
755781
}
756782

783+
static void devm_action_free(struct devres_node *node)
784+
{
785+
struct devres_action *action = container_of(node, struct devres_action, node);
786+
787+
kfree(action);
788+
}
789+
757790
/**
758791
* __devm_add_action() - add a custom action to list of managed resources
759792
* @dev: Device that owns the action
@@ -772,7 +805,7 @@ int __devm_add_action(struct device *dev, void (*action)(void *), void *data, co
772805
if (!devres)
773806
return -ENOMEM;
774807

775-
devres_node_init(&devres->node, devm_action_release);
808+
devres_node_init(&devres->node, devm_action_release, devm_action_free);
776809
set_node_dbginfo(&devres->node, name, sizeof(*devres));
777810

778811
devres->action.data = data;
@@ -1015,7 +1048,7 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp)
10151048
old_dr = find_dr(dev, devm_kmalloc_release, devm_kmalloc_match, ptr);
10161049
if (!old_dr) {
10171050
spin_unlock_irqrestore(&dev->devres_lock, flags);
1018-
kfree(new_dr);
1051+
free_dr(new_dr);
10191052
WARN(1, "Memory chunk not managed or managed by a different device.");
10201053
return NULL;
10211054
}
@@ -1035,7 +1068,7 @@ void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp)
10351068
* list. This is also the reason why we must not use devm_kfree() - the
10361069
* links are no longer valid.
10371070
*/
1038-
kfree(old_dr);
1071+
free_dr(old_dr);
10391072

10401073
return new_dr->data;
10411074
}

0 commit comments

Comments
 (0)