devres: provide and use devm_krealloc()
Subsystems (5)
v3 cover devres: provide and use devm_krealloc()
From: Bartosz Golaszewski <[email protected]>
Hi Greg,
As discussed, resending the remaining devm_krealloc() patches.
===
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
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 | 50 +++++++++++++++++++ drivers/hwmon/pmbus/pmbus_core.c | 28 ++++------- drivers/iio/adc/xilinx-xadc-core.c | 16 +++--- include/linux/device.h | 2 + 5 files changed, 70 insertions(+), 27 deletions(-)
Signature · 1 line
2.26.1
PATCH v3 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 | 50 +++++++++++++++++++ include/linux/device.h | 2 + 3 files changed, 53 insertions(+)
Documentation/driver-api/driver-model/devres.rst +1 -0
@@ -353,6 +353,7 @@ MEM devm_kfree() devm_kmalloc() devm_kmalloc_array() + devm_krealloc() devm_kmemdup() devm_kstrdup() devm_kvasprintf()
drivers/base/devres.c +50 -0
56 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 v3 1/3] devres: provide devm_krealloc()
Quoted 8 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().
...
Quoted 7 lines
devm_kfree()
devm_kmalloc()
devm_kmalloc_array()
+devm_krealloc()
devm_kmemdup()
devm_kstrdup()
devm_kvasprintf()
Order?
...
Quoted 1 line
+void *devm_krealloc(struct device *dev, void *ptr,
size_tnew_size,gfp_tgfp)
Do we really need the 'new_' prefix in the parameter?
drivers/base/devres.c void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) · line 846
Quoted 6 lines
drivers/base/devres.c +6
-0+{ +struct devres *old_dr, *new_dr; +struct list_head old_head; +unsigned long flags; +void *ret =NULL ; +size_t tot_size;
tot -> total.
drivers/base/devres.c void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) · line 851
Quoted 5 lines
drivers/base/devres.c +5
-0+ +if (unlikely (!new_size)) { +devm_kfree (dev, ptr); +return ZERO_SIZE_PTR ; + }
I guess here we need a comment of the possibilities below to have ZERO_SIZE_PTR as input.
Quoted 8 lines
drivers/base/devres.c +8
-0+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(). +*/
drivers/base/devres.c void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) · line 869
Quoted 10 lines
drivers/base/devres.c +9
-0+return NULL ; + +if (!check_dr_size (new_size, &tot_size)) +return NULL ; + +spin_lock_irqsave (&dev->devres_lock, flags); + + old_dr =find_dr (dev, devm_kmalloc_release, devm_kmalloc_match, ptr); +if (WARN_ON (!old_dr))
Under spin lock? I would rather see spin unlock followed by WARN.
Quoted 18 lines
drivers/base/devres.c +18
-0+/* Memory chunk not managed or managed by a different device. */ + goto out; + + old_head = old_dr->node.entry; + + new_dr =krealloc (old_dr, tot_size, gfp); +if (!new_dr) + goto out; + +if (new_dr != old_dr) +list_replace (&old_head, &new_dr->node.entry); + + ret = new_dr->data; + +out: +spin_unlock_irqrestore (&dev->devres_lock, flags); +return ret; +}
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v3 1/3] devres: provide devm_krealloc()
Quoted 21 lines · Andy Shevchenko
Quoted 8 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()....
Quoted 7 lines
devm_kfree()
devm_kmalloc()
devm_kmalloc_array()
+devm_krealloc()
devm_kmemdup()
devm_kstrdup()
devm_kvasprintf()
Quoted 2 lines
Order?
I didn't notice these were ordered alphabetically, I thought it was by functionality.
Quoted 6 lines
...
Quoted 1 line
+void *devm_krealloc(struct device *dev, void *ptr,
size_tnew_size,gfp_tgfp)Do we really need the '
new_' prefix in the parameter?
Yes, I think this is a good name for a function that's meant to modify the size of a memory chunk.
Quoted 9 lines
drivers/base/devres.c void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) · line 846
Quoted 6 lines
drivers/base/devres.c +6
-0+{ +struct devres *old_dr, *new_dr; +struct list_head old_head; +unsigned long flags; +void *ret =NULL ; +size_t tot_size;tot -> total.
Meh, ok.
Quoted 9 lines
drivers/base/devres.c void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) · line 851
Quoted 5 lines
drivers/base/devres.c +5
-0+ +if (unlikely (!new_size)) { +devm_kfree (dev, ptr); +return ZERO_SIZE_PTR ; + }I guess here we need a comment of the possibilities below to have
ZERO_SIZE_PTRas input.
Better yet: I'll just add a kernel doc for this function.
Quoted 17 lines
Quoted 16 lines
drivers/base/devres.c +16
-0+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, &tot_size)) +return NULL ; + +spin_lock_irqsave (&dev->devres_lock, flags); + + old_dr =find_dr (dev, devm_kmalloc_release, devm_kmalloc_match, ptr);
Quoted 4 lines
Quoted 1 line
+ if (
WARN_ON(!old_dr))Under spin lock? I would rather see spin unlock followed by WARN.
Yeah, can be done.
Quoted 14 lines
Quoted 14 lines
drivers/base/devres.c +14
-0+/* Memory chunk not managed or managed by a different device. */ + goto out; + + old_head = old_dr->node.entry; + + new_dr =krealloc (old_dr, tot_size, gfp); +if (!new_dr) + goto out; + +if (new_dr != old_dr) +list_replace (&old_head, &new_dr->node.entry); + + ret = new_dr->data; +
Quoted 8 lines
drivers/base/devres.c void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) · line 887
Quoted 4 lines
drivers/base/devres.c +4
-0+out: +spin_unlock_irqrestore (&dev->devres_lock, flags); +return ret; +}--
With Best Regards,
Andy Shevchenko
Bartosz
PATCH v3 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 v3 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