Skip to content

Commit 0829f6d

Browse files
pantoniouglikely
authored andcommitted
of: device_node kobject lifecycle fixes
After the move to having device nodes be proper kobjects the lifecycle of the node needs to be controlled better. At first convert of_add_node() in the unflattened functions to of_init_node() which initializes the kobject so that of_node_get/put work correctly even before of_init is called. Afterwards introduce of_node_is_initialized & of_node_is_attached that query the underlying kobject about the state (attached means kobj is visible in sysfs) Using that make sure the lifecycle of the tree is correct at all times. Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com> [grant.likely: moved of_node_init() calls, fixed up locking, and dropped __of_populate() hunks] Signed-off-by: Grant Likely <grant.likely@linaro.org>
1 parent 8357041 commit 0829f6d

File tree

4 files changed

+47
-13
lines changed

4 files changed

+47
-13
lines changed

drivers/of/base.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,19 @@ static int __of_node_add(struct device_node *np)
246246
int of_node_add(struct device_node *np)
247247
{
248248
int rc = 0;
249-
kobject_init(&np->kobj, &of_node_ktype);
249+
250+
BUG_ON(!of_node_is_initialized(np));
251+
252+
/*
253+
* Grab the mutex here so that in a race condition between of_init() and
254+
* of_node_add(), node addition will still be consistent.
255+
*/
250256
mutex_lock(&of_aliases_mutex);
251257
if (of_kset)
252258
rc = __of_node_add(np);
259+
else
260+
/* This scenario may be perfectly valid, but report it anyway */
261+
pr_info("of_node_add(%s) before of_init()\n", np->full_name);
253262
mutex_unlock(&of_aliases_mutex);
254263
return rc;
255264
}
@@ -259,10 +268,17 @@ static void of_node_remove(struct device_node *np)
259268
{
260269
struct property *pp;
261270

262-
for_each_property_of_node(np, pp)
263-
sysfs_remove_bin_file(&np->kobj, &pp->attr);
271+
BUG_ON(!of_node_is_initialized(np));
272+
273+
/* only remove properties if on sysfs */
274+
if (of_node_is_attached(np)) {
275+
for_each_property_of_node(np, pp)
276+
sysfs_remove_bin_file(&np->kobj, &pp->attr);
277+
kobject_del(&np->kobj);
278+
}
264279

265-
kobject_del(&np->kobj);
280+
/* finally remove the kobj_init ref */
281+
of_node_put(np);
266282
}
267283
#endif
268284

@@ -1631,6 +1647,10 @@ static int of_property_notify(int action, struct device_node *np,
16311647
{
16321648
struct of_prop_reconfig pr;
16331649

1650+
/* only call notifiers if the node is attached */
1651+
if (!of_node_is_attached(np))
1652+
return 0;
1653+
16341654
pr.dn = np;
16351655
pr.prop = prop;
16361656
return of_reconfig_notify(action, &pr);
@@ -1682,11 +1702,8 @@ int of_add_property(struct device_node *np, struct property *prop)
16821702
if (rc)
16831703
return rc;
16841704

1685-
/* at early boot, bail hear and defer setup to of_init() */
1686-
if (!of_kset)
1687-
return 0;
1688-
1689-
__of_add_property_sysfs(np, prop);
1705+
if (of_node_is_attached(np))
1706+
__of_add_property_sysfs(np, prop);
16901707

16911708
return rc;
16921709
}

drivers/of/fdt.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
202202
__alignof__(struct device_node));
203203
if (allnextpp) {
204204
char *fn;
205+
of_node_init(np);
205206
np->full_name = fn = ((char *)np) + sizeof(*np);
206207
if (new_format) {
207208
/* rebuild full path for new format */
@@ -326,8 +327,6 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
326327
np->name = "<NULL>";
327328
if (!np->type)
328329
np->type = "<NULL>";
329-
330-
of_node_add(np);
331330
}
332331
while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
333332
if (tag == OF_DT_NOP)

drivers/of/pdt.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ static struct device_node * __init of_pdt_create_node(phandle node,
176176
return NULL;
177177

178178
dp = prom_early_alloc(sizeof(*dp));
179+
of_node_init(dp);
179180
of_pdt_incr_unique_id(dp);
180181
dp->parent = parent;
181182

@@ -213,7 +214,6 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
213214
*nextp = &dp->allnext;
214215

215216
dp->full_name = of_pdt_build_full_name(dp);
216-
of_node_add(dp);
217217

218218
dp->child = of_pdt_build_tree(dp,
219219
of_pdt_prom_ops->getchild(node), nextp);
@@ -244,7 +244,6 @@ void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
244244
of_allnodes->path_component_name = "";
245245
#endif
246246
of_allnodes->full_name = "/";
247-
of_node_add(of_allnodes);
248247

249248
nextp = &of_allnodes->allnext;
250249
of_allnodes->child = of_pdt_build_tree(of_allnodes,

include/linux/of.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,25 @@ struct of_phandle_args {
7676

7777
extern int of_node_add(struct device_node *node);
7878

79+
/* initialize a node */
80+
extern struct kobj_type of_node_ktype;
81+
static inline void of_node_init(struct device_node *node)
82+
{
83+
kobject_init(&node->kobj, &of_node_ktype);
84+
}
85+
86+
/* true when node is initialized */
87+
static inline int of_node_is_initialized(struct device_node *node)
88+
{
89+
return node && node->kobj.state_initialized;
90+
}
91+
92+
/* true when node is attached (i.e. present on sysfs) */
93+
static inline int of_node_is_attached(struct device_node *node)
94+
{
95+
return node && node->kobj.state_in_sysfs;
96+
}
97+
7998
#ifdef CONFIG_OF_DYNAMIC
8099
extern struct device_node *of_node_get(struct device_node *node);
81100
extern void of_node_put(struct device_node *node);

0 commit comments

Comments
 (0)