Message ID | 20240208095920.8035-23-brgl@bgdev.pl |
---|---|
State | New |
Headers | show |
Series | gpio: rework locking and object life-time control | expand |
Hello, kernel test robot noticed "WARNING:suspicious_RCU_usage" on: commit: c21131f83abc1f7227e7a6d5311e1df68bfa44e0 ("[PATCH v3 22/24] gpio: protect the pointer to gpio_chip in gpio_device 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-23-brgl@bgdev.pl/ patch subject: [PATCH v3 22/24] gpio: protect the pointer to gpio_chip in gpio_device 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) +-----------------------------------------------------------------+------------+------------+ | | a3dfc11062 | c21131f83a | +-----------------------------------------------------------------+------------+------------+ | drivers/gpio/gpiolib.c:#suspicious_rcu_dereference_check()usage | 0 | 8 | | drivers/gpio/gpiolib.h:#suspicious_rcu_dereference_check()usage | 0 | 8 | +-----------------------------------------------------------------+------------+------------+ 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 <oliver.sang@intel.com> | Closes: https://lore.kernel.org/oe-lkp/202402122234.d85cca9b-lkp@intel.com [ 76.432519][ T1] gpiochip_find_base_unlocked: found new base at 512 [ 76.434591][ T1] [ 76.435240][ T1] ============================= [ 76.436545][ T1] WARNING: suspicious RCU usage [ 76.437813][ T1] 6.8.0-rc1-00050-gc21131f83abc #1 Tainted: G N [ 76.439873][ T1] ----------------------------- [ 76.441158][ T1] drivers/gpio/gpiolib.c:219 suspicious rcu_dereference_check() usage! [ 76.443364][ T1] [ 76.443364][ T1] other info that might help us debug this: [ 76.443364][ T1] [ 76.446059][ T1] [ 76.446059][ T1] rcu_scheduler_active = 2, debug_locks = 1 [ 76.448217][ T1] 1 lock held by swapper/1: [ 76.449412][ T1] #0: ffff88816954f0f0 (&dev->mutex){....}-{3:3}, at: __driver_attach (drivers/base/dd.c:1216) [ 76.451938][ T1] [ 76.451938][ T1] stack backtrace: [ 76.453486][ T1] CPU: 0 PID: 1 Comm: swapper Tainted: G N 6.8.0-rc1-00050-gc21131f83abc #1 [ 76.456114][ T1] Call Trace: [ 76.456936][ T1] <TASK> [ 76.457682][ T1] dump_stack_lvl (lib/dump_stack.c:107 (discriminator 1)) [ 76.458833][ T1] lockdep_rcu_suspicious (include/linux/context_tracking.h:153 kernel/locking/lockdep.c:6713) [ 76.460205][ T1] gpiod_to_chip (drivers/gpio/gpiolib.c:219 (discriminator 9)) [ 76.461346][ T1] gpiod_hog (drivers/gpio/gpiolib.h:243 drivers/gpio/gpiolib.c:4502) [ 76.462400][ T1] ? of_find_property (drivers/of/base.c:223) [ 76.463671][ T1] of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:799) [ 76.464933][ T1] ? __pfx_of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:785) [ 76.466378][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) [ 76.467894][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) [ 76.469220][ T1] ? _raw_spin_unlock_irqrestore (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:152 kernel/locking/spinlock.c:194) [ 76.470786][ T1] of_gpiochip_add (drivers/gpio/gpiolib-of.c:828 drivers/gpio/gpiolib-of.c:1143) [ 76.472060][ T1] ? fwnode_property_read_int_array (drivers/base/property.c:268 (discriminator 5)) [ 76.473692][ T1] gpiochip_add_data_with_key (drivers/gpio/gpiolib.c:989) [ 76.475271][ T1] ? kasan_save_track (arch/x86/include/asm/current.h:42 mm/kasan/common.c:60 mm/kasan/common.c:70) [ 76.476567][ T1] unittest_gpio_probe (drivers/of/unittest.c:1886) [ 76.477928][ T1] platform_probe (drivers/base/platform.c:1404) [ 76.479162][ T1] really_probe (drivers/base/dd.c:579 drivers/base/dd.c:658) [ 76.480403][ T1] __driver_probe_device (drivers/base/dd.c:800) [ 76.481791][ T1] driver_probe_device (drivers/base/dd.c:830) [ 76.483097][ T1] __driver_attach (drivers/base/dd.c:1217) [ 76.484388][ T1] ? __pfx___driver_attach (drivers/base/dd.c:1157) [ 76.485805][ T1] bus_for_each_dev (drivers/base/bus.c:367) [ 76.487037][ T1] ? lockdep_init_map_type (kernel/locking/lockdep.c:4892) [ 76.488477][ T1] ? __pfx_bus_for_each_dev (drivers/base/bus.c:356) [ 76.489897][ T1] ? bus_add_driver (drivers/base/bus.c:672) [ 76.491195][ T1] bus_add_driver (drivers/base/bus.c:674) [ 76.492463][ T1] driver_register (drivers/base/driver.c:246) [ 76.493723][ T1] of_unittest_overlay_gpio (drivers/of/unittest.c:1969 (discriminator 4)) [ 76.495167][ T1] of_unittest_overlay (drivers/of/unittest.c:2189 drivers/of/unittest.c:3217) [ 76.496478][ T1] ? __pfx_of_unittest_overlay (drivers/of/unittest.c:3155) [ 76.497886][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) [ 76.499410][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) [ 76.500744][ T1] of_unittest (drivers/of/unittest.c:4129) [ 76.501862][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) [ 76.503098][ T1] ? add_device_randomness (drivers/char/random.c:918) [ 76.504492][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) [ 76.505807][ T1] do_one_initcall (init/main.c:1236) [ 76.507054][ T1] ? __pfx_do_one_initcall (init/main.c:1227) [ 76.508517][ T1] do_initcalls (init/main.c:1297 init/main.c:1314) [ 76.509731][ T1] kernel_init_freeable (init/main.c:1555) [ 76.511106][ T1] ? __pfx_kernel_init (init/main.c:1433) [ 76.512435][ T1] kernel_init (init/main.c:1443) [ 76.513566][ T1] ? _raw_spin_unlock_irq (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:160 kernel/locking/spinlock.c:202) [ 76.514947][ T1] ret_from_fork (arch/x86/kernel/process.c:153) [ 76.516125][ T1] ? __pfx_kernel_init (init/main.c:1433) [ 76.517440][ T1] ret_from_fork_asm (arch/x86/entry/entry_64.S:250) [ 76.518731][ T1] </TASK> [ 76.519758][ T1] [ 76.520477][ T1] ============================= [ 76.521774][ T1] WARNING: suspicious RCU usage [ 76.523076][ T1] 6.8.0-rc1-00050-gc21131f83abc #1 Tainted: G N [ 76.525108][ T1] ----------------------------- [ 76.526429][ T1] drivers/gpio/gpiolib.h:210 suspicious rcu_dereference_check() usage! [ 76.528621][ T1] [ 76.528621][ T1] other info that might help us debug this: [ 76.528621][ T1] [ 76.531350][ T1] [ 76.531350][ T1] rcu_scheduler_active = 2, debug_locks = 1 [ 76.533414][ T1] 2 locks held by swapper/1: [ 76.534616][ T1] #0: ffff88816954f0f0 (&dev->mutex){....}-{3:3}, at: __driver_attach (drivers/base/dd.c:1216) [ 76.537073][ T1] #1: ffff888163afb6d0 (&gdev->srcu){.+.+}-{0:0}, at: gpiod_request_commit (include/linux/srcu.h:116 include/linux/srcu.h:215 drivers/gpio/gpiolib.h:202 drivers/gpio/gpiolib.c:2243) [ 76.539703][ T1] [ 76.539703][ T1] stack backtrace: [ 76.541276][ T1] CPU: 0 PID: 1 Comm: swapper Tainted: G N 6.8.0-rc1-00050-gc21131f83abc #1 [ 76.543890][ T1] Call Trace: [ 76.544767][ T1] <TASK> [ 76.545549][ T1] dump_stack_lvl (lib/dump_stack.c:107 (discriminator 1)) [ 76.546740][ T1] lockdep_rcu_suspicious (include/linux/context_tracking.h:153 kernel/locking/lockdep.c:6713) [ 76.548196][ T1] gpiod_request_commit (drivers/gpio/gpiolib.h:202 drivers/gpio/gpiolib.c:2243) [ 76.549584][ T1] ? dump_stack_lvl (lib/dump_stack.c:108) [ 76.550829][ T1] gpiochip_request_own_desc (drivers/gpio/gpiolib.c:2454) [ 76.552354][ T1] gpiod_hog (drivers/gpio/gpiolib.c:4504) [ 76.553556][ T1] of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:799) [ 76.554948][ T1] ? __pfx_of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:785) [ 76.556536][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) [ 76.558176][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) [ 76.559633][ T1] ? _raw_spin_unlock_irqrestore (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:152 kernel/locking/spinlock.c:194) [ 76.561252][ T1] of_gpiochip_add (drivers/gpio/gpiolib-of.c:828 drivers/gpio/gpiolib-of.c:1143) [ 76.562584][ T1] ? fwnode_property_read_int_array (drivers/base/property.c:268 (discriminator 5)) [ 76.564302][ T1] gpiochip_add_data_with_key (drivers/gpio/gpiolib.c:989) [ 76.565974][ T1] ? kasan_save_track (arch/x86/include/asm/current.h:42 mm/kasan/common.c:60 mm/kasan/common.c:70) [ 76.567328][ T1] unittest_gpio_probe (drivers/of/unittest.c:1886) [ 76.568780][ T1] platform_probe (drivers/base/platform.c:1404) [ 76.570065][ T1] really_probe (drivers/base/dd.c:579 drivers/base/dd.c:658) [ 76.571309][ T1] __driver_probe_device (drivers/base/dd.c:800) [ 76.572801][ T1] driver_probe_device (drivers/base/dd.c:830) [ 76.574175][ T1] __driver_attach (drivers/base/dd.c:1217) [ 76.575513][ T1] ? __pfx___driver_attach (drivers/base/dd.c:1157) [ 76.576994][ T1] bus_for_each_dev (drivers/base/bus.c:367) [ 76.578331][ T1] ? lockdep_init_map_type (kernel/locking/lockdep.c:4892) [ 76.579877][ T1] ? __pfx_bus_for_each_dev (drivers/base/bus.c:356) [ 76.581368][ T1] ? bus_add_driver (drivers/base/bus.c:672) [ 76.582799][ T1] bus_add_driver (drivers/base/bus.c:674) [ 76.584128][ T1] driver_register (drivers/base/driver.c:246) [ 76.585452][ T1] of_unittest_overlay_gpio (drivers/of/unittest.c:1969 (discriminator 4)) [ 76.586969][ T1] of_unittest_overlay (drivers/of/unittest.c:2189 drivers/of/unittest.c:3217) [ 76.588400][ T1] ? __pfx_of_unittest_overlay (drivers/of/unittest.c:3155) [ 76.589958][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) [ 76.591624][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) [ 76.593071][ T1] of_unittest (drivers/of/unittest.c:4129) [ 76.594323][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) [ 76.595700][ T1] ? add_device_randomness (drivers/char/random.c:918) [ 76.597164][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) [ 76.598482][ T1] do_one_initcall (init/main.c:1236) [ 76.599728][ T1] ? __pfx_do_one_initcall (init/main.c:1227) [ 76.601163][ T1] do_initcalls (init/main.c:1297 init/main.c:1314) [ 76.602389][ T1] kernel_init_freeable (init/main.c:1555) [ 76.603810][ T1] ? __pfx_kernel_init (init/main.c:1433) [ 76.605101][ T1] kernel_init (init/main.c:1443) [ 76.606235][ T1] ? _raw_spin_unlock_irq (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:160 kernel/locking/spinlock.c:202) [ 76.607627][ T1] ret_from_fork (arch/x86/kernel/process.c:153) [ 76.608797][ T1] ? __pfx_kernel_init (init/main.c:1433) [ 76.610112][ T1] ret_from_fork_asm (arch/x86/entry/entry_64.S:250) [ 76.611412][ T1] </TASK> [ 76.612591][ T1] general protection fault, probably for non-canonical address 0xdffffc000000002f: 0000 [#1] PREEMPT KASAN PTI [ 76.615654][ T1] KASAN: null-ptr-deref in range [0x0000000000000178-0x000000000000017f] [ 76.617847][ T1] CPU: 0 PID: 1 Comm: swapper Tainted: G N 6.8.0-rc1-00050-gc21131f83abc #1 [ 76.620463][ T1] RIP: 0010:check_init_srcu_struct (kernel/rcu/srcutree.c:408) [ 76.622072][ 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 [ 76.627183][ T1] RSP: 0018:ffff888103a6f718 EFLAGS: 00010202 [ 76.628803][ T1] RAX: dffffc0000000000 RBX: ffff88810ee660f8 RCX: 0000000000000000 [ 76.630879][ T1] RDX: 000000000000002f RSI: ffff88816976b000 RDI: 0000000000000178 [ 76.632960][ T1] RBP: 0000000000000000 R08: 692d422d656e696c R09: 007475706e692d42 [ 76.635045][ T1] R10: ffff888103a6f750 R11: ffffffff810b3aef R12: ffff88810ee66130 [ 76.641151][ T1] R13: ffff888163afb6c0 R14: 0000000000000000 R15: ffff888163afb6d0 [ 76.643224][ T1] FS: 0000000000000000(0000) GS:ffffffff84cd1000(0000) knlGS:0000000000000000 [ 76.645563][ T1] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 76.647278][ T1] CR2: 00007fab8f4456f4 CR3: 0000000004cac000 CR4: 00000000000406b0 [ 76.649355][ T1] Call Trace: [ 76.650221][ T1] <TASK> [ 76.651020][ T1] ? die_addr (arch/x86/kernel/dumpstack.c:421 arch/x86/kernel/dumpstack.c:460) [ 76.652132][ T1] ? exc_general_protection (arch/x86/kernel/traps.c:701 arch/x86/kernel/traps.c:643) [ 76.653604][ T1] ? asm_exc_general_protection (arch/x86/include/asm/idtentry.h:564) [ 76.655133][ T1] ? ret_from_fork (arch/x86/kernel/process.c:153) [ 76.656355][ T1] ? check_init_srcu_struct (kernel/rcu/srcutree.c:408) [ 76.657792][ T1] synchronize_srcu (kernel/rcu/srcutree.c:1167 kernel/rcu/srcutree.c:1458) [ 76.659048][ T1] gpiod_request_commit (drivers/gpio/gpiolib.c:127 drivers/gpio/gpiolib.c:2273) [ 76.660430][ T1] gpiochip_request_own_desc (drivers/gpio/gpiolib.c:2454) [ 76.661898][ T1] gpiod_hog (drivers/gpio/gpiolib.c:4504) [ 76.663000][ T1] of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:799) [ 76.664334][ T1] ? __pfx_of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:785) [ 76.665830][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) [ 76.667387][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) [ 76.668763][ T1] ? _raw_spin_unlock_irqrestore (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:152 kernel/locking/spinlock.c:194) [ 76.670279][ T1] of_gpiochip_add (drivers/gpio/gpiolib-of.c:828 drivers/gpio/gpiolib-of.c:1143) [ 76.671550][ T1] ? fwnode_property_read_int_array (drivers/base/property.c:268 (discriminator 5)) [ 76.673171][ T1] gpiochip_add_data_with_key (drivers/gpio/gpiolib.c:989) [ 76.674714][ T1] ? kasan_save_track (arch/x86/include/asm/current.h:42 mm/kasan/common.c:60 mm/kasan/common.c:70) [ 76.676002][ T1] unittest_gpio_probe (drivers/of/unittest.c:1886) [ 76.677340][ T1] platform_probe (drivers/base/platform.c:1404) [ 76.678544][ T1] really_probe (drivers/base/dd.c:579 drivers/base/dd.c:658) [ 76.679745][ T1] __driver_probe_device (drivers/base/dd.c:800) [ 76.681126][ T1] driver_probe_device (drivers/base/dd.c:830) [ 76.682411][ T1] __driver_attach (drivers/base/dd.c:1217) [ 76.683679][ T1] ? __pfx___driver_attach (drivers/base/dd.c:1157) [ 76.685074][ T1] bus_for_each_dev (drivers/base/bus.c:367) [ 76.686340][ T1] ? lockdep_init_map_type (kernel/locking/lockdep.c:4892) [ 76.687774][ T1] ? __pfx_bus_for_each_dev (drivers/base/bus.c:356) [ 76.689176][ T1] ? bus_add_driver (drivers/base/bus.c:672) [ 76.690452][ T1] bus_add_driver (drivers/base/bus.c:674) [ 76.691691][ T1] driver_register (drivers/base/driver.c:246) [ 76.692949][ T1] of_unittest_overlay_gpio (drivers/of/unittest.c:1969 (discriminator 4)) [ 76.694377][ T1] of_unittest_overlay (drivers/of/unittest.c:2189 drivers/of/unittest.c:3217) [ 76.695724][ T1] ? __pfx_of_unittest_overlay (drivers/of/unittest.c:3155) [ 76.697198][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) [ 76.698764][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) [ 76.700151][ T1] of_unittest (drivers/of/unittest.c:4129) [ 76.701323][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) [ 76.702622][ T1] ? add_device_randomness (drivers/char/random.c:918) [ 76.704050][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) [ 76.705347][ T1] do_one_initcall (init/main.c:1236) [ 76.706572][ T1] ? __pfx_do_one_initcall (init/main.c:1227) [ 76.708227][ T1] do_initcalls (init/main.c:1297 init/main.c:1314) The kernel config and materials to reproduce are available at: https://download.01.org/0day-ci/archive/20240212/202402122234.d85cca9b-lkp@intel.com
On Mon, Feb 12, 2024 at 4:11 PM kernel test robot <oliver.sang@intel.com> wrote: > > > > Hello, > > kernel test robot noticed "WARNING:suspicious_RCU_usage" on: > > commit: c21131f83abc1f7227e7a6d5311e1df68bfa44e0 ("[PATCH v3 22/24] gpio: protect the pointer to gpio_chip in gpio_device 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-23-brgl@bgdev.pl/ > patch subject: [PATCH v3 22/24] gpio: protect the pointer to gpio_chip in gpio_device 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) > > > +-----------------------------------------------------------------+------------+------------+ > | | a3dfc11062 | c21131f83a | > +-----------------------------------------------------------------+------------+------------+ > | drivers/gpio/gpiolib.c:#suspicious_rcu_dereference_check()usage | 0 | 8 | > | drivers/gpio/gpiolib.h:#suspicious_rcu_dereference_check()usage | 0 | 8 | > +-----------------------------------------------------------------+------------+------------+ > > > 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 <oliver.sang@intel.com> > | Closes: https://lore.kernel.org/oe-lkp/202402122234.d85cca9b-lkp@intel.com > > > > [ 76.432519][ T1] gpiochip_find_base_unlocked: found new base at 512 > [ 76.434591][ T1] > [ 76.435240][ T1] ============================= > [ 76.436545][ T1] WARNING: suspicious RCU usage > [ 76.437813][ T1] 6.8.0-rc1-00050-gc21131f83abc #1 Tainted: G N > [ 76.439873][ T1] ----------------------------- > [ 76.441158][ T1] drivers/gpio/gpiolib.c:219 suspicious rcu_dereference_check() usage! > [ 76.443364][ T1] > [ 76.443364][ T1] other info that might help us debug this: > [ 76.443364][ T1] > [ 76.446059][ T1] > [ 76.446059][ T1] rcu_scheduler_active = 2, debug_locks = 1 > [ 76.448217][ T1] 1 lock held by swapper/1: > [ 76.449412][ T1] #0: ffff88816954f0f0 (&dev->mutex){....}-{3:3}, at: __driver_attach (drivers/base/dd.c:1216) > [ 76.451938][ T1] > [ 76.451938][ T1] stack backtrace: > [ 76.453486][ T1] CPU: 0 PID: 1 Comm: swapper Tainted: G N 6.8.0-rc1-00050-gc21131f83abc #1 > [ 76.456114][ T1] Call Trace: > [ 76.456936][ T1] <TASK> > [ 76.457682][ T1] dump_stack_lvl (lib/dump_stack.c:107 (discriminator 1)) > [ 76.458833][ T1] lockdep_rcu_suspicious (include/linux/context_tracking.h:153 kernel/locking/lockdep.c:6713) > [ 76.460205][ T1] gpiod_to_chip (drivers/gpio/gpiolib.c:219 (discriminator 9)) > [ 76.461346][ T1] gpiod_hog (drivers/gpio/gpiolib.h:243 drivers/gpio/gpiolib.c:4502) Ah, gpiod_hog() is not taking the SRCU read lock as it should. I'll send a fix. Bart [snip]
On Mon, Feb 12, 2024 at 4:11 PM kernel test robot <oliver.sang@intel.com> wrote: > > > > Hello, > > kernel test robot noticed "WARNING:suspicious_RCU_usage" on: > > commit: c21131f83abc1f7227e7a6d5311e1df68bfa44e0 ("[PATCH v3 22/24] gpio: protect the pointer to gpio_chip in gpio_device 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-23-brgl@bgdev.pl/ > patch subject: [PATCH v3 22/24] gpio: protect the pointer to gpio_chip in gpio_device 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) > > > +-----------------------------------------------------------------+------------+------------+ > | | a3dfc11062 | c21131f83a | > +-----------------------------------------------------------------+------------+------------+ > | drivers/gpio/gpiolib.c:#suspicious_rcu_dereference_check()usage | 0 | 8 | > | drivers/gpio/gpiolib.h:#suspicious_rcu_dereference_check()usage | 0 | 8 | > +-----------------------------------------------------------------+------------+------------+ > > > 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 <oliver.sang@intel.com> > | Closes: https://lore.kernel.org/oe-lkp/202402122234.d85cca9b-lkp@intel.com > > > > [ 76.432519][ T1] gpiochip_find_base_unlocked: found new base at 512 > [ 76.434591][ T1] > [ 76.435240][ T1] ============================= > [ 76.436545][ T1] WARNING: suspicious RCU usage > [ 76.437813][ T1] 6.8.0-rc1-00050-gc21131f83abc #1 Tainted: G N > [ 76.439873][ T1] ----------------------------- > [ 76.441158][ T1] drivers/gpio/gpiolib.c:219 suspicious rcu_dereference_check() usage! > [ 76.443364][ T1] > [ 76.443364][ T1] other info that might help us debug this: > [ 76.443364][ T1] > [ 76.446059][ T1] > [ 76.446059][ T1] rcu_scheduler_active = 2, debug_locks = 1 > [ 76.448217][ T1] 1 lock held by swapper/1: > [ 76.449412][ T1] #0: ffff88816954f0f0 (&dev->mutex){....}-{3:3}, at: __driver_attach (drivers/base/dd.c:1216) > [ 76.451938][ T1] > [ 76.451938][ T1] stack backtrace: > [ 76.453486][ T1] CPU: 0 PID: 1 Comm: swapper Tainted: G N 6.8.0-rc1-00050-gc21131f83abc #1 > [ 76.456114][ T1] Call Trace: > [ 76.456936][ T1] <TASK> > [ 76.457682][ T1] dump_stack_lvl (lib/dump_stack.c:107 (discriminator 1)) > [ 76.458833][ T1] lockdep_rcu_suspicious (include/linux/context_tracking.h:153 kernel/locking/lockdep.c:6713) > [ 76.460205][ T1] gpiod_to_chip (drivers/gpio/gpiolib.c:219 (discriminator 9)) > [ 76.461346][ T1] gpiod_hog (drivers/gpio/gpiolib.h:243 drivers/gpio/gpiolib.c:4502) > [ 76.462400][ T1] ? of_find_property (drivers/of/base.c:223) > [ 76.463671][ T1] of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:799) > [ 76.464933][ T1] ? __pfx_of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:785) > [ 76.466378][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) > [ 76.467894][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) > [ 76.469220][ T1] ? _raw_spin_unlock_irqrestore (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:152 kernel/locking/spinlock.c:194) > [ 76.470786][ T1] of_gpiochip_add (drivers/gpio/gpiolib-of.c:828 drivers/gpio/gpiolib-of.c:1143) > [ 76.472060][ T1] ? fwnode_property_read_int_array (drivers/base/property.c:268 (discriminator 5)) > [ 76.473692][ T1] gpiochip_add_data_with_key (drivers/gpio/gpiolib.c:989) > [ 76.475271][ T1] ? kasan_save_track (arch/x86/include/asm/current.h:42 mm/kasan/common.c:60 mm/kasan/common.c:70) > [ 76.476567][ T1] unittest_gpio_probe (drivers/of/unittest.c:1886) > [ 76.477928][ T1] platform_probe (drivers/base/platform.c:1404) > [ 76.479162][ T1] really_probe (drivers/base/dd.c:579 drivers/base/dd.c:658) > [ 76.480403][ T1] __driver_probe_device (drivers/base/dd.c:800) > [ 76.481791][ T1] driver_probe_device (drivers/base/dd.c:830) > [ 76.483097][ T1] __driver_attach (drivers/base/dd.c:1217) > [ 76.484388][ T1] ? __pfx___driver_attach (drivers/base/dd.c:1157) > [ 76.485805][ T1] bus_for_each_dev (drivers/base/bus.c:367) > [ 76.487037][ T1] ? lockdep_init_map_type (kernel/locking/lockdep.c:4892) > [ 76.488477][ T1] ? __pfx_bus_for_each_dev (drivers/base/bus.c:356) > [ 76.489897][ T1] ? bus_add_driver (drivers/base/bus.c:672) > [ 76.491195][ T1] bus_add_driver (drivers/base/bus.c:674) > [ 76.492463][ T1] driver_register (drivers/base/driver.c:246) > [ 76.493723][ T1] of_unittest_overlay_gpio (drivers/of/unittest.c:1969 (discriminator 4)) > [ 76.495167][ T1] of_unittest_overlay (drivers/of/unittest.c:2189 drivers/of/unittest.c:3217) > [ 76.496478][ T1] ? __pfx_of_unittest_overlay (drivers/of/unittest.c:3155) > [ 76.497886][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) > [ 76.499410][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) > [ 76.500744][ T1] of_unittest (drivers/of/unittest.c:4129) > [ 76.501862][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) > [ 76.503098][ T1] ? add_device_randomness (drivers/char/random.c:918) > [ 76.504492][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) > [ 76.505807][ T1] do_one_initcall (init/main.c:1236) > [ 76.507054][ T1] ? __pfx_do_one_initcall (init/main.c:1227) > [ 76.508517][ T1] do_initcalls (init/main.c:1297 init/main.c:1314) > [ 76.509731][ T1] kernel_init_freeable (init/main.c:1555) > [ 76.511106][ T1] ? __pfx_kernel_init (init/main.c:1433) > [ 76.512435][ T1] kernel_init (init/main.c:1443) > [ 76.513566][ T1] ? _raw_spin_unlock_irq (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:160 kernel/locking/spinlock.c:202) > [ 76.514947][ T1] ret_from_fork (arch/x86/kernel/process.c:153) > [ 76.516125][ T1] ? __pfx_kernel_init (init/main.c:1433) > [ 76.517440][ T1] ret_from_fork_asm (arch/x86/entry/entry_64.S:250) > [ 76.518731][ T1] </TASK> > [ 76.519758][ T1] > [ 76.520477][ T1] ============================= > [ 76.521774][ T1] WARNING: suspicious RCU usage > [ 76.523076][ T1] 6.8.0-rc1-00050-gc21131f83abc #1 Tainted: G N > [ 76.525108][ T1] ----------------------------- > [ 76.526429][ T1] drivers/gpio/gpiolib.h:210 suspicious rcu_dereference_check() usage! > [ 76.528621][ T1] > [ 76.528621][ T1] other info that might help us debug this: > [ 76.528621][ T1] > [ 76.531350][ T1] > [ 76.531350][ T1] rcu_scheduler_active = 2, debug_locks = 1 > [ 76.533414][ T1] 2 locks held by swapper/1: > [ 76.534616][ T1] #0: ffff88816954f0f0 (&dev->mutex){....}-{3:3}, at: __driver_attach (drivers/base/dd.c:1216) > [ 76.537073][ T1] #1: ffff888163afb6d0 (&gdev->srcu){.+.+}-{0:0}, at: gpiod_request_commit (include/linux/srcu.h:116 include/linux/srcu.h:215 drivers/gpio/gpiolib.h:202 drivers/gpio/gpiolib.c:2243) > [ 76.539703][ T1] > [ 76.539703][ T1] stack backtrace: > [ 76.541276][ T1] CPU: 0 PID: 1 Comm: swapper Tainted: G N 6.8.0-rc1-00050-gc21131f83abc #1 > [ 76.543890][ T1] Call Trace: > [ 76.544767][ T1] <TASK> > [ 76.545549][ T1] dump_stack_lvl (lib/dump_stack.c:107 (discriminator 1)) > [ 76.546740][ T1] lockdep_rcu_suspicious (include/linux/context_tracking.h:153 kernel/locking/lockdep.c:6713) > [ 76.548196][ T1] gpiod_request_commit (drivers/gpio/gpiolib.h:202 drivers/gpio/gpiolib.c:2243) > [ 76.549584][ T1] ? dump_stack_lvl (lib/dump_stack.c:108) > [ 76.550829][ T1] gpiochip_request_own_desc (drivers/gpio/gpiolib.c:2454) > [ 76.552354][ T1] gpiod_hog (drivers/gpio/gpiolib.c:4504) > [ 76.553556][ T1] of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:799) > [ 76.554948][ T1] ? __pfx_of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:785) > [ 76.556536][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) > [ 76.558176][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) > [ 76.559633][ T1] ? _raw_spin_unlock_irqrestore (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:152 kernel/locking/spinlock.c:194) > [ 76.561252][ T1] of_gpiochip_add (drivers/gpio/gpiolib-of.c:828 drivers/gpio/gpiolib-of.c:1143) > [ 76.562584][ T1] ? fwnode_property_read_int_array (drivers/base/property.c:268 (discriminator 5)) > [ 76.564302][ T1] gpiochip_add_data_with_key (drivers/gpio/gpiolib.c:989) > [ 76.565974][ T1] ? kasan_save_track (arch/x86/include/asm/current.h:42 mm/kasan/common.c:60 mm/kasan/common.c:70) > [ 76.567328][ T1] unittest_gpio_probe (drivers/of/unittest.c:1886) > [ 76.568780][ T1] platform_probe (drivers/base/platform.c:1404) > [ 76.570065][ T1] really_probe (drivers/base/dd.c:579 drivers/base/dd.c:658) > [ 76.571309][ T1] __driver_probe_device (drivers/base/dd.c:800) > [ 76.572801][ T1] driver_probe_device (drivers/base/dd.c:830) > [ 76.574175][ T1] __driver_attach (drivers/base/dd.c:1217) > [ 76.575513][ T1] ? __pfx___driver_attach (drivers/base/dd.c:1157) > [ 76.576994][ T1] bus_for_each_dev (drivers/base/bus.c:367) > [ 76.578331][ T1] ? lockdep_init_map_type (kernel/locking/lockdep.c:4892) > [ 76.579877][ T1] ? __pfx_bus_for_each_dev (drivers/base/bus.c:356) > [ 76.581368][ T1] ? bus_add_driver (drivers/base/bus.c:672) > [ 76.582799][ T1] bus_add_driver (drivers/base/bus.c:674) > [ 76.584128][ T1] driver_register (drivers/base/driver.c:246) > [ 76.585452][ T1] of_unittest_overlay_gpio (drivers/of/unittest.c:1969 (discriminator 4)) > [ 76.586969][ T1] of_unittest_overlay (drivers/of/unittest.c:2189 drivers/of/unittest.c:3217) > [ 76.588400][ T1] ? __pfx_of_unittest_overlay (drivers/of/unittest.c:3155) > [ 76.589958][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) > [ 76.591624][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) > [ 76.593071][ T1] of_unittest (drivers/of/unittest.c:4129) > [ 76.594323][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) > [ 76.595700][ T1] ? add_device_randomness (drivers/char/random.c:918) > [ 76.597164][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) > [ 76.598482][ T1] do_one_initcall (init/main.c:1236) > [ 76.599728][ T1] ? __pfx_do_one_initcall (init/main.c:1227) > [ 76.601163][ T1] do_initcalls (init/main.c:1297 init/main.c:1314) > [ 76.602389][ T1] kernel_init_freeable (init/main.c:1555) > [ 76.603810][ T1] ? __pfx_kernel_init (init/main.c:1433) > [ 76.605101][ T1] kernel_init (init/main.c:1443) > [ 76.606235][ T1] ? _raw_spin_unlock_irq (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:160 kernel/locking/spinlock.c:202) > [ 76.607627][ T1] ret_from_fork (arch/x86/kernel/process.c:153) > [ 76.608797][ T1] ? __pfx_kernel_init (init/main.c:1433) > [ 76.610112][ T1] ret_from_fork_asm (arch/x86/entry/entry_64.S:250) > [ 76.611412][ T1] </TASK> > [ 76.612591][ T1] general protection fault, probably for non-canonical address 0xdffffc000000002f: 0000 [#1] PREEMPT KASAN PTI > [ 76.615654][ T1] KASAN: null-ptr-deref in range [0x0000000000000178-0x000000000000017f] > [ 76.617847][ T1] CPU: 0 PID: 1 Comm: swapper Tainted: G N 6.8.0-rc1-00050-gc21131f83abc #1 > [ 76.620463][ T1] RIP: 0010:check_init_srcu_struct (kernel/rcu/srcutree.c:408) > [ 76.622072][ 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 > [ 76.627183][ T1] RSP: 0018:ffff888103a6f718 EFLAGS: 00010202 > [ 76.628803][ T1] RAX: dffffc0000000000 RBX: ffff88810ee660f8 RCX: 0000000000000000 > [ 76.630879][ T1] RDX: 000000000000002f RSI: ffff88816976b000 RDI: 0000000000000178 > [ 76.632960][ T1] RBP: 0000000000000000 R08: 692d422d656e696c R09: 007475706e692d42 > [ 76.635045][ T1] R10: ffff888103a6f750 R11: ffffffff810b3aef R12: ffff88810ee66130 > [ 76.641151][ T1] R13: ffff888163afb6c0 R14: 0000000000000000 R15: ffff888163afb6d0 > [ 76.643224][ T1] FS: 0000000000000000(0000) GS:ffffffff84cd1000(0000) knlGS:0000000000000000 > [ 76.645563][ T1] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 > [ 76.647278][ T1] CR2: 00007fab8f4456f4 CR3: 0000000004cac000 CR4: 00000000000406b0 > [ 76.649355][ T1] Call Trace: > [ 76.650221][ T1] <TASK> > [ 76.651020][ T1] ? die_addr (arch/x86/kernel/dumpstack.c:421 arch/x86/kernel/dumpstack.c:460) > [ 76.652132][ T1] ? exc_general_protection (arch/x86/kernel/traps.c:701 arch/x86/kernel/traps.c:643) > [ 76.653604][ T1] ? asm_exc_general_protection (arch/x86/include/asm/idtentry.h:564) > [ 76.655133][ T1] ? ret_from_fork (arch/x86/kernel/process.c:153) > [ 76.656355][ T1] ? check_init_srcu_struct (kernel/rcu/srcutree.c:408) > [ 76.657792][ T1] synchronize_srcu (kernel/rcu/srcutree.c:1167 kernel/rcu/srcutree.c:1458) > [ 76.659048][ T1] gpiod_request_commit (drivers/gpio/gpiolib.c:127 drivers/gpio/gpiolib.c:2273) > [ 76.660430][ T1] gpiochip_request_own_desc (drivers/gpio/gpiolib.c:2454) > [ 76.661898][ T1] gpiod_hog (drivers/gpio/gpiolib.c:4504) > [ 76.663000][ T1] of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:799) > [ 76.664334][ T1] ? __pfx_of_gpiochip_add_hog (drivers/gpio/gpiolib-of.c:785) > [ 76.665830][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) > [ 76.667387][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) > [ 76.668763][ T1] ? _raw_spin_unlock_irqrestore (arch/x86/include/asm/preempt.h:103 include/linux/spinlock_api_smp.h:152 kernel/locking/spinlock.c:194) > [ 76.670279][ T1] of_gpiochip_add (drivers/gpio/gpiolib-of.c:828 drivers/gpio/gpiolib-of.c:1143) > [ 76.671550][ T1] ? fwnode_property_read_int_array (drivers/base/property.c:268 (discriminator 5)) > [ 76.673171][ T1] gpiochip_add_data_with_key (drivers/gpio/gpiolib.c:989) > [ 76.674714][ T1] ? kasan_save_track (arch/x86/include/asm/current.h:42 mm/kasan/common.c:60 mm/kasan/common.c:70) > [ 76.676002][ T1] unittest_gpio_probe (drivers/of/unittest.c:1886) > [ 76.677340][ T1] platform_probe (drivers/base/platform.c:1404) > [ 76.678544][ T1] really_probe (drivers/base/dd.c:579 drivers/base/dd.c:658) > [ 76.679745][ T1] __driver_probe_device (drivers/base/dd.c:800) > [ 76.681126][ T1] driver_probe_device (drivers/base/dd.c:830) > [ 76.682411][ T1] __driver_attach (drivers/base/dd.c:1217) > [ 76.683679][ T1] ? __pfx___driver_attach (drivers/base/dd.c:1157) > [ 76.685074][ T1] bus_for_each_dev (drivers/base/bus.c:367) > [ 76.686340][ T1] ? lockdep_init_map_type (kernel/locking/lockdep.c:4892) > [ 76.687774][ T1] ? __pfx_bus_for_each_dev (drivers/base/bus.c:356) > [ 76.689176][ T1] ? bus_add_driver (drivers/base/bus.c:672) > [ 76.690452][ T1] bus_add_driver (drivers/base/bus.c:674) > [ 76.691691][ T1] driver_register (drivers/base/driver.c:246) > [ 76.692949][ T1] of_unittest_overlay_gpio (drivers/of/unittest.c:1969 (discriminator 4)) > [ 76.694377][ T1] of_unittest_overlay (drivers/of/unittest.c:2189 drivers/of/unittest.c:3217) > [ 76.695724][ T1] ? __pfx_of_unittest_overlay (drivers/of/unittest.c:3155) > [ 76.697198][ T1] ? lockdep_hardirqs_on_prepare (kernel/locking/lockdep.c:467 kernel/locking/lockdep.c:4360) > [ 76.698764][ T1] ? lockdep_hardirqs_on (kernel/locking/lockdep.c:4423) > [ 76.700151][ T1] of_unittest (drivers/of/unittest.c:4129) > [ 76.701323][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) > [ 76.702622][ T1] ? add_device_randomness (drivers/char/random.c:918) > [ 76.704050][ T1] ? __pfx_of_unittest (drivers/of/unittest.c:4080) > [ 76.705347][ T1] do_one_initcall (init/main.c:1236) > [ 76.706572][ T1] ? __pfx_do_one_initcall (init/main.c:1227) > [ 76.708227][ T1] do_initcalls (init/main.c:1297 init/main.c:1314) > > > The kernel config and materials to reproduce are available at: > https://download.01.org/0day-ci/archive/20240212/202402122234.d85cca9b-lkp@intel.com > > > > -- > 0-DAY CI Kernel Test Service > https://github.com/intel/lkp-tests/wiki Paul, Could you help me out here? It seems that lockdep complains (with "suspicious RCU usage") whenever an RCU-protected pointer is passed to rcu_dereference() but is not actually dereferenced later - in which case switching to rcu_access_pointer() helps. But in the case of the of_unittests() it also emits the same warning for gpiod_direction_input() where gdev->chip is fetched with rcu_dereference() using CLASS(gpio_chip_guard) and later actually dereferenced by calling guard.gc->... Any hints as to what I'm doing wrong? Thanks, Bartosz
On Mon, Feb 12, 2024 at 10:20 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote: > [snip] > > > > > > [ 76.432519][ T1] gpiochip_find_base_unlocked: found new base at 512 > > [ 76.434591][ T1] > > [ 76.435240][ T1] ============================= > > [ 76.436545][ T1] WARNING: suspicious RCU usage > > [ 76.437813][ T1] 6.8.0-rc1-00050-gc21131f83abc #1 Tainted: G N > > [ 76.439873][ T1] ----------------------------- > > [ 76.441158][ T1] drivers/gpio/gpiolib.c:219 suspicious rcu_dereference_check() usage! > > [ 76.443364][ T1] [snip] > > Paul, > > Could you help me out here? It seems that lockdep complains (with > "suspicious RCU usage") whenever an RCU-protected pointer is passed to > rcu_dereference() but is not actually dereferenced later - in which > case switching to rcu_access_pointer() helps. But in the case of the > of_unittests() it also emits the same warning for > gpiod_direction_input() where gdev->chip is fetched with > rcu_dereference() using CLASS(gpio_chip_guard) and later actually > dereferenced by calling guard.gc->... > > Any hints as to what I'm doing wrong? > > Thanks, > Bartosz Seems like these can be silenced with rcu_dereference_protected() so I'll use it for now. Bart
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index e993c6a7215a..ccdeed013f6b 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -205,9 +205,9 @@ static long linehandle_ioctl(struct file *file, unsigned int cmd, unsigned int i; int ret; - guard(rwsem_read)(&lh->gdev->sem); + guard(srcu)(&lh->gdev->srcu); - if (!lh->gdev->chip) + if (!rcu_dereference(lh->gdev->chip)) return -ENODEV; switch (cmd) { @@ -1520,9 +1520,9 @@ static long linereq_ioctl(struct file *file, unsigned int cmd, struct linereq *lr = file->private_data; void __user *ip = (void __user *)arg; - guard(rwsem_read)(&lr->gdev->sem); + guard(srcu)(&lr->gdev->srcu); - if (!lr->gdev->chip) + if (!rcu_dereference(lr->gdev->chip)) return -ENODEV; switch (cmd) { @@ -1551,9 +1551,9 @@ static __poll_t linereq_poll(struct file *file, struct linereq *lr = file->private_data; __poll_t events = 0; - guard(rwsem_read)(&lr->gdev->sem); + guard(srcu)(&lr->gdev->srcu); - if (!lr->gdev->chip) + if (!rcu_dereference(lr->gdev->chip)) return EPOLLHUP | EPOLLERR; poll_wait(file, &lr->wait, wait); @@ -1573,9 +1573,9 @@ static ssize_t linereq_read(struct file *file, char __user *buf, ssize_t bytes_read = 0; int ret; - guard(rwsem_read)(&lr->gdev->sem); + guard(srcu)(&lr->gdev->srcu); - if (!lr->gdev->chip) + if (!rcu_dereference(lr->gdev->chip)) return -ENODEV; if (count < sizeof(le)) @@ -1874,9 +1874,9 @@ static __poll_t lineevent_poll(struct file *file, struct lineevent_state *le = file->private_data; __poll_t events = 0; - guard(rwsem_read)(&le->gdev->sem); + guard(srcu)(&le->gdev->srcu); - if (!le->gdev->chip) + if (!rcu_dereference(le->gdev->chip)) return EPOLLHUP | EPOLLERR; poll_wait(file, &le->wait, wait); @@ -1912,9 +1912,9 @@ static ssize_t lineevent_read(struct file *file, char __user *buf, ssize_t ge_size; int ret; - guard(rwsem_read)(&le->gdev->sem); + guard(srcu)(&le->gdev->srcu); - if (!le->gdev->chip) + if (!rcu_dereference(le->gdev->chip)) return -ENODEV; /* @@ -1995,9 +1995,9 @@ static long lineevent_ioctl(struct file *file, unsigned int cmd, void __user *ip = (void __user *)arg; struct gpiohandle_data ghd; - guard(rwsem_read)(&le->gdev->sem); + guard(srcu)(&le->gdev->srcu); - if (!le->gdev->chip) + if (!rcu_dereference(le->gdev->chip)) return -ENODEV; /* @@ -2295,10 +2295,13 @@ static void gpio_v2_line_info_changed_to_v1( static void gpio_desc_to_lineinfo(struct gpio_desc *desc, struct gpio_v2_line_info *info) { - struct gpio_chip *gc = desc->gdev->chip; unsigned long dflags; const char *label; + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return; + memset(info, 0, sizeof(*info)); info->offset = gpio_chip_hwgpio(desc); @@ -2331,8 +2334,8 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, test_bit(FLAG_USED_AS_IRQ, &dflags) || test_bit(FLAG_EXPORT, &dflags) || test_bit(FLAG_SYSFS, &dflags) || - !gpiochip_line_is_valid(gc, info->offset) || - !pinctrl_gpio_can_use_line(gc, info->offset)) + !gpiochip_line_is_valid(guard.gc, info->offset) || + !pinctrl_gpio_can_use_line(guard.gc, info->offset)) info->flags |= GPIO_V2_LINE_FLAG_USED; if (test_bit(FLAG_IS_OUT, &dflags)) @@ -2505,10 +2508,10 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct gpio_device *gdev = cdev->gdev; void __user *ip = (void __user *)arg; - guard(rwsem_read)(&gdev->sem); + guard(srcu)(&gdev->srcu); /* We fail any subsequent ioctl():s when the chip is gone */ - if (!gdev->chip) + if (!rcu_dereference(gdev->chip)) return -ENODEV; /* Fill in the struct and pass to userspace */ @@ -2591,9 +2594,9 @@ static __poll_t lineinfo_watch_poll(struct file *file, struct gpio_chardev_data *cdev = file->private_data; __poll_t events = 0; - guard(rwsem_read)(&cdev->gdev->sem); + guard(srcu)(&cdev->gdev->srcu); - if (!cdev->gdev->chip) + if (!rcu_dereference(cdev->gdev->chip)) return EPOLLHUP | EPOLLERR; poll_wait(file, &cdev->wait, pollt); @@ -2614,9 +2617,9 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf, int ret; size_t event_size; - guard(rwsem_read)(&cdev->gdev->sem); + guard(srcu)(&cdev->gdev->srcu); - if (!cdev->gdev->chip) + if (!rcu_dereference(cdev->gdev->chip)) return -ENODEV; #ifndef CONFIG_GPIO_CDEV_V1 @@ -2691,10 +2694,10 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file) struct gpio_chardev_data *cdev; int ret = -ENOMEM; - guard(rwsem_read)(&gdev->sem); + guard(srcu)(&gdev->srcu); /* Fail on open if the backing gpiochip is gone */ - if (!gdev->chip) + if (!rcu_dereference(gdev->chip)) return -ENODEV; cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); @@ -2781,6 +2784,7 @@ static const struct file_operations gpio_fileops = { int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt) { + struct gpio_chip *gc; int ret; cdev_init(&gdev->chrdev, &gpio_fileops); @@ -2791,8 +2795,13 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt) if (ret) return ret; - chip_dbg(gdev->chip, "added GPIO chardev (%d:%d)\n", - MAJOR(devt), gdev->id); + guard(srcu)(&gdev->srcu); + + gc = rcu_dereference(gdev->chip); + if (!gc) + return -ENODEV; + + chip_dbg(gc, "added GPIO chardev (%d:%d)\n", MAJOR(devt), gdev->id); return 0; } diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 2e3edf41e853..9f7b5e20fc25 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -171,6 +171,10 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags) unsigned long irq_flags; int ret; + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + data->irq = gpiod_to_irq(desc); if (data->irq < 0) return -EIO; @@ -195,7 +199,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags) * Remove this redundant call (along with the corresponding * unlock) when those drivers have been fixed. */ - ret = gpiochip_lock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc)); + ret = gpiochip_lock_as_irq(guard.gc, gpio_chip_hwgpio(desc)); if (ret < 0) goto err_put_kn; @@ -209,7 +213,7 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags) return 0; err_unlock: - gpiochip_unlock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc)); + gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc)); err_put_kn: sysfs_put(data->value_kn); @@ -225,9 +229,13 @@ static void gpio_sysfs_free_irq(struct device *dev) struct gpiod_data *data = dev_get_drvdata(dev); struct gpio_desc *desc = data->desc; + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return; + data->irq_flags = 0; free_irq(data->irq, data); - gpiochip_unlock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc)); + gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc)); sysfs_put(data->value_kn); } @@ -444,13 +452,12 @@ static ssize_t export_store(const struct class *class, const char *buf, size_t len) { struct gpio_desc *desc; - struct gpio_chip *gc; int status, offset; long gpio; status = kstrtol(buf, 0, &gpio); - if (status < 0) - goto done; + if (status) + return status; desc = gpio_to_desc(gpio); /* reject invalid GPIOs */ @@ -458,9 +465,13 @@ static ssize_t export_store(const struct class *class, pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); return -EINVAL; } - gc = desc->gdev->chip; + + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + offset = gpio_chip_hwgpio(desc); - if (!gpiochip_line_is_valid(gc, offset)) { + if (!gpiochip_line_is_valid(guard.gc, offset)) { pr_warn("%s: GPIO %ld masked\n", __func__, gpio); return -EINVAL; } @@ -563,7 +574,6 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) const char *ioname = NULL; struct gpio_device *gdev; struct gpiod_data *data; - struct gpio_chip *chip; struct device *dev; int status, offset; @@ -578,16 +588,19 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) return -EINVAL; } + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + if (!test_and_set_bit(FLAG_EXPORT, &desc->flags)) return -EPERM; gdev = desc->gdev; - chip = gdev->chip; mutex_lock(&sysfs_lock); /* check if chip is being removed */ - if (!chip || !gdev->mockdev) { + if (!gdev->mockdev) { status = -ENODEV; goto err_unlock; } @@ -606,14 +619,14 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) data->desc = desc; mutex_init(&data->mutex); - if (chip->direction_input && chip->direction_output) + if (guard.gc->direction_input && guard.gc->direction_output) data->direction_can_change = direction_may_change; else data->direction_can_change = false; offset = gpio_chip_hwgpio(desc); - if (chip->names && chip->names[offset]) - ioname = chip->names[offset]; + if (guard.gc->names && guard.gc->names[offset]) + ioname = guard.gc->names[offset]; dev = device_create_with_groups(&gpio_class, &gdev->dev, MKDEV(0, 0), data, gpio_groups, @@ -728,7 +741,7 @@ EXPORT_SYMBOL_GPL(gpiod_unexport); int gpiochip_sysfs_register(struct gpio_device *gdev) { - struct gpio_chip *chip = gdev->chip; + struct gpio_chip *chip; struct device *parent; struct device *dev; @@ -741,6 +754,12 @@ int gpiochip_sysfs_register(struct gpio_device *gdev) if (!class_is_registered(&gpio_class)) return 0; + guard(srcu)(&gdev->srcu); + + chip = rcu_dereference(gdev->chip); + if (!chip) + return -ENODEV; + /* * For sysfs backward compatibility we need to preserve this * preferred parenting to the gpio_chip parent field, if set. @@ -767,7 +786,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev) void gpiochip_sysfs_unregister(struct gpio_device *gdev) { struct gpio_desc *desc; - struct gpio_chip *chip = gdev->chip; + struct gpio_chip *chip; scoped_guard(mutex, &sysfs_lock) { if (!gdev->mockdev) @@ -779,6 +798,12 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev) gdev->mockdev = NULL; } + guard(srcu)(&gdev->srcu); + + chip = rcu_dereference(gdev->chip); + if (chip) + return; + /* unregister gpiod class devices owned by sysfs */ for_each_gpio_desc_with_flag(chip, desc, FLAG_SYSFS) { gpiod_unexport(desc); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9b1907f3e400..a14717a3e222 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -216,7 +216,7 @@ struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) { if (!desc) return NULL; - return desc->gdev->chip; + return rcu_dereference(desc->gdev->chip); } EXPORT_SYMBOL_GPL(gpiod_to_chip); @@ -285,7 +285,7 @@ EXPORT_SYMBOL(gpio_device_get_label); */ struct gpio_chip *gpio_device_get_chip(struct gpio_device *gdev) { - return gdev->chip; + return rcu_dereference(gdev->chip); } EXPORT_SYMBOL_GPL(gpio_device_get_chip); @@ -325,12 +325,21 @@ static int gpiochip_find_base_unlocked(int ngpio) */ int gpiod_get_direction(struct gpio_desc *desc) { - struct gpio_chip *gc; unsigned long flags; unsigned int offset; int ret; - gc = gpiod_to_chip(desc); + /* + * We cannot use VALIDATE_DESC() as we must not return 0 for a NULL + * descriptor like we usually do. + */ + if (!desc || IS_ERR(desc)) + return -EINVAL; + + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + offset = gpio_chip_hwgpio(desc); flags = READ_ONCE(desc->flags); @@ -342,10 +351,10 @@ int gpiod_get_direction(struct gpio_desc *desc) test_bit(FLAG_IS_OUT, &flags)) return 0; - if (!gc->get_direction) + if (!guard.gc->get_direction) return -ENOTSUPP; - ret = gc->get_direction(gc, offset); + ret = guard.gc->get_direction(guard.gc, offset); if (ret < 0) return ret; @@ -421,6 +430,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) { struct gpio_device *gdev; struct gpio_desc *desc; + struct gpio_chip *gc; if (!name) return NULL; @@ -429,7 +439,13 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) list_for_each_entry_srcu(gdev, &gpio_devices, list, srcu_read_lock_held(&gpio_devices_srcu)) { - for_each_gpio_desc(gdev->chip, desc) { + guard(srcu)(&gdev->srcu); + + gc = rcu_dereference(gdev->chip); + if (!gc) + continue; + + for_each_gpio_desc(gc, desc) { if (desc->name && !strcmp(desc->name, name)) return desc; } @@ -853,7 +869,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, gdev->dev.type = &gpio_dev_type; gdev->dev.bus = &gpio_bus_type; gdev->dev.parent = gc->parent; - gdev->chip = gc; + rcu_assign_pointer(gdev->chip, gc); gc->gpiodev = gdev; gpiochip_set_data(gc, data); @@ -1097,7 +1113,8 @@ void gpiochip_remove(struct gpio_chip *gc) synchronize_srcu(&gpio_devices_srcu); /* Numb the device, cancelling all outstanding operations */ - gdev->chip = NULL; + rcu_assign_pointer(gdev->chip, NULL); + synchronize_srcu(&gdev->srcu); gpiochip_irqchip_remove(gc); acpi_gpiochip_remove(gc); of_gpiochip_remove(gc); @@ -1156,6 +1173,7 @@ struct gpio_device *gpio_device_find(void *data, void *data)) { struct gpio_device *gdev; + struct gpio_chip *gc; /* * Not yet but in the future the spinlock below will become a mutex. @@ -1166,8 +1184,13 @@ struct gpio_device *gpio_device_find(void *data, guard(srcu)(&gpio_devices_srcu); - list_for_each_entry(gdev, &gpio_devices, list) { - if (gdev->chip && match(gdev->chip, data)) + list_for_each_entry_srcu(gdev, &gpio_devices, list, + srcu_read_lock_held(&gpio_devices_srcu)) { + guard(srcu)(&gdev->srcu); + + gc = rcu_dereference(gdev->chip); + + if (gc && match(gc, data)) return gpio_device_get(gdev); } @@ -2214,10 +2237,13 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); */ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) { - struct gpio_chip *gc = desc->gdev->chip; unsigned int offset; int ret; + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + if (test_and_set_bit(FLAG_REQUESTED, &desc->flags)) return -EBUSY; @@ -2231,17 +2257,17 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) * before IRQs are enabled, for non-sleeping (SOC) GPIOs. */ - if (gc->request) { + if (guard.gc->request) { offset = gpio_chip_hwgpio(desc); - if (gpiochip_line_is_valid(gc, offset)) - ret = gc->request(gc, offset); + if (gpiochip_line_is_valid(guard.gc, offset)) + ret = guard.gc->request(guard.gc, offset); else ret = -EINVAL; if (ret) goto out_clear_bit; } - if (gc->get_direction) + if (guard.gc->get_direction) gpiod_get_direction(desc); ret = desc_set_label(desc, label ? : "?"); @@ -2308,18 +2334,18 @@ int gpiod_request(struct gpio_desc *desc, const char *label) static bool gpiod_free_commit(struct gpio_desc *desc) { - struct gpio_chip *gc; unsigned long flags; bool ret = false; might_sleep(); - gc = desc->gdev->chip; + CLASS(gpio_chip_guard, guard)(desc); + flags = READ_ONCE(desc->flags); - if (gc && test_bit(FLAG_REQUESTED, &flags)) { - if (gc->free) - gc->free(gc, gpio_chip_hwgpio(desc)); + if (guard.gc && test_bit(FLAG_REQUESTED, &flags)) { + if (guard.gc->free) + guard.gc->free(guard.gc, gpio_chip_hwgpio(desc)); clear_bit(FLAG_ACTIVE_LOW, &flags); clear_bit(FLAG_REQUESTED, &flags); @@ -2476,11 +2502,14 @@ static int gpio_set_config_with_argument(struct gpio_desc *desc, enum pin_config_param mode, u32 argument) { - struct gpio_chip *gc = desc->gdev->chip; unsigned long config; + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + config = pinconf_to_config_packed(mode, argument); - return gpio_do_set_config(gc, gpio_chip_hwgpio(desc), config); + return gpio_do_set_config(guard.gc, gpio_chip_hwgpio(desc), config); } static int gpio_set_config_with_argument_optional(struct gpio_desc *desc, @@ -2570,18 +2599,20 @@ int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce) */ int gpiod_direction_input(struct gpio_desc *desc) { - struct gpio_chip *gc; int ret = 0; VALIDATE_DESC(desc); - gc = desc->gdev->chip; + + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; /* * It is legal to have no .get() and .direction_input() specified if * the chip is output-only, but you can't specify .direction_input() * and not support the .get() operation, that doesn't make sense. */ - if (!gc->get && gc->direction_input) { + if (!guard.gc->get && guard.gc->direction_input) { gpiod_warn(desc, "%s: missing get() but have direction_input()\n", __func__); @@ -2594,10 +2625,12 @@ int gpiod_direction_input(struct gpio_desc *desc) * direction (if .get_direction() is supported) else we silently * assume we are in input mode after this. */ - if (gc->direction_input) { - ret = gc->direction_input(gc, gpio_chip_hwgpio(desc)); - } else if (gc->get_direction && - (gc->get_direction(gc, gpio_chip_hwgpio(desc)) != 1)) { + if (guard.gc->direction_input) { + ret = guard.gc->direction_input(guard.gc, + gpio_chip_hwgpio(desc)); + } else if (guard.gc->get_direction && + (guard.gc->get_direction(guard.gc, + gpio_chip_hwgpio(desc)) != 1)) { gpiod_warn(desc, "%s: missing direction_input() operation and line is output\n", __func__); @@ -2616,28 +2649,31 @@ EXPORT_SYMBOL_GPL(gpiod_direction_input); static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) { - struct gpio_chip *gc = desc->gdev->chip; - int val = !!value; - int ret = 0; + int val = !!value, ret = 0; + + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; /* * It's OK not to specify .direction_output() if the gpiochip is * output-only, but if there is then not even a .set() operation it * is pretty tricky to drive the output line. */ - if (!gc->set && !gc->direction_output) { + if (!guard.gc->set && !guard.gc->direction_output) { gpiod_warn(desc, "%s: missing set() and direction_output() operations\n", __func__); return -EIO; } - if (gc->direction_output) { - ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val); + if (guard.gc->direction_output) { + ret = guard.gc->direction_output(guard.gc, + gpio_chip_hwgpio(desc), val); } else { /* Check that we are in output mode if we can */ - if (gc->get_direction && - gc->get_direction(gc, gpio_chip_hwgpio(desc))) { + if (guard.gc->get_direction && + guard.gc->get_direction(guard.gc, gpio_chip_hwgpio(desc))) { gpiod_warn(desc, "%s: missing direction_output() operation\n", __func__); @@ -2647,7 +2683,7 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) * If we can't actively set the direction, we are some * output-only chip, so just drive the output as desired. */ - gc->set(gc, gpio_chip_hwgpio(desc), val); + guard.gc->set(guard.gc, gpio_chip_hwgpio(desc), val); } if (!ret) @@ -2763,17 +2799,20 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output); int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags) { int ret = 0; - struct gpio_chip *gc; VALIDATE_DESC(desc); - gc = desc->gdev->chip; - if (!gc->en_hw_timestamp) { + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + + if (!guard.gc->en_hw_timestamp) { gpiod_warn(desc, "%s: hw ts not supported\n", __func__); return -ENOTSUPP; } - ret = gc->en_hw_timestamp(gc, gpio_chip_hwgpio(desc), flags); + ret = guard.gc->en_hw_timestamp(guard.gc, + gpio_chip_hwgpio(desc), flags); if (ret) gpiod_warn(desc, "%s: hw ts request failed\n", __func__); @@ -2792,17 +2831,20 @@ EXPORT_SYMBOL_GPL(gpiod_enable_hw_timestamp_ns); int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags) { int ret = 0; - struct gpio_chip *gc; VALIDATE_DESC(desc); - gc = desc->gdev->chip; - if (!gc->dis_hw_timestamp) { + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + + if (!guard.gc->dis_hw_timestamp) { gpiod_warn(desc, "%s: hw ts not supported\n", __func__); return -ENOTSUPP; } - ret = gc->dis_hw_timestamp(gc, gpio_chip_hwgpio(desc), flags); + ret = guard.gc->dis_hw_timestamp(guard.gc, gpio_chip_hwgpio(desc), + flags); if (ret) gpiod_warn(desc, "%s: hw ts release failed\n", __func__); @@ -2821,12 +2863,13 @@ EXPORT_SYMBOL_GPL(gpiod_disable_hw_timestamp_ns); */ int gpiod_set_config(struct gpio_desc *desc, unsigned long config) { - struct gpio_chip *gc; - VALIDATE_DESC(desc); - gc = desc->gdev->chip; - return gpio_do_set_config(gc, gpio_chip_hwgpio(desc), config); + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + + return gpio_do_set_config(guard.gc, gpio_chip_hwgpio(desc), config); } EXPORT_SYMBOL_GPL(gpiod_set_config); @@ -2924,10 +2967,19 @@ static int gpio_chip_get_value(struct gpio_chip *gc, const struct gpio_desc *des static int gpiod_get_raw_value_commit(const struct gpio_desc *desc) { + struct gpio_device *gdev; struct gpio_chip *gc; int value; - gc = desc->gdev->chip; + /* FIXME Unable to use gpio_chip_guard due to const desc. */ + gdev = desc->gdev; + + guard(srcu)(&gdev->srcu); + + gc = rcu_dereference(gdev->chip); + if (!gc) + return -ENODEV; + value = gpio_chip_get_value(gc, desc); value = value < 0 ? value : !!value; trace_gpio_value(desc_to_gpio(desc), 1, value); @@ -2953,6 +3005,14 @@ static int gpio_chip_get_multiple(struct gpio_chip *gc, return -EIO; } +/* The 'other' chip must be protected with its GPIO device's SRCU. */ +static bool gpio_device_chip_cmp(struct gpio_device *gdev, struct gpio_chip *gc) +{ + guard(srcu)(&gdev->srcu); + + return gc == rcu_dereference(gdev->chip); +} + int gpiod_get_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, @@ -2990,33 +3050,36 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, } while (i < array_size) { - struct gpio_chip *gc = desc_array[i]->gdev->chip; DECLARE_BITMAP(fastpath_mask, FASTPATH_NGPIO); DECLARE_BITMAP(fastpath_bits, FASTPATH_NGPIO); unsigned long *mask, *bits; int first, j; - if (likely(gc->ngpio <= FASTPATH_NGPIO)) { + CLASS(gpio_chip_guard, guard)(desc_array[i]); + if (!guard.gc) + return -ENODEV; + + if (likely(guard.gc->ngpio <= FASTPATH_NGPIO)) { mask = fastpath_mask; bits = fastpath_bits; } else { gfp_t flags = can_sleep ? GFP_KERNEL : GFP_ATOMIC; - mask = bitmap_alloc(gc->ngpio, flags); + mask = bitmap_alloc(guard.gc->ngpio, flags); if (!mask) return -ENOMEM; - bits = bitmap_alloc(gc->ngpio, flags); + bits = bitmap_alloc(guard.gc->ngpio, flags); if (!bits) { bitmap_free(mask); return -ENOMEM; } } - bitmap_zero(mask, gc->ngpio); + bitmap_zero(mask, guard.gc->ngpio); if (!can_sleep) - WARN_ON(gc->can_sleep); + WARN_ON(guard.gc->can_sleep); /* collect all inputs belonging to the same chip */ first = i; @@ -3031,9 +3094,9 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, i = find_next_zero_bit(array_info->get_mask, array_size, i); } while ((i < array_size) && - (desc_array[i]->gdev->chip == gc)); + gpio_device_chip_cmp(desc_array[i]->gdev, guard.gc)); - ret = gpio_chip_get_multiple(gc, mask, bits); + ret = gpio_chip_get_multiple(guard.gc, mask, bits); if (ret) { if (mask != fastpath_mask) bitmap_free(mask); @@ -3174,14 +3237,16 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value); */ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) { - int ret = 0; - struct gpio_chip *gc = desc->gdev->chip; - int offset = gpio_chip_hwgpio(desc); + int ret = 0, offset = gpio_chip_hwgpio(desc); + + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return; if (value) { - ret = gc->direction_input(gc, offset); + ret = guard.gc->direction_input(guard.gc, offset); } else { - ret = gc->direction_output(gc, offset, 0); + ret = guard.gc->direction_output(guard.gc, offset, 0); if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); } @@ -3199,16 +3264,18 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) */ static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value) { - int ret = 0; - struct gpio_chip *gc = desc->gdev->chip; - int offset = gpio_chip_hwgpio(desc); + int ret = 0, offset = gpio_chip_hwgpio(desc); + + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return; if (value) { - ret = gc->direction_output(gc, offset, 1); + ret = guard.gc->direction_output(guard.gc, offset, 1); if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); } else { - ret = gc->direction_input(gc, offset); + ret = guard.gc->direction_input(guard.gc, offset); } trace_gpio_direction(desc_to_gpio(desc), !value, ret); if (ret < 0) @@ -3219,11 +3286,12 @@ static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) { - struct gpio_chip *gc; + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return; - gc = desc->gdev->chip; trace_gpio_value(desc_to_gpio(desc), 0, value); - gc->set(gc, gpio_chip_hwgpio(desc), value); + guard.gc->set(guard.gc, gpio_chip_hwgpio(desc), value); } /* @@ -3284,33 +3352,36 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, } while (i < array_size) { - struct gpio_chip *gc = desc_array[i]->gdev->chip; DECLARE_BITMAP(fastpath_mask, FASTPATH_NGPIO); DECLARE_BITMAP(fastpath_bits, FASTPATH_NGPIO); unsigned long *mask, *bits; int count = 0; - if (likely(gc->ngpio <= FASTPATH_NGPIO)) { + CLASS(gpio_chip_guard, guard)(desc_array[i]); + if (!guard.gc) + return -ENODEV; + + if (likely(guard.gc->ngpio <= FASTPATH_NGPIO)) { mask = fastpath_mask; bits = fastpath_bits; } else { gfp_t flags = can_sleep ? GFP_KERNEL : GFP_ATOMIC; - mask = bitmap_alloc(gc->ngpio, flags); + mask = bitmap_alloc(guard.gc->ngpio, flags); if (!mask) return -ENOMEM; - bits = bitmap_alloc(gc->ngpio, flags); + bits = bitmap_alloc(guard.gc->ngpio, flags); if (!bits) { bitmap_free(mask); return -ENOMEM; } } - bitmap_zero(mask, gc->ngpio); + bitmap_zero(mask, guard.gc->ngpio); if (!can_sleep) - WARN_ON(gc->can_sleep); + WARN_ON(guard.gc->can_sleep); do { struct gpio_desc *desc = desc_array[i]; @@ -3346,10 +3417,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, i = find_next_zero_bit(array_info->set_mask, array_size, i); } while ((i < array_size) && - (desc_array[i]->gdev->chip == gc)); + gpio_device_chip_cmp(desc_array[i]->gdev, guard.gc)); /* push collected bits to outputs */ if (count != 0) - gpio_chip_set_multiple(gc, mask, bits); + gpio_chip_set_multiple(guard.gc, mask, bits); if (mask != fastpath_mask) bitmap_free(mask); @@ -3505,6 +3576,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_consumer_name); */ int gpiod_to_irq(const struct gpio_desc *desc) { + struct gpio_device *gdev; struct gpio_chip *gc; int offset; @@ -3516,7 +3588,13 @@ int gpiod_to_irq(const struct gpio_desc *desc) if (!desc || IS_ERR(desc)) return -EINVAL; - gc = desc->gdev->chip; + gdev = desc->gdev; + /* FIXME Cannot use gpio_chip_guard due to const desc. */ + guard(srcu)(&gdev->srcu); + gc = rcu_dereference(gdev->chip); + if (!gc) + return -ENODEV; + offset = gpio_chip_hwgpio(desc); if (gc->to_irq) { int retirq = gc->to_irq(gc, offset); @@ -4696,12 +4774,20 @@ core_initcall(gpiolib_dev_init); static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) { - struct gpio_chip *gc = gdev->chip; bool active_low, is_irq, is_out; unsigned int gpio = gdev->base; struct gpio_desc *desc; + struct gpio_chip *gc; int value; + guard(srcu)(&gdev->srcu); + + gc = rcu_dereference(gdev->chip); + if (!gc) { + seq_puts(s, "Underlying GPIO chip is gone\n"); + return; + } + for_each_gpio_desc(gc, desc) { guard(srcu)(&desc->srcu); if (test_bit(FLAG_REQUESTED, &desc->flags)) { @@ -4776,9 +4862,12 @@ static int gpiolib_seq_show(struct seq_file *s, void *v) { struct gpiolib_seq_priv *priv = s->private; struct gpio_device *gdev = v; - struct gpio_chip *gc = gdev->chip; + struct gpio_chip *gc; struct device *parent; + guard(srcu)(&gdev->srcu); + + gc = rcu_dereference(gdev->chip); if (!gc) { seq_printf(s, "%s%s: (dangling chip)", priv->newline ? "\n" : "", diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 35d71e30c546..b3810f7d286a 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -63,7 +63,7 @@ struct gpio_device { int id; struct device *mockdev; struct module *owner; - struct gpio_chip *chip; + struct gpio_chip __rcu *chip; struct gpio_desc *descs; int base; u16 ngpio; @@ -193,6 +193,26 @@ struct gpio_desc { #define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) +struct gpio_chip_guard { + struct gpio_device *gdev; + struct gpio_chip *gc; + int idx; +}; + +DEFINE_CLASS(gpio_chip_guard, + struct gpio_chip_guard, + srcu_read_unlock(&_T.gdev->srcu, _T.idx), + ({ + struct gpio_chip_guard _guard; + + _guard.gdev = desc->gdev; + _guard.idx = srcu_read_lock(&_guard.gdev->srcu); + _guard.gc = rcu_dereference(_guard.gdev->chip); + + _guard; + }), + struct gpio_desc *desc) + int gpiod_request(struct gpio_desc *desc, const char *label); void gpiod_free(struct gpio_desc *desc);