devres: provide and use devm_krealloc()
Subsystems (5)
v4 cover devres: provide and use devm_krealloc()
From: Bartosz Golaszewski <[email protected]>
Regular krealloc() obviously can't work with managed memory. This series implements devm_krealloc() and adds the first users with hope that this helper will be adopted by other drivers currently using non-managed krealloc().
Some additional changes to the code modified by main patches are included.
v1 -> v2:
- remove leftover call to hwmon_device_unregister() from pmbus_core.c
- add a patch extending devm_kmalloc() to handle zero size case
- use WARN_ON() instead of WARN_ONCE() in devm_krealloc() when passed a pointer to non-managed memory
- correctly handle the case when devm_krealloc() is passed a pointer to memory in .rodata (potentially returned by devm_kstrdup_const())
- correctly handle ZERO_SIZE_PTR passed as the ptr argument in devm_krealloc()
v2 -> v3:
- drop already applied patches
- collect Acks
- add an additional user in iio
v3 -> v4:
- add the kerneldoc for devm_krealloc()
- WARN() outside of spinlock
- rename local variable
Bartosz Golaszewski (3):
devres: provide devm_krealloc()
hwmon: pmbus: use more devres helpers
iio: adc: xilinx-xadc: use devm_krealloc()
.../driver-api/driver-model/devres.rst | 1 + drivers/base/devres.c | 67 +++++++++++++++++++ drivers/hwmon/pmbus/pmbus_core.c | 28 +++----- drivers/iio/adc/xilinx-xadc-core.c | 16 ++--- include/linux/device.h | 2 + 5 files changed, 87 insertions(+), 27 deletions(-)
Signature · 1 line
2.26.1
PATCH v4 1/3 devres: provide devm_krealloc()
From: Bartosz Golaszewski <[email protected]>
Implement the managed variant of krealloc(). This function works with all memory allocated by devm_kmalloc() (or devres functions using it implicitly like devm_kmemdup(), devm_kstrdup() etc.).
Managed realloc'ed chunks can be manually released with devm_kfree().
--- .../driver-api/driver-model/devres.rst | 1 + drivers/base/devres.c | 67 +++++++++++++++++++ include/linux/device.h | 2 + 3 files changed, 70 insertions(+)
Documentation/driver-api/driver-model/devres.rst +1 -0
@@ -354,6 +354,7 @@ MEM devm_kmalloc() devm_kmalloc_array() devm_kmemdup() + devm_krealloc() devm_kstrdup() devm_kvasprintf() devm_kzalloc()
drivers/base/devres.c +67 -0
73 lines not on this page · raw message
include/linux/device.h +2 -0
@@ -206,6 +206,8 @@ int devres_release_group(struct device *dev, void *id);/* managed devm_k.alloc/kfree for device drivers */ void *devm_kmalloc (struct device *dev,size_t size,gfp_t gfp) __malloc; +void *devm_krealloc (struct device *dev,void *ptr,size_t size, +gfp_t gfp)__must_check ; __printf(3, 0) char *devm_kvasprintf(struct device *dev, gfp_t gfp,const char *fmt,va_list ap) __malloc; __printf(3, 4) char *devm_kasprintf(struct device *dev, gfp_t gfp,
Signature · 1 line
2.26.1
Re: [PATCH v4 1/3] devres: provide devm_krealloc()
Quoted 35 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
Implement the managed variant of
krealloc(). This function works with all memory allocated bydevm_kmalloc()(or devres functions using it implicitly likedevm_kmemdup(),devm_kstrdup()etc.).Managed realloc'ed chunks can be manually released with
devm_kfree().Signed-off-by Bartosz Golaszewski <[email protected]>--- .../driver-api/driver-model/devres.rst | 1 + drivers/base/devres.c | 67 +++++++++++++++++++ include/linux/device.h | 2 + 3 files changed, 70 insertions(+)Documentation/driver-api/driver-model/devres.rst +1
-0@@ -354,6 +354,7 @@ MEM devm_kmalloc() devm_kmalloc_array() devm_kmemdup() + devm_krealloc() devm_kstrdup() devm_kvasprintf() devm_kzalloc()drivers/base/devres.c +0
-0@@ -837,6 +837,73 @@ void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) }EXPORT_SYMBOL_GPL (devm_kmalloc);
drivers/base/devres.c void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) · line 849
Quoted 10 lines
drivers/base/devres.c +10
-0+/** +* devm_krealloc - Resource-managed krealloc() +* @dev: Device to re-allocate memory for +* @ptr: Pointer to the memory chunk to re-allocate +* @new_size: New allocation size +* @gfp: Allocation gfp flags +* +* Managed krealloc(). Resizes the memory chunk allocated with devm_kmalloc(). +* Behaves similarly to regular krealloc(): if @ptr is NULL or ZERO_SIZE_PTR, +* it's the equivalent of devm_kmalloc(). If new_size is zero, it returns
'it frees the previously allocated memory and returns'
drivers/base/devres.c void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
Quoted 3 lines
drivers/base/devres.c +3
-0+* ZERO_SIZE_PTR. This function doesn't change the order in which the release +* callback for the re-alloc'ed devres will be called (except when falling back +* to devm_kmalloc()
'or when freeing resources when new_size is zero'
Quoted 63 lines
). The contents of the memory are preserved up to the
+ * lesser of new and old sizes.
+ */drivers/base/devres.c +52
-0+void *devm_krealloc (struct device *dev,void *ptr,size_t new_size,gfp_t gfp) +{ +struct devres *old_dr, *new_dr; +struct list_head old_head; +unsigned long flags; +size_t total_size; +void *ret =NULL ; + +if (unlikely (!new_size)) { +devm_kfree (dev, ptr); +return ZERO_SIZE_PTR ; + } + +if (unlikely (ZERO_OR_NULL_PTR (ptr))) +return devm_kmalloc (dev, new_size, gfp); + +if (WARN_ON (is_kernel_rodata ((unsigned long )ptr))) +/* +* We cannot reliably realloc a const string returned by +* devm_kstrdup_const(). +*/ +return NULL ; + +if (!check_dr_size (new_size, &total_size)) +return NULL ; + +spin_lock_irqsave (&dev->devres_lock, flags); + + old_dr =find_dr (dev, devm_kmalloc_release, devm_kmalloc_match, ptr); +if (!old_dr) { +spin_unlock_irqrestore (&dev->devres_lock, flags); +WARN (1 ,"Memory chunk not managed or managed by a different device." ); +return NULL ; + } + + old_head = old_dr->node.entry; + + new_dr =krealloc (old_dr, total_size, gfp); +if (!new_dr) { +spin_unlock_irqrestore (&dev->devres_lock, flags); +return NULL ; + } + +if (new_dr != old_dr) +list_replace (&old_head, &new_dr->node.entry); + + ret = new_dr->data; +spin_unlock_irqrestore (&dev->devres_lock, flags); +return ret; +} +EXPORT_SYMBOL_GPL (devm_krealloc); +/** * devm_kstrdup - Allocate resource managed space and * copy an existing string into that. include/linux/device.h +0
-0
include/linux/device.h int devres_release_group(struct device *dev, void *id); · line 211
Quoted 6 lines
include/linux/device.h +2
-0@@ -206,6 +206,8 @@ int devres_release_group(struct device *dev, void *id);/* managed devm_k.alloc/kfree for device drivers */ void *devm_kmalloc (struct device *dev,size_t size,gfp_t gfp) __malloc; +void *devm_krealloc (struct device *dev,void *ptr,size_t size, +gfp_t gfp)__must_check ;
Strange indentation, also you can move __must_check to the beginning of the declaration.
Quoted 6 lines
include/linux/device.h +0
-0__printf(3, 0) char *devm_kvasprintf(struct device *dev, gfp_t gfp,const char *fmt,va_list ap) __malloc;
__printf(3, 4)char *devm_kasprintf(struct device *dev,gfp_tgfp,Signature · 1 line
2.26.1
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v4 1/3] devres: provide devm_krealloc()
Quoted 50 lines · Andy Shevchenko
Quoted 35 lines · Bartosz Golaszewski
From: Bartosz Golaszewski <[email protected]>
Implement the managed variant of
krealloc(). This function works with all memory allocated bydevm_kmalloc()(or devres functions using it implicitly likedevm_kmemdup(),devm_kstrdup()etc.).Managed realloc'ed chunks can be manually released with
devm_kfree().Signed-off-by Bartosz Golaszewski <[email protected]>--- .../driver-api/driver-model/devres.rst | 1 + drivers/base/devres.c | 67 +++++++++++++++++++ include/linux/device.h | 2 + 3 files changed, 70 insertions(+)Documentation/driver-api/driver-model/devres.rst +1
-0@@ -354,6 +354,7 @@ MEM devm_kmalloc() devm_kmalloc_array() devm_kmemdup() + devm_krealloc() devm_kstrdup() devm_kvasprintf() devm_kzalloc()drivers/base/devres.c +0
-0@@ -837,6 +837,73 @@ void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) }EXPORT_SYMBOL_GPL (devm_kmalloc);drivers/base/devres.c void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) · line 849
Quoted 10 lines
drivers/base/devres.c +10
-0+/** +* devm_krealloc - Resource-managed krealloc() +* @dev: Device to re-allocate memory for +* @ptr: Pointer to the memory chunk to re-allocate +* @new_size: New allocation size +* @gfp: Allocation gfp flags +* +* Managed krealloc(). Resizes the memory chunk allocated with devm_kmalloc(). +* Behaves similarly to regular krealloc(): if @ptr is NULL or ZERO_SIZE_PTR, +* it's the equivalent of devm_kmalloc(). If new_size is zero, it returns 'it frees the previously allocated memory and returns'
Quoted 6 lines
drivers/base/devres.c void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
Quoted 3 lines
drivers/base/devres.c +3
-0+* ZERO_SIZE_PTR. This function doesn't change the order in which the release +* callback for the re-alloc'ed devres will be called (except when falling back +* to devm_kmalloc() 'or when freeing resources when
new_sizeis zero'
This is nit-picking but ok. :)
[snip!]
Quoted 12 lines
drivers/base/devres.c int devres_release_group(struct device *dev, void *id); · line 211
Quoted 8 lines
drivers/base/devres.c +3
-0+++ b/include/linux/device.h@@ -206,6 +206,8 @@ int devres_release_group(struct device *dev, void *id);/* managed devm_k.alloc/kfree for device drivers */ void *devm_kmalloc (struct device *dev,size_t size,gfp_t gfp) __malloc; +void *devm_krealloc (struct device *dev,void *ptr,size_t size, +gfp_t gfp)__must_check ;Strange indentation, also you can move
__must_checkto the beginning of the declaration.
There's nothing wrong with this indentation, what do you mean? __must_check is usually put at the end of the line.
[snip!]
Bart
PATCH v4 2/3 hwmon: pmbus: use more devres helpers
In reply to Bartosz GolaszewskiFrom: Bartosz Golaszewski <[email protected]>
Shrink pmbus code by using devm_hwmon_device_register_with_groups() and devm_krealloc() instead of their non-managed variants.
--- drivers/hwmon/pmbus/pmbus_core.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-)
drivers/hwmon/pmbus/pmbus_core.c +9 -19
@@ -1018,9 +1018,9 @@ static int pmbus_add_attribute(struct pmbus_data *data, struct attribute *attr) {if (data->num_attributes >= data->max_attributes -1 ) {int new_max_attrs = data->max_attributes +PMBUS_ATTR_ALLOC_SIZE ; -void *new_attrs =krealloc (data->group.attrs, - new_max_attrs *sizeof (void *), -GFP_KERNEL ); +void *new_attrs =devm_krealloc (data->dev, data->group.attrs, + new_max_attrs *sizeof (void *), +GFP_KERNEL );if (!new_attrs)return -ENOMEM ; data->group.attrs = new_attrs;
@@ -2534,7 +2534,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, ret =pmbus_find_attributes (client, data);if (ret) - goto out_kfree; +return ret;/* * If there are no attributes, something is wrong.
@@ -2542,35 +2542,27 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,*/ if (!data->num_attributes) {dev_err (dev,"No attributes found\n" ); - ret = -ENODEV ; - goto out_kfree; +return -ENODEV ; } data->groups[0 ] = &data->group;memcpy (data->groups +1 , info->groups,sizeof (void *) * groups_num); - data->hwmon_dev =hwmon_device_register_with_groups (dev, client->name, - data, data->groups); + data->hwmon_dev =devm_hwmon_device_register_with_groups (dev, + client->name, data, data->groups);if (IS_ERR (data->hwmon_dev)) { - ret =PTR_ERR (data->hwmon_dev);dev_err (dev,"Failed to register hwmon device\n" ); - goto out_kfree; +return PTR_ERR (data->hwmon_dev); } ret =pmbus_regulator_register (data);if (ret) - goto out_unregister; +return ret; ret =pmbus_init_debugfs (client, data);if (ret)dev_warn (dev,"Failed to register debugfs\n" );return 0 ; - -out_unregister: -hwmon_device_unregister (data->hwmon_dev); -out_kfree: -kfree (data->group.attrs); -return ret; }EXPORT_SYMBOL_GPL (pmbus_do_probe);
@@ -2580,8 +2572,6 @@ int pmbus_do_remove(struct i2c_client *client)debugfs_remove_recursive (data->debugfs); -hwmon_device_unregister (data->hwmon_dev); -kfree (data->group.attrs);return 0 ; }EXPORT_SYMBOL_GPL (pmbus_do_remove);
Signature · 1 line
2.26.1
PATCH v4 3/3 iio: adc: xilinx-xadc: use devm_krealloc()
In reply to Bartosz GolaszewskiFrom: Bartosz Golaszewski <[email protected]>
Use the managed variant of krealloc() and shrink the code a bit.
--- drivers/iio/adc/xilinx-xadc-core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
drivers/iio/adc/xilinx-xadc-core.c +8 -8
@@ -1094,6 +1094,7 @@ MODULE_DEVICE_TABLE(of, xadc_of_match_table);static int xadc_parse_dt (struct iio_dev *indio_dev,struct device_node *np,unsigned int *conf) { +struct device *dev = indio_dev->dev.parent;struct xadc *xadc =iio_priv (indio_dev);struct iio_chan_spec *channels, *chan;struct device_node *chan_node, *child;
@@ -1138,7 +1139,8 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np, *conf |=XADC_CONF0_MUX |XADC_CONF0_CHAN (ext_mux_chan); } - channels =kmemdup (xadc_channels,sizeof (xadc_channels),GFP_KERNEL ); + channels =devm_kmemdup (dev, xadc_channels, +sizeof (xadc_channels),GFP_KERNEL );if (!channels)return -ENOMEM ;
@@ -1174,8 +1176,9 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,of_node_put (chan_node); indio_dev->num_channels = num_channels; - indio_dev->channels =krealloc (channels,sizeof (*channels) * - num_channels,GFP_KERNEL ); + indio_dev->channels =devm_krealloc (dev, channels, +sizeof (*channels) * num_channels, +GFP_KERNEL );/* If we can't resize the channels array, just use the original */ if (!indio_dev->channels) indio_dev->channels = channels;
@@ -1229,14 +1232,14 @@ static int xadc_probe(struct platform_device *pdev) ret =xadc_parse_dt (indio_dev, pdev->dev.of_node, &conf0);if (ret) - goto err_device_free; +return ret;if (xadc->ops->flags &XADC_FLAGS_BUFFERED ) { ret =iio_triggered_buffer_setup (indio_dev, &iio_pollfunc_store_time, &xadc_trigger_handler, &xadc_buffer_ops);if (ret) - goto err_device_free; +return ret; xadc->convst_trigger =xadc_alloc_trigger (indio_dev,"convst" );if (IS_ERR (xadc->convst_trigger)) {
@@ -1354,8 +1357,6 @@ static int xadc_probe(struct platform_device *pdev) err_triggered_buffer_cleanup:if (xadc->ops->flags &XADC_FLAGS_BUFFERED )iio_triggered_buffer_cleanup (indio_dev); -err_device_free: -kfree (indio_dev->channels);return ret; }
@@ -1375,7 +1376,6 @@ static int xadc_remove(struct platform_device *pdev)cancel_delayed_work_sync (&xadc->zynq_unmask_work);clk_disable_unprepare (xadc->clk);kfree (xadc->data); -kfree (indio_dev->channels);return 0 ; }
Signature · 1 line
2.26.1