From bec84da8d1da6677c458e6eedd8e814eea91b9fc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 2 Feb 2017 17:41:25 -0800 Subject: device property: allow to constify properties There is no reason why statically defined properties should be modifiable, so let's make device_add_properties() and the rest of pset_*() functions to take const pointers to properties. This will allow us to mark properties as const/__initconst at definition sites. Signed-off-by: Dmitry Torokhov Reviewed-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/property.c b/drivers/base/property.c index 43a36d68c3fd..e9fa75645d69 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -21,7 +21,7 @@ struct property_set { struct fwnode_handle fwnode; - struct property_entry *properties; + const struct property_entry *properties; }; static inline bool is_pset_node(struct fwnode_handle *fwnode) @@ -35,10 +35,10 @@ static inline struct property_set *to_pset_node(struct fwnode_handle *fwnode) container_of(fwnode, struct property_set, fwnode) : NULL; } -static struct property_entry *pset_prop_get(struct property_set *pset, - const char *name) +static const struct property_entry *pset_prop_get(struct property_set *pset, + const char *name) { - struct property_entry *prop; + const struct property_entry *prop; if (!pset || !pset->properties) return NULL; @@ -50,11 +50,11 @@ static struct property_entry *pset_prop_get(struct property_set *pset, return NULL; } -static void *pset_prop_find(struct property_set *pset, const char *propname, - size_t length) +static const void *pset_prop_find(struct property_set *pset, + const char *propname, size_t length) { - struct property_entry *prop; - void *pointer; + const struct property_entry *prop; + const void *pointer; prop = pset_prop_get(pset, propname); if (!prop) @@ -74,7 +74,7 @@ static int pset_prop_read_u8_array(struct property_set *pset, const char *propname, u8 *values, size_t nval) { - void *pointer; + const void *pointer; size_t length = nval * sizeof(*values); pointer = pset_prop_find(pset, propname, length); @@ -89,7 +89,7 @@ static int pset_prop_read_u16_array(struct property_set *pset, const char *propname, u16 *values, size_t nval) { - void *pointer; + const void *pointer; size_t length = nval * sizeof(*values); pointer = pset_prop_find(pset, propname, length); @@ -104,7 +104,7 @@ static int pset_prop_read_u32_array(struct property_set *pset, const char *propname, u32 *values, size_t nval) { - void *pointer; + const void *pointer; size_t length = nval * sizeof(*values); pointer = pset_prop_find(pset, propname, length); @@ -119,7 +119,7 @@ static int pset_prop_read_u64_array(struct property_set *pset, const char *propname, u64 *values, size_t nval) { - void *pointer; + const void *pointer; size_t length = nval * sizeof(*values); pointer = pset_prop_find(pset, propname, length); @@ -133,7 +133,7 @@ static int pset_prop_read_u64_array(struct property_set *pset, static int pset_prop_count_elems_of_size(struct property_set *pset, const char *propname, size_t length) { - struct property_entry *prop; + const struct property_entry *prop; prop = pset_prop_get(pset, propname); if (!prop) @@ -146,7 +146,7 @@ static int pset_prop_read_string_array(struct property_set *pset, const char *propname, const char **strings, size_t nval) { - void *pointer; + const void *pointer; size_t length = nval * sizeof(*strings); pointer = pset_prop_find(pset, propname, length); @@ -160,8 +160,8 @@ static int pset_prop_read_string_array(struct property_set *pset, static int pset_prop_read_string(struct property_set *pset, const char *propname, const char **strings) { - struct property_entry *prop; - const char **pointer; + const struct property_entry *prop; + const char * const *pointer; prop = pset_prop_get(pset, propname); if (!prop) @@ -776,7 +776,7 @@ static int pset_copy_entry(struct property_entry *dst, */ static struct property_set *pset_copy_set(const struct property_set *pset) { - const struct property_entry *entry; + struct property_entry *props; struct property_set *p; size_t i, n = 0; @@ -787,14 +787,14 @@ static struct property_set *pset_copy_set(const struct property_set *pset) while (pset->properties[n].name) n++; - p->properties = kcalloc(n + 1, sizeof(*entry), GFP_KERNEL); + p->properties = props = kcalloc(n + 1, sizeof(*props), GFP_KERNEL); if (!p->properties) { kfree(p); return ERR_PTR(-ENOMEM); } for (i = 0; i < n; i++) { - int ret = pset_copy_entry(&p->properties[i], + int ret = pset_copy_entry(&props[i], &pset->properties[i]); if (ret) { pset_free_set(p); @@ -847,7 +847,8 @@ EXPORT_SYMBOL_GPL(device_remove_properties); * @dev as its secondary firmware node. The function takes a copy of * @properties. */ -int device_add_properties(struct device *dev, struct property_entry *properties) +int device_add_properties(struct device *dev, + const struct property_entry *properties) { struct property_set *p, pset; -- cgit From 9426998ce6f8616c48c2834cafbe5616da3f5abd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 2 Feb 2017 17:41:26 -0800 Subject: device property: constify property arrays values Data that is fed into property arrays should not be modified, so let's mark relevant pointers as const. This will allow us making source arrays as const/__initconst. Signed-off-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/property.c b/drivers/base/property.c index e9fa75645d69..31b942a29fdc 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -718,7 +718,8 @@ static void pset_free_set(struct property_set *pset) static int pset_copy_entry(struct property_entry *dst, const struct property_entry *src) { - const char **d, **s; + const char * const *s; + char **d; size_t i, nval; dst->name = kstrdup(src->name, GFP_KERNEL); @@ -731,12 +732,11 @@ static int pset_copy_entry(struct property_entry *dst, if (src->is_string) { nval = src->length / sizeof(const char *); - dst->pointer.str = kcalloc(nval, sizeof(const char *), - GFP_KERNEL); - if (!dst->pointer.str) + d = kcalloc(nval, sizeof(const char *), GFP_KERNEL); + if (!d) return -ENOMEM; - d = dst->pointer.str; + dst->pointer.raw_data = d; s = src->pointer.str; for (i = 0; i < nval; i++) { d[i] = kstrdup(s[i], GFP_KERNEL); -- cgit From 2d479e1fa2d09c5a9518a75a5d21ef2713117946 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 2 Feb 2017 17:41:27 -0800 Subject: device property: export code duplicating array of property entries When augmenting ACPI-enumerated devices with additional property data based on DMI info, a module has often several potential property sets, with only one being active on a given box. In order to save memory it should be possible to mark everything and __initdata or __initconst, execute DMI match early, and duplicate relevant properties. Then kernel will discard the rest of them. Signed-off-by: Dmitry Torokhov Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 194 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 129 insertions(+), 65 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/property.c b/drivers/base/property.c index 31b942a29fdc..c458c63e353f 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -682,77 +682,64 @@ out: } EXPORT_SYMBOL_GPL(fwnode_property_match_string); -/** - * pset_free_set - releases memory allocated for copied property set - * @pset: Property set to release - * - * Function takes previously copied property set and releases all the - * memory allocated to it. - */ -static void pset_free_set(struct property_set *pset) +static int property_copy_string_array(struct property_entry *dst, + const struct property_entry *src) { - const struct property_entry *prop; - size_t i, nval; + char **d; + size_t nval = src->length / sizeof(*d); + int i; - if (!pset) - return; + d = kcalloc(nval, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; - for (prop = pset->properties; prop->name; prop++) { - if (prop->is_array) { - if (prop->is_string && prop->pointer.str) { - nval = prop->length / sizeof(const char *); - for (i = 0; i < nval; i++) - kfree(prop->pointer.str[i]); - } - kfree(prop->pointer.raw_data); - } else if (prop->is_string) { - kfree(prop->value.str); + for (i = 0; i < nval; i++) { + d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL); + if (!d[i] && src->pointer.str[i]) { + while (--i >= 0) + kfree(d[i]); + kfree(d); + return -ENOMEM; } - kfree(prop->name); } - kfree(pset->properties); - kfree(pset); + dst->pointer.raw_data = d; + return 0; } -static int pset_copy_entry(struct property_entry *dst, - const struct property_entry *src) +static int property_entry_copy_data(struct property_entry *dst, + const struct property_entry *src) { - const char * const *s; - char **d; - size_t i, nval; + int error; dst->name = kstrdup(src->name, GFP_KERNEL); if (!dst->name) return -ENOMEM; if (src->is_array) { - if (!src->length) - return -ENODATA; + if (!src->length) { + error = -ENODATA; + goto out_free_name; + } if (src->is_string) { - nval = src->length / sizeof(const char *); - d = kcalloc(nval, sizeof(const char *), GFP_KERNEL); - if (!d) - return -ENOMEM; - - dst->pointer.raw_data = d; - s = src->pointer.str; - for (i = 0; i < nval; i++) { - d[i] = kstrdup(s[i], GFP_KERNEL); - if (!d[i] && s[i]) - return -ENOMEM; - } + error = property_copy_string_array(dst, src); + if (error) + goto out_free_name; } else { dst->pointer.raw_data = kmemdup(src->pointer.raw_data, src->length, GFP_KERNEL); - if (!dst->pointer.raw_data) - return -ENOMEM; + if (!dst->pointer.raw_data) { + error = -ENOMEM; + goto out_free_name; + } } } else if (src->is_string) { dst->value.str = kstrdup(src->value.str, GFP_KERNEL); - if (!dst->value.str && src->value.str) - return -ENOMEM; + if (!dst->value.str && src->value.str) { + error = -ENOMEM; + goto out_free_name; + } } else { dst->value.raw_data = src->value.raw_data; } @@ -762,6 +749,95 @@ static int pset_copy_entry(struct property_entry *dst, dst->is_string = src->is_string; return 0; + +out_free_name: + kfree(dst->name); + return error; +} + +static void property_entry_free_data(const struct property_entry *p) +{ + size_t i, nval; + + if (p->is_array) { + if (p->is_string && p->pointer.str) { + nval = p->length / sizeof(const char *); + for (i = 0; i < nval; i++) + kfree(p->pointer.str[i]); + } + kfree(p->pointer.raw_data); + } else if (p->is_string) { + kfree(p->value.str); + } + kfree(p->name); +} + +/** + * property_entries_dup - duplicate array of properties + * @properties: array of properties to copy + * + * This function creates a deep copy of the given NULL-terminated array + * of property entries. + */ +struct property_entry * +property_entries_dup(const struct property_entry *properties) +{ + struct property_entry *p; + int i, n = 0; + + while (properties[n].name) + n++; + + p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL); + if (!p) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < n; i++) { + int ret = property_entry_copy_data(&p[i], &properties[i]); + if (ret) { + while (--i >= 0) + property_entry_free_data(&p[i]); + kfree(p); + return ERR_PTR(ret); + } + } + + return p; +} +EXPORT_SYMBOL_GPL(property_entries_dup); + +/** + * property_entries_free - free previously allocated array of properties + * @properties: array of properties to destroy + * + * This function frees given NULL-terminated array of property entries, + * along with their data. + */ +void property_entries_free(const struct property_entry *properties) +{ + const struct property_entry *p; + + for (p = properties; p->name; p++) + property_entry_free_data(p); + + kfree(properties); +} +EXPORT_SYMBOL_GPL(property_entries_free); + +/** + * pset_free_set - releases memory allocated for copied property set + * @pset: Property set to release + * + * Function takes previously copied property set and releases all the + * memory allocated to it. + */ +static void pset_free_set(struct property_set *pset) +{ + if (!pset) + return; + + property_entries_free(pset->properties); + kfree(pset); } /** @@ -776,32 +852,20 @@ static int pset_copy_entry(struct property_entry *dst, */ static struct property_set *pset_copy_set(const struct property_set *pset) { - struct property_entry *props; + struct property_entry *properties; struct property_set *p; - size_t i, n = 0; p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) return ERR_PTR(-ENOMEM); - while (pset->properties[n].name) - n++; - - p->properties = props = kcalloc(n + 1, sizeof(*props), GFP_KERNEL); - if (!p->properties) { + properties = property_entries_dup(pset->properties); + if (IS_ERR(properties)) { kfree(p); - return ERR_PTR(-ENOMEM); - } - - for (i = 0; i < n; i++) { - int ret = pset_copy_entry(&props[i], - &pset->properties[i]); - if (ret) { - pset_free_set(p); - return ERR_PTR(ret); - } + return ERR_CAST(properties); } + p->properties = properties; return p; } -- cgit