diff mbox series

[v3,07/24] gpio: protect the descriptor label with SRCU

Message ID 20240208095920.8035-8-brgl@bgdev.pl
State New
Headers show
Series gpio: rework locking and object life-time control | expand

Commit Message

Bartosz Golaszewski Feb. 8, 2024, 9:59 a.m. UTC
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

In order to ensure that the label is not freed while it's being
accessed, let's protect it with SRCU and synchronize it everytime it's
changed.

Let's modify desc_set_label() to manage the memory used for the label as
it can only be freed once synchronize_srcu() returns.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/gpio/gpiolib-cdev.c | 10 +++++---
 drivers/gpio/gpiolib.c      | 47 +++++++++++++++++++++++--------------
 drivers/gpio/gpiolib.h      | 34 +++++++++++++++++++--------
 3 files changed, 61 insertions(+), 30 deletions(-)

Comments

kernel test robot Feb. 12, 2024, 2:56 p.m. UTC | #1
Hello,

kernel test robot noticed "canonical_address#:#[##]" on:

commit: 04cb69cd30bb05c127e2b86b31ee778100439d14 ("[PATCH v3 07/24] gpio: protect the descriptor label with SRCU")
url: https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240208-180822
base: https://git.kernel.org/cgit/linux/kernel/git/brgl/linux.git gpio/for-next
patch link: https://lore.kernel.org/all/20240208095920.8035-8-brgl@bgdev.pl/
patch subject: [PATCH v3 07/24] gpio: protect the descriptor label with SRCU

in testcase: boot

compiler: gcc-12
test machine: qemu-system-x86_64 -enable-kvm -cpu SandyBridge -smp 2 -m 16G

(please refer to attached dmesg/kmsg for entire log/backtrace)


+----------------------------------------------------------------------------------+------------+------------+
|                                                                                  | 47b87115af | 04cb69cd30 |
+----------------------------------------------------------------------------------+------------+------------+
| canonical_address#:#[##]                                                         | 0          | 9          |
| RIP:check_init_srcu_struct                                                       | 0          | 9          |
| Kernel_panic-not_syncing:Fatal_exception                                         | 0          | 9          |
+----------------------------------------------------------------------------------+------------+------------+


If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-lkp/202402122228.e607a080-lkp@intel.com



[   53.381777][    T1] gpiochip_find_base_unlocked: found new base at 512
[   53.383799][    T1] general protection fault, probably for non-canonical address 0xdffffc000000002f: 0000 [#1] PREEMPT KASAN PTI
[   53.384902][    T1] KASAN: null-ptr-deref in range [0x0000000000000178-0x000000000000017f]
[   53.384902][    T1] CPU: 0 PID: 1 Comm: swapper Tainted: G                 N 6.8.0-rc1-00035-g04cb69cd30bb #1
[ 53.384902][ T1] RIP: 0010:check_init_srcu_struct (kernel/rcu/srcutree.c:408) 
[ 53.384902][ T1] Code: 53 48 89 fb 80 3c 02 00 0f 85 fe 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 8b 6b 38 48 8d bd 78 01 00 00 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 ce 00 00 00 48 8b 85 78 01 00 00 a8 03 75 0b 5b
All code
========
   0:	53                   	push   %rbx
   1:	48 89 fb             	mov    %rdi,%rbx
   4:	80 3c 02 00          	cmpb   $0x0,(%rdx,%rax,1)
   8:	0f 85 fe 00 00 00    	jne    0x10c
   e:	48 b8 00 00 00 00 00 	movabs $0xdffffc0000000000,%rax
  15:	fc ff df 
  18:	48 8b 6b 38          	mov    0x38(%rbx),%rbp
  1c:	48 8d bd 78 01 00 00 	lea    0x178(%rbp),%rdi
  23:	48 89 fa             	mov    %rdi,%rdx
  26:	48 c1 ea 03          	shr    $0x3,%rdx
  2a:*	80 3c 02 00          	cmpb   $0x0,(%rdx,%rax,1)		<-- trapping instruction
  2e:	0f 85 ce 00 00 00    	jne    0x102
  34:	48 8b 85 78 01 00 00 	mov    0x178(%rbp),%rax
  3b:	a8 03                	test   $0x3,%al
  3d:	75 0b                	jne    0x4a
  3f:	5b                   	pop    %rbx

Code starting with the faulting instruction
===========================================
   0:	80 3c 02 00          	cmpb   $0x0,(%rdx,%rax,1)
   4:	0f 85 ce 00 00 00    	jne    0xd8
   a:	48 8b 85 78 01 00 00 	mov    0x178(%rbp),%rax
  11:	a8 03                	test   $0x3,%al
  13:	75 0b                	jne    0x20
  15:	5b                   	pop    %rbx
[   53.384902][    T1] RSP: 0018:ffff888103e67730 EFLAGS: 00010202
[   53.384902][    T1] RAX: dffffc0000000000 RBX: ffff88810a65f8f8 RCX: 0000000000000000
[   53.384902][    T1] RDX: 000000000000002f RSI: ffff888168ad7b40 RDI: 0000000000000178
[   53.384902][    T1] RBP: 0000000000000000 R08: 692d422d656e696c R09: 007475706e692d42
[   53.384902][    T1] R10: ffff888103e67768 R11: ffffffff8190f8d4 R12: ffff88810a65f930
[   53.384902][    T1] R13: 0000000000000000 R14: ffff88810a65f8d8 R15: 0000000000000000
[   53.384902][    T1] FS:  0000000000000000(0000) GS:ffffffff84cd1000(0000) knlGS:0000000000000000
[   53.384902][    T1] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   53.384902][    T1] CR2: 00007fb8169d96f4 CR3: 0000000004cac000 CR4: 00000000000406b0
[   53.384902][    T1] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   53.384902][    T1] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   53.384902][    T1] Call Trace:
[   53.384902][    T1]  <TASK>
[ 53.384902][ T1] ? die_addr (arch/x86/kernel/dumpstack.c:421 arch/x86/kernel/dumpstack.c:460) 
[ 53.384902][ T1] ? exc_general_protection (arch/x86/kernel/traps.c:701 arch/x86/kernel/traps.c:643) 
[ 53.384902][ T1] ? asm_exc_general_protection (arch/x86/include/asm/idtentry.h:564) 
[ 53.384902][ T1] ? kasan_save_track (arch/x86/include/asm/current.h:42 mm/kasan/common.c:60 mm/kasan/common.c:70) 
[ 53.384902][ T1] ? check_init_srcu_struct (kernel/rcu/srcutree.c:408) 
[ 53.384902][ T1] synchronize_srcu (kernel/rcu/srcutree.c:1167 kernel/rcu/srcutree.c:1458) 
[ 53.384902][ T1] ? kstrdup (mm/util.c:62) 
[ 53.384902][ T1] gpiod_request_commit (drivers/gpio/gpiolib.c:134 drivers/gpio/gpiolib.c:2275) 
[ 53.384902][ T1] gpiochip_request_own_desc (drivers/gpio/gpiolib.c:2484) 
[ 53.384902][ T1] gpiod_hog (drivers/gpio/gpiolib.c:4474) 
[ 53.384902][ T1] ? of_find_property (drivers/of/base.c:223) 
[ 53.384902][ T1] of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:799) 
[ 53.384902][ T1] ? __pfx_of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:785) 
[ 53.384902][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) 
[ 53.384902][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) 
[ 53.384902][ T1] ? _raw_spin_unlock_irqrestore (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:152 kernel/locking/spinlock.c:194) 
[ 53.384902][ T1] of_gpiochip_add (drivers/gpio/gpiolib-of.c:828 drivers/gpio/gpiolib-of.c:1143) 
[ 53.384902][ T1] ? fwnode_property_read_int_array (drivers/base/property.c:268 (discriminator 5)) 
[ 53.384902][ T1] gpiochip_add_data_with_key (drivers/gpio/gpiolib.c:985) 
[ 53.384902][ T1] ? kasan_save_track (arch/x86/include/asm/current.h:42 mm/kasan/common.c:60 mm/kasan/common.c:70) 
[ 53.384902][ T1] unittest_gpio_probe (drivers/of/unittest.c:1886) 
[ 53.384902][ T1] platform_probe (drivers/base/platform.c:1404) 
[ 53.384902][ T1] really_probe (drivers/base/dd.c:579 drivers/base/dd.c:658) 
[ 53.384902][ T1] __driver_probe_device (drivers/base/dd.c:800) 
[ 53.384902][ T1] driver_probe_device (drivers/base/dd.c:830) 
[ 53.384902][ T1] __driver_attach (drivers/base/dd.c:1217) 
[ 53.384902][ T1] ? __pfx___driver_attach (drivers/base/dd.c:1157) 
[ 53.384902][ T1] bus_for_each_dev (drivers/base/bus.c:367) 
[ 53.384902][ T1] ? lockdep_init_map_type (kernel/locking/lockdep.c:4892) 
[ 53.384902][ T1] ? __pfx_bus_for_each_dev (drivers/base/bus.c:356) 
[ 53.384902][ T1] ? bus_add_driver (drivers/base/bus.c:672) 
[ 53.384902][ T1] bus_add_driver (drivers/base/bus.c:674) 
[ 53.384902][ T1] driver_register (drivers/base/driver.c:246) 
[ 53.384902][ T1] of_unittest_overlay_gpio (drivers/of/unittest.c:1969 (discriminator 4)) 
[ 53.384902][ T1] of_unittest_overlay (drivers/of/unittest.c:2189 drivers/of/unittest.c:3217) 
[ 53.384902][ T1] ? __pfx_of_unittest_overlay (drivers/of/unittest.c:3155) 
[ 53.384902][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) 
[ 53.384902][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) 
[ 53.384902][ T1] of_unittest (drivers/of/unittest.c:4129) 
[ 53.384902][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) 
[ 53.384902][ T1] ? add_device_randomness (drivers/char/random.c:918) 
[ 53.384902][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) 
[ 53.384902][ T1] do_one_initcall (init/main.c:1236) 
[ 53.384902][ T1] ? __pfx_do_one_initcall (init/main.c:1227) 
[ 53.384902][ T1] do_initcalls (init/main.c:1297 init/main.c:1314) 
[ 53.384902][ T1] kernel_init_freeable (init/main.c:1555) 
[ 53.384902][ T1] ? __pfx_kernel_init (init/main.c:1433) 
[ 53.384902][ T1] kernel_init (init/main.c:1443) 
[ 53.384902][ T1] ? _raw_spin_unlock_irq (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:160 kernel/locking/spinlock.c:202) 
[ 53.384902][ T1] ret_from_fork (arch/x86/kernel/process.c:153) 
[ 53.384902][ T1] ? __pfx_kernel_init (init/main.c:1433) 
[ 53.384902][ T1] ret_from_fork_asm (arch/x86/entry/entry_64.S:250) 
[   53.384902][    T1]  </TASK>
[   53.384902][    T1] Modules linked in:
[   53.485664][    T1] ---[ end trace 0000000000000000 ]---
[ 53.486974][ T1] RIP: 0010:check_init_srcu_struct (kernel/rcu/srcutree.c:408) 
[ 53.488507][ T1] Code: 53 48 89 fb 80 3c 02 00 0f 85 fe 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 8b 6b 38 48 8d bd 78 01 00 00 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 ce 00 00 00 48 8b 85 78 01 00 00 a8 03 75 0b 5b
All code
========
   0:	53                   	push   %rbx
   1:	48 89 fb             	mov    %rdi,%rbx
   4:	80 3c 02 00          	cmpb   $0x0,(%rdx,%rax,1)
   8:	0f 85 fe 00 00 00    	jne    0x10c
   e:	48 b8 00 00 00 00 00 	movabs $0xdffffc0000000000,%rax
  15:	fc ff df 
  18:	48 8b 6b 38          	mov    0x38(%rbx),%rbp
  1c:	48 8d bd 78 01 00 00 	lea    0x178(%rbp),%rdi
  23:	48 89 fa             	mov    %rdi,%rdx
  26:	48 c1 ea 03          	shr    $0x3,%rdx
  2a:*	80 3c 02 00          	cmpb   $0x0,(%rdx,%rax,1)		<-- trapping instruction
  2e:	0f 85 ce 00 00 00    	jne    0x102
  34:	48 8b 85 78 01 00 00 	mov    0x178(%rbp),%rax
  3b:	a8 03                	test   $0x3,%al
  3d:	75 0b                	jne    0x4a
  3f:	5b                   	pop    %rbx

Code starting with the faulting instruction
===========================================
   0:	80 3c 02 00          	cmpb   $0x0,(%rdx,%rax,1)
   4:	0f 85 ce 00 00 00    	jne    0xd8
   a:	48 8b 85 78 01 00 00 	mov    0x178(%rbp),%rax
  11:	a8 03                	test   $0x3,%al
  13:	75 0b                	jne    0x20
  15:	5b                   	pop    %rbx


The kernel config and materials to reproduce are available at:
https://download.01.org/0day-ci/archive/20240212/202402122228.e607a080-lkp@intel.com
Bartosz Golaszewski Feb. 13, 2024, 10:07 p.m. UTC | #2
On Tue, Feb 13, 2024 at 10:16 PM Mark Brown <broonie@kernel.org> wrote:
>
> On Thu, Feb 08, 2024 at 10:59:03AM +0100, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > In order to ensure that the label is not freed while it's being
> > accessed, let's protect it with SRCU and synchronize it everytime it's
> > changed.
>
> This patch, which is now in -next as 1f2bcb8c8ccd, appears to cause a
> boot regression on imx8mp-verdin-nonwifi-dahlia with arm64 defconfig.
> We die with an invalid pointer dereference after registering the GPIOs:
>
> [    1.973513] gpio gpiochip3: Static allocation of GPIO base is deprecated, use dynamic allocation.
> [    1.982467] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000078
>
> ...
>
> [    2.161467] Call trace:
> [    2.163915]  check_init_srcu_struct+0x1c/0xa0
> [    2.168284]  synchronize_srcu+0x1c/0x100
> [    2.172216]  gpiod_request_commit+0xec/0x1e0
> [    2.176496]  gpiochip_request_own_desc+0x58/0x124
> [    2.181205]  gpiod_hog+0x74/0x140
> [    2.184529]  of_gpiochip_add+0x208/0x370
> [    2.188456]  gpiochip_add_data_with_key+0x720/0xf14
>
> and a bisect appears to converge smoothly onto this commit.  None of my
> other platforms (including the i.MX8MP EVK with the same SoC in it) are
> showing similar issues, I've not checked the CI systems and haven't done
> any investigation beyond checking that the commit does look like it
> could plausibly be related to the symptom.
>
> You can see a full boot log at:
>
>    https://lava.sirena.org.uk/scheduler/job/579038
>
> bisect log:
>
> git bisect start
> # good: [7b17b1384cd6454c4ea2744c8e8a06de0d27b5b3] Merge branch 'for-linux-next-fixes' of git://anongit.freedesktop.org/drm/drm-misc
> git bisect good 7b17b1384cd6454c4ea2744c8e8a06de0d27b5b3
> # bad: [46d4e2eb58e14c8935fa0e27d16d4c62ef82849a] Add linux-next specific files for 20240213
> git bisect bad 46d4e2eb58e14c8935fa0e27d16d4c62ef82849a
> # good: [f85363faaa040a9b9ac6502464a8b1ed7f711eab] Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
> git bisect good f85363faaa040a9b9ac6502464a8b1ed7f711eab
> # good: [0ca88723ff14aa0a28d31772ef330f3eef97cba1] Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
> git bisect good 0ca88723ff14aa0a28d31772ef330f3eef97cba1
> # good: [c9545b54561efbedfe184a97dd07b4cdd8176146] Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
> git bisect good c9545b54561efbedfe184a97dd07b4cdd8176146
> # good: [4e22a2de97fb3b37e241058a4f9b91f3245590ea] Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
> git bisect good 4e22a2de97fb3b37e241058a4f9b91f3245590ea
> # bad: [903a65bcdcda676e86b1504f909c6565b1bd9df2] Merge branch 'pwm/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux.git
> git bisect bad 903a65bcdcda676e86b1504f909c6565b1bd9df2
> # good: [a3468cca30fe896b58f9f7b3bb5484f079010a12] Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git
> git bisect good a3468cca30fe896b58f9f7b3bb5484f079010a12
> # bad: [7fe595b3c3cf3f9b8f21fce72f1f48a2cb41522e] gpio: don't dereference gdev->chip in gpiochip_setup_dev()
> git bisect bad 7fe595b3c3cf3f9b8f21fce72f1f48a2cb41522e
> # good: [f57595788244a838deec2d3be375291327cbc035] gpio: vf610: allow disabling the vf610 driver
> git bisect good f57595788244a838deec2d3be375291327cbc035
> # good: [ccfb6ff4f6c0574e01fb16934fb60a46285c5f3f] gpio: don't set label from irq helpers
> git bisect good ccfb6ff4f6c0574e01fb16934fb60a46285c5f3f
> # bad: [b6f87adbacfab9001d08e56ac869e1c75734633d] gpio: remove unneeded code from gpio_device_get_desc()
> git bisect bad b6f87adbacfab9001d08e56ac869e1c75734633d
> # bad: [2a9101e875bc3aa6423b559e0ea43b2077f3be87] gpio: sysfs: use gpio_device_find() to iterate over existing devices
> git bisect bad 2a9101e875bc3aa6423b559e0ea43b2077f3be87
> # bad: [1f2bcb8c8ccdf9dc2e46f7986e1e22408506a6d6] gpio: protect the descriptor label with SRCU
> git bisect bad 1f2bcb8c8ccdf9dc2e46f7986e1e22408506a6d6
> # good: [be711caa87c5c81d5dc00b244cac3a0b775adb18] gpio: add SRCU infrastructure to struct gpio_desc
> git bisect good be711caa87c5c81d5dc00b244cac3a0b775adb18
> # first bad commit: [1f2bcb8c8ccdf9dc2e46f7986e1e22408506a6d6] gpio: protect the descriptor label with SRCU

Hi Mark,

Thanks for the report. Patch fixing this crash is already on the list
as of this morning. I'll queue it tomorrow and next should be fixed on
Thursday.

Bartosz
diff mbox series

Patch

diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 2c0a0700762d..75f4912339a6 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -2297,6 +2297,7 @@  static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
 {
 	struct gpio_chip *gc = desc->gdev->chip;
 	unsigned long dflags;
+	const char *label;
 
 	memset(info, 0, sizeof(*info));
 	info->offset = gpio_chip_hwgpio(desc);
@@ -2305,9 +2306,12 @@  static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
 		if (desc->name)
 			strscpy(info->name, desc->name, sizeof(info->name));
 
-		if (gpiod_get_label(desc))
-			strscpy(info->consumer, gpiod_get_label(desc),
-				sizeof(info->consumer));
+		scoped_guard(srcu, &desc->srcu) {
+			label = gpiod_get_label(desc);
+			if (label)
+				strscpy(info->consumer, label,
+					sizeof(info->consumer));
+		}
 
 		dflags = READ_ONCE(desc->flags);
 	}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index b26d39bc3389..a87ab8f013c4 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -114,12 +114,26 @@  const char *gpiod_get_label(struct gpio_desc *desc)
 	    !test_bit(FLAG_REQUESTED, &flags))
 		return "interrupt";
 
-	return test_bit(FLAG_REQUESTED, &flags) ? desc->label : NULL;
+	return test_bit(FLAG_REQUESTED, &flags) ?
+			rcu_dereference(desc->label) : NULL;
 }
 
-static inline void desc_set_label(struct gpio_desc *d, const char *label)
+static int desc_set_label(struct gpio_desc *desc, const char *label)
 {
-	d->label = label;
+	const char *new = NULL, *old;
+
+	if (label) {
+		/* FIXME: make this GFP_KERNEL once the spinlock is out. */
+		new = kstrdup_const(label, GFP_ATOMIC);
+		if (!new)
+			return -ENOMEM;
+	}
+
+	old = rcu_replace_pointer(desc->label, new, 1);
+	synchronize_srcu(&desc->srcu);
+	kfree_const(old);
+
+	return 0;
 }
 
 /**
@@ -2229,9 +2243,7 @@  static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
 	 * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
 	 */
 
-	if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
-		desc_set_label(desc, label ? : "?");
-	} else {
+	if (test_and_set_bit(FLAG_REQUESTED, &desc->flags)) {
 		ret = -EBUSY;
 		goto out_free_unlock;
 	}
@@ -2259,6 +2271,13 @@  static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
 		spin_lock_irqsave(&gpio_lock, flags);
 	}
 	spin_unlock_irqrestore(&gpio_lock, flags);
+
+	ret = desc_set_label(desc, label ? : "?");
+	if (ret) {
+		clear_bit(FLAG_REQUESTED, &desc->flags);
+		return ret;
+	}
+
 	return 0;
 
 out_free_unlock:
@@ -2343,8 +2362,6 @@  static bool gpiod_free_commit(struct gpio_desc *desc)
 			gc->free(gc, gpio_chip_hwgpio(desc));
 			spin_lock_irqsave(&gpio_lock, flags);
 		}
-		kfree_const(desc->label);
-		desc_set_label(desc, NULL);
 		clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
 		clear_bit(FLAG_REQUESTED, &desc->flags);
 		clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
@@ -2362,6 +2379,7 @@  static bool gpiod_free_commit(struct gpio_desc *desc)
 	}
 
 	spin_unlock_irqrestore(&gpio_lock, flags);
+	desc_set_label(desc, NULL);
 	gpiod_line_state_notify(desc, GPIOLINE_CHANGED_RELEASED);
 
 	return ret;
@@ -2409,6 +2427,8 @@  char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset)
 	if (!test_bit(FLAG_REQUESTED, &desc->flags))
 		return NULL;
 
+	guard(srcu)(&desc->srcu);
+
 	/*
 	 * FIXME: Once we mark gpiod_direction_input/output() and
 	 * gpiod_get_direction() with might_sleep(), we'll be able to protect
@@ -3520,16 +3540,8 @@  EXPORT_SYMBOL_GPL(gpiod_cansleep);
 int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name)
 {
 	VALIDATE_DESC(desc);
-	if (name) {
-		name = kstrdup_const(name, GFP_KERNEL);
-		if (!name)
-			return -ENOMEM;
-	}
 
-	kfree_const(desc->label);
-	desc_set_label(desc, name);
-
-	return 0;
+	return desc_set_label(desc, name);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_consumer_name);
 
@@ -4739,6 +4751,7 @@  static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
 	int value;
 
 	for_each_gpio_desc(gc, desc) {
+		guard(srcu)(&desc->srcu);
 		if (test_bit(FLAG_REQUESTED, &desc->flags)) {
 			gpiod_get_direction(desc);
 			is_out = test_bit(FLAG_IS_OUT, &desc->flags);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 6e14b629c48b..d2e73eea9e92 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -180,7 +180,7 @@  struct gpio_desc {
 #define FLAG_EVENT_CLOCK_HTE		19 /* GPIO CDEV reports hardware timestamps in events */
 
 	/* Connection label */
-	const char		*label;
+	const char __rcu	*label;
 	/* Name of the GPIO */
 	const char		*name;
 #ifdef CONFIG_OF_DYNAMIC
@@ -223,15 +223,29 @@  static inline int gpio_chip_hwgpio(const struct gpio_desc *desc)
 
 /* With descriptor prefix */
 
-#define gpiod_err(desc, fmt, ...)					       \
-	pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",  \
-		 ##__VA_ARGS__)
-#define gpiod_warn(desc, fmt, ...)					       \
-	pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
-		 ##__VA_ARGS__)
-#define gpiod_dbg(desc, fmt, ...)					       \
-	pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
-		 ##__VA_ARGS__)
+#define gpiod_err(desc, fmt, ...) \
+do { \
+	scoped_guard(srcu, &desc->srcu) { \
+		pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), \
+		       gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \
+	} \
+} while (0)
+
+#define gpiod_warn(desc, fmt, ...) \
+do { \
+	scoped_guard(srcu, &desc->srcu) { \
+		pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), \
+			gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \
+	} \
+} while (0)
+
+#define gpiod_dbg(desc, fmt, ...) \
+do { \
+	scoped_guard(srcu, &desc->srcu) { \
+		pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), \
+			 gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \
+	} \
+} while (0)
 
 /* With chip prefix */