Re: [PATCH 5/5] OF: Introduce utility helper functions
From: Pantelis Antoniou
Date: Wed Nov 06 2013 - 04:34:45 EST
Hi Ionut,
On Nov 6, 2013, at 11:21 AM, Ionut Nicu wrote:
> Hi,
>
> First of all, good to see this patch set being submitted again!
>
> We're using an older version of your patch set for some time and
> they're working good for us.
>
Thanks, that's good to know.
> On 05.11.2013 18:50, ext Pantelis Antoniou wrote:
>> Introduce helper functions for working with the live DT tree.
>>
>> __of_free_property() frees a dynamically created property
>> __of_free_tree() recursively frees a device node tree
>> __of_copy_property() copies a property dynamically
>> __of_create_empty_node() creates an empty node
>> __of_find_node_by_full_name() finds the node with the full name
>> and
>> of_multi_prop_cmp() performs a multi property compare but without
>> having to take locks.
>>
>> Signed-off-by: Pantelis Antoniou <panto@xxxxxxxxxxxxxxxxxxxxxxx>
>> ---
>> drivers/of/Makefile | 2 +-
>> drivers/of/util.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>> include/linux/of.h | 59 ++++++++++++
>> 3 files changed, 313 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/of/util.c
>>
>> diff --git a/drivers/of/Makefile b/drivers/of/Makefile
>> index efd0510..9bc6d8c 100644
>> --- a/drivers/of/Makefile
>> +++ b/drivers/of/Makefile
>> @@ -1,4 +1,4 @@
>> -obj-y = base.o device.o platform.o
>> +obj-y = base.o device.o platform.o util.o
>> obj-$(CONFIG_OF_FLATTREE) += fdt.o
>> obj-$(CONFIG_OF_PROMTREE) += pdt.o
>> obj-$(CONFIG_OF_ADDRESS) += address.o
>> diff --git a/drivers/of/util.c b/drivers/of/util.c
>> new file mode 100644
>> index 0000000..5117e2b
>> --- /dev/null
>> +++ b/drivers/of/util.c
>> @@ -0,0 +1,253 @@
>> +/*
>> + * Utility functions for working with device tree(s)
>> + *
>> + * Copyright (C) 2012 Pantelis Antoniou <panto@xxxxxxxxxxxxxxxxxxxxxxx>
>> + * Copyright (C) 2012 Texas Instruments Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * version 2 as published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/string.h>
>> +#include <linux/ctype.h>
>> +#include <linux/errno.h>
>> +#include <linux/string.h>
>> +#include <linux/slab.h>
>> +#include <linux/err.h>
>> +
>> +/**
>> + * __of_free_property - release the memory of an allocated property
>> + * @prop: Property to release
>> + *
>> + * Release the memory of an allocated property only after checking
>> + * that the property has been marked as OF_DYNAMIC.
>> + * Only call on known allocated properties.
>> + */
>> +void __of_free_property(struct property *prop)
>> +{
>> + if (prop == NULL)
>> + return;
>> +
>> + if (of_property_check_flag(prop, OF_DYNAMIC)) {
>> + kfree(prop->value);
>> + kfree(prop->name);
>> + kfree(prop);
>> + } else {
>> + pr_warn("%s: property %p cannot be freed; memory is gone\n",
>> + __func__, prop);
>> + }
>> +}
>> +
>> +/**
>> + * __of_free_tree - release the memory of a device tree node and
>> + * of all it's children + properties.
>> + * @node: Device Tree node to release
>> + *
>> + * Release the memory of a device tree node and of all it's children.
>> + * Also release the properties and the dead properties.
>> + * Only call on detached node trees, and you better be sure that
>> + * no pointer exist for any properties. Only safe to do if you
>> + * absolutely control the life cycle of the node.
>> + * Also note that the node is not removed from the all_nodes list,
>> + * neither from the parent's child list; this should be handled before
>> + * calling this function.
>> + */
>> +void __of_free_tree(struct device_node *node)
>> +{
>> + struct property *prop;
>> + struct device_node *noden;
>> +
>> + /* sanity check */
>> + if (!node)
>> + return;
>> +
>> + /* free recursively any children */
>> + while ((noden = node->child) != NULL) {
>> + node->child = noden->sibling;
>> + __of_free_tree(noden);
>> + }
>> +
>> + /* free every property already allocated */
>> + while ((prop = node->properties) != NULL) {
>> + node->properties = prop->next;
>> + __of_free_property(prop);
>> + }
>> +
>> + /* free dead properties already allocated */
>> + while ((prop = node->deadprops) != NULL) {
>> + node->deadprops = prop->next;
>> + __of_free_property(prop);
>> + }
>> +
>> + if (of_node_check_flag(node, OF_DYNAMIC)) {
>> + kfree(node->type);
>> + kfree(node->name);
>> + kfree(node);
>> + } else {
>> + pr_warn("%s: node %p cannot be freed; memory is gone\n",
>> + __func__, node);
>> + }
>> +}
>> +
>> +/**
>> + * __of_copy_property - Copy a property dynamically.
>> + * @prop: Property to copy
>> + * @flags: Allocation flags (typically pass GFP_KERNEL)
>> + *
>> + * Copy a property by dynamically allocating the memory of both the
>> + * property stucture and the property name & contents. The property's
>> + * flags have the OF_DYNAMIC bit set so that we can differentiate between
>> + * dynamically allocated properties and not.
>> + * Returns the newly allocated property or NULL on out of memory error.
>> + */
>> +struct property *__of_copy_property(const struct property *prop, gfp_t flags)
>> +{
>> + struct property *propn;
>> +
>> + propn = kzalloc(sizeof(*prop), flags);
>> + if (propn == NULL)
>> + return NULL;
>> +
>> + propn->name = kstrdup(prop->name, flags);
>> + if (propn->name == NULL)
>> + goto err_fail_name;
>> +
>> + if (prop->length > 0) {
>> + propn->value = kmalloc(prop->length, flags);
>> + if (propn->value == NULL)
>> + goto err_fail_value;
>> + memcpy(propn->value, prop->value, prop->length);
>> + propn->length = prop->length;
>> + }
>
>
> I think the prop->length check, should be removed. Properties with length 0, such
> as "interrupt-controller;" have length 0 and some parts of the linux kernel actually
> rely on their value being not NULL.
>
> For example in drivers/of/irq.c, of_irq_map_raw() checks that a node is an interrupt
> controller by calling:
>
> of_get_property(ipar, "interrupt-controller", NULL)
>
> and checking that it returns a non-null value.
>
> We can safely use kmalloc with size 0 which will return ZERO_SIZE_PTR. This will cause
> all the tests for non-null values in case of zero length properties to pass.
>
> I've sent you a patch a while ago for this. I'm not sure you had time to review it.
>
I am aware of that, and your patch looks sane.
As I mentioned earlier I'm trying to get this accepted in general term and then we'll
get around fixing any minor problems.
> Thanks,
> Ionut
>
Regards
-- Pantelis
>> +
>> + /* mark the property as dynamic */
>> + of_property_set_flag(propn, OF_DYNAMIC);
>> +
>> + return propn;
>> +
>> +err_fail_value:
>> + kfree(propn->name);
>> +err_fail_name:
>> + kfree(propn);
>> + return NULL;
>> +}
>> +
>> +/**
>> + * __of_create_empty_node - Create an empty device node dynamically.
>> + * @name: Name of the new device node
>> + * @type: Type of the new device node
>> + * @full_name: Full name of the new device node
>> + * @phandle: Phandle of the new device node
>> + * @flags: Allocation flags (typically pass GFP_KERNEL)
>> + *
>> + * Create an empty device tree node, suitable for further modification.
>> + * The node data are dynamically allocated and all the node flags
>> + * have the OF_DYNAMIC & OF_DETACHED bits set.
>> + * Returns the newly allocated node or NULL on out of memory error.
>> + */
>> +struct device_node *__of_create_empty_node(
>> + const char *name, const char *type, const char *full_name,
>> + phandle phandle, gfp_t flags)
>> +{
>> + struct device_node *node;
>> +
>> + node = kzalloc(sizeof(*node), flags);
>> + if (node == NULL)
>> + return NULL;
>> +
>> + node->name = kstrdup(name, flags);
>> + if (node->name == NULL)
>> + goto err_return;
>> +
>> + node->type = kstrdup(type, flags);
>> + if (node->type == NULL)
>> + goto err_return;
>> +
>> + node->full_name = kstrdup(full_name, flags);
>> + if (node->type == NULL)
>> + goto err_return;
>> +
>> + node->phandle = phandle;
>> + kref_init(&node->kref);
>> + of_node_set_flag(node, OF_DYNAMIC);
>> + of_node_set_flag(node, OF_DETACHED);
>> +
>> + return node;
>> +
>> +err_return:
>> + __of_free_tree(node);
>> + return NULL;
>> +}
>> +
>> +/**
>> + * __of_find_node_by_full_name - Find a node with the full name recursively
>> + * @node: Root of the tree to perform the search
>> + * @full_name: Full name of the node to find.
>> + *
>> + * Find a node with the give full name by recursively following any of
>> + * the child node links.
>> + * Returns the matching node, or NULL if not found.
>> + * Note that the devtree lock is not taken, so this function is only
>> + * safe to call on either detached trees, or when devtree lock is already
>> + * taken.
>> + */
>> +struct device_node *__of_find_node_by_full_name(struct device_node *node,
>> + const char *full_name)
>> +{
>> + struct device_node *child, *found;
>> +
>> + if (node == NULL)
>> + return NULL;
>> +
>> + /* check */
>> + if (of_node_cmp(node->full_name, full_name) == 0)
>> + return node;
>> +
>> + __for_each_child_of_node(node, child) {
>> + found = __of_find_node_by_full_name(child, full_name);
>> + if (found != NULL)
>> + return found;
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +/**
>> + * of_multi_prop_cmp - Check if a property matches a value
>> + * @prop: Property to check
>> + * @value: Value to check against
>> + *
>> + * Check whether a property matches a value, using the standard
>> + * of_compat_cmp() test on each string. It is similar to the test
>> + * of_device_is_compatible() makes, but it can be performed without
>> + * taking the devtree_lock, which is required in some cases.
>> + * Returns 0 on a match, -1 on no match.
>> + */
>> +int of_multi_prop_cmp(const struct property *prop, const char *value)
>> +{
>> + const char *cp;
>> + int cplen, vlen, l;
>> +
>> + if (prop == NULL || value == NULL)
>> + return -1;
>> +
>> + cp = prop->value;
>> + cplen = prop->length;
>> + vlen = strlen(value);
>> +
>> + while (cplen > 0) {
>> + if (of_compat_cmp(cp, value, vlen) == 0)
>> + return 0;
>> + l = strlen(cp) + 1;
>> + cp += l;
>> + cplen -= l;
>> + }
>> +
>> + return -1;
>> +}
>> +
>> diff --git a/include/linux/of.h b/include/linux/of.h
>> index a56c450..9d69bd2 100644
>> --- a/include/linux/of.h
>> +++ b/include/linux/of.h
>> @@ -662,4 +662,63 @@ extern void proc_device_tree_update_prop(struct proc_dir_entry *pde,
>> struct property *oldprop);
>> #endif
>>
>> +/**
>> + * General utilities for working with live trees.
>> + *
>> + * All functions with two leading underscores operate
>> + * without taking node references, so you either have to
>> + * own the devtree lock or work on detached trees only.
>> + */
>> +
>> +#ifdef CONFIG_OF
>> +
>> +/* iterator for internal use; not references, neither affects devtree lock */
>> +#define __for_each_child_of_node(dn, chld) \
>> + for (chld = (dn)->child; chld != NULL; chld = chld->sibling)
>> +
>> +void __of_free_property(struct property *prop);
>> +void __of_free_tree(struct device_node *node);
>> +struct property *__of_copy_property(const struct property *prop, gfp_t flags);
>> +struct device_node *__of_create_empty_node( const char *name,
>> + const char *type, const char *full_name,
>> + phandle phandle, gfp_t flags);
>> +struct device_node *__of_find_node_by_full_name(struct device_node *node,
>> + const char *full_name);
>> +int of_multi_prop_cmp(const struct property *prop, const char *value);
>> +
>> +#else /* !CONFIG_OF */
>> +
>> +#define __for_each_child_of_node(dn, chld) \
>> + while (0)
>> +
>> +static inline void __of_free_property(struct property *prop) { }
>> +
>> +static inline void __of_free_tree(struct device_node *node) { }
>> +
>> +static inline struct property *__of_copy_property(const struct property *prop,
>> + gfp_t flags)
>> +{
>> + return NULL;
>> +}
>> +
>> +static inline struct device_node *__of_create_empty_node( const char *name,
>> + const char *type, const char *full_name,
>> + phandle phandle, gfp_t flags)
>> +{
>> + return NULL;
>> +}
>> +
>> +static inline struct device_node *__of_find_node_by_full_name(struct device_node *node,
>> + const char *full_name)
>> +{
>> + return NULL;
>> +}
>> +
>> +static inline int of_multi_prop_cmp(const struct property *prop, const char *value)
>> +{
>> + return -1;
>> +}
>> +
>> +#endif /* !CONFIG_OF */
>> +
>> #endif /* _LINUX_OF_H */
>>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/