diff mbox series

[v3,06/11] iio: core: merge buffer/ & scan_elements/ attributes

Message ID 20210201145105.20459-7-alexandru.ardelean@analog.com (mailing list archive)
State New, archived
Headers show
Series iio: core,buffer: add support for multiple IIO buffers per IIO device | expand

Commit Message

Alexandru Ardelean Feb. 1, 2021, 2:51 p.m. UTC
With this change, we create a new directory for the IIO device called
buffer0, under which both the old buffer/ and scan_elements/ are stored.

This is done to simplify the addition of multiple IIO buffers per IIO
device. Otherwise we would need to add a bufferX/ and scan_elementsX/
directory for each IIO buffer.
With the current way of storing attribute groups, we can't have directories
stored under each other (i.e. scan_elements/ under buffer/), so the best
approach moving forward is to merge their attributes.

The old/legacy buffer/ & scan_elements/ groups are not stored on the opaque
IIO device object. This way the IIO buffer can have just a single
attribute_group object, saving a bit of memory when adding multiple IIO
buffers.

Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
 drivers/iio/industrialio-buffer.c | 111 +++++++++++++++++++++++-------
 include/linux/iio/buffer_impl.h   |   9 +--
 include/linux/iio/iio-opaque.h    |   4 ++
 3 files changed, 93 insertions(+), 31 deletions(-)

Comments

kernel test robot Feb. 1, 2021, 8:02 p.m. UTC | #1
Hi Alexandru,

I love your patch! Perhaps something to improve:

[auto build test WARNING on iio/togreg]
[also build test WARNING on linux/master next-20210125]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Alexandru-Ardelean/iio-core-buffer-add-support-for-multiple-IIO-buffers-per-IIO-device/20210201-233550
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
config: openrisc-randconfig-p001-20210201 (attached as .config)
compiler: or1k-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/418ff389a5a48a8a515a106734474e98d6d924ad
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Alexandru-Ardelean/iio-core-buffer-add-support-for-multiple-IIO-buffers-per-IIO-device/20210201-233550
        git checkout 418ff389a5a48a8a515a106734474e98d6d924ad
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=openrisc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/iio/industrialio-buffer.c:1306:6: warning: no previous prototype for 'iio_buffer_unregister_legacy_sysfs_groups' [-Wmissing-prototypes]
    1306 | void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev)
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iio/industrialio-buffer.c:1178:27: warning: 'iio_scan_elements_group_name' defined but not used [-Wunused-const-variable=]
    1178 | static const char * const iio_scan_elements_group_name = "scan_elements";
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/iio_buffer_unregister_legacy_sysfs_groups +1306 drivers/iio/industrialio-buffer.c

  1305	
> 1306	void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev)
  1307	{
  1308		struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
  1309	
  1310		kfree(iio_dev_opaque->legacy_buffer_group.attrs);
  1311		kfree(iio_dev_opaque->legacy_scan_el_group.attrs);
  1312	}
  1313	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Dan Carpenter Feb. 2, 2021, 6:07 a.m. UTC | #2
Hi Alexandru,

url:    https://github.com/0day-ci/linux/commits/Alexandru-Ardelean/iio-core-buffer-add-support-for-multiple-IIO-buffers-per-IIO-device/20210201-233550
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
config: arc-randconfig-m031-20210201 (attached as .config)
compiler: arc-elf-gcc (GCC) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

New smatch warnings:
drivers/iio/industrialio-buffer.c:1413 __iio_buffer_alloc_sysfs_and_mask() error: uninitialized symbol 'ret'.

vim +/ret +1413 drivers/iio/industrialio-buffer.c

e16e0a778fec8a Alexandru Ardelean 2020-09-17  1314  static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
418ff389a5a48a Alexandru Ardelean 2021-02-01  1315  					     struct iio_dev *indio_dev,
418ff389a5a48a Alexandru Ardelean 2021-02-01  1316  					     int index)
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1317  {
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1318  	struct iio_dev_attr *p;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1319  	struct attribute **attr;
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1320  	int ret, i, attrn, scan_el_attrcount, buffer_attrcount;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1321  	const struct iio_chan_spec *channels;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1322  
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1323  	buffer_attrcount = 0;
08e7e0adaa1720 Lars-Peter Clausen 2014-11-26  1324  	if (buffer->attrs) {
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1325  		while (buffer->attrs[buffer_attrcount] != NULL)
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1326  			buffer_attrcount++;
08e7e0adaa1720 Lars-Peter Clausen 2014-11-26  1327  	}
08e7e0adaa1720 Lars-Peter Clausen 2014-11-26  1328  
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1329  	scan_el_attrcount = 0;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1330  	INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1331  	channels = indio_dev->channels;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1332  	if (channels) {
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1333  		/* new magic */
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1334  		for (i = 0; i < indio_dev->num_channels; i++) {
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1335  			if (channels[i].scan_index < 0)
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1336  				continue;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1337  
ff3f7e049aef92 Alexandru Ardelean 2020-04-24  1338  			ret = iio_buffer_add_channel_sysfs(indio_dev, buffer,
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1339  							 &channels[i]);
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1340  			if (ret < 0)
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1341  				goto error_cleanup_dynamic;
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1342  			scan_el_attrcount += ret;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1343  			if (channels[i].type == IIO_TIMESTAMP)
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1344  				indio_dev->scan_index_timestamp =
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1345  					channels[i].scan_index;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1346  		}
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1347  		if (indio_dev->masklength && buffer->scan_mask == NULL) {
3862828a903d3c Andy Shevchenko    2019-03-04  1348  			buffer->scan_mask = bitmap_zalloc(indio_dev->masklength,
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1349  							  GFP_KERNEL);
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1350  			if (buffer->scan_mask == NULL) {
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1351  				ret = -ENOMEM;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1352  				goto error_cleanup_dynamic;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1353  			}
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1354  		}
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1355  	}
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1356  
418ff389a5a48a Alexandru Ardelean 2021-02-01  1357  	attrn = buffer_attrcount + scan_el_attrcount + ARRAY_SIZE(iio_buffer_attrs);
418ff389a5a48a Alexandru Ardelean 2021-02-01  1358  	attr = kcalloc(attrn + 1, sizeof(struct attribute *), GFP_KERNEL);
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1359  	if (!attr) {
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1360  		ret = -ENOMEM;
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1361  		goto error_free_scan_mask;
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1362  	}
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1363  
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1364  	memcpy(attr, iio_buffer_attrs, sizeof(iio_buffer_attrs));
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1365  	if (!buffer->access->set_length)
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1366  		attr[0] = &dev_attr_length_ro.attr;
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1367  
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1368  	if (buffer->access->flags & INDIO_BUFFER_FLAG_FIXED_WATERMARK)
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1369  		attr[2] = &dev_attr_watermark_ro.attr;
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1370  
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1371  	if (buffer->attrs)
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1372  		memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs,
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1373  		       sizeof(struct attribute *) * buffer_attrcount);
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1374  
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1375  	buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs);
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1376  
418ff389a5a48a Alexandru Ardelean 2021-02-01  1377  	attrn = buffer_attrcount;
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1378  
418ff389a5a48a Alexandru Ardelean 2021-02-01  1379  	list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
418ff389a5a48a Alexandru Ardelean 2021-02-01  1380  		attr[attrn++] = &p->dev_attr.attr;
418ff389a5a48a Alexandru Ardelean 2021-02-01  1381  
418ff389a5a48a Alexandru Ardelean 2021-02-01  1382  	buffer->buffer_group.name = kasprintf(GFP_KERNEL, "buffer%d", index);
418ff389a5a48a Alexandru Ardelean 2021-02-01  1383  	if (!buffer->buffer_group.name)
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1384  		goto error_free_buffer_attrs;

This needs to be "ret = -ENOMEM;"

e5d01923ab9239 Alexandru Ardelean 2021-02-01  1385  
418ff389a5a48a Alexandru Ardelean 2021-02-01  1386  	buffer->buffer_group.attrs = attr;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1387  
418ff389a5a48a Alexandru Ardelean 2021-02-01  1388  	ret = iio_device_register_sysfs_group(indio_dev, &buffer->buffer_group);
418ff389a5a48a Alexandru Ardelean 2021-02-01  1389  	if (ret)
418ff389a5a48a Alexandru Ardelean 2021-02-01  1390  		goto error_free_buffer_attr_group_name;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1391  
418ff389a5a48a Alexandru Ardelean 2021-02-01  1392  	/* we only need to link the legacy buffer groups for the first buffer */
418ff389a5a48a Alexandru Ardelean 2021-02-01  1393  	if (index > 0)
418ff389a5a48a Alexandru Ardelean 2021-02-01  1394  		return 0;
2dca9525701e36 Alexandru Ardelean 2021-02-01  1395  
418ff389a5a48a Alexandru Ardelean 2021-02-01  1396  	ret = iio_buffer_register_legacy_sysfs_groups(indio_dev, attr,
418ff389a5a48a Alexandru Ardelean 2021-02-01  1397  						      buffer_attrcount,
418ff389a5a48a Alexandru Ardelean 2021-02-01  1398  						      scan_el_attrcount);
2dca9525701e36 Alexandru Ardelean 2021-02-01  1399  	if (ret)
418ff389a5a48a Alexandru Ardelean 2021-02-01  1400  		goto error_free_buffer_attr_group_name;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1401  
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1402  	return 0;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1403  
418ff389a5a48a Alexandru Ardelean 2021-02-01  1404  error_free_buffer_attr_group_name:
418ff389a5a48a Alexandru Ardelean 2021-02-01  1405  	kfree(buffer->buffer_group.name);
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1406  error_free_buffer_attrs:
e5d01923ab9239 Alexandru Ardelean 2021-02-01  1407  	kfree(buffer->buffer_group.attrs);
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1408  error_free_scan_mask:
3862828a903d3c Andy Shevchenko    2019-03-04  1409  	bitmap_free(buffer->scan_mask);
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1410  error_cleanup_dynamic:
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1411  	iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1412  
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26 @1413  	return ret;
d967cb6bd4e79c Lars-Peter Clausen 2014-11-26  1414  }

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Andy Shevchenko Feb. 3, 2021, 10:02 a.m. UTC | #3
On Mon, Feb 1, 2021 at 5:28 PM Alexandru Ardelean
<alexandru.ardelean@analog.com> wrote:
>
> With this change, we create a new directory for the IIO device called
> buffer0, under which both the old buffer/ and scan_elements/ are stored.
>
> This is done to simplify the addition of multiple IIO buffers per IIO
> device. Otherwise we would need to add a bufferX/ and scan_elementsX/
> directory for each IIO buffer.
> With the current way of storing attribute groups, we can't have directories
> stored under each other (i.e. scan_elements/ under buffer/), so the best
> approach moving forward is to merge their attributes.
>
> The old/legacy buffer/ & scan_elements/ groups are not stored on the opaque
> IIO device object. This way the IIO buffer can have just a single
> attribute_group object, saving a bit of memory when adding multiple IIO
> buffers.

...

> +static int iio_buffer_register_legacy_sysfs_groups(struct iio_dev *indio_dev,
> +                                                  struct attribute **buffer_attrs,
> +                                                  int buffer_attrcount,
> +                                                  int scan_el_attrcount)
> +{
> +       struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> +       struct attribute_group *group;
> +       int ret;
> +
> +       group = &iio_dev_opaque->legacy_buffer_group;

> +       group->attrs = kcalloc(buffer_attrcount + 1,
> +                              sizeof(struct attribute *), GFP_KERNEL);
> +       if (!group->attrs)
> +               return -ENOMEM;
> +
> +       memcpy(group->attrs, buffer_attrs,
> +              buffer_attrcount * sizeof(struct attribute *));

kmemdup() ?
Perhaps introduce kmemdup_array().

> +       group->name = "buffer";
> +
> +       ret = iio_device_register_sysfs_group(indio_dev, group);
> +       if (ret)
> +               goto error_free_buffer_attrs;
> +
> +       group = &iio_dev_opaque->legacy_scan_el_group;

> +       group->attrs = kcalloc(scan_el_attrcount + 1,
> +                              sizeof(struct attribute *), GFP_KERNEL);
> +       if (!group->attrs) {
> +               ret = -ENOMEM;
> +               goto error_free_buffer_attrs;
> +       }
> +
> +       memcpy(group->attrs, &buffer_attrs[buffer_attrcount],
> +              scan_el_attrcount * sizeof(struct attribute *));

Ditto.

> +       group->name = "scan_elements";
> +
> +       ret = iio_device_register_sysfs_group(indio_dev, group);
> +       if (ret)
> +               goto error_free_scan_el_attrs;
> +
> +       return 0;
> +
> +error_free_buffer_attrs:
> +       kfree(iio_dev_opaque->legacy_buffer_group.attrs);
> +error_free_scan_el_attrs:
> +       kfree(iio_dev_opaque->legacy_scan_el_group.attrs);
> +
> +       return ret;
> +}
Alexandru Ardelean Feb. 4, 2021, 1:41 p.m. UTC | #4
On Wed, Feb 3, 2021 at 12:04 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>
> On Mon, Feb 1, 2021 at 5:28 PM Alexandru Ardelean
> <alexandru.ardelean@analog.com> wrote:
> >
> > With this change, we create a new directory for the IIO device called
> > buffer0, under which both the old buffer/ and scan_elements/ are stored.
> >
> > This is done to simplify the addition of multiple IIO buffers per IIO
> > device. Otherwise we would need to add a bufferX/ and scan_elementsX/
> > directory for each IIO buffer.
> > With the current way of storing attribute groups, we can't have directories
> > stored under each other (i.e. scan_elements/ under buffer/), so the best
> > approach moving forward is to merge their attributes.
> >
> > The old/legacy buffer/ & scan_elements/ groups are not stored on the opaque
> > IIO device object. This way the IIO buffer can have just a single
> > attribute_group object, saving a bit of memory when adding multiple IIO
> > buffers.
>
> ...
>
> > +static int iio_buffer_register_legacy_sysfs_groups(struct iio_dev *indio_dev,
> > +                                                  struct attribute **buffer_attrs,
> > +                                                  int buffer_attrcount,
> > +                                                  int scan_el_attrcount)
> > +{
> > +       struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> > +       struct attribute_group *group;
> > +       int ret;
> > +
> > +       group = &iio_dev_opaque->legacy_buffer_group;
>
> > +       group->attrs = kcalloc(buffer_attrcount + 1,
> > +                              sizeof(struct attribute *), GFP_KERNEL);
> > +       if (!group->attrs)
> > +               return -ENOMEM;
> > +
> > +       memcpy(group->attrs, buffer_attrs,
> > +              buffer_attrcount * sizeof(struct attribute *));
>
> kmemdup() ?
> Perhaps introduce kmemdup_array().

doesn't add much benefit from what i can tell;
and it complicates things with the fact that we need to add the extra
null terminator element;
[1] if we kmemdup(buffer_attrcount + 1) , the copy an extra element we
don't need, which needs to be null-ed

>
> > +       group->name = "buffer";
> > +
> > +       ret = iio_device_register_sysfs_group(indio_dev, group);
> > +       if (ret)
> > +               goto error_free_buffer_attrs;
> > +
> > +       group = &iio_dev_opaque->legacy_scan_el_group;
>
> > +       group->attrs = kcalloc(scan_el_attrcount + 1,
> > +                              sizeof(struct attribute *), GFP_KERNEL);
> > +       if (!group->attrs) {
> > +               ret = -ENOMEM;
> > +               goto error_free_buffer_attrs;
> > +       }
> > +
> > +       memcpy(group->attrs, &buffer_attrs[buffer_attrcount],
> > +              scan_el_attrcount * sizeof(struct attribute *));
>
> Ditto.

continuing from [1]
here it may be worse, because kmemdup() would copy 1 element from
undefined memory;

>
> > +       group->name = "scan_elements";
> > +
> > +       ret = iio_device_register_sysfs_group(indio_dev, group);
> > +       if (ret)
> > +               goto error_free_scan_el_attrs;
> > +
> > +       return 0;
> > +
> > +error_free_buffer_attrs:
> > +       kfree(iio_dev_opaque->legacy_buffer_group.attrs);
> > +error_free_scan_el_attrs:
> > +       kfree(iio_dev_opaque->legacy_scan_el_group.attrs);
> > +
> > +       return ret;
> > +}
>
> --
> With Best Regards,
> Andy Shevchenko
Andy Shevchenko Feb. 5, 2021, 11:07 a.m. UTC | #5
On Thu, Feb 4, 2021 at 3:41 PM Alexandru Ardelean
<ardeleanalex@gmail.com> wrote:
> On Wed, Feb 3, 2021 at 12:04 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:
> > On Mon, Feb 1, 2021 at 5:28 PM Alexandru Ardelean
> > <alexandru.ardelean@analog.com> wrote:

...

> > > +       group->attrs = kcalloc(buffer_attrcount + 1,
> > > +                              sizeof(struct attribute *), GFP_KERNEL);
> > > +       if (!group->attrs)
> > > +               return -ENOMEM;
> > > +
> > > +       memcpy(group->attrs, buffer_attrs,
> > > +              buffer_attrcount * sizeof(struct attribute *));
> >
> > kmemdup() ?
> > Perhaps introduce kmemdup_array().
>
> doesn't add much benefit from what i can tell;
> and it complicates things with the fact that we need to add the extra
> null terminator element;
> [1] if we kmemdup(buffer_attrcount + 1) , the copy an extra element we
> don't need, which needs to be null-ed

Ah, I see now. Thanks for pointing it out!


> > > +       group->attrs = kcalloc(scan_el_attrcount + 1,
> > > +                              sizeof(struct attribute *), GFP_KERNEL);
> > > +       if (!group->attrs) {
> > > +               ret = -ENOMEM;
> > > +               goto error_free_buffer_attrs;
> > > +       }
> > > +
> > > +       memcpy(group->attrs, &buffer_attrs[buffer_attrcount],
> > > +              scan_el_attrcount * sizeof(struct attribute *));
> >
> > Ditto.
>
> continuing from [1]
> here it may be worse, because kmemdup() would copy 1 element from
> undefined memory;
diff mbox series

Patch

diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 23f22be62cc7..f82decf92b7c 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -1252,8 +1252,68 @@  static struct attribute *iio_buffer_attrs[] = {
 	&dev_attr_data_available.attr,
 };
 
+static int iio_buffer_register_legacy_sysfs_groups(struct iio_dev *indio_dev,
+						   struct attribute **buffer_attrs,
+						   int buffer_attrcount,
+						   int scan_el_attrcount)
+{
+	struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+	struct attribute_group *group;
+	int ret;
+
+	group = &iio_dev_opaque->legacy_buffer_group;
+
+	group->attrs = kcalloc(buffer_attrcount + 1,
+			       sizeof(struct attribute *), GFP_KERNEL);
+	if (!group->attrs)
+		return -ENOMEM;
+
+	memcpy(group->attrs, buffer_attrs,
+	       buffer_attrcount * sizeof(struct attribute *));
+	group->name = "buffer";
+
+	ret = iio_device_register_sysfs_group(indio_dev, group);
+	if (ret)
+		goto error_free_buffer_attrs;
+
+	group = &iio_dev_opaque->legacy_scan_el_group;
+
+	group->attrs = kcalloc(scan_el_attrcount + 1,
+			       sizeof(struct attribute *), GFP_KERNEL);
+	if (!group->attrs) {
+		ret = -ENOMEM;
+		goto error_free_buffer_attrs;
+	}
+
+	memcpy(group->attrs, &buffer_attrs[buffer_attrcount],
+	       scan_el_attrcount * sizeof(struct attribute *));
+	group->name = "scan_elements";
+
+	ret = iio_device_register_sysfs_group(indio_dev, group);
+	if (ret)
+		goto error_free_scan_el_attrs;
+
+	return 0;
+
+error_free_buffer_attrs:
+	kfree(iio_dev_opaque->legacy_buffer_group.attrs);
+error_free_scan_el_attrs:
+	kfree(iio_dev_opaque->legacy_scan_el_group.attrs);
+
+	return ret;
+}
+
+void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev)
+{
+	struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
+
+	kfree(iio_dev_opaque->legacy_buffer_group.attrs);
+	kfree(iio_dev_opaque->legacy_scan_el_group.attrs);
+}
+
 static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
-					     struct iio_dev *indio_dev)
+					     struct iio_dev *indio_dev,
+					     int index)
 {
 	struct iio_dev_attr *p;
 	struct attribute **attr;
@@ -1294,8 +1354,8 @@  static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
 		}
 	}
 
-	attr = kcalloc(buffer_attrcount + ARRAY_SIZE(iio_buffer_attrs) + 1,
-		       sizeof(struct attribute *), GFP_KERNEL);
+	attrn = buffer_attrcount + scan_el_attrcount + ARRAY_SIZE(iio_buffer_attrs);
+	attr = kcalloc(attrn + 1, sizeof(struct attribute *), GFP_KERNEL);
 	if (!attr) {
 		ret = -ENOMEM;
 		goto error_free_scan_mask;
@@ -1313,37 +1373,36 @@  static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
 		       sizeof(struct attribute *) * buffer_attrcount);
 
 	buffer_attrcount += ARRAY_SIZE(iio_buffer_attrs);
-	attr[buffer_attrcount] = NULL;
 
-	buffer->buffer_group.name = "buffer";
-	buffer->buffer_group.attrs = attr;
+	attrn = buffer_attrcount;
 
-	ret = iio_device_register_sysfs_group(indio_dev, &buffer->buffer_group);
-	if (ret)
+	list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
+		attr[attrn++] = &p->dev_attr.attr;
+
+	buffer->buffer_group.name = kasprintf(GFP_KERNEL, "buffer%d", index);
+	if (!buffer->buffer_group.name)
 		goto error_free_buffer_attrs;
 
-	buffer->scan_el_group.name = iio_scan_elements_group_name;
+	buffer->buffer_group.attrs = attr;
 
-	buffer->scan_el_group.attrs = kcalloc(scan_el_attrcount + 1,
-					      sizeof(buffer->scan_el_group.attrs[0]),
-					      GFP_KERNEL);
-	if (buffer->scan_el_group.attrs == NULL) {
-		ret = -ENOMEM;
-		goto error_free_scan_mask;
-	}
-	attrn = 0;
+	ret = iio_device_register_sysfs_group(indio_dev, &buffer->buffer_group);
+	if (ret)
+		goto error_free_buffer_attr_group_name;
 
-	list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
-		buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
+	/* we only need to link the legacy buffer groups for the first buffer */
+	if (index > 0)
+		return 0;
 
-	ret = iio_device_register_sysfs_group(indio_dev, &buffer->scan_el_group);
+	ret = iio_buffer_register_legacy_sysfs_groups(indio_dev, attr,
+						      buffer_attrcount,
+						      scan_el_attrcount);
 	if (ret)
-		goto error_free_scan_el_attrs;
+		goto error_free_buffer_attr_group_name;
 
 	return 0;
 
-error_free_scan_el_attrs:
-	kfree(buffer->scan_el_group.attrs);
+error_free_buffer_attr_group_name:
+	kfree(buffer->buffer_group.name);
 error_free_buffer_attrs:
 	kfree(buffer->buffer_group.attrs);
 error_free_scan_mask:
@@ -1372,14 +1431,14 @@  int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
 	if (!buffer)
 		return 0;
 
-	return __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev);
+	return __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev, 0);
 }
 
 static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer)
 {
 	bitmap_free(buffer->scan_mask);
+	kfree(buffer->buffer_group.name);
 	kfree(buffer->buffer_group.attrs);
-	kfree(buffer->scan_el_group.attrs);
 	iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
 }
 
@@ -1390,6 +1449,8 @@  void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev)
 	if (!buffer)
 		return;
 
+	iio_buffer_unregister_legacy_sysfs_groups(indio_dev);
+
 	__iio_buffer_free_sysfs_and_mask(buffer);
 }
 
diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h
index a63dc07b7350..3e555e58475b 100644
--- a/include/linux/iio/buffer_impl.h
+++ b/include/linux/iio/buffer_impl.h
@@ -100,14 +100,11 @@  struct iio_buffer {
 	/* @scan_el_dev_attr_list: List of scan element related attributes. */
 	struct list_head scan_el_dev_attr_list;
 
-	/* @buffer_group: Attributes of the buffer group. */
-	struct attribute_group buffer_group;
-
 	/*
-	 * @scan_el_group: Attribute group for those attributes not
-	 * created from the iio_chan_info array.
+	 * @buffer_group: Attributes of the new buffer group.
+	 * Includes scan elements attributes.
 	 */
-	struct attribute_group scan_el_group;
+	struct attribute_group buffer_group;
 
 	/* @attrs: Standard attributes of the buffer. */
 	const struct attribute **attrs;
diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h
index 8ba13a5c7af6..3e4c3cd248fd 100644
--- a/include/linux/iio/iio-opaque.h
+++ b/include/linux/iio/iio-opaque.h
@@ -14,6 +14,8 @@ 
  * @ioctl_handlers:		ioctl handlers registered with the core handler
  * @groups:			attribute groups
  * @groupcounter:		index of next attribute group
+ * @legacy_scan_el_group:	attribute group for legacy scan elements attribute group
+ * @legacy_buffer_el_group:	attribute group for legacy buffer attributes group
  * @debugfs_dentry:		device specific debugfs dentry
  * @cached_reg_addr:		cached register address for debugfs reads
  * @read_buf:			read buffer to be used for the initial reg read
@@ -28,6 +30,8 @@  struct iio_dev_opaque {
 	struct list_head		ioctl_handlers;
 	const struct attribute_group	**groups;
 	int				groupcounter;
+	struct attribute_group		legacy_scan_el_group;
+	struct attribute_group		legacy_buffer_group;
 #if defined(CONFIG_DEBUG_FS)
 	struct dentry			*debugfs_dentry;
 	unsigned			cached_reg_addr;