[6/7] fs/sysfs/group: make attribute_group pointers const

Message ID 20231009165741.746184-6-max.kellermann@ionos.com
State New
Headers
Series [1/7] drivers/rtc/sysfs: move code to count_attribute_groups() |

Commit Message

Max Kellermann Oct. 9, 2023, 4:57 p.m. UTC
  This allows passing arrays of const pointers.  The goal is to make
lots of global variables "const" to allow them to live in the
".rodata" section.

Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
---
 block/genhd.c                       |  2 +-
 drivers/base/base.h                 |  4 ++--
 drivers/base/bus.c                  |  6 +++---
 drivers/base/cacheinfo.c            |  4 ++--
 drivers/base/core.c                 | 14 +++++++-------
 drivers/base/cpu.c                  |  4 ++--
 drivers/base/driver.c               |  4 ++--
 drivers/edac/edac_mc.c              |  2 +-
 drivers/edac/edac_mc.h              |  2 +-
 drivers/edac/edac_mc_sysfs.c        |  2 +-
 drivers/edac/edac_module.h          |  2 +-
 drivers/hwmon/hwmon.c               | 12 ++++++------
 drivers/hwmon/pmbus/pmbus.h         |  2 +-
 drivers/infiniband/core/core_priv.h |  4 ++--
 drivers/infiniband/core/sysfs.c     |  4 ++--
 drivers/infiniband/ulp/srp/ib_srp.c |  2 +-
 drivers/iommu/iommu-sysfs.c         |  2 +-
 drivers/nvdimm/dimm_devs.c          |  2 +-
 drivers/nvme/host/nvme.h            |  2 +-
 drivers/rtc/rtc-core.h              |  4 ++--
 drivers/rtc/sysfs.c                 |  6 +++---
 drivers/tty/tty_io.c                |  2 +-
 drivers/tty/tty_port.c              |  4 ++--
 fs/sysfs/group.c                    | 10 +++++-----
 include/linux/blkdev.h              |  2 +-
 include/linux/coresight.h           |  2 +-
 include/linux/cpu.h                 |  2 +-
 include/linux/device.h              | 16 ++++++++--------
 include/linux/device/bus.h          |  6 +++---
 include/linux/device/class.h        |  4 ++--
 include/linux/device/driver.h       |  4 ++--
 include/linux/hwmon.h               |  8 ++++----
 include/linux/iommu.h               |  4 ++--
 include/linux/kobject.h             |  2 +-
 include/linux/leds.h                |  4 ++--
 include/linux/libnvdimm.h           |  8 ++++----
 include/linux/miscdevice.h          |  2 +-
 include/linux/pci.h                 |  4 ++--
 include/linux/perf_event.h          |  2 +-
 include/linux/power_supply.h        |  2 +-
 include/linux/rtc.h                 |  4 ++--
 include/linux/sysfs.h               | 16 ++++++++--------
 include/linux/tty_driver.h          |  2 +-
 include/linux/tty_port.h            |  4 ++--
 include/linux/usb.h                 |  4 ++--
 include/linux/w1.h                  |  2 +-
 include/linux/watchdog.h            |  2 +-
 include/rdma/ib_verbs.h             |  2 +-
 include/scsi/scsi_host.h            |  4 ++--
 49 files changed, 107 insertions(+), 107 deletions(-)
  

Comments

Guenter Roeck Oct. 9, 2023, 5:24 p.m. UTC | #1
On Mon, Oct 09, 2023 at 06:57:39PM +0200, Max Kellermann wrote:
> This allows passing arrays of const pointers.  The goal is to make
> lots of global variables "const" to allow them to live in the
> ".rodata" section.
> 
> Signed-off-by: Max Kellermann <max.kellermann@ionos.com>

In my opinion this touches way too many subsystems in a single patch.
If someting is wrong with just one of the changes, it will be all but
impossible to revert the whole thing.

Also, I don't know why checkpatch is happy with all the

	const struct attribute_group *const*groups;

instead of

	const struct attribute_group *const *groups;

but I still don't like it.

Guenter
  
Greg KH Oct. 9, 2023, 5:25 p.m. UTC | #2
On Mon, Oct 09, 2023 at 06:57:39PM +0200, Max Kellermann wrote:
> This allows passing arrays of const pointers.  The goal is to make
> lots of global variables "const" to allow them to live in the
> ".rodata" section.

I'm all for doing this type of work, but this is going to be rough.  You
sent patch 6/7 that hit almost all subsystems at once :(

Also, the code:

> -int driver_add_groups(struct device_driver *drv, const struct attribute_group **groups);
> -void driver_remove_groups(struct device_driver *drv, const struct attribute_group **groups);
> +int driver_add_groups(struct device_driver *drv, const struct attribute_group *const*groups);
> +void driver_remove_groups(struct device_driver *drv, const struct attribute_group *const*groups);
>  void device_driver_detach(struct device *dev);

"*const*groups"?   That's a parsing nightmare, really hard for humans to
read and understand.  Doesn't checkpatch complain about this?

thanks,

greg k-h
  
Max Kellermann Oct. 9, 2023, 5:30 p.m. UTC | #3
On Mon, Oct 9, 2023 at 7:26 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> I'm all for doing this type of work, but this is going to be rough.  You
> sent patch 6/7 that hit almost all subsystems at once :(

I wasn't sure whether splitting patches was desired. In the past, I
was often asked to fold multiple patches into one. There are so many
opinions :-) but I'll gladly change to whatever is asked.

> "*const*groups"?   That's a parsing nightmare, really hard for humans to
> read and understand.  Doesn't checkpatch complain about this?

No. I'll change the coding style (and maybe take some time to fix checkpatch?)
  
Greg KH Oct. 9, 2023, 5:31 p.m. UTC | #4
On Mon, Oct 09, 2023 at 07:25:57PM +0200, Greg Kroah-Hartman wrote:
> On Mon, Oct 09, 2023 at 06:57:39PM +0200, Max Kellermann wrote:
> > This allows passing arrays of const pointers.  The goal is to make
> > lots of global variables "const" to allow them to live in the
> > ".rodata" section.
> 
> I'm all for doing this type of work, but this is going to be rough.  You
> sent patch 6/7 that hit almost all subsystems at once :(

The way to do this right is one-subsystem-at-a-time, right?  Why not
start there, doing it cleanly, and then at the end, change the driver
core and then just the subsystem pointers?  That should be much simpler,
easier to review and verify, and many more changes (and probably take a
kernel release or two to get through.)

thanks,

greg k-h
  
Max Kellermann Oct. 9, 2023, 8:05 p.m. UTC | #5
On Mon, Oct 9, 2023 at 7:24 PM Guenter Roeck <linux@roeck-us.net> wrote:
> Also, I don't know why checkpatch is happy with all the
>
>         const struct attribute_group *const*groups;
>
> instead of
>
>         const struct attribute_group *const *groups;

I found out that checkpatch has no check for this at all; it does
complain about such lines, but only for local variables. But that
warning is actually a bug, because this is a check for unary
operators: it thinks the asterisk is a dereference operator, not a
pointer declaration, and complains that the unary operator must be
preceded by a space. Thus warnings on local variable are only correct
by coincidence, not by design.

Inside structs or parameters (where my coding style violations can be
found), it's a different context and thus checkpatch doesn't apply the
rules for unary operators.
  
Max Kellermann Oct. 9, 2023, 8:20 p.m. UTC | #6
On Mon, Oct 9, 2023 at 7:26 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
> "*const*groups"?   That's a parsing nightmare, really hard for humans to
> read and understand.  Doesn't checkpatch complain about this?

No, checkpatch does not implement a check/warning for this style (see
my other email). There's no rule for this in coding-style.rst. Should
there be one?
  
Greg KH Oct. 10, 2023, 5:59 a.m. UTC | #7
On Mon, Oct 09, 2023 at 10:05:55PM +0200, Max Kellermann wrote:
> On Mon, Oct 9, 2023 at 7:24 PM Guenter Roeck <linux@roeck-us.net> wrote:
> > Also, I don't know why checkpatch is happy with all the
> >
> >         const struct attribute_group *const*groups;
> >
> > instead of
> >
> >         const struct attribute_group *const *groups;
> 
> I found out that checkpatch has no check for this at all; it does
> complain about such lines, but only for local variables. But that
> warning is actually a bug, because this is a check for unary
> operators: it thinks the asterisk is a dereference operator, not a
> pointer declaration, and complains that the unary operator must be
> preceded by a space. Thus warnings on local variable are only correct
> by coincidence, not by design.
> 
> Inside structs or parameters (where my coding style violations can be
> found), it's a different context and thus checkpatch doesn't apply the
> rules for unary operators.

Ok, checkpatch support isn't always required, we can notice that changes
like this obviously are not sane and shouldn't be allowed just by
reading them :)

thanks,

greg k-h
  
Joe Perches Oct. 10, 2023, 6:48 a.m. UTC | #8
On Mon, 2023-10-09 at 22:05 +0200, Max Kellermann wrote:
> On Mon, Oct 9, 2023 at 7:24 PM Guenter Roeck <linux@roeck-us.net> wrote:
> > Also, I don't know why checkpatch is happy with all the
> > 
> >         const struct attribute_group *const*groups;
> > 
> > instead of
> > 
> >         const struct attribute_group *const *groups;
> 
> I found out that checkpatch has no check for this at all; it does
> complain about such lines, but only for local variables. But that
> warning is actually a bug, because this is a check for unary
> operators: it thinks the asterisk is a dereference operator, not a
> pointer declaration, and complains that the unary operator must be
> preceded by a space. Thus warnings on local variable are only correct
> by coincidence, not by design.
> 
> Inside structs or parameters (where my coding style violations can be
> found), it's a different context and thus checkpatch doesn't apply the
> rules for unary operators.

My opinion is that const use in the kernel should almost
always have whitespace before and after it except when
preceded by a open parenthesis or a newline.

$ git grep -wh const -- '*.[ch]' | \
  grep -oP "[ \*\(]?const[ \*]?" | \
  sort | uniq -c | sort -rn
 222438  const 
  83386 const 
  51667 (const 
   2766 *const 
    834 const
    442  const
    343  const*
     88 *const
     37 (const
      4 *const*
  
Greg KH Oct. 10, 2023, 6:57 a.m. UTC | #9
On Mon, Oct 09, 2023 at 11:48:10PM -0700, Joe Perches wrote:
> On Mon, 2023-10-09 at 22:05 +0200, Max Kellermann wrote:
> > On Mon, Oct 9, 2023 at 7:24 PM Guenter Roeck <linux@roeck-us.net> wrote:
> > > Also, I don't know why checkpatch is happy with all the
> > > 
> > >         const struct attribute_group *const*groups;
> > > 
> > > instead of
> > > 
> > >         const struct attribute_group *const *groups;
> > 
> > I found out that checkpatch has no check for this at all; it does
> > complain about such lines, but only for local variables. But that
> > warning is actually a bug, because this is a check for unary
> > operators: it thinks the asterisk is a dereference operator, not a
> > pointer declaration, and complains that the unary operator must be
> > preceded by a space. Thus warnings on local variable are only correct
> > by coincidence, not by design.
> > 
> > Inside structs or parameters (where my coding style violations can be
> > found), it's a different context and thus checkpatch doesn't apply the
> > rules for unary operators.
> 
> My opinion is that const use in the kernel should almost
> always have whitespace before and after it except when
> preceded by a open parenthesis or a newline.

I totally agree.
  
Max Kellermann Oct. 10, 2023, 7:38 a.m. UTC | #10
On Tue, Oct 10, 2023 at 8:48 AM Joe Perches <joe@perches.com> wrote:
> My opinion is that const use in the kernel should almost
> always have whitespace before and after it except when
> preceded by a open parenthesis or a newline.

So it shall be "void * const foo" (16k occurrences in the kernel)
instead of "void *const foo" (3k occurrences)?
  
Joe Perches Oct. 10, 2023, 8:01 a.m. UTC | #11
On Tue, 2023-10-10 at 09:38 +0200, Max Kellermann wrote:
> On Tue, Oct 10, 2023 at 8:48 AM Joe Perches <joe@perches.com> wrote:
> > My opinion is that const use in the kernel should almost
> > always have whitespace before and after it except when
> > preceded by a open parenthesis or a newline.
> 
> So it shall be "void * const foo" (16k occurrences in the kernel)
> instead of "void *const foo" (3k occurrences)?

I think so.

$ git grep -P -oh "\bconst\s*\*" | sort | uniq -c | sort -rn | head -3
   2538 const *
    349 const*
     20 const	*
$ git grep -P -oh "\*\s*const\b" | sort | uniq -c | sort -rn | head -3
  16677 * const
   2912 *const
      8 *   const

Documentation/process/coding-style.rst doesn't mention const.
Maybe it should.
  

Patch

diff --git a/block/genhd.c b/block/genhd.c
index cc32a0c704eb..d82560a79b04 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -394,7 +394,7 @@  int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode)
  * with the kernel.
  */
 int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
-				 const struct attribute_group **groups)
+				 const struct attribute_group *const*groups)
 
 {
 	struct device *ddev = disk_to_dev(disk);
diff --git a/drivers/base/base.h b/drivers/base/base.h
index eb4c0ace9242..a2c011d9a5ca 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -175,8 +175,8 @@  static inline void dev_sync_state(struct device *dev)
 		dev->driver->sync_state(dev);
 }
 
-int driver_add_groups(struct device_driver *drv, const struct attribute_group **groups);
-void driver_remove_groups(struct device_driver *drv, const struct attribute_group **groups);
+int driver_add_groups(struct device_driver *drv, const struct attribute_group *const*groups);
+void driver_remove_groups(struct device_driver *drv, const struct attribute_group *const*groups);
 void device_driver_detach(struct device *dev);
 
 int devres_release_all(struct device *dev);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 84a21084d67d..d0331d07fffe 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -1195,7 +1195,7 @@  static void system_root_device_release(struct device *dev)
 }
 
 static int subsys_register(struct bus_type *subsys,
-			   const struct attribute_group **groups,
+			   const struct attribute_group *const*groups,
 			   struct kobject *parent_of_root)
 {
 	struct subsys_private *sp;
@@ -1265,7 +1265,7 @@  static int subsys_register(struct bus_type *subsys,
  * /sys/devices/system/<name>.
  */
 int subsys_system_register(struct bus_type *subsys,
-			   const struct attribute_group **groups)
+			   const struct attribute_group *const*groups)
 {
 	return subsys_register(subsys, groups, &system_kset->kobj);
 }
@@ -1283,7 +1283,7 @@  EXPORT_SYMBOL_GPL(subsys_system_register);
  * constructs which need sysfs interface.
  */
 int subsys_virtual_register(struct bus_type *subsys,
-			    const struct attribute_group **groups)
+			    const struct attribute_group *const*groups)
 {
 	struct kobject *virtual_dir;
 
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index cbae8be1fe52..b91c31c2a393 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -803,7 +803,7 @@  __weak cache_get_priv_group(struct cacheinfo *this_leaf)
 	return NULL;
 }
 
-static const struct attribute_group **
+static const struct attribute_group *const*
 cache_get_attribute_groups(struct cacheinfo *this_leaf)
 {
 	const struct attribute_group *priv_group =
@@ -868,7 +868,7 @@  static int cache_add_dev(unsigned int cpu)
 	int rc;
 	struct device *ci_dev, *parent;
 	struct cacheinfo *this_leaf;
-	const struct attribute_group **cache_groups;
+	const struct attribute_group *const*cache_groups;
 
 	rc = cpu_cache_sysfs_init(cpu);
 	if (unlikely(rc < 0))
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 4d8b315c48a1..b0debc3b751d 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2721,14 +2721,14 @@  static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(removable);
 
-int device_add_groups(struct device *dev, const struct attribute_group **groups)
+int device_add_groups(struct device *dev, const struct attribute_group *const*groups)
 {
 	return sysfs_create_groups(&dev->kobj, groups);
 }
 EXPORT_SYMBOL_GPL(device_add_groups);
 
 void device_remove_groups(struct device *dev,
-			  const struct attribute_group **groups)
+			  const struct attribute_group *const*groups)
 {
 	sysfs_remove_groups(&dev->kobj, groups);
 }
@@ -2736,7 +2736,7 @@  EXPORT_SYMBOL_GPL(device_remove_groups);
 
 union device_attr_group_devres {
 	const struct attribute_group *group;
-	const struct attribute_group **groups;
+	const struct attribute_group *const*groups;
 };
 
 static void devm_attr_group_remove(struct device *dev, void *res)
@@ -2751,7 +2751,7 @@  static void devm_attr_group_remove(struct device *dev, void *res)
 static void devm_attr_groups_remove(struct device *dev, void *res)
 {
 	union device_attr_group_devres *devres = res;
-	const struct attribute_group **groups = devres->groups;
+	const struct attribute_group *const*groups = devres->groups;
 
 	dev_dbg(dev, "%s: removing groups %p\n", __func__, groups);
 	sysfs_remove_groups(&dev->kobj, groups);
@@ -2803,7 +2803,7 @@  EXPORT_SYMBOL_GPL(devm_device_add_group);
  * Returns 0 on success or error code from sysfs_create_group on failure.
  */
 int devm_device_add_groups(struct device *dev,
-			   const struct attribute_group **groups)
+			   const struct attribute_group *const*groups)
 {
 	union device_attr_group_devres *devres;
 	int error;
@@ -4281,7 +4281,7 @@  static void device_create_release(struct device *dev)
 static __printf(6, 0) struct device *
 device_create_groups_vargs(const struct class *class, struct device *parent,
 			   dev_t devt, void *drvdata,
-			   const struct attribute_group **groups,
+			   const struct attribute_group *const*groups,
 			   const char *fmt, va_list args)
 {
 	struct device *dev = NULL;
@@ -4381,7 +4381,7 @@  EXPORT_SYMBOL_GPL(device_create);
 struct device *device_create_with_groups(const struct class *class,
 					 struct device *parent, dev_t devt,
 					 void *drvdata,
-					 const struct attribute_group **groups,
+					 const struct attribute_group *const*groups,
 					 const char *fmt, ...)
 {
 	va_list vargs;
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 9ea22e165acd..bd51cb4e6e8c 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -434,7 +434,7 @@  static void device_create_release(struct device *dev)
 __printf(4, 0)
 static struct device *
 __cpu_device_create(struct device *parent, void *drvdata,
-		    const struct attribute_group **groups,
+		    const struct attribute_group *const*groups,
 		    const char *fmt, va_list args)
 {
 	struct device *dev = NULL;
@@ -467,7 +467,7 @@  __cpu_device_create(struct device *parent, void *drvdata,
 }
 
 struct device *cpu_device_create(struct device *parent, void *drvdata,
-				 const struct attribute_group **groups,
+				 const struct attribute_group *const*groups,
 				 const char *fmt, ...)
 {
 	va_list vargs;
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index c8436c26ed6a..770bc8543f46 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -200,13 +200,13 @@  void driver_remove_file(struct device_driver *drv,
 EXPORT_SYMBOL_GPL(driver_remove_file);
 
 int driver_add_groups(struct device_driver *drv,
-		      const struct attribute_group **groups)
+		      const struct attribute_group *const*groups)
 {
 	return sysfs_create_groups(&drv->p->kobj, groups);
 }
 
 void driver_remove_groups(struct device_driver *drv,
-			  const struct attribute_group **groups)
+			  const struct attribute_group *const*groups)
 {
 	sysfs_remove_groups(&drv->p->kobj, groups);
 }
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 6faeb2ab3960..766ba8ac4f47 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -598,7 +598,7 @@  EXPORT_SYMBOL_GPL(edac_get_owner);
 
 /* FIXME - should a warning be printed if no error detection? correction? */
 int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
-			       const struct attribute_group **groups)
+			       const struct attribute_group *const*groups)
 {
 	int ret = -EINVAL;
 	edac_dbg(0, "\n");
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h
index 881b00eadf7a..0ded68555d1c 100644
--- a/drivers/edac/edac_mc.h
+++ b/drivers/edac/edac_mc.h
@@ -146,7 +146,7 @@  extern const char *edac_get_owner(void);
  *	0 on Success, or an error code on failure
  */
 extern int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
-				      const struct attribute_group **groups);
+				      const struct attribute_group *const*groups);
 #define edac_mc_add_mc(mci)	edac_mc_add_mc_with_groups(mci, NULL)
 
 /**
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 15f63452a9be..9ef2b139d8ae 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -931,7 +931,7 @@  static const struct device_type mci_attr_type = {
  *	!0	Failure
  */
 int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
-				 const struct attribute_group **groups)
+				 const struct attribute_group *const*groups)
 {
 	struct dimm_info *dimm;
 	int err;
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index 47593afdc234..734673339be5 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -27,7 +27,7 @@ 
 int edac_mc_sysfs_init(void);
 void edac_mc_sysfs_exit(void);
 extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
-					const struct attribute_group **groups);
+					const struct attribute_group *const*groups);
 extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
 extern int edac_mc_get_log_ue(void);
 extern int edac_mc_get_log_ce(void);
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index e50ab229b27d..d0305eaefa8b 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -37,7 +37,7 @@  struct hwmon_device {
 	const struct hwmon_chip_info *chip;
 	struct list_head tzdata;
 	struct attribute_group group;
-	const struct attribute_group **groups;
+	const struct attribute_group *const*groups;
 };
 
 #define to_hwmon_device(d) container_of(d, struct hwmon_device, dev)
@@ -756,7 +756,7 @@  __hwmon_create_attrs(const void *drvdata, const struct hwmon_chip_info *chip)
 static struct device *
 __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
 			const struct hwmon_chip_info *chip,
-			const struct attribute_group **groups)
+			const struct attribute_group *const*groups)
 {
 	struct hwmon_device *hwdev;
 	const char *label;
@@ -884,7 +884,7 @@  __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
 struct device *
 hwmon_device_register_with_groups(struct device *dev, const char *name,
 				  void *drvdata,
-				  const struct attribute_group **groups)
+				  const struct attribute_group *const*groups)
 {
 	if (!name)
 		return ERR_PTR(-EINVAL);
@@ -911,7 +911,7 @@  struct device *
 hwmon_device_register_with_info(struct device *dev, const char *name,
 				void *drvdata,
 				const struct hwmon_chip_info *chip,
-				const struct attribute_group **extra_groups)
+				const struct attribute_group *const*extra_groups)
 {
 	if (!dev || !name || !chip)
 		return ERR_PTR(-EINVAL);
@@ -1004,7 +1004,7 @@  static void devm_hwmon_release(struct device *dev, void *res)
 struct device *
 devm_hwmon_device_register_with_groups(struct device *dev, const char *name,
 				       void *drvdata,
-				       const struct attribute_group **groups)
+				       const struct attribute_group *const*groups)
 {
 	struct device **ptr, *hwdev;
 
@@ -1044,7 +1044,7 @@  struct device *
 devm_hwmon_device_register_with_info(struct device *dev, const char *name,
 				     void *drvdata,
 				     const struct hwmon_chip_info *chip,
-				     const struct attribute_group **extra_groups)
+				     const struct attribute_group *const*extra_groups)
 {
 	struct device **ptr, *hwdev;
 
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index b0832a4c690d..bf039994b84f 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -456,7 +456,7 @@  struct pmbus_driver_info {
 	const struct regulator_desc *reg_desc;
 
 	/* custom attributes */
-	const struct attribute_group **groups;
+	const struct attribute_group *const*groups;
 };
 
 /* Regulator ops */
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h
index f66f48d860ec..d4a444e52743 100644
--- a/drivers/infiniband/core/core_priv.h
+++ b/drivers/infiniband/core/core_priv.h
@@ -351,9 +351,9 @@  int ib_setup_device_attrs(struct ib_device *ibdev);
 int rdma_compatdev_set(u8 enable);
 
 int ib_port_register_client_groups(struct ib_device *ibdev, u32 port_num,
-				   const struct attribute_group **groups);
+				   const struct attribute_group *const*groups);
 void ib_port_unregister_client_groups(struct ib_device *ibdev, u32 port_num,
-				     const struct attribute_group **groups);
+				     const struct attribute_group *const*groups);
 
 int ib_device_set_netns_put(struct sk_buff *skb,
 			    struct ib_device *dev, u32 ns_fd);
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index ee59d7391568..fdd15d6a9c2f 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -1464,7 +1464,7 @@  int ib_setup_port_attrs(struct ib_core_device *coredev)
  * Do not use. Only for legacy sysfs compatibility.
  */
 int ib_port_register_client_groups(struct ib_device *ibdev, u32 port_num,
-				   const struct attribute_group **groups)
+				   const struct attribute_group *const*groups)
 {
 	return sysfs_create_groups(&ibdev->port_data[port_num].sysfs->kobj,
 				   groups);
@@ -1472,7 +1472,7 @@  int ib_port_register_client_groups(struct ib_device *ibdev, u32 port_num,
 EXPORT_SYMBOL(ib_port_register_client_groups);
 
 void ib_port_unregister_client_groups(struct ib_device *ibdev, u32 port_num,
-				      const struct attribute_group **groups)
+				      const struct attribute_group *const*groups)
 {
 	return sysfs_remove_groups(&ibdev->port_data[port_num].sysfs->kobj,
 				   groups);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 2916e77f589b..0633b17fc082 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1021,7 +1021,7 @@  static int srp_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
  */
 static void srp_del_scsi_host_attr(struct Scsi_Host *shost)
 {
-	const struct attribute_group **g;
+	const struct attribute_group *const*g;
 	struct attribute **attr;
 
 	for (g = shost->hostt->shost_groups; *g; ++g) {
diff --git a/drivers/iommu/iommu-sysfs.c b/drivers/iommu/iommu-sysfs.c
index cbe378c34ba3..ef92144b679f 100644
--- a/drivers/iommu/iommu-sysfs.c
+++ b/drivers/iommu/iommu-sysfs.c
@@ -53,7 +53,7 @@  postcore_initcall(iommu_dev_init);
  */
 int iommu_device_sysfs_add(struct iommu_device *iommu,
 			   struct device *parent,
-			   const struct attribute_group **groups,
+			   const struct attribute_group *const*groups,
 			   const char *fmt, ...)
 {
 	va_list vargs;
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index 1273873582be..924dfc43f94c 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -580,7 +580,7 @@  bool is_nvdimm(const struct device *dev)
 static struct lock_class_key nvdimm_key;
 
 struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
-		void *provider_data, const struct attribute_group **groups,
+		void *provider_data, const struct attribute_group *const*groups,
 		unsigned long flags, unsigned long cmd_mask, int num_flush,
 		struct resource *flush_wpq, const char *dimm_id,
 		const struct nvdimm_security_ops *sec_ops,
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index f35647c470af..90d0a1892b23 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -524,7 +524,7 @@  struct nvme_ctrl_ops {
 #define NVME_F_METADATA_SUPPORTED	(1 << 1)
 #define NVME_F_BLOCKING			(1 << 2)
 
-	const struct attribute_group **dev_attr_groups;
+	const struct attribute_group *const*dev_attr_groups;
 	int (*reg_read32)(struct nvme_ctrl *ctrl, u32 off, u32 *val);
 	int (*reg_write32)(struct nvme_ctrl *ctrl, u32 off, u32 val);
 	int (*reg_read64)(struct nvme_ctrl *ctrl, u32 off, u64 *val);
diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h
index 4b10a1b8f370..d21a967914dc 100644
--- a/drivers/rtc/rtc-core.h
+++ b/drivers/rtc/rtc-core.h
@@ -34,9 +34,9 @@  static inline void rtc_proc_del_device(struct rtc_device *rtc)
 #endif
 
 #ifdef CONFIG_RTC_INTF_SYSFS
-const struct attribute_group **rtc_get_dev_attribute_groups(void);
+const struct attribute_group *const*rtc_get_dev_attribute_groups(void);
 #else
-static inline const struct attribute_group **rtc_get_dev_attribute_groups(void)
+static inline const struct attribute_group *const*rtc_get_dev_attribute_groups(void)
 {
 	return NULL;
 }
diff --git a/drivers/rtc/sysfs.c b/drivers/rtc/sysfs.c
index 617933d52324..9c45c2557e28 100644
--- a/drivers/rtc/sysfs.c
+++ b/drivers/rtc/sysfs.c
@@ -308,7 +308,7 @@  static const struct attribute_group *rtc_attr_groups[] = {
 	NULL
 };
 
-const struct attribute_group **rtc_get_dev_attribute_groups(void)
+const struct attribute_group *const*rtc_get_dev_attribute_groups(void)
 {
 	return rtc_attr_groups;
 }
@@ -322,10 +322,10 @@  static size_t count_attribute_groups(const struct attribute_group *const*groups)
 	return count;
 }
 
-int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
+int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group *const*grps)
 {
 	size_t old_cnt, add_cnt, new_cnt;
-	const struct attribute_group **groups, **old;
+	const struct attribute_group **groups, *const *old;
 
 	if (!grps)
 		return -EINVAL;
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 8a94e5a43c6d..2bbc193a6f47 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -3212,7 +3212,7 @@  static void tty_device_create_release(struct device *dev)
 struct device *tty_register_device_attr(struct tty_driver *driver,
 				   unsigned index, struct device *device,
 				   void *drvdata,
-				   const struct attribute_group **attr_grp)
+				   const struct attribute_group *const*attr_grp)
 {
 	char name[64];
 	dev_t devt = MKDEV(driver->major, driver->minor_start) + index;
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 624d104bd145..f0f95e64ca64 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -158,7 +158,7 @@  EXPORT_SYMBOL_GPL(tty_port_register_device);
 struct device *tty_port_register_device_attr(struct tty_port *port,
 		struct tty_driver *driver, unsigned index,
 		struct device *device, void *drvdata,
-		const struct attribute_group **attr_grp)
+		const struct attribute_group *const*attr_grp)
 {
 	tty_port_link_device(port, driver, index);
 	return tty_register_device_attr(driver, index, device, drvdata,
@@ -181,7 +181,7 @@  EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
 struct device *tty_port_register_device_attr_serdev(struct tty_port *port,
 		struct tty_driver *driver, unsigned index,
 		struct device *device, void *drvdata,
-		const struct attribute_group **attr_grp)
+		const struct attribute_group *const*attr_grp)
 {
 	struct device *dev;
 
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 138676463336..4e14df4da39d 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -180,7 +180,7 @@  int sysfs_create_group(struct kobject *kobj,
 EXPORT_SYMBOL_GPL(sysfs_create_group);
 
 static int internal_create_groups(struct kobject *kobj, int update,
-				  const struct attribute_group **groups)
+				  const struct attribute_group *const*groups)
 {
 	int error = 0;
 	int i;
@@ -213,7 +213,7 @@  static int internal_create_groups(struct kobject *kobj, int update,
  * Returns 0 on success or error code from sysfs_create_group on failure.
  */
 int sysfs_create_groups(struct kobject *kobj,
-			const struct attribute_group **groups)
+			const struct attribute_group *const*groups)
 {
 	return internal_create_groups(kobj, 0, groups);
 }
@@ -231,7 +231,7 @@  EXPORT_SYMBOL_GPL(sysfs_create_groups);
  * Returns 0 on success or error code from sysfs_update_group on failure.
  */
 int sysfs_update_groups(struct kobject *kobj,
-			const struct attribute_group **groups)
+			const struct attribute_group *const*groups)
 {
 	return internal_create_groups(kobj, 1, groups);
 }
@@ -306,7 +306,7 @@  EXPORT_SYMBOL_GPL(sysfs_remove_group);
  * If groups is not NULL, remove the specified groups from the kobject.
  */
 void sysfs_remove_groups(struct kobject *kobj,
-			 const struct attribute_group **groups)
+			 const struct attribute_group *const*groups)
 {
 	int i;
 
@@ -561,7 +561,7 @@  EXPORT_SYMBOL_GPL(sysfs_group_change_owner);
  * Returns 0 on success or error code on failure.
  */
 int sysfs_groups_change_owner(struct kobject *kobj,
-			      const struct attribute_group **groups,
+			      const struct attribute_group *const*groups,
 			      kuid_t kuid, kgid_t kgid)
 {
 	int error = 0, i;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index eef450f25982..7917b072775e 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -729,7 +729,7 @@  static inline unsigned int blk_queue_depth(struct request_queue *q)
 	for (; _bio; _bio = _bio->bi_next)
 
 int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
-				 const struct attribute_group **groups);
+				 const struct attribute_group *const*groups);
 static inline int __must_check add_disk(struct gendisk *disk)
 {
 	return device_add_disk(NULL, disk, NULL);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index a269fffaf991..5dbe3883c02f 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -157,7 +157,7 @@  struct coresight_desc {
 	const struct coresight_ops *ops;
 	struct coresight_platform_data *pdata;
 	struct device *dev;
-	const struct attribute_group **groups;
+	const struct attribute_group *const*groups;
 	const char *name;
 	struct csdev_access access;
 };
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 0abd60a7987b..612955f50ed7 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -78,7 +78,7 @@  extern ssize_t cpu_show_gds(struct device *dev,
 
 extern __printf(4, 5)
 struct device *cpu_device_create(struct device *parent, void *drvdata,
-				 const struct attribute_group **groups,
+				 const struct attribute_group *const*groups,
 				 const char *fmt, ...);
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *cpu);
diff --git a/include/linux/device.h b/include/linux/device.h
index 56d93a1ffb7b..cf6ee60ecdb4 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -73,9 +73,9 @@  int subsys_interface_register(struct subsys_interface *sif);
 void subsys_interface_unregister(struct subsys_interface *sif);
 
 int subsys_system_register(struct bus_type *subsys,
-			   const struct attribute_group **groups);
+			   const struct attribute_group *const*groups);
 int subsys_virtual_register(struct bus_type *subsys,
-			    const struct attribute_group **groups);
+			    const struct attribute_group *const*groups);
 
 /*
  * The type of device, "struct device" is embedded in. A class
@@ -88,7 +88,7 @@  int subsys_virtual_register(struct bus_type *subsys,
  */
 struct device_type {
 	const char *name;
-	const struct attribute_group **groups;
+	const struct attribute_group *const*groups;
 	int (*uevent)(const struct device *dev, struct kobj_uevent_env *env);
 	char *(*devnode)(const struct device *dev, umode_t *mode,
 			 kuid_t *uid, kgid_t *gid);
@@ -782,7 +782,7 @@  struct device {
 	struct list_head	devres_head;
 
 	const struct class	*class;
-	const struct attribute_group **groups;	/* optional groups */
+	const struct attribute_group *const*groups;	/* optional groups */
 
 	void	(*release)(struct device *dev);
 	struct iommu_group	*iommu_group;
@@ -1177,14 +1177,14 @@  device_create(const struct class *cls, struct device *parent, dev_t devt,
 	      void *drvdata, const char *fmt, ...);
 __printf(6, 7) struct device *
 device_create_with_groups(const struct class *cls, struct device *parent, dev_t devt,
-			  void *drvdata, const struct attribute_group **groups,
+			  void *drvdata, const struct attribute_group *const*groups,
 			  const char *fmt, ...);
 void device_destroy(const struct class *cls, dev_t devt);
 
 int __must_check device_add_groups(struct device *dev,
-				   const struct attribute_group **groups);
+				   const struct attribute_group *const*groups);
 void device_remove_groups(struct device *dev,
-			  const struct attribute_group **groups);
+			  const struct attribute_group *const*groups);
 
 static inline int __must_check device_add_group(struct device *dev,
 					const struct attribute_group *grp)
@@ -1203,7 +1203,7 @@  static inline void device_remove_group(struct device *dev,
 }
 
 int __must_check devm_device_add_groups(struct device *dev,
-					const struct attribute_group **groups);
+					const struct attribute_group *const*groups);
 int __must_check devm_device_add_group(struct device *dev,
 				       const struct attribute_group *grp);
 
diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h
index ae10c4322754..5867948b64ca 100644
--- a/include/linux/device/bus.h
+++ b/include/linux/device/bus.h
@@ -80,9 +80,9 @@  struct fwnode_handle;
 struct bus_type {
 	const char		*name;
 	const char		*dev_name;
-	const struct attribute_group **bus_groups;
-	const struct attribute_group **dev_groups;
-	const struct attribute_group **drv_groups;
+	const struct attribute_group *const*bus_groups;
+	const struct attribute_group *const*dev_groups;
+	const struct attribute_group *const*drv_groups;
 
 	int (*match)(struct device *dev, struct device_driver *drv);
 	int (*uevent)(const struct device *dev, struct kobj_uevent_env *env);
diff --git a/include/linux/device/class.h b/include/linux/device/class.h
index abf3d3bfb6fe..649020a67b87 100644
--- a/include/linux/device/class.h
+++ b/include/linux/device/class.h
@@ -52,8 +52,8 @@  struct fwnode_handle;
 struct class {
 	const char		*name;
 
-	const struct attribute_group	**class_groups;
-	const struct attribute_group	**dev_groups;
+	const struct attribute_group	*const*class_groups;
+	const struct attribute_group	*const*dev_groups;
 
 	int (*dev_uevent)(const struct device *dev, struct kobj_uevent_env *env);
 	char *(*devnode)(const struct device *dev, umode_t *mode);
diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h
index 7738f458995f..cb8171124bbf 100644
--- a/include/linux/device/driver.h
+++ b/include/linux/device/driver.h
@@ -112,8 +112,8 @@  struct device_driver {
 	void (*shutdown) (struct device *dev);
 	int (*suspend) (struct device *dev, pm_message_t state);
 	int (*resume) (struct device *dev);
-	const struct attribute_group **groups;
-	const struct attribute_group **dev_groups;
+	const struct attribute_group *const*groups;
+	const struct attribute_group *const*dev_groups;
 
 	const struct dev_pm_ops *pm;
 	void (*coredump) (struct device *dev);
diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h
index 8cd6a6b33593..fa3f3a6be5b5 100644
--- a/include/linux/hwmon.h
+++ b/include/linux/hwmon.h
@@ -453,16 +453,16 @@  struct device *hwmon_device_register(struct device *dev);
 struct device *
 hwmon_device_register_with_groups(struct device *dev, const char *name,
 				  void *drvdata,
-				  const struct attribute_group **groups);
+				  const struct attribute_group *const*groups);
 struct device *
 devm_hwmon_device_register_with_groups(struct device *dev, const char *name,
 				       void *drvdata,
-				       const struct attribute_group **groups);
+				       const struct attribute_group *const*groups);
 struct device *
 hwmon_device_register_with_info(struct device *dev,
 				const char *name, void *drvdata,
 				const struct hwmon_chip_info *info,
-				const struct attribute_group **extra_groups);
+				const struct attribute_group *const*extra_groups);
 struct device *
 hwmon_device_register_for_thermal(struct device *dev, const char *name,
 				  void *drvdata);
@@ -470,7 +470,7 @@  struct device *
 devm_hwmon_device_register_with_info(struct device *dev,
 				const char *name, void *drvdata,
 				const struct hwmon_chip_info *info,
-				const struct attribute_group **extra_groups);
+				const struct attribute_group *const*extra_groups);
 
 void hwmon_device_unregister(struct device *dev);
 void devm_hwmon_device_unregister(struct device *dev);
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index c50a769d569a..4169cfca3098 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -441,7 +441,7 @@  int iommu_device_register(struct iommu_device *iommu,
 void iommu_device_unregister(struct iommu_device *iommu);
 int  iommu_device_sysfs_add(struct iommu_device *iommu,
 			    struct device *parent,
-			    const struct attribute_group **groups,
+			    const struct attribute_group *const*groups,
 			    const char *fmt, ...) __printf(4, 5);
 void iommu_device_sysfs_remove(struct iommu_device *iommu);
 int  iommu_device_link(struct iommu_device   *iommu, struct device *link);
@@ -975,7 +975,7 @@  static inline void iommu_device_unregister(struct iommu_device *iommu)
 
 static inline int  iommu_device_sysfs_add(struct iommu_device *iommu,
 					  struct device *parent,
-					  const struct attribute_group **groups,
+					  const struct attribute_group *const*groups,
 					  const char *fmt, ...)
 {
 	return -ENODEV;
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index c30affcc43b4..989afe775880 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -116,7 +116,7 @@  char *kobject_get_path(const struct kobject *kobj, gfp_t flag);
 struct kobj_type {
 	void (*release)(struct kobject *kobj);
 	const struct sysfs_ops *sysfs_ops;
-	const struct attribute_group **default_groups;
+	const struct attribute_group *const*default_groups;
 	const struct kobj_ns_type_operations *(*child_ns_type)(const struct kobject *kobj);
 	const void *(*namespace)(const struct kobject *kobj);
 	void (*get_ownership)(const struct kobject *kobj, kuid_t *uid, kgid_t *gid);
diff --git a/include/linux/leds.h b/include/linux/leds.h
index aa16dc2a8230..6d84f5eb0883 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -166,7 +166,7 @@  struct led_classdev {
 	int (*pattern_clear)(struct led_classdev *led_cdev);
 
 	struct device		*dev;
-	const struct attribute_group	**groups;
+	const struct attribute_group	*const*groups;
 
 	struct list_head	 node;			/* LED Device list */
 	const char		*default_trigger;	/* Trigger to use */
@@ -484,7 +484,7 @@  struct led_trigger {
 	/* Link to next registered trigger */
 	struct list_head  next_trig;
 
-	const struct attribute_group **groups;
+	const struct attribute_group *const*groups;
 };
 
 /*
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index e772aae71843..7c629ee16215 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -82,7 +82,7 @@  typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc,
 
 struct device_node;
 struct nvdimm_bus_descriptor {
-	const struct attribute_group **attr_groups;
+	const struct attribute_group *const*attr_groups;
 	unsigned long cmd_mask;
 	unsigned long dimm_family_mask;
 	unsigned long bus_family_mask;
@@ -126,7 +126,7 @@  struct nd_region_desc {
 	struct resource *res;
 	struct nd_mapping_desc *mapping;
 	u16 num_mappings;
-	const struct attribute_group **attr_groups;
+	const struct attribute_group *const*attr_groups;
 	struct nd_interleave_set *nd_set;
 	void *provider_data;
 	int num_lanes;
@@ -259,13 +259,13 @@  struct kobject *nvdimm_kobj(struct nvdimm *nvdimm);
 unsigned long nvdimm_cmd_mask(struct nvdimm *nvdimm);
 void *nvdimm_provider_data(struct nvdimm *nvdimm);
 struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
-		void *provider_data, const struct attribute_group **groups,
+		void *provider_data, const struct attribute_group *const*groups,
 		unsigned long flags, unsigned long cmd_mask, int num_flush,
 		struct resource *flush_wpq, const char *dimm_id,
 		const struct nvdimm_security_ops *sec_ops,
 		const struct nvdimm_fw_ops *fw_ops);
 static inline struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus,
-		void *provider_data, const struct attribute_group **groups,
+		void *provider_data, const struct attribute_group *const*groups,
 		unsigned long flags, unsigned long cmd_mask, int num_flush,
 		struct resource *flush_wpq)
 {
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index c0fea6ca5076..32b0caf86cd1 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -83,7 +83,7 @@  struct miscdevice  {
 	struct list_head list;
 	struct device *parent;
 	struct device *this_device;
-	const struct attribute_group **groups;
+	const struct attribute_group *const*groups;
 	const char *nodename;
 	umode_t mode;
 };
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 8c7c2c3c6c65..57dbfd890ae7 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -928,8 +928,8 @@  struct pci_driver {
 	int  (*sriov_set_msix_vec_count)(struct pci_dev *vf, int msix_vec_count); /* On PF */
 	u32  (*sriov_get_vf_total_msix)(struct pci_dev *pf);
 	const struct pci_error_handlers *err_handler;
-	const struct attribute_group **groups;
-	const struct attribute_group **dev_groups;
+	const struct attribute_group *const*groups;
+	const struct attribute_group *const*dev_groups;
 	struct device_driver	driver;
 	struct pci_dynids	dynids;
 	bool driver_managed_dma;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index e85cd1c0eaf3..e9d68c611974 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -306,7 +306,7 @@  struct pmu {
 	struct device			*dev;
 	struct device			*parent;
 	const struct attribute_group	**attr_groups;
-	const struct attribute_group	**attr_update;
+	const struct attribute_group	*const*attr_update;
 	const char			*name;
 	int				type;
 
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index a427f13c757f..b7f592a20729 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -232,7 +232,7 @@  struct power_supply_config {
 	void *drv_data;
 
 	/* Device specific sysfs attributes */
-	const struct attribute_group **attr_grp;
+	const struct attribute_group *const*attr_grp;
 
 	char **supplied_to;
 	size_t num_supplicants;
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 4c0bcbeb1f00..f72e70186b2f 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -247,7 +247,7 @@  static inline int devm_rtc_nvmem_register(struct rtc_device *rtc,
 
 #ifdef CONFIG_RTC_INTF_SYSFS
 int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp);
-int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps);
+int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group *const*grps);
 #else
 static inline
 int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp)
@@ -256,7 +256,7 @@  int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp)
 }
 
 static inline
-int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
+int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group *const*grps)
 {
 	return 0;
 }
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index fd3fe5c8c17f..2b97fb34204b 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -307,15 +307,15 @@  void sysfs_delete_link(struct kobject *dir, struct kobject *targ,
 int __must_check sysfs_create_group(struct kobject *kobj,
 				    const struct attribute_group *grp);
 int __must_check sysfs_create_groups(struct kobject *kobj,
-				     const struct attribute_group **groups);
+				     const struct attribute_group *const*groups);
 int __must_check sysfs_update_groups(struct kobject *kobj,
-				     const struct attribute_group **groups);
+				     const struct attribute_group *const*groups);
 int sysfs_update_group(struct kobject *kobj,
 		       const struct attribute_group *grp);
 void sysfs_remove_group(struct kobject *kobj,
 			const struct attribute_group *grp);
 void sysfs_remove_groups(struct kobject *kobj,
-			 const struct attribute_group **groups);
+			 const struct attribute_group *const*groups);
 int sysfs_add_file_to_group(struct kobject *kobj,
 			const struct attribute *attr, const char *group);
 void sysfs_remove_file_from_group(struct kobject *kobj,
@@ -348,7 +348,7 @@  int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid);
 int sysfs_link_change_owner(struct kobject *kobj, struct kobject *targ,
 			    const char *name, kuid_t kuid, kgid_t kgid);
 int sysfs_groups_change_owner(struct kobject *kobj,
-			      const struct attribute_group **groups,
+			      const struct attribute_group *const*groups,
 			      kuid_t kuid, kgid_t kgid);
 int sysfs_group_change_owner(struct kobject *kobj,
 			     const struct attribute_group *groups, kuid_t kuid,
@@ -487,13 +487,13 @@  static inline int sysfs_create_group(struct kobject *kobj,
 }
 
 static inline int sysfs_create_groups(struct kobject *kobj,
-				      const struct attribute_group **groups)
+				      const struct attribute_group *const*groups)
 {
 	return 0;
 }
 
 static inline int sysfs_update_groups(struct kobject *kobj,
-				      const struct attribute_group **groups)
+				      const struct attribute_group *const*groups)
 {
 	return 0;
 }
@@ -510,7 +510,7 @@  static inline void sysfs_remove_group(struct kobject *kobj,
 }
 
 static inline void sysfs_remove_groups(struct kobject *kobj,
-				       const struct attribute_group **groups)
+				       const struct attribute_group *const*groups)
 {
 }
 
@@ -591,7 +591,7 @@  static inline int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t k
 }
 
 static inline int sysfs_groups_change_owner(struct kobject *kobj,
-			  const struct attribute_group **groups,
+			  const struct attribute_group *const*groups,
 			  kuid_t kuid, kgid_t kgid)
 {
 	return 0;
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 18beff0cec1a..3041bebb1051 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -571,7 +571,7 @@  struct device *tty_register_device(struct tty_driver *driver, unsigned index,
 		struct device *dev);
 struct device *tty_register_device_attr(struct tty_driver *driver,
 		unsigned index, struct device *device, void *drvdata,
-		const struct attribute_group **attr_grp);
+		const struct attribute_group *const*attr_grp);
 void tty_unregister_device(struct tty_driver *driver, unsigned index);
 
 #ifdef CONFIG_PROC_FS
diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h
index 6b367eb17979..811aa134150c 100644
--- a/include/linux/tty_port.h
+++ b/include/linux/tty_port.h
@@ -146,14 +146,14 @@  struct device *tty_port_register_device(struct tty_port *port,
 struct device *tty_port_register_device_attr(struct tty_port *port,
 		struct tty_driver *driver, unsigned index,
 		struct device *device, void *drvdata,
-		const struct attribute_group **attr_grp);
+		const struct attribute_group *const*attr_grp);
 struct device *tty_port_register_device_serdev(struct tty_port *port,
 		struct tty_driver *driver, unsigned index,
 		struct device *device);
 struct device *tty_port_register_device_attr_serdev(struct tty_port *port,
 		struct tty_driver *driver, unsigned index,
 		struct device *device, void *drvdata,
-		const struct attribute_group **attr_grp);
+		const struct attribute_group *const*attr_grp);
 void tty_port_unregister_device(struct tty_port *port,
 		struct tty_driver *driver, unsigned index);
 int tty_port_alloc_xmit_buf(struct tty_port *port);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index a21074861f91..321ded34928f 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1239,7 +1239,7 @@  struct usb_driver {
 	int (*post_reset)(struct usb_interface *intf);
 
 	const struct usb_device_id *id_table;
-	const struct attribute_group **dev_groups;
+	const struct attribute_group *const*dev_groups;
 
 	struct usb_dynids dynids;
 	struct usbdrv_wrap drvwrap;
@@ -1287,7 +1287,7 @@  struct usb_device_driver {
 
 	int (*suspend) (struct usb_device *udev, pm_message_t message);
 	int (*resume) (struct usb_device *udev, pm_message_t message);
-	const struct attribute_group **dev_groups;
+	const struct attribute_group *const*dev_groups;
 	struct usbdrv_wrap drvwrap;
 	const struct usb_device_id *id_table;
 	unsigned int supports_autosuspend:1;
diff --git a/include/linux/w1.h b/include/linux/w1.h
index 9a2a0ef39018..0c86a9ed7013 100644
--- a/include/linux/w1.h
+++ b/include/linux/w1.h
@@ -253,7 +253,7 @@  void w1_remove_master_device(struct w1_bus_master *master);
 struct w1_family_ops {
 	int  (*add_slave)(struct w1_slave *sl);
 	void (*remove_slave)(struct w1_slave *sl);
-	const struct attribute_group **groups;
+	const struct attribute_group *const*groups;
 	const struct hwmon_chip_info *chip_info;
 };
 
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 99660197a36c..1f4a0fae13ab 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -94,7 +94,7 @@  struct watchdog_ops {
 struct watchdog_device {
 	int id;
 	struct device *parent;
-	const struct attribute_group **groups;
+	const struct attribute_group *const*groups;
 	const struct watchdog_info *info;
 	const struct watchdog_ops *ops;
 	const struct watchdog_governor *gov;
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 533ab92684d8..1a9511b99506 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -2343,7 +2343,7 @@  struct ib_device_ops {
 	 * mechanism exists only for existing drivers.
 	 */
 	const struct attribute_group *device_group;
-	const struct attribute_group **port_groups;
+	const struct attribute_group *const*port_groups;
 
 	int (*post_send)(struct ib_qp *qp, const struct ib_send_wr *send_wr,
 			 const struct ib_send_wr **bad_send_wr);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 4c2dc8150c6d..c9da91e96232 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -478,13 +478,13 @@  struct scsi_host_template {
 	/*
 	 * Pointer to the SCSI host sysfs attribute groups, NULL terminated.
 	 */
-	const struct attribute_group **shost_groups;
+	const struct attribute_group *const*shost_groups;
 
 	/*
 	 * Pointer to the SCSI device attribute groups for this host,
 	 * NULL terminated.
 	 */
-	const struct attribute_group **sdev_groups;
+	const struct attribute_group *const*sdev_groups;
 
 	/*
 	 * Vendor Identifier associated with the host