Commit 8a2b22a2 authored by Grant Likely's avatar Grant Likely

of: Make devicetree sysfs update functions consistent.

All of the DT modification functions are split into two parts, the first
part manipulates the DT data structure, and the second part updates
sysfs, but the code isn't very consistent about how the second half is
called. They don't all enforce the same rules about when it is valid to
update sysfs, and there isn't any clarity on locking.

The transactional DT modification feature that is coming also needs
access to these functions so that it can perform all the structure
changes together, and then all the sysfs updates as a second stage
instead of doing each one at a time.

Fix up the second have by creating a separate __of_*_sysfs() function
for each of the helpers. The new functions have consistent naming (ie.
of_node_add() becomes __of_attach_node_sysfs()) and all of them now
defer if of_init hasn't been called yet.

Callers of the new functions must hold the of_mutex to ensure there are
no race conditions with of_init(). The mutex ensures that there will
only ever be one writer to the tree at any given time. There can still
be any number of readers and the raw_spin_lock is still used to make
sure access to the data structure is still consistent.

Finally, put the function prototypes into of_private.h so they are
accessible to the transaction code.
Signed-off-by: default avatarPantelis Antoniou <pantelis.antoniou@konsulko.com>
[grant.likely: Changed suffix from _post to _sysfs to match existing code]
[grant.likely: Reorganized to eliminate trivial wrappers]
Signed-off-by: default avatarGrant Likely <grant.likely@linaro.org>
parent d8c50088
...@@ -37,10 +37,13 @@ struct device_node *of_chosen; ...@@ -37,10 +37,13 @@ struct device_node *of_chosen;
struct device_node *of_aliases; struct device_node *of_aliases;
static struct device_node *of_stdout; static struct device_node *of_stdout;
static struct kset *of_kset; struct kset *of_kset;
/* /*
* Used to protect the of_aliases, to hold off addition of nodes to sysfs * Used to protect the of_aliases, to hold off addition of nodes to sysfs.
* This mutex must be held whenever modifications are being made to the
* device tree. The of_{attach,detach}_node() and
* of_{add,remove,update}_property() helpers make sure this happens.
*/ */
DEFINE_MUTEX(of_mutex); DEFINE_MUTEX(of_mutex);
...@@ -127,13 +130,16 @@ static const char *safe_name(struct kobject *kobj, const char *orig_name) ...@@ -127,13 +130,16 @@ static const char *safe_name(struct kobject *kobj, const char *orig_name)
return name; return name;
} }
static int __of_add_property_sysfs(struct device_node *np, struct property *pp) int __of_add_property_sysfs(struct device_node *np, struct property *pp)
{ {
int rc; int rc;
/* Important: Don't leak passwords */ /* Important: Don't leak passwords */
bool secure = strncmp(pp->name, "security-", 9) == 0; bool secure = strncmp(pp->name, "security-", 9) == 0;
if (!of_kset || !of_node_is_attached(np))
return 0;
sysfs_bin_attr_init(&pp->attr); sysfs_bin_attr_init(&pp->attr);
pp->attr.attr.name = safe_name(&np->kobj, pp->name); pp->attr.attr.name = safe_name(&np->kobj, pp->name);
pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO;
...@@ -145,12 +151,15 @@ static int __of_add_property_sysfs(struct device_node *np, struct property *pp) ...@@ -145,12 +151,15 @@ static int __of_add_property_sysfs(struct device_node *np, struct property *pp)
return rc; return rc;
} }
static int __of_node_add(struct device_node *np) int __of_attach_node_sysfs(struct device_node *np)
{ {
const char *name; const char *name;
struct property *pp; struct property *pp;
int rc; int rc;
if (!of_kset)
return 0;
np->kobj.kset = of_kset; np->kobj.kset = of_kset;
if (!np->parent) { if (!np->parent) {
/* Nodes without parents are new top level trees */ /* Nodes without parents are new top level trees */
...@@ -172,26 +181,6 @@ static int __of_node_add(struct device_node *np) ...@@ -172,26 +181,6 @@ static int __of_node_add(struct device_node *np)
return 0; return 0;
} }
int of_node_add(struct device_node *np)
{
int rc = 0;
BUG_ON(!of_node_is_initialized(np));
/*
* Grab the mutex here so that in a race condition between of_init() and
* of_node_add(), node addition will still be consistent.
*/
mutex_lock(&of_mutex);
if (of_kset)
rc = __of_node_add(np);
else
/* This scenario may be perfectly valid, but report it anyway */
pr_info("of_node_add(%s) before of_init()\n", np->full_name);
mutex_unlock(&of_mutex);
return rc;
}
static int __init of_init(void) static int __init of_init(void)
{ {
struct device_node *np; struct device_node *np;
...@@ -204,7 +193,7 @@ static int __init of_init(void) ...@@ -204,7 +193,7 @@ static int __init of_init(void)
return -ENOMEM; return -ENOMEM;
} }
for_each_of_allnodes(np) for_each_of_allnodes(np)
__of_node_add(np); __of_attach_node_sysfs(np);
mutex_unlock(&of_mutex); mutex_unlock(&of_mutex);
/* Symlink in /proc as required by userspace ABI */ /* Symlink in /proc as required by userspace ABI */
...@@ -1689,15 +1678,17 @@ int of_add_property(struct device_node *np, struct property *prop) ...@@ -1689,15 +1678,17 @@ int of_add_property(struct device_node *np, struct property *prop)
if (rc) if (rc)
return rc; return rc;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
rc = __of_add_property(np, prop); rc = __of_add_property(np, prop);
raw_spin_unlock_irqrestore(&devtree_lock, flags); raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (rc)
return rc;
if (of_node_is_attached(np)) if (!rc)
__of_add_property_sysfs(np, prop); __of_add_property_sysfs(np, prop);
mutex_unlock(&of_mutex);
return rc; return rc;
} }
...@@ -1720,6 +1711,13 @@ int __of_remove_property(struct device_node *np, struct property *prop) ...@@ -1720,6 +1711,13 @@ int __of_remove_property(struct device_node *np, struct property *prop)
return 0; return 0;
} }
void __of_remove_property_sysfs(struct device_node *np, struct property *prop)
{
/* at early boot, bail here and defer setup to of_init() */
if (of_kset && of_node_is_attached(np))
sysfs_remove_bin_file(&np->kobj, &prop->attr);
}
/** /**
* of_remove_property - Remove a property from a node. * of_remove_property - Remove a property from a node.
* *
...@@ -1737,20 +1735,18 @@ int of_remove_property(struct device_node *np, struct property *prop) ...@@ -1737,20 +1735,18 @@ int of_remove_property(struct device_node *np, struct property *prop)
if (rc) if (rc)
return rc; return rc;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
rc = __of_remove_property(np, prop); rc = __of_remove_property(np, prop);
raw_spin_unlock_irqrestore(&devtree_lock, flags); raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (rc) if (!rc)
return rc; __of_remove_property_sysfs(np, prop);
/* at early boot, bail hear and defer setup to of_init() */
if (!of_kset)
return 0;
sysfs_remove_bin_file(&np->kobj, &prop->attr); mutex_unlock(&of_mutex);
return 0; return rc;
} }
int __of_update_property(struct device_node *np, struct property *newprop, int __of_update_property(struct device_node *np, struct property *newprop,
...@@ -1779,6 +1775,18 @@ int __of_update_property(struct device_node *np, struct property *newprop, ...@@ -1779,6 +1775,18 @@ int __of_update_property(struct device_node *np, struct property *newprop,
return 0; return 0;
} }
void __of_update_property_sysfs(struct device_node *np, struct property *newprop,
struct property *oldprop)
{
/* At early boot, bail out and defer setup to of_init() */
if (!of_kset)
return;
if (oldprop)
sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
__of_add_property_sysfs(np, newprop);
}
/* /*
* of_update_property - Update a property in a node, if the property does * of_update_property - Update a property in a node, if the property does
* not exist, add it. * not exist, add it.
...@@ -1801,22 +1809,18 @@ int of_update_property(struct device_node *np, struct property *newprop) ...@@ -1801,22 +1809,18 @@ int of_update_property(struct device_node *np, struct property *newprop)
if (rc) if (rc)
return rc; return rc;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
rc = __of_update_property(np, newprop, &oldprop); rc = __of_update_property(np, newprop, &oldprop);
raw_spin_unlock_irqrestore(&devtree_lock, flags); raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (rc)
return rc;
/* At early boot, bail out and defer setup to of_init() */ if (!rc)
if (!of_kset) __of_update_property_sysfs(np, newprop, oldprop);
return 0;
/* Update the sysfs attribute */ mutex_unlock(&of_mutex);
if (oldprop)
sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
__of_add_property_sysfs(np, newprop);
return 0; return rc;
} }
static void of_alias_add(struct alias_prop *ap, struct device_node *np, static void of_alias_add(struct alias_prop *ap, struct device_node *np,
......
...@@ -41,11 +41,13 @@ void of_node_put(struct device_node *node) ...@@ -41,11 +41,13 @@ void of_node_put(struct device_node *node)
} }
EXPORT_SYMBOL(of_node_put); EXPORT_SYMBOL(of_node_put);
static void of_node_remove(struct device_node *np) void __of_detach_node_sysfs(struct device_node *np)
{ {
struct property *pp; struct property *pp;
BUG_ON(!of_node_is_initialized(np)); BUG_ON(!of_node_is_initialized(np));
if (!of_kset)
return;
/* only remove properties if on sysfs */ /* only remove properties if on sysfs */
if (of_node_is_attached(np)) { if (of_node_is_attached(np)) {
...@@ -115,11 +117,13 @@ int of_attach_node(struct device_node *np) ...@@ -115,11 +117,13 @@ int of_attach_node(struct device_node *np)
if (rc) if (rc)
return rc; return rc;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
__of_attach_node(np); __of_attach_node(np);
raw_spin_unlock_irqrestore(&devtree_lock, flags); raw_spin_unlock_irqrestore(&devtree_lock, flags);
of_node_add(np); __of_attach_node_sysfs(np);
mutex_unlock(&of_mutex);
return 0; return 0;
} }
...@@ -174,11 +178,13 @@ int of_detach_node(struct device_node *np) ...@@ -174,11 +178,13 @@ int of_detach_node(struct device_node *np)
if (rc) if (rc)
return rc; return rc;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags); raw_spin_lock_irqsave(&devtree_lock, flags);
__of_detach_node(np); __of_detach_node(np);
raw_spin_unlock_irqrestore(&devtree_lock, flags); raw_spin_unlock_irqrestore(&devtree_lock, flags);
of_node_remove(np); __of_detach_node_sysfs(np);
mutex_unlock(&of_mutex);
return rc; return rc;
} }
......
...@@ -33,6 +33,8 @@ struct alias_prop { ...@@ -33,6 +33,8 @@ struct alias_prop {
extern struct mutex of_mutex; extern struct mutex of_mutex;
extern struct list_head aliases_lookup; extern struct list_head aliases_lookup;
extern struct kset *of_kset;
static inline struct device_node *kobj_to_device_node(struct kobject *kobj) static inline struct device_node *kobj_to_device_node(struct kobject *kobj)
{ {
...@@ -62,11 +64,19 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); ...@@ -62,11 +64,19 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags);
struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags); struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags);
extern int __of_add_property(struct device_node *np, struct property *prop); extern int __of_add_property(struct device_node *np, struct property *prop);
extern int __of_add_property_sysfs(struct device_node *np,
struct property *prop);
extern int __of_remove_property(struct device_node *np, struct property *prop); extern int __of_remove_property(struct device_node *np, struct property *prop);
extern void __of_remove_property_sysfs(struct device_node *np,
struct property *prop);
extern int __of_update_property(struct device_node *np, extern int __of_update_property(struct device_node *np,
struct property *newprop, struct property **oldprop); struct property *newprop, struct property **oldprop);
extern void __of_update_property_sysfs(struct device_node *np,
struct property *newprop, struct property *oldprop);
extern void __of_attach_node(struct device_node *np); extern void __of_attach_node(struct device_node *np);
extern int __of_attach_node_sysfs(struct device_node *np);
extern void __of_detach_node(struct device_node *np); extern void __of_detach_node(struct device_node *np);
extern void __of_detach_node_sysfs(struct device_node *np);
#endif /* _LINUX_OF_PRIVATE_H */ #endif /* _LINUX_OF_PRIVATE_H */
...@@ -74,8 +74,6 @@ struct of_phandle_args { ...@@ -74,8 +74,6 @@ struct of_phandle_args {
uint32_t args[MAX_PHANDLE_ARGS]; uint32_t args[MAX_PHANDLE_ARGS];
}; };
extern int of_node_add(struct device_node *node);
/* initialize a node */ /* initialize a node */
extern struct kobj_type of_node_ktype; extern struct kobj_type of_node_ktype;
static inline void of_node_init(struct device_node *node) static inline void of_node_init(struct device_node *node)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment