linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/22] gpio: rework locking and object life-time control
@ 2024-01-30 12:48 Bartosz Golaszewski
  2024-01-30 12:48 ` [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU Bartosz Golaszewski
                   ` (22 more replies)
  0 siblings, 23 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

This has been brewing for some time now but is finally ready to send out
for review. This series relies on SRCU a lot so I'm Cc'ing Paul.

This is a big rework of locking in GPIOLIB. The current serialization is
pretty much useless. There is one big spinlock (gpio_lock) that "protects"
both the GPIO device list, GPIO descriptor access and who knows what else.

I'm putting "protects" in quotes as in several places the lock is
taken, released whenever a sleeping function is called and re-taken
without any regards for the "protected" state that may have changed.

First a little background on what we're dealing with in GPIOLIB. We have
consumer API functions that can be called from any context explicitly
(get/set value, set direction) as well as many others which will get
called in atomic context implicitly (e.g. set config called in certain
situations from gpiod_direction_output()).

On the other side: we have GPIO provider drivers whose callbacks may or
may not sleep depending on the underlying protocol but they're called
from the same code paths.

This makes any attempts at serialization quite complex. We typically
cannot use sleeping locks - we may be called from atomic - but we also
often cannot use spinlocks - provider callbacks may sleep. Moreover: we
have close ties with the interrupt and pinctrl subsystems, often either
calling into them or getting called from them. They use their own locking
schemes which are at odds with ours (pinctrl uses mutexes, the interrupt
subsystem can call GPIO helpers with spinlock taken).

There is also another significant issue: the GPIO device object contains
a pointer to gpio_chip which is the implementation of the GPIO provider.
This object can be removed at any point - as GPIOLIB officially supports
hotplugging with all the dynamic expanders that we provide drivers for -
and leave the GPIO API callbacks with a suddenly NULL pointer. This is
a problem that allowed user-space processes to easily crash the kernel
until we patched it with a read-write semaphore in the user-space facing
code (but the problem still exists for in-kernel users). This was
recognized before as evidenced by the implementation of validate_desc()
but without proper serialization, simple checking for a NULL pointer is
pointless and we do need a generic solution for that issue as well.

If we want to get it right - the more lockless we go, the better. This is
why SRCU seems to be the right candidate for the mechanism to use. In fact
it's the only mechanism we can use for our read-only critical sections to
be called from atomic and process contexts as well as be able to call
driver callbacks that may sleep (for the latter case).

We're going to use it in three places: to protect the global list of GPIO
devices, to ensure consistency when dereferencing the chip pointer in GPIO
device struct and finally to ensure that users can access GPIO descriptors
and always see a consistent state.

We do NOT serialize all API callbacks. This means that provider callbacks
may be called simultaneously and GPIO drivers need to provide their own
locking if needed. This is on purpose. First: we only support exclusive
GPIO usage[1] so there's no risk of two drivers getting in each other's
way over the same GPIO. Second: with this series, we ensure enough
consistency to limit the chance of drivers or user-space users crashing
the kernel. With additional improvements in handling the flags field in
GPIO descriptors there's very little to gain, while bitbanging drivers
may care about the increased performance of going lockless.

This series brings in one somewhat significant functional change for
in-kernel users, namely: GPIO API calls, for which the underlying GPIO
chip is gone, will no longer return 0 and emit a log message but instead
will return -ENODEV.

I tested the series with libgpiod tests, ran it on some x86 and aarch64
boards and tested some corner cases with user-space command-line tools.

Thanks,
Bartosz

[1] - This is not technically true. We do provide the
GPIOD_FLAGS_BIT_NONEXCLUSIVE flag. However this is just another piece of
technical debt. This is a hack provided for a single use-case in the
regulator framework which got out of control and is now used in many
places that should have never touched it. It's utterly broken and doesn't
even provide any contract as to what a "shared GPIO" is. I would argue
that it's the next thing we should address by providing "reference counted
GPIO enable", not just a flag allowing to request the same GPIO twice
and then allow two drivers to fight over who toggles it as is the case
now. For now, let's just treat users of GPIOD_FLAGS_BIT_NONEXCLUSIVE like
they're consciously and deliberately choosing to risk undefined behavior.

Bartosz Golaszewski (22):
  gpio: protect the list of GPIO devices with SRCU
  gpio: of: assign and read the hog pointer atomically
  gpio: remove unused logging helpers
  gpio: provide and use gpiod_get_label()
  gpio: don't set label from irq helpers
  gpio: add SRCU infrastructure to struct gpio_desc
  gpio: protect the descriptor label with SRCU
  gpio: sysfs: use gpio_device_find() to iterate over existing devices
  gpio: remove gpio_lock
  gpio: reinforce desc->flags handling
  gpio: remove unneeded code from gpio_device_get_desc()
  gpio: sysfs: extend the critical section for unregistering sysfs
    devices
  gpio: sysfs: pass the GPIO device - not chip - to sysfs callbacks
  gpio: cdev: replace gpiochip_get_desc() with gpio_device_get_desc()
  gpio: cdev: don't access gdev->chip if it's not needed
  gpio: reduce the functionality of validate_desc()
  gpio: remove unnecessary checks from gpiod_to_chip()
  gpio: add the can_sleep flag to struct gpio_device
  gpio: add SRCU infrastructure to struct gpio_device
  gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  gpio: remove the RW semaphore from the GPIO device
  gpio: mark unsafe gpio_chip manipulators as deprecated

 drivers/gpio/gpiolib-cdev.c  |  82 ++--
 drivers/gpio/gpiolib-of.c    |   4 +-
 drivers/gpio/gpiolib-sysfs.c | 155 +++++---
 drivers/gpio/gpiolib.c       | 735 +++++++++++++++++++----------------
 drivers/gpio/gpiolib.h       |  84 ++--
 5 files changed, 595 insertions(+), 465 deletions(-)

-- 
2.40.1


^ permalink raw reply	[flat|nested] 66+ messages in thread

* [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31  9:34   ` kernel test robot
  2024-01-31 15:01   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 02/22] gpio: of: assign and read the hog pointer atomically Bartosz Golaszewski
                   ` (21 subsequent siblings)
  22 siblings, 2 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

We're working towards removing the "multi-function" GPIO spinlock that's
implemented terribly wrong. We tried using an RW-semaphore to protect
the list of GPIO devices but it turned out that we still have old code
using legacy GPIO calls that need to translate the global GPIO number to
the address of the associated descriptor and - to that end - traverse
the list while holding the lock. If we change the spinlock to a sleeping
lock then we'll end up with "scheduling while atomic" bugs.

Let's allow lockless traversal of the list using SRCU and only use the
mutex when modyfing the list.

While at it: let's protect the period between when we start the lookup
and when we finally request the descriptor (increasing the reference
count of the GPIO device) with the SRCU read lock.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.c | 203 +++++++++++++++++++++--------------------
 1 file changed, 104 insertions(+), 99 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d50a786f8176..69979de76485 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2,6 +2,7 @@
 
 #include <linux/acpi.h>
 #include <linux/bitmap.h>
+#include <linux/cleanup.h>
 #include <linux/compat.h>
 #include <linux/debugfs.h>
 #include <linux/device.h>
@@ -14,12 +15,14 @@
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/lockdep.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/srcu.h>
 #include <linux/string.h>
 
 #include <linux/gpio.h>
@@ -81,7 +84,12 @@ DEFINE_SPINLOCK(gpio_lock);
 
 static DEFINE_MUTEX(gpio_lookup_lock);
 static LIST_HEAD(gpio_lookup_list);
+
 LIST_HEAD(gpio_devices);
+/* Protects the GPIO device list against concurrent modifications. */
+static DEFINE_MUTEX(gpio_devices_lock);
+/* Ensures coherence during read-only accesses to the list of GPIO devices. */
+DEFINE_STATIC_SRCU(gpio_devices_srcu);
 
 static DEFINE_MUTEX(gpio_machine_hogs_mutex);
 static LIST_HEAD(gpio_machine_hogs);
@@ -113,20 +121,16 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
 struct gpio_desc *gpio_to_desc(unsigned gpio)
 {
 	struct gpio_device *gdev;
-	unsigned long flags;
 
-	spin_lock_irqsave(&gpio_lock, flags);
-
-	list_for_each_entry(gdev, &gpio_devices, list) {
-		if (gdev->base <= gpio &&
-		    gdev->base + gdev->ngpio > gpio) {
-			spin_unlock_irqrestore(&gpio_lock, flags);
-			return &gdev->descs[gpio - gdev->base];
+	scoped_guard(srcu, &gpio_devices_srcu) {
+		list_for_each_entry_srcu(gdev, &gpio_devices, list,
+				srcu_read_lock_held(&gpio_devices_srcu)) {
+			if (gdev->base <= gpio &&
+			    gdev->base + gdev->ngpio > gpio)
+				return &gdev->descs[gpio - gdev->base];
 		}
 	}
 
-	spin_unlock_irqrestore(&gpio_lock, flags);
-
 	if (!gpio_is_valid(gpio))
 		pr_warn("invalid GPIO %d\n", gpio);
 
@@ -282,7 +286,8 @@ static int gpiochip_find_base_unlocked(int ngpio)
 	struct gpio_device *gdev;
 	int base = GPIO_DYNAMIC_BASE;
 
-	list_for_each_entry(gdev, &gpio_devices, list) {
+	list_for_each_entry_srcu(gdev, &gpio_devices, list,
+				 lockdep_is_held(&gpio_devices_lock)) {
 		/* found a free space? */
 		if (gdev->base >= base + ngpio)
 			break;
@@ -354,23 +359,25 @@ static int gpiodev_add_to_list_unlocked(struct gpio_device *gdev)
 {
 	struct gpio_device *prev, *next;
 
+	lockdep_assert_held(&gpio_devices_lock);
+
 	if (list_empty(&gpio_devices)) {
 		/* initial entry in list */
-		list_add_tail(&gdev->list, &gpio_devices);
+		list_add_tail_rcu(&gdev->list, &gpio_devices);
 		return 0;
 	}
 
 	next = list_first_entry(&gpio_devices, struct gpio_device, list);
 	if (gdev->base + gdev->ngpio <= next->base) {
 		/* add before first entry */
-		list_add(&gdev->list, &gpio_devices);
+		list_add_rcu(&gdev->list, &gpio_devices);
 		return 0;
 	}
 
 	prev = list_last_entry(&gpio_devices, struct gpio_device, list);
 	if (prev->base + prev->ngpio <= gdev->base) {
 		/* add behind last entry */
-		list_add_tail(&gdev->list, &gpio_devices);
+		list_add_tail_rcu(&gdev->list, &gpio_devices);
 		return 0;
 	}
 
@@ -382,11 +389,13 @@ static int gpiodev_add_to_list_unlocked(struct gpio_device *gdev)
 		/* add between prev and next */
 		if (prev->base + prev->ngpio <= gdev->base
 				&& gdev->base + gdev->ngpio <= next->base) {
-			list_add(&gdev->list, &prev->list);
+			list_add_rcu(&gdev->list, &prev->list);
 			return 0;
 		}
 	}
 
+	synchronize_srcu(&gpio_devices_srcu);
+
 	return -EBUSY;
 }
 
@@ -399,26 +408,21 @@ static int gpiodev_add_to_list_unlocked(struct gpio_device *gdev)
 static struct gpio_desc *gpio_name_to_desc(const char * const name)
 {
 	struct gpio_device *gdev;
-	unsigned long flags;
+	struct gpio_desc *desc;
 
 	if (!name)
 		return NULL;
 
-	spin_lock_irqsave(&gpio_lock, flags);
-
-	list_for_each_entry(gdev, &gpio_devices, list) {
-		struct gpio_desc *desc;
+	guard(srcu)(&gpio_devices_srcu);
 
+	list_for_each_entry_srcu(gdev, &gpio_devices, list,
+				 srcu_read_lock_held(&gpio_devices_srcu)) {
 		for_each_gpio_desc(gdev->chip, desc) {
-			if (desc->name && !strcmp(desc->name, name)) {
-				spin_unlock_irqrestore(&gpio_lock, flags);
+			if (desc->name && !strcmp(desc->name, name))
 				return desc;
-			}
 		}
 	}
 
-	spin_unlock_irqrestore(&gpio_lock, flags);
-
 	return NULL;
 }
 
@@ -813,7 +817,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 			       struct lock_class_key *request_key)
 {
 	struct gpio_device *gdev;
-	unsigned long flags;
 	unsigned int i;
 	int base = 0;
 	int ret = 0;
@@ -878,49 +881,47 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 
 	gdev->ngpio = gc->ngpio;
 
-	spin_lock_irqsave(&gpio_lock, flags);
-
-	/*
-	 * TODO: this allocates a Linux GPIO number base in the global
-	 * GPIO numberspace for this chip. In the long run we want to
-	 * get *rid* of this numberspace and use only descriptors, but
-	 * it may be a pipe dream. It will not happen before we get rid
-	 * of the sysfs interface anyways.
-	 */
-	base = gc->base;
-	if (base < 0) {
-		base = gpiochip_find_base_unlocked(gc->ngpio);
+	scoped_guard(mutex, &gpio_devices_lock) {
+		/*
+		 * TODO: this allocates a Linux GPIO number base in the global
+		 * GPIO numberspace for this chip. In the long run we want to
+		 * get *rid* of this numberspace and use only descriptors, but
+		 * it may be a pipe dream. It will not happen before we get rid
+		 * of the sysfs interface anyways.
+		 */
+		base = gc->base;
 		if (base < 0) {
-			spin_unlock_irqrestore(&gpio_lock, flags);
-			ret = base;
-			base = 0;
+			base = gpiochip_find_base_unlocked(gc->ngpio);
+			if (base < 0) {
+				ret = base;
+				base = 0;
+				goto err_free_label;
+			}
+
+			/*
+			 * TODO: it should not be necessary to reflect the
+			 * assigned base outside of the GPIO subsystem. Go over
+			 * drivers and see if anyone makes use of this, else
+			 * drop this and assign a poison instead.
+			 */
+			gc->base = base;
+		} else {
+			dev_warn(&gdev->dev,
+				 "Static allocation of GPIO base is deprecated, use dynamic allocation.\n");
+		}
+
+		gdev->base = base;
+
+		ret = gpiodev_add_to_list_unlocked(gdev);
+		if (ret) {
+			chip_err(gc, "GPIO integer space overlap, cannot add chip\n");
 			goto err_free_label;
 		}
-		/*
-		 * TODO: it should not be necessary to reflect the assigned
-		 * base outside of the GPIO subsystem. Go over drivers and
-		 * see if anyone makes use of this, else drop this and assign
-		 * a poison instead.
-		 */
-		gc->base = base;
-	} else {
-		dev_warn(&gdev->dev,
-			 "Static allocation of GPIO base is deprecated, use dynamic allocation.\n");
-	}
-	gdev->base = base;
-
-	ret = gpiodev_add_to_list_unlocked(gdev);
-	if (ret) {
-		spin_unlock_irqrestore(&gpio_lock, flags);
-		chip_err(gc, "GPIO integer space overlap, cannot add chip\n");
-		goto err_free_label;
 	}
 
 	for (i = 0; i < gc->ngpio; i++)
 		gdev->descs[i].gdev = gdev;
 
-	spin_unlock_irqrestore(&gpio_lock, flags);
-
 	BLOCKING_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier);
 	BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier);
 	init_rwsem(&gdev->sem);
@@ -1011,9 +1012,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 		goto err_print_message;
 	}
 err_remove_from_list:
-	spin_lock_irqsave(&gpio_lock, flags);
-	list_del(&gdev->list);
-	spin_unlock_irqrestore(&gpio_lock, flags);
+	scoped_guard(mutex, &gpio_devices_lock)
+		list_del_rcu(&gdev->list);
+	synchronize_srcu(&gpio_devices_srcu);
 err_free_label:
 	kfree_const(gdev->label);
 err_free_descs:
@@ -1076,8 +1077,9 @@ void gpiochip_remove(struct gpio_chip *gc)
 		dev_crit(&gdev->dev,
 			 "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
 
-	scoped_guard(spinlock_irqsave, &gpio_lock)
-		list_del(&gdev->list);
+	scoped_guard(mutex, &gpio_devices_lock)
+		list_del_rcu(&gdev->list);
+	synchronize_srcu(&gpio_devices_srcu);
 
 	/*
 	 * The gpiochip side puts its use of the device to rest here:
@@ -1125,7 +1127,7 @@ struct gpio_device *gpio_device_find(void *data,
 	 */
 	might_sleep();
 
-	guard(spinlock_irqsave)(&gpio_lock);
+	guard(srcu)(&gpio_devices_srcu);
 
 	list_for_each_entry(gdev, &gpio_devices, list) {
 		if (gdev->chip && match(gdev->chip, data))
@@ -4136,27 +4138,32 @@ static struct gpio_desc *gpiod_find_and_request(struct device *consumer,
 	struct gpio_desc *desc;
 	int ret;
 
-	desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx, &flags, &lookupflags);
-	if (gpiod_not_found(desc) && platform_lookup_allowed) {
+	scoped_guard(srcu, &gpio_devices_srcu) {
+		desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx,
+					    &flags, &lookupflags);
+		if (gpiod_not_found(desc) && platform_lookup_allowed) {
+			/*
+			 * Either we are not using DT or ACPI, or their lookup
+			 * did not return a result. In that case, use platform
+			 * lookup as a fallback.
+			 */
+			dev_dbg(consumer,
+				"using lookup tables for GPIO lookup\n");
+			desc = gpiod_find(consumer, con_id, idx, &lookupflags);
+		}
+
+		if (IS_ERR(desc)) {
+			dev_dbg(consumer, "No GPIO consumer %s found\n",
+				con_id);
+			return desc;
+		}
+
 		/*
-		 * Either we are not using DT or ACPI, or their lookup did not
-		 * return a result. In that case, use platform lookup as a
-		 * fallback.
+		 * If a connection label was passed use that, else attempt to use
+		 * the device name as label
 		 */
-		dev_dbg(consumer, "using lookup tables for GPIO lookup\n");
-		desc = gpiod_find(consumer, con_id, idx, &lookupflags);
+		ret = gpiod_request(desc, label);
 	}
-
-	if (IS_ERR(desc)) {
-		dev_dbg(consumer, "No GPIO consumer %s found\n", con_id);
-		return desc;
-	}
-
-	/*
-	 * If a connection label was passed use that, else attempt to use
-	 * the device name as label
-	 */
-	ret = gpiod_request(desc, label);
 	if (ret) {
 		if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
 			return ERR_PTR(ret);
@@ -4727,35 +4734,33 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
 
 static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
 {
-	unsigned long flags;
 	struct gpio_device *gdev = NULL;
 	loff_t index = *pos;
 
 	s->private = "";
 
-	spin_lock_irqsave(&gpio_lock, flags);
-	list_for_each_entry(gdev, &gpio_devices, list)
-		if (index-- == 0) {
-			spin_unlock_irqrestore(&gpio_lock, flags);
+	guard(srcu)(&gpio_devices_srcu);
+
+	list_for_each_entry(gdev, &gpio_devices, list) {
+		if (index-- == 0)
 			return gdev;
-		}
-	spin_unlock_irqrestore(&gpio_lock, flags);
+	}
 
 	return NULL;
 }
 
 static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-	unsigned long flags;
 	struct gpio_device *gdev = v;
 	void *ret = NULL;
 
-	spin_lock_irqsave(&gpio_lock, flags);
-	if (list_is_last(&gdev->list, &gpio_devices))
-		ret = NULL;
-	else
-		ret = list_first_entry(&gdev->list, struct gpio_device, list);
-	spin_unlock_irqrestore(&gpio_lock, flags);
+	scoped_guard(srcu, &gpio_devices_srcu) {
+		if (list_is_last(&gdev->list, &gpio_devices))
+			ret = NULL;
+		else
+			ret = list_first_entry(&gdev->list, struct gpio_device,
+					       list);
+	}
 
 	s->private = "\n";
 	++*pos;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 02/22] gpio: of: assign and read the hog pointer atomically
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
  2024-01-30 12:48 ` [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 17:38   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 03/22] gpio: remove unused logging helpers Bartosz Golaszewski
                   ` (20 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

The device nodes representing GPIO hogs cannot be deleted without
unregistering the GPIO chip so there's no need to serialize their access.
However we must ensure that users can get the right address so write and
read it atomically.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-of.c | 4 ++--
 drivers/gpio/gpiolib.c    | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 77509aa19900..bd6b8702c790 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -800,7 +800,7 @@ static int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog)
 			return ret;
 
 #ifdef CONFIG_OF_DYNAMIC
-		desc->hog = hog;
+		WRITE_ONCE(desc->hog, hog);
 #endif
 	}
 
@@ -848,7 +848,7 @@ static void of_gpiochip_remove_hog(struct gpio_chip *chip,
 	struct gpio_desc *desc;
 
 	for_each_gpio_desc_with_flag(chip, desc, FLAG_IS_HOGGED)
-		if (desc->hog == hog)
+		if (READ_ONCE(desc->hog) == hog)
 			gpiochip_free_own_desc(desc);
 }
 
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 69979de76485..543d80457647 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2321,7 +2321,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
 		clear_bit(FLAG_EDGE_FALLING, &desc->flags);
 		clear_bit(FLAG_IS_HOGGED, &desc->flags);
 #ifdef CONFIG_OF_DYNAMIC
-		desc->hog = NULL;
+		WRITE_ONCE(desc->hog, NULL);
 #endif
 		ret = true;
 	}
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 03/22] gpio: remove unused logging helpers
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
  2024-01-30 12:48 ` [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU Bartosz Golaszewski
  2024-01-30 12:48 ` [PATCH 02/22] gpio: of: assign and read the hog pointer atomically Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 17:39   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 04/22] gpio: provide and use gpiod_get_label() Bartosz Golaszewski
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

The general rule of the kernel is to not provide symbols that have no
users upstream. Let's remove logging helpers that are not used anywhere.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.h | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index a4a2520b5f31..c3ae5bfa3f2e 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -219,31 +219,18 @@ static inline int gpio_chip_hwgpio(const struct gpio_desc *desc)
 
 /* With descriptor prefix */
 
-#define gpiod_emerg(desc, fmt, ...)					       \
-	pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
-		 ##__VA_ARGS__)
-#define gpiod_crit(desc, fmt, ...)					       \
-	pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
-		 ##__VA_ARGS__)
 #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_info(desc, fmt, ...)					       \
-	pr_info("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__)
 
 /* With chip prefix */
 
-#define chip_emerg(gc, fmt, ...)					\
-	dev_emerg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
-#define chip_crit(gc, fmt, ...)					\
-	dev_crit(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
 #define chip_err(gc, fmt, ...)					\
 	dev_err(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
 #define chip_warn(gc, fmt, ...)					\
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 04/22] gpio: provide and use gpiod_get_label()
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (2 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 03/22] gpio: remove unused logging helpers Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 19:36   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 05/22] gpio: don't set label from irq helpers Bartosz Golaszewski
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

We will soon serialize access to the descriptor label using SRCU. The
write-side of the protection will require calling synchronize_srcu()
which must not be called from atomic context. We have two irq helpers:
gpiochip_lock_as_irq() and gpiochip_unlock_as_irq() that set the label
if the GPIO is not requested but is being used as interrupt. They are
called with a spinlock held from the interrupt subsystem.

They must not do it if we are to use SRCU so instead let's move the
special corner case to a dedicated getter.

First: let's implement and use the getter where it's applicable.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-cdev.c | 4 ++--
 drivers/gpio/gpiolib.c      | 9 +++++++--
 drivers/gpio/gpiolib.h      | 1 +
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 34d6712fa07c..2c0a0700762d 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -2305,8 +2305,8 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
 		if (desc->name)
 			strscpy(info->name, desc->name, sizeof(info->name));
 
-		if (desc->label)
-			strscpy(info->consumer, desc->label,
+		if (gpiod_get_label(desc))
+			strscpy(info->consumer, gpiod_get_label(desc),
 				sizeof(info->consumer));
 
 		dflags = READ_ONCE(desc->flags);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 543d80457647..d0a2f014dacd 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -105,6 +105,11 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc);
 
 static bool gpiolib_initialized;
 
+const char *gpiod_get_label(struct gpio_desc *desc)
+{
+	return desc->label;
+}
+
 static inline void desc_set_label(struct gpio_desc *d, const char *label)
 {
 	d->label = label;
@@ -2382,7 +2387,7 @@ char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset)
 	 *
 	 * Until this happens, this allocation needs to be atomic.
 	 */
-	label = kstrdup(desc->label, GFP_ATOMIC);
+	label = kstrdup(gpiod_get_label(desc), GFP_ATOMIC);
 	if (!label)
 		return ERR_PTR(-ENOMEM);
 
@@ -4719,7 +4724,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
 			is_irq = test_bit(FLAG_USED_AS_IRQ, &desc->flags);
 			active_low = test_bit(FLAG_ACTIVE_LOW, &desc->flags);
 			seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s\n",
-				   gpio, desc->name ?: "", desc->label,
+				   gpio, desc->name ?: "", gpiod_get_label(desc),
 				   is_out ? "out" : "in ",
 				   value >= 0 ? (value ? "hi" : "lo") : "?  ",
 				   is_irq ? "IRQ " : "",
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index c3ae5bfa3f2e..1058f326fe2b 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -208,6 +208,7 @@ int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce);
 int gpiod_hog(struct gpio_desc *desc, const char *name,
 		unsigned long lflags, enum gpiod_flags dflags);
 int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev);
+const char *gpiod_get_label(struct gpio_desc *desc);
 
 /*
  * Return the GPIO number of the passed descriptor relative to its chip
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 05/22] gpio: don't set label from irq helpers
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (3 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 04/22] gpio: provide and use gpiod_get_label() Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 19:38   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 06/22] gpio: add SRCU infrastructure to struct gpio_desc Bartosz Golaszewski
                   ` (17 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

We will soon serialize access to the descriptor label using SRCU. The
write-side of the protection will require calling synchronize_srcu()
which must not be called from atomic context. We have two irq helpers:
gpiochip_lock_as_irq() and gpiochip_unlock_as_irq() that set the label
if the GPIO is not requested but is being used as interrupt. They are
called with a spinlock held from the interrupt subsystem.

They must not do it if we are to use SRCU so instead let's move the
special corner case to a dedicated getter.

Let's use the flags of the descriptor to figure out whether we should
use the special "interrupt" label.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.c | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d0a2f014dacd..4e6b26b3febb 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -107,7 +107,14 @@ static bool gpiolib_initialized;
 
 const char *gpiod_get_label(struct gpio_desc *desc)
 {
-	return desc->label;
+	unsigned long flags;
+
+	flags = READ_ONCE(desc->flags);
+	if (test_bit(FLAG_USED_AS_IRQ, &flags) &&
+	    !test_bit(FLAG_REQUESTED, &flags))
+		return "interrupt";
+
+	return test_bit(FLAG_REQUESTED, &flags) ? desc->label : NULL;
 }
 
 static inline void desc_set_label(struct gpio_desc *d, const char *label)
@@ -3590,14 +3597,6 @@ int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset)
 	set_bit(FLAG_USED_AS_IRQ, &desc->flags);
 	set_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
 
-	/*
-	 * If the consumer has not set up a label (such as when the
-	 * IRQ is referenced from .to_irq()) we set up a label here
-	 * so it is clear this is used as an interrupt.
-	 */
-	if (!desc->label)
-		desc_set_label(desc, "interrupt");
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq);
@@ -3620,10 +3619,6 @@ void gpiochip_unlock_as_irq(struct gpio_chip *gc, unsigned int offset)
 
 	clear_bit(FLAG_USED_AS_IRQ, &desc->flags);
 	clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
-
-	/* If we only had this marking, erase it */
-	if (desc->label && !strcmp(desc->label, "interrupt"))
-		desc_set_label(desc, NULL);
 }
 EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq);
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 06/22] gpio: add SRCU infrastructure to struct gpio_desc
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (4 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 05/22] gpio: don't set label from irq helpers Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 19:35   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 07/22] gpio: protect the descriptor label with SRCU Bartosz Golaszewski
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Extend the GPIO descriptor with an SRCU structure in order to serialize
the access to the label. Initialize and clean it up where applicable.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.c | 18 ++++++++++++++++--
 drivers/gpio/gpiolib.h |  3 +++
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4e6b26b3febb..94e1a603cf8b 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -672,6 +672,10 @@ EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
 static void gpiodev_release(struct device *dev)
 {
 	struct gpio_device *gdev = to_gpio_device(dev);
+	unsigned int i;
+
+	for (i = 0; i < gdev->ngpio; i++)
+		cleanup_srcu_struct(&gdev->descs[i].srcu);
 
 	ida_free(&gpio_ida, gdev->id);
 	kfree_const(gdev->label);
@@ -829,7 +833,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 			       struct lock_class_key *request_key)
 {
 	struct gpio_device *gdev;
-	unsigned int i;
+	unsigned int i, j;
 	int base = 0;
 	int ret = 0;
 
@@ -962,6 +966,13 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 	for (i = 0; i < gc->ngpio; i++) {
 		struct gpio_desc *desc = &gdev->descs[i];
 
+		ret = init_srcu_struct(&desc->srcu);
+		if (ret) {
+			for (j = 0; j < i; j++)
+				cleanup_srcu_struct(&desc->srcu);
+			goto err_remove_of_chip;
+		}
+
 		if (gc->get_direction && gpiochip_line_is_valid(gc, i)) {
 			assign_bit(FLAG_IS_OUT,
 				   &desc->flags, !gc->get_direction(gc, i));
@@ -973,7 +984,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 
 	ret = gpiochip_add_pin_ranges(gc);
 	if (ret)
-		goto err_remove_of_chip;
+		goto err_cleanup_desc_srcu;
 
 	acpi_gpiochip_add(gc);
 
@@ -1012,6 +1023,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 	gpiochip_irqchip_free_valid_mask(gc);
 err_remove_acpi_chip:
 	acpi_gpiochip_remove(gc);
+err_cleanup_desc_srcu:
+	for (i = 0; i < gdev->ngpio; i++)
+		cleanup_srcu_struct(&gdev->descs[i].srcu);
 err_remove_of_chip:
 	gpiochip_free_hogs(gc);
 	of_gpiochip_remove(gc);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 1058f326fe2b..6e14b629c48b 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/notifier.h>
 #include <linux/rwsem.h>
+#include <linux/srcu.h>
 
 #define GPIOCHIP_NAME	"gpiochip"
 
@@ -147,6 +148,7 @@ void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action);
  * @label:		Name of the consumer
  * @name:		Line name
  * @hog:		Pointer to the device node that hogs this line (if any)
+ * @srcu:		SRCU struct protecting the label pointer.
  *
  * These are obtained using gpiod_get() and are preferable to the old
  * integer-based handles.
@@ -184,6 +186,7 @@ struct gpio_desc {
 #ifdef CONFIG_OF_DYNAMIC
 	struct device_node	*hog;
 #endif
+	struct srcu_struct	srcu;
 };
 
 #define gpiod_not_found(desc)		(IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 07/22] gpio: protect the descriptor label with SRCU
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (5 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 06/22] gpio: add SRCU infrastructure to struct gpio_desc Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 19:41   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 08/22] gpio: sysfs: use gpio_device_find() to iterate over existing devices Bartosz Golaszewski
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

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>
---
 drivers/gpio/gpiolib-cdev.c | 10 +++++---
 drivers/gpio/gpiolib.c      | 47 +++++++++++++++++++++++--------------
 drivers/gpio/gpiolib.h      | 34 +++++++++++++++++++--------
 3 files changed, 61 insertions(+), 30 deletions(-)

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 94e1a603cf8b..93b80f3e9fe2 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;
 }
 
 /**
@@ -2220,9 +2234,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;
 	}
@@ -2250,6 +2262,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:
@@ -2334,8 +2353,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);
@@ -2353,6 +2370,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;
@@ -2400,6 +2418,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
@@ -3511,16 +3531,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);
 
@@ -4726,6 +4738,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 */
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 08/22] gpio: sysfs: use gpio_device_find() to iterate over existing devices
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (6 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 07/22] gpio: protect the descriptor label with SRCU Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 19:42   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 09/22] gpio: remove gpio_lock Bartosz Golaszewski
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

With the list of GPIO devices now protected with SRCU we can use
gpio_device_find() to traverse it from sysfs.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-sysfs.c | 41 ++++++++++++++++--------------------
 drivers/gpio/gpiolib.c       |  2 +-
 drivers/gpio/gpiolib.h       |  1 -
 3 files changed, 19 insertions(+), 25 deletions(-)

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 6bf5332136e5..3c3b8559cff5 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -790,11 +790,24 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
 	}
 }
 
+static int gpiofind_sysfs_register(struct gpio_chip *gc, void *data)
+{
+	struct gpio_device *gdev = gc->gpiodev;
+	int ret;
+
+	if (gdev->mockdev)
+		return 0;
+
+	ret = gpiochip_sysfs_register(gdev);
+	if (ret)
+		chip_err(gc, "failed to register the sysfs entry: %d\n", ret);
+
+	return 0;
+}
+
 static int __init gpiolib_sysfs_init(void)
 {
-	int		status;
-	unsigned long	flags;
-	struct gpio_device *gdev;
+	int status;
 
 	status = class_register(&gpio_class);
 	if (status < 0)
@@ -806,26 +819,8 @@ static int __init gpiolib_sysfs_init(void)
 	 * We run before arch_initcall() so chip->dev nodes can have
 	 * registered, and so arch_initcall() can always gpiod_export().
 	 */
-	spin_lock_irqsave(&gpio_lock, flags);
-	list_for_each_entry(gdev, &gpio_devices, list) {
-		if (gdev->mockdev)
-			continue;
+	gpio_device_find(NULL, gpiofind_sysfs_register);
 
-		/*
-		 * TODO we yield gpio_lock here because
-		 * gpiochip_sysfs_register() acquires a mutex. This is unsafe
-		 * and needs to be fixed.
-		 *
-		 * Also it would be nice to use gpio_device_find() here so we
-		 * can keep gpio_chips local to gpiolib.c, but the yield of
-		 * gpio_lock prevents us from doing this.
-		 */
-		spin_unlock_irqrestore(&gpio_lock, flags);
-		status = gpiochip_sysfs_register(gdev);
-		spin_lock_irqsave(&gpio_lock, flags);
-	}
-	spin_unlock_irqrestore(&gpio_lock, flags);
-
-	return status;
+	return 0;
 }
 postcore_initcall(gpiolib_sysfs_init);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 93b80f3e9fe2..87d05134384e 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -85,7 +85,7 @@ DEFINE_SPINLOCK(gpio_lock);
 static DEFINE_MUTEX(gpio_lookup_lock);
 static LIST_HEAD(gpio_lookup_list);
 
-LIST_HEAD(gpio_devices);
+static LIST_HEAD(gpio_devices);
 /* Protects the GPIO device list against concurrent modifications. */
 static DEFINE_MUTEX(gpio_devices_lock);
 /* Ensures coherence during read-only accesses to the list of GPIO devices. */
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index d2e73eea9e92..2bf3f9e13ae4 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -136,7 +136,6 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
 int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
 
 extern spinlock_t gpio_lock;
-extern struct list_head gpio_devices;
 
 void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action);
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 09/22] gpio: remove gpio_lock
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (7 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 08/22] gpio: sysfs: use gpio_device_find() to iterate over existing devices Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 19:51   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 10/22] gpio: reinforce desc->flags handling Bartosz Golaszewski
                   ` (13 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

The "multi-function" gpio_lock is pretty much useless with how it's used
in GPIOLIB currently. Because many GPIO API calls can be called from all
contexts but may also call into sleeping driver callbacks, there are
many places with utterly broken workarounds like yielding the lock to
call a possibly sleeping function and then re-acquiring it again without
taking into account that the protected state may have changed.

It was also used to protect several unrelated things: like individual
descriptors AND the GPIO device list. We now serialize access to these
two with SRCU and so can finally remove the spinlock.

There is of course the question of consistency of lockless access to
GPIO descriptors. Because we only support exclusive access to GPIOs
(officially anyway, I'm looking at you broken
GPIOD_FLAGS_BIT_NONEXCLUSIVE bit...) and the API contract with providers
does not guarantee serialization, it's enough to ensure we cannot
accidentally dereference an invalid pointer and that the state we present
to both users and providers remains consistent. To achieve that: read the
flags field atomically except for a few special cases. Read their current
value before executing callback code and use this value for any subsequent
logic. Modifying the flags depends on the particular use-case and can
differ. For instance: when requesting a GPIO, we need to set the
REQUESTED bit immediately so that the next user trying to request the
same line sees -EBUSY.

While at it: the allocations that used GFP_ATOMIC until this point can
now switch to GFP_KERNEL.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-cdev.c  |  18 +++---
 drivers/gpio/gpiolib-sysfs.c |  17 ++----
 drivers/gpio/gpiolib.c       | 106 +++++++++++------------------------
 drivers/gpio/gpiolib.h       |   2 -
 4 files changed, 46 insertions(+), 97 deletions(-)

diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 75f4912339a6..3588aaf90e45 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -2302,18 +2302,16 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
 	memset(info, 0, sizeof(*info));
 	info->offset = gpio_chip_hwgpio(desc);
 
-	scoped_guard(spinlock_irqsave, &gpio_lock) {
-		if (desc->name)
-			strscpy(info->name, desc->name, sizeof(info->name));
+	if (desc->name)
+		strscpy(info->name, desc->name, sizeof(info->name));
 
-		scoped_guard(srcu, &desc->srcu) {
-			label = gpiod_get_label(desc);
-			if (label)
-				strscpy(info->consumer, label,
-					sizeof(info->consumer));
-		}
+	dflags = READ_ONCE(desc->flags);
 
-		dflags = READ_ONCE(desc->flags);
+	scoped_guard(srcu, &desc->srcu) {
+		label = gpiod_get_label(desc);
+		if (label && test_bit(FLAG_REQUESTED, &dflags))
+			strscpy(info->consumer, label,
+				sizeof(info->consumer));
 	}
 
 	/*
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 3c3b8559cff5..1cc707685f87 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -563,7 +563,6 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 	struct gpio_device *gdev;
 	struct gpiod_data *data;
 	struct gpio_chip *chip;
-	unsigned long flags;
 	struct device *dev;
 	int status, offset;
 
@@ -578,6 +577,9 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 		return -EINVAL;
 	}
 
+	if (!test_and_set_bit(FLAG_EXPORT, &desc->flags))
+		return -EPERM;
+
 	gdev = desc->gdev;
 	chip = gdev->chip;
 
@@ -589,18 +591,11 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 		goto err_unlock;
 	}
 
-	spin_lock_irqsave(&gpio_lock, flags);
-	if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
-	     test_bit(FLAG_EXPORT, &desc->flags)) {
-		spin_unlock_irqrestore(&gpio_lock, flags);
-		gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n",
-				__func__,
-				test_bit(FLAG_REQUESTED, &desc->flags),
-				test_bit(FLAG_EXPORT, &desc->flags));
+	if (!test_bit(FLAG_REQUESTED, &desc->flags)) {
+		gpiod_dbg(desc, "%s: unavailable (not requested)\n", __func__);
 		status = -EPERM;
 		goto err_unlock;
 	}
-	spin_unlock_irqrestore(&gpio_lock, flags);
 
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data) {
@@ -628,7 +623,6 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 		goto err_free_data;
 	}
 
-	set_bit(FLAG_EXPORT, &desc->flags);
 	mutex_unlock(&sysfs_lock);
 	return 0;
 
@@ -636,6 +630,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 	kfree(data);
 err_unlock:
 	mutex_unlock(&sysfs_lock);
+	clear_bit(FLAG_EXPORT, &desc->flags);
 	gpiod_dbg(desc, "%s: status %d\n", __func__, status);
 	return status;
 }
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 87d05134384e..2a7439db7392 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -76,12 +76,6 @@ static struct bus_type gpio_bus_type = {
  */
 #define FASTPATH_NGPIO CONFIG_GPIOLIB_FASTPATH_LIMIT
 
-/* gpio_lock prevents conflicts during gpio_desc[] table updates.
- * While any GPIO is requested, its gpio_chip is not removable;
- * each GPIO's "requested" flag serves as a lock and refcount.
- */
-DEFINE_SPINLOCK(gpio_lock);
-
 static DEFINE_MUTEX(gpio_lookup_lock);
 static LIST_HEAD(gpio_lookup_list);
 
@@ -123,8 +117,7 @@ static int desc_set_label(struct gpio_desc *desc, const char *label)
 	const char *new = NULL, *old;
 
 	if (label) {
-		/* FIXME: make this GFP_KERNEL once the spinlock is out. */
-		new = kstrdup_const(label, GFP_ATOMIC);
+		new = kstrdup_const(label, GFP_KERNEL);
 		if (!new)
 			return -ENOMEM;
 	}
@@ -1085,7 +1078,6 @@ EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key);
 void gpiochip_remove(struct gpio_chip *gc)
 {
 	struct gpio_device *gdev = gc->gpiodev;
-	unsigned long flags;
 	unsigned int i;
 
 	down_write(&gdev->sem);
@@ -1106,12 +1098,10 @@ void gpiochip_remove(struct gpio_chip *gc)
 	 */
 	gpiochip_set_data(gc, NULL);
 
-	spin_lock_irqsave(&gpio_lock, flags);
 	for (i = 0; i < gdev->ngpio; i++) {
 		if (test_bit(FLAG_REQUESTED, &gdev->descs[i].flags))
 			break;
 	}
-	spin_unlock_irqrestore(&gpio_lock, flags);
 
 	if (i != gdev->ngpio)
 		dev_crit(&gdev->dev,
@@ -2218,62 +2208,43 @@ 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 long flags;
 	unsigned int offset;
 	int ret;
 
+	if (test_and_set_bit(FLAG_REQUESTED, &desc->flags))
+		return -EBUSY;
+
 	if (label) {
 		label = kstrdup_const(label, GFP_KERNEL);
 		if (!label)
 			return -ENOMEM;
 	}
 
-	spin_lock_irqsave(&gpio_lock, flags);
-
 	/* NOTE:  gpio_request() can be called in early boot,
 	 * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
 	 */
 
-	if (test_and_set_bit(FLAG_REQUESTED, &desc->flags)) {
-		ret = -EBUSY;
-		goto out_free_unlock;
-	}
-
 	if (gc->request) {
-		/* gc->request may sleep */
-		spin_unlock_irqrestore(&gpio_lock, flags);
 		offset = gpio_chip_hwgpio(desc);
 		if (gpiochip_line_is_valid(gc, offset))
 			ret = gc->request(gc, offset);
 		else
 			ret = -EINVAL;
-		spin_lock_irqsave(&gpio_lock, flags);
+		if (ret)
+			goto out_clear_bit;
+	}
 
-		if (ret) {
-			desc_set_label(desc, NULL);
-			clear_bit(FLAG_REQUESTED, &desc->flags);
-			goto out_free_unlock;
-		}
-	}
-	if (gc->get_direction) {
-		/* gc->get_direction may sleep */
-		spin_unlock_irqrestore(&gpio_lock, flags);
+	if (gc->get_direction)
 		gpiod_get_direction(desc);
-		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;
-	}
+	if (ret)
+		goto out_clear_bit;
 
 	return 0;
 
-out_free_unlock:
-	spin_unlock_irqrestore(&gpio_lock, flags);
-	kfree_const(label);
+out_clear_bit:
+	clear_bit(FLAG_REQUESTED, &desc->flags);
 	return ret;
 }
 
@@ -2343,35 +2314,32 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
 
 	might_sleep();
 
-	spin_lock_irqsave(&gpio_lock, flags);
-
 	gc = desc->gdev->chip;
-	if (gc && test_bit(FLAG_REQUESTED, &desc->flags)) {
-		if (gc->free) {
-			spin_unlock_irqrestore(&gpio_lock, flags);
-			might_sleep_if(gc->can_sleep);
+	flags = READ_ONCE(desc->flags);
+
+	if (gc && test_bit(FLAG_REQUESTED, &flags)) {
+		if (gc->free)
 			gc->free(gc, gpio_chip_hwgpio(desc));
-			spin_lock_irqsave(&gpio_lock, flags);
-		}
-		clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
-		clear_bit(FLAG_REQUESTED, &desc->flags);
-		clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
-		clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
-		clear_bit(FLAG_PULL_UP, &desc->flags);
-		clear_bit(FLAG_PULL_DOWN, &desc->flags);
-		clear_bit(FLAG_BIAS_DISABLE, &desc->flags);
-		clear_bit(FLAG_EDGE_RISING, &desc->flags);
-		clear_bit(FLAG_EDGE_FALLING, &desc->flags);
-		clear_bit(FLAG_IS_HOGGED, &desc->flags);
+
+		clear_bit(FLAG_ACTIVE_LOW, &flags);
+		clear_bit(FLAG_REQUESTED, &flags);
+		clear_bit(FLAG_OPEN_DRAIN, &flags);
+		clear_bit(FLAG_OPEN_SOURCE, &flags);
+		clear_bit(FLAG_PULL_UP, &flags);
+		clear_bit(FLAG_PULL_DOWN, &flags);
+		clear_bit(FLAG_BIAS_DISABLE, &flags);
+		clear_bit(FLAG_EDGE_RISING, &flags);
+		clear_bit(FLAG_EDGE_FALLING, &flags);
+		clear_bit(FLAG_IS_HOGGED, &flags);
 #ifdef CONFIG_OF_DYNAMIC
 		WRITE_ONCE(desc->hog, NULL);
 #endif
 		ret = true;
-	}
+		desc_set_label(desc, NULL);
+		WRITE_ONCE(desc->flags, flags);
 
-	spin_unlock_irqrestore(&gpio_lock, flags);
-	desc_set_label(desc, NULL);
-	gpiod_line_state_notify(desc, GPIOLINE_CHANGED_RELEASED);
+		gpiod_line_state_notify(desc, GPIOLINE_CHANGED_RELEASED);
+	}
 
 	return ret;
 }
@@ -2413,22 +2381,12 @@ char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset)
 	if (IS_ERR(desc))
 		return NULL;
 
-	guard(spinlock_irqsave)(&gpio_lock);
-
 	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
-	 * the GPIO descriptors with mutex (while value setting operations will
-	 * become lockless).
-	 *
-	 * Until this happens, this allocation needs to be atomic.
-	 */
-	label = kstrdup(gpiod_get_label(desc), GFP_ATOMIC);
+	label = kstrdup(gpiod_get_label(desc), GFP_KERNEL);
 	if (!label)
 		return ERR_PTR(-ENOMEM);
 
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 2bf3f9e13ae4..9b7afe87f1bd 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -135,8 +135,6 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
 
 int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
 
-extern spinlock_t gpio_lock;
-
 void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action);
 
 /**
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 10/22] gpio: reinforce desc->flags handling
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (8 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 09/22] gpio: remove gpio_lock Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 20:01   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 11/22] gpio: remove unneeded code from gpio_device_get_desc() Bartosz Golaszewski
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

We now removed the gpio_lock spinlock and modified the places
previously protected by it to handle desc->flags access in a consistent
way. Let's improve other places that were previously unprotected by
reading the flags field of gpio_desc once and using the stored value for
logic consistency. If we need to modify the field, let's also write it
back once with a consistent value resulting from the function's logic.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.c | 42 +++++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 17 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 2a7439db7392..f15b854bbcb2 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -336,18 +336,20 @@ 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);
 	offset = gpio_chip_hwgpio(desc);
+	flags = READ_ONCE(desc->flags);
 
 	/*
 	 * Open drain emulation using input mode may incorrectly report
 	 * input here, fix that up.
 	 */
-	if (test_bit(FLAG_OPEN_DRAIN, &desc->flags) &&
-	    test_bit(FLAG_IS_OUT, &desc->flags))
+	if (test_bit(FLAG_OPEN_DRAIN, &flags) &&
+	    test_bit(FLAG_IS_OUT, &flags))
 		return 0;
 
 	if (!gc->get_direction)
@@ -361,7 +363,8 @@ int gpiod_get_direction(struct gpio_desc *desc)
 	if (ret > 0)
 		ret = 1;
 
-	assign_bit(FLAG_IS_OUT, &desc->flags, !ret);
+	assign_bit(FLAG_IS_OUT, &flags, !ret);
+	WRITE_ONCE(desc->flags, flags);
 
 	return ret;
 }
@@ -747,9 +750,6 @@ static void gpiochip_machine_hog(struct gpio_chip *gc, struct gpiod_hog *hog)
 		return;
 	}
 
-	if (test_bit(FLAG_IS_HOGGED, &desc->flags))
-		return;
-
 	rv = gpiod_hog(desc, hog->line_name, hog->lflags, hog->dflags);
 	if (rv)
 		gpiod_err(desc, "%s: unable to hog GPIO line (%s:%u): %d\n",
@@ -2519,13 +2519,16 @@ static int gpio_set_config(struct gpio_desc *desc, enum pin_config_param mode)
 static int gpio_set_bias(struct gpio_desc *desc)
 {
 	enum pin_config_param bias;
+	unsigned long flags;
 	unsigned int arg;
 
-	if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
+	flags = READ_ONCE(desc->flags);
+
+	if (test_bit(FLAG_BIAS_DISABLE, &flags))
 		bias = PIN_CONFIG_BIAS_DISABLE;
-	else if (test_bit(FLAG_PULL_UP, &desc->flags))
+	else if (test_bit(FLAG_PULL_UP, &flags))
 		bias = PIN_CONFIG_BIAS_PULL_UP;
-	else if (test_bit(FLAG_PULL_DOWN, &desc->flags))
+	else if (test_bit(FLAG_PULL_DOWN, &flags))
 		bias = PIN_CONFIG_BIAS_PULL_DOWN;
 	else
 		return 0;
@@ -2691,24 +2694,28 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw);
  */
 int gpiod_direction_output(struct gpio_desc *desc, int value)
 {
+	unsigned long flags;
 	int ret;
 
 	VALIDATE_DESC(desc);
-	if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+
+	flags = READ_ONCE(desc->flags);
+
+	if (test_bit(FLAG_ACTIVE_LOW, &flags))
 		value = !value;
 	else
 		value = !!value;
 
 	/* GPIOs used for enabled IRQs shall not be set as output */
-	if (test_bit(FLAG_USED_AS_IRQ, &desc->flags) &&
-	    test_bit(FLAG_IRQ_IS_ENABLED, &desc->flags)) {
+	if (test_bit(FLAG_USED_AS_IRQ, &flags) &&
+	    test_bit(FLAG_IRQ_IS_ENABLED, &flags)) {
 		gpiod_err(desc,
 			  "%s: tried to set a GPIO tied to an IRQ as output\n",
 			  __func__);
 		return -EIO;
 	}
 
-	if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
+	if (test_bit(FLAG_OPEN_DRAIN, &flags)) {
 		/* First see if we can enable open drain in hardware */
 		ret = gpio_set_config(desc, PIN_CONFIG_DRIVE_OPEN_DRAIN);
 		if (!ret)
@@ -2718,7 +2725,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
 			ret = gpiod_direction_input(desc);
 			goto set_output_flag;
 		}
-	} else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
+	} else if (test_bit(FLAG_OPEN_SOURCE, &flags)) {
 		ret = gpio_set_config(desc, PIN_CONFIG_DRIVE_OPEN_SOURCE);
 		if (!ret)
 			goto set_output_value;
@@ -4411,21 +4418,22 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
 	int hwnum;
 	int ret;
 
+	if (test_and_set_bit(FLAG_IS_HOGGED, &desc->flags))
+		return 0;
+
 	gc = gpiod_to_chip(desc);
 	hwnum = gpio_chip_hwgpio(desc);
 
 	local_desc = gpiochip_request_own_desc(gc, hwnum, name,
 					       lflags, dflags);
 	if (IS_ERR(local_desc)) {
+		clear_bit(FLAG_IS_HOGGED, &desc->flags);
 		ret = PTR_ERR(local_desc);
 		pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n",
 		       name, gc->label, hwnum, ret);
 		return ret;
 	}
 
-	/* Mark GPIO as hogged so it can be identified and removed later */
-	set_bit(FLAG_IS_HOGGED, &desc->flags);
-
 	gpiod_dbg(desc, "hogged as %s%s\n",
 		(dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input",
 		(dflags & GPIOD_FLAGS_BIT_DIR_OUT) ?
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 11/22] gpio: remove unneeded code from gpio_device_get_desc()
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (9 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 10/22] gpio: reinforce desc->flags handling Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 20:02   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 12/22] gpio: sysfs: extend the critical section for unregistering sysfs devices Bartosz Golaszewski
                   ` (11 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

The GPIO chip pointer is unused. Let's remove it.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.c | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f15b854bbcb2..ddf7d93f8b76 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -184,16 +184,6 @@ EXPORT_SYMBOL_GPL(gpiochip_get_desc);
 struct gpio_desc *
 gpio_device_get_desc(struct gpio_device *gdev, unsigned int hwnum)
 {
-	struct gpio_chip *gc;
-
-	/*
-	 * FIXME: This will be locked once we protect gdev->chip everywhere
-	 * with SRCU.
-	 */
-	gc = gdev->chip;
-	if (!gc)
-		return ERR_PTR(-ENODEV);
-
 	if (hwnum >= gdev->ngpio)
 		return ERR_PTR(-EINVAL);
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 12/22] gpio: sysfs: extend the critical section for unregistering sysfs devices
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (10 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 11/22] gpio: remove unneeded code from gpio_device_get_desc() Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 20:06   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 13/22] gpio: sysfs: pass the GPIO device - not chip - to sysfs callbacks Bartosz Golaszewski
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Checking the gdev->mockdev pointer for NULL must be part of the critical
section.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-sysfs.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 1cc707685f87..5da316ea9cc7 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 #include <linux/bitops.h>
+#include <linux/cleanup.h>
 #include <linux/device.h>
 #include <linux/idr.h>
 #include <linux/init.h>
@@ -768,15 +769,15 @@ void gpiochip_sysfs_unregister(struct gpio_device *gdev)
 	struct gpio_desc *desc;
 	struct gpio_chip *chip = gdev->chip;
 
-	if (!gdev->mockdev)
-		return;
+	scoped_guard(mutex, &sysfs_lock) {
+		if (!gdev->mockdev)
+			return;
 
-	device_unregister(gdev->mockdev);
+		device_unregister(gdev->mockdev);
 
-	/* prevent further gpiod exports */
-	mutex_lock(&sysfs_lock);
-	gdev->mockdev = NULL;
-	mutex_unlock(&sysfs_lock);
+		/* prevent further gpiod exports */
+		gdev->mockdev = NULL;
+	}
 
 	/* unregister gpiod class devices owned by sysfs */
 	for_each_gpio_desc_with_flag(chip, desc, FLAG_SYSFS) {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 13/22] gpio: sysfs: pass the GPIO device - not chip - to sysfs callbacks
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (11 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 12/22] gpio: sysfs: extend the critical section for unregistering sysfs devices Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 20:09   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 14/22] gpio: cdev: replace gpiochip_get_desc() with gpio_device_get_desc() Bartosz Golaszewski
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

We're working towards protecting the chip pointer in struct gpio_device
with SRCU. In order to use it in sysfs callbacks we must pass the pointer
to the GPIO device that wraps the chip instead of the address of the
chip itself as the user data.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-sysfs.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 5da316ea9cc7..654a5bc53047 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -401,27 +401,27 @@ static const struct attribute_group *gpio_groups[] = {
 static ssize_t base_show(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
-	const struct gpio_chip *chip = dev_get_drvdata(dev);
+	const struct gpio_device *gdev = dev_get_drvdata(dev);
 
-	return sysfs_emit(buf, "%d\n", chip->base);
+	return sysfs_emit(buf, "%d\n", gdev->chip->base);
 }
 static DEVICE_ATTR_RO(base);
 
 static ssize_t label_show(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
-	const struct gpio_chip *chip = dev_get_drvdata(dev);
+	const struct gpio_device *gdev = dev_get_drvdata(dev);
 
-	return sysfs_emit(buf, "%s\n", chip->label ?: "");
+	return sysfs_emit(buf, "%s\n", gdev->chip->label ?: "");
 }
 static DEVICE_ATTR_RO(label);
 
 static ssize_t ngpio_show(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
-	const struct gpio_chip *chip = dev_get_drvdata(dev);
+	const struct gpio_device *gdev = dev_get_drvdata(dev);
 
-	return sysfs_emit(buf, "%u\n", chip->ngpio);
+	return sysfs_emit(buf, "%u\n", gdev->chip->ngpio);
 }
 static DEVICE_ATTR_RO(ngpio);
 
@@ -751,7 +751,7 @@ int gpiochip_sysfs_register(struct gpio_device *gdev)
 		parent = &gdev->dev;
 
 	/* use chip->base for the ID; it's already known to be unique */
-	dev = device_create_with_groups(&gpio_class, parent, MKDEV(0, 0), chip,
+	dev = device_create_with_groups(&gpio_class, parent, MKDEV(0, 0), gdev,
 					gpiochip_groups, GPIOCHIP_NAME "%d",
 					chip->base);
 	if (IS_ERR(dev))
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 14/22] gpio: cdev: replace gpiochip_get_desc() with gpio_device_get_desc()
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (12 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 13/22] gpio: sysfs: pass the GPIO device - not chip - to sysfs callbacks Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 20:10   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 15/22] gpio: cdev: don't access gdev->chip if it's not needed Bartosz Golaszewski
                   ` (8 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

gpio_device_get_desc() is the safer alternative to gpiochip_get_desc().
As we don't really need to dereference the chip pointer to retrieve the
descriptors in character device code, let's use it.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-cdev.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 3588aaf90e45..8e37e3befa08 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -332,7 +332,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
 	/* Request each GPIO */
 	for (i = 0; i < handlereq.lines; i++) {
 		u32 offset = handlereq.lineoffsets[i];
-		struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
+		struct gpio_desc *desc = gpio_device_get_desc(gdev, offset);
 
 		if (IS_ERR(desc)) {
 			ret = PTR_ERR(desc);
@@ -1739,7 +1739,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
 	/* Request each GPIO */
 	for (i = 0; i < ulr.num_lines; i++) {
 		u32 offset = ulr.offsets[i];
-		struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
+		struct gpio_desc *desc = gpio_device_get_desc(gdev, offset);
 
 		if (IS_ERR(desc)) {
 			ret = PTR_ERR(desc);
@@ -2123,7 +2123,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
 	lflags = eventreq.handleflags;
 	eflags = eventreq.eventflags;
 
-	desc = gpiochip_get_desc(gdev->chip, offset);
+	desc = gpio_device_get_desc(gdev, offset);
 	if (IS_ERR(desc))
 		return PTR_ERR(desc);
 
@@ -2419,7 +2419,7 @@ static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip,
 		return -EFAULT;
 
 	/* this doubles as a range check on line_offset */
-	desc = gpiochip_get_desc(cdev->gdev->chip, lineinfo.line_offset);
+	desc = gpio_device_get_desc(cdev->gdev, lineinfo.line_offset);
 	if (IS_ERR(desc))
 		return PTR_ERR(desc);
 
@@ -2456,7 +2456,7 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip,
 	if (memchr_inv(lineinfo.padding, 0, sizeof(lineinfo.padding)))
 		return -EINVAL;
 
-	desc = gpiochip_get_desc(cdev->gdev->chip, lineinfo.offset);
+	desc = gpio_device_get_desc(cdev->gdev, lineinfo.offset);
 	if (IS_ERR(desc))
 		return PTR_ERR(desc);
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 15/22] gpio: cdev: don't access gdev->chip if it's not needed
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (13 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 14/22] gpio: cdev: replace gpiochip_get_desc() with gpio_device_get_desc() Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 20:11   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 16/22] gpio: reduce the functionality of validate_desc() Bartosz Golaszewski
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

The variable holding the number of GPIO lines is duplicated in GPIO
device so read it instead of unnecessarily dereferencing the chip
pointer.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-cdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 8e37e3befa08..e993c6a7215a 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -2701,7 +2701,7 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
 	if (!cdev)
 		return -ENODEV;
 
-	cdev->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL);
+	cdev->watched_lines = bitmap_zalloc(gdev->ngpio, GFP_KERNEL);
 	if (!cdev->watched_lines)
 		goto out_free_cdev;
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 16/22] gpio: reduce the functionality of validate_desc()
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (14 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 15/22] gpio: cdev: don't access gdev->chip if it's not needed Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 20:16   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 17/22] gpio: remove unnecessary checks from gpiod_to_chip() Bartosz Golaszewski
                   ` (6 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Checking desc->gdev->chip for NULL without holding it in place with some
serializing mechanism is pointless. Remove this check. Also don't check
desc->gdev for NULL as it can never happen.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.c | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index ddf7d93f8b76..0cb44578bc72 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2248,19 +2248,12 @@ static int validate_desc(const struct gpio_desc *desc, const char *func)
 {
 	if (!desc)
 		return 0;
+
 	if (IS_ERR(desc)) {
 		pr_warn("%s: invalid GPIO (errorpointer)\n", func);
 		return PTR_ERR(desc);
 	}
-	if (!desc->gdev) {
-		pr_warn("%s: invalid GPIO (no device)\n", func);
-		return -EINVAL;
-	}
-	if (!desc->gdev->chip) {
-		dev_warn(&desc->gdev->dev,
-			 "%s: backing chip is gone\n", func);
-		return 0;
-	}
+
 	return 1;
 }
 
@@ -2336,12 +2329,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
 
 void gpiod_free(struct gpio_desc *desc)
 {
-	/*
-	 * We must not use VALIDATE_DESC_VOID() as the underlying gdev->chip
-	 * may already be NULL but we still want to put the references.
-	 */
-	if (!desc)
-		return;
+	VALIDATE_DESC_VOID(desc);
 
 	if (!gpiod_free_commit(desc))
 		WARN_ON(1);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 17/22] gpio: remove unnecessary checks from gpiod_to_chip()
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (15 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 16/22] gpio: reduce the functionality of validate_desc() Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-30 12:48 ` [PATCH 18/22] gpio: add the can_sleep flag to struct gpio_device Bartosz Golaszewski
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

We don't need to check the gdev pointer in struct gpio_desc - it's
always assigned and never cleared. It's also pointless to check
gdev->chip before we actually serialize access to it.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 0cb44578bc72..e6b9f1c82a7d 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -214,7 +214,7 @@ EXPORT_SYMBOL_GPL(desc_to_gpio);
  */
 struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
 {
-	if (!desc || !desc->gdev)
+	if (!desc)
 		return NULL;
 	return desc->gdev->chip;
 }
@@ -3496,7 +3496,7 @@ int gpiod_to_irq(const struct gpio_desc *desc)
 	 * requires this function to not return zero on an invalid descriptor
 	 * but rather a negative error number.
 	 */
-	if (!desc || IS_ERR(desc) || !desc->gdev || !desc->gdev->chip)
+	if (!desc || IS_ERR(desc))
 		return -EINVAL;
 
 	gc = desc->gdev->chip;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 18/22] gpio: add the can_sleep flag to struct gpio_device
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (16 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 17/22] gpio: remove unnecessary checks from gpiod_to_chip() Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 20:17   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 19/22] gpio: add SRCU infrastructure " Bartosz Golaszewski
                   ` (4 subsequent siblings)
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Duplicating the can_sleep value in GPIO device will allow us to not
needlessly dereference the chip pointer in several places and reduce the
number of SRCU read-only critical sections.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.c | 11 ++++++-----
 drivers/gpio/gpiolib.h |  3 +++
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e6b9f1c82a7d..9548c9e53197 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -893,6 +893,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 	}
 
 	gdev->ngpio = gc->ngpio;
+	gdev->can_sleep = gc->can_sleep;
 
 	scoped_guard(mutex, &gpio_devices_lock) {
 		/*
@@ -3063,7 +3064,7 @@ int gpiod_get_raw_value(const struct gpio_desc *desc)
 {
 	VALIDATE_DESC(desc);
 	/* Should be using gpiod_get_raw_value_cansleep() */
-	WARN_ON(desc->gdev->chip->can_sleep);
+	WARN_ON(desc->gdev->can_sleep);
 	return gpiod_get_raw_value_commit(desc);
 }
 EXPORT_SYMBOL_GPL(gpiod_get_raw_value);
@@ -3084,7 +3085,7 @@ int gpiod_get_value(const struct gpio_desc *desc)
 
 	VALIDATE_DESC(desc);
 	/* Should be using gpiod_get_value_cansleep() */
-	WARN_ON(desc->gdev->chip->can_sleep);
+	WARN_ON(desc->gdev->can_sleep);
 
 	value = gpiod_get_raw_value_commit(desc);
 	if (value < 0)
@@ -3357,7 +3358,7 @@ void gpiod_set_raw_value(struct gpio_desc *desc, int value)
 {
 	VALIDATE_DESC_VOID(desc);
 	/* Should be using gpiod_set_raw_value_cansleep() */
-	WARN_ON(desc->gdev->chip->can_sleep);
+	WARN_ON(desc->gdev->can_sleep);
 	gpiod_set_raw_value_commit(desc, value);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_raw_value);
@@ -3398,7 +3399,7 @@ void gpiod_set_value(struct gpio_desc *desc, int value)
 {
 	VALIDATE_DESC_VOID(desc);
 	/* Should be using gpiod_set_value_cansleep() */
-	WARN_ON(desc->gdev->chip->can_sleep);
+	WARN_ON(desc->gdev->can_sleep);
 	gpiod_set_value_nocheck(desc, value);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_value);
@@ -3462,7 +3463,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_array_value);
 int gpiod_cansleep(const struct gpio_desc *desc)
 {
 	VALIDATE_DESC(desc);
-	return desc->gdev->chip->can_sleep;
+	return desc->gdev->can_sleep;
 }
 EXPORT_SYMBOL_GPL(gpiod_cansleep);
 
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 9b7afe87f1bd..43ff4931e2c3 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -34,6 +34,8 @@
  * @descs: array of ngpio descriptors.
  * @ngpio: the number of GPIO lines on this GPIO device, equal to the size
  * of the @descs array.
+ * @can_sleep: indicate whether the GPIO chip driver's callbacks can sleep
+ * implying that they cannot be used from atomic context
  * @base: GPIO base in the DEPRECATED global Linux GPIO numberspace, assigned
  * at device creation time.
  * @label: a descriptive name for the GPIO device, such as the part number
@@ -64,6 +66,7 @@ struct gpio_device {
 	struct gpio_desc	*descs;
 	int			base;
 	u16			ngpio;
+	bool			can_sleep;
 	const char		*label;
 	void			*data;
 	struct list_head        list;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 19/22] gpio: add SRCU infrastructure to struct gpio_device
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (17 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 18/22] gpio: add the can_sleep flag to struct gpio_device Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-30 12:48 ` [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU Bartosz Golaszewski
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Add the SRCU struct to GPIO device. It will be used to serialize access
to the GPIO chip pointer. Initialize and clean it up where applicable.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.c | 13 ++++++++++---
 drivers/gpio/gpiolib.h |  2 ++
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 9548c9e53197..a1a46f2127f8 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -680,6 +680,7 @@ static void gpiodev_release(struct device *dev)
 	ida_free(&gpio_ida, gdev->id);
 	kfree_const(gdev->label);
 	kfree(gdev->descs);
+	cleanup_srcu_struct(&gdev->srcu);
 	kfree(gdev);
 }
 
@@ -940,6 +941,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 	BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier);
 	init_rwsem(&gdev->sem);
 
+	ret = init_srcu_struct(&gdev->srcu);
+	if (ret)
+		goto err_remove_from_list;
+
 #ifdef CONFIG_PINCTRL
 	INIT_LIST_HEAD(&gdev->pin_ranges);
 #endif
@@ -947,15 +952,15 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 	if (gc->names) {
 		ret = gpiochip_set_desc_names(gc);
 		if (ret)
-			goto err_remove_from_list;
+			goto err_cleanup_gdev_srcu;
 	}
 	ret = gpiochip_set_names(gc);
 	if (ret)
-		goto err_remove_from_list;
+		goto err_cleanup_gdev_srcu;
 
 	ret = gpiochip_init_valid_mask(gc);
 	if (ret)
-		goto err_remove_from_list;
+		goto err_cleanup_gdev_srcu;
 
 	ret = of_gpiochip_add(gc);
 	if (ret)
@@ -1035,6 +1040,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 		gpio_device_put(gdev);
 		goto err_print_message;
 	}
+err_cleanup_gdev_srcu:
+	cleanup_srcu_struct(&gdev->srcu);
 err_remove_from_list:
 	scoped_guard(mutex, &gpio_devices_lock)
 		list_del_rcu(&gdev->list);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 43ff4931e2c3..35d71e30c546 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -49,6 +49,7 @@
  * @sem: protects the structure from a NULL-pointer dereference of @chip by
  *       user-space operations when the device gets unregistered during
  *       a hot-unplug event
+ * @srcu: protects the pointer to the underlying GPIO chip
  * @pin_ranges: range of pins served by the GPIO driver
  *
  * This state container holds most of the runtime variable data
@@ -73,6 +74,7 @@ struct gpio_device {
 	struct blocking_notifier_head line_state_notifier;
 	struct blocking_notifier_head device_notifier;
 	struct rw_semaphore	sem;
+	struct srcu_struct	srcu;
 
 #ifdef CONFIG_PINCTRL
 	/*
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (18 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 19/22] gpio: add SRCU infrastructure " Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31  0:41   ` kernel test robot
                     ` (3 more replies)
  2024-01-30 12:48 ` [PATCH 21/22] gpio: remove the RW semaphore from the GPIO device Bartosz Golaszewski
                   ` (2 subsequent siblings)
  22 siblings, 4 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Ensure we cannot crash if the GPIO device gets unregistered (and the
chip pointer set to NULL) during any of the API calls.

To that end: wait for all users of gdev->chip to exit their read-only
SRCU critical sections in gpiochip_remove().

For brevity: add a guard class which can be instantiated at the top of
every function requiring read-only access to the chip pointer and use it
in all API calls taking a GPIO descriptor as argument. In places where
we only deal with the GPIO device - use regular guard() helpers and
rcu_dereference() for chip access. Do the same in API calls taking a
const pointer to gpio_desc.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-cdev.c  |  53 ++++----
 drivers/gpio/gpiolib-sysfs.c |  78 ++++++++---
 drivers/gpio/gpiolib.c       | 251 +++++++++++++++++++++++------------
 drivers/gpio/gpiolib.h       |  20 +++
 4 files changed, 276 insertions(+), 126 deletions(-)

diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index e993c6a7215a..9aaddcc08e29 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);
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 654a5bc53047..c45b71adff2c 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);
 }
 
@@ -401,27 +409,48 @@ static const struct attribute_group *gpio_groups[] = {
 static ssize_t base_show(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
-	const struct gpio_device *gdev = dev_get_drvdata(dev);
+	struct gpio_device *gdev = dev_get_drvdata(dev);
+	struct gpio_chip *gc;
 
-	return sysfs_emit(buf, "%d\n", gdev->chip->base);
+	guard(srcu)(&gdev->srcu);
+
+	gc = rcu_dereference(gdev->chip);
+	if (!gc)
+		return -ENODEV;
+
+	return sysfs_emit(buf, "%d\n", gc->base);
 }
 static DEVICE_ATTR_RO(base);
 
 static ssize_t label_show(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
-	const struct gpio_device *gdev = dev_get_drvdata(dev);
+	struct gpio_device *gdev = dev_get_drvdata(dev);
+	struct gpio_chip *gc;
 
-	return sysfs_emit(buf, "%s\n", gdev->chip->label ?: "");
+	guard(srcu)(&gdev->srcu);
+
+	gc = rcu_dereference(gdev->chip);
+	if (!gc)
+		return -ENODEV;
+
+	return sysfs_emit(buf, "%s\n", gc->label ?: "");
 }
 static DEVICE_ATTR_RO(label);
 
 static ssize_t ngpio_show(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
-	const struct gpio_device *gdev = dev_get_drvdata(dev);
+	struct gpio_device *gdev = dev_get_drvdata(dev);
+	struct gpio_chip *gc;
 
-	return sysfs_emit(buf, "%u\n", gdev->chip->ngpio);
+	guard(srcu)(&gdev->srcu);
+
+	gc = rcu_dereference(gdev->chip);
+	if (!gc)
+		return -ENODEV;
+
+	return sysfs_emit(buf, "%u\n", gc->ngpio);
 }
 static DEVICE_ATTR_RO(ngpio);
 
@@ -444,7 +473,6 @@ 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;
 
@@ -458,9 +486,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 +595,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 +609,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 +640,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,
@@ -767,7 +801,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 +813,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 a1a46f2127f8..9990d87e32fe 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -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);
+	if (!desc)
+		/* Sane default is INPUT. */
+		return 1;
+
+	if (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;
 		}
@@ -844,7 +860,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 		return -ENOMEM;
 	gdev->dev.bus = &gpio_bus_type;
 	gdev->dev.parent = gc->parent;
-	gdev->chip = gc;
+	WRITE_ONCE(gdev->chip, gc);
 
 	gc->gpiodev = gdev;
 	gpiochip_set_data(gc, data);
@@ -1084,7 +1100,8 @@ void gpiochip_remove(struct gpio_chip *gc)
 	gpiochip_sysfs_unregister(gdev);
 	gpiochip_free_hogs(gc);
 	/* 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);
@@ -1147,6 +1164,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.
@@ -1157,8 +1175,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);
 	}
 
@@ -2205,10 +2228,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;
 
@@ -2222,17 +2248,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 ? : "?");
@@ -2299,18 +2325,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);
@@ -2467,11 +2493,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,
@@ -2561,18 +2590,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__);
@@ -2585,10 +2616,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__);
@@ -2607,28 +2640,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__);
@@ -2638,7 +2674,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)
@@ -2754,17 +2790,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__);
 
@@ -2783,17 +2822,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__);
 
@@ -2812,12 +2854,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);
 
@@ -2915,10 +2958,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);
@@ -2944,6 +2996,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,
@@ -2981,33 +3041,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;
@@ -3022,9 +3085,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);
@@ -3165,14 +3228,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);
 	}
@@ -3190,16 +3255,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)
@@ -3210,11 +3277,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);
 }
 
 /*
@@ -3275,33 +3343,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];
@@ -3337,10 +3408,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);
@@ -3496,6 +3567,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;
 
@@ -3507,7 +3579,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);
@@ -4683,12 +4761,18 @@ 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");
+
 	for_each_gpio_desc(gc, desc) {
 		guard(srcu)(&desc->srcu);
 		if (test_bit(FLAG_REQUESTED, &desc->flags)) {
@@ -4754,9 +4838,12 @@ static void gpiolib_seq_stop(struct seq_file *s, void *v)
 static int gpiolib_seq_show(struct seq_file *s, void *v)
 {
 	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)", (char *)s->private,
 			   dev_name(&gdev->dev));
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 35d71e30c546..c96afc800bea 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -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);
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 21/22] gpio: remove the RW semaphore from the GPIO device
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (19 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 20:24   ` Linus Walleij
  2024-01-30 12:48 ` [PATCH 22/22] gpio: mark unsafe gpio_chip manipulators as deprecated Bartosz Golaszewski
  2024-01-31 20:32 ` [PATCH 00/22] gpio: rework locking and object life-time control Linus Walleij
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

With all accesses to gdev->chip being protected with SRCU, we can now
remove the RW-semaphore specific to the character device which
fullfilled the same role up to this point.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib-cdev.c | 1 -
 drivers/gpio/gpiolib.c      | 4 ----
 drivers/gpio/gpiolib.h      | 5 -----
 3 files changed, 10 deletions(-)

diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 9aaddcc08e29..be0a3f591af4 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -24,7 +24,6 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/poll.h>
 #include <linux/rbtree.h>
-#include <linux/rwsem.h>
 #include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/timekeeping.h>
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 9990d87e32fe..5741bbfdc178 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -955,7 +955,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
 
 	BLOCKING_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier);
 	BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier);
-	init_rwsem(&gdev->sem);
 
 	ret = init_srcu_struct(&gdev->srcu);
 	if (ret)
@@ -1094,8 +1093,6 @@ void gpiochip_remove(struct gpio_chip *gc)
 	struct gpio_device *gdev = gc->gpiodev;
 	unsigned int i;
 
-	down_write(&gdev->sem);
-
 	/* FIXME: should the legacy sysfs handling be moved to gpio_device? */
 	gpiochip_sysfs_unregister(gdev);
 	gpiochip_free_hogs(gc);
@@ -1133,7 +1130,6 @@ void gpiochip_remove(struct gpio_chip *gc)
 	 * gone.
 	 */
 	gcdev_unregister(gdev);
-	up_write(&gdev->sem);
 	gpio_device_put(gdev);
 }
 EXPORT_SYMBOL_GPL(gpiochip_remove);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index c96afc800bea..c76acb8f95c6 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -16,7 +16,6 @@
 #include <linux/gpio/driver.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
-#include <linux/rwsem.h>
 #include <linux/srcu.h>
 
 #define GPIOCHIP_NAME	"gpiochip"
@@ -46,9 +45,6 @@
  *                       requested, released or reconfigured
  * @device_notifier: used to notify character device wait queues about the GPIO
  *                   device being unregistered
- * @sem: protects the structure from a NULL-pointer dereference of @chip by
- *       user-space operations when the device gets unregistered during
- *       a hot-unplug event
  * @srcu: protects the pointer to the underlying GPIO chip
  * @pin_ranges: range of pins served by the GPIO driver
  *
@@ -73,7 +69,6 @@ struct gpio_device {
 	struct list_head        list;
 	struct blocking_notifier_head line_state_notifier;
 	struct blocking_notifier_head device_notifier;
-	struct rw_semaphore	sem;
 	struct srcu_struct	srcu;
 
 #ifdef CONFIG_PINCTRL
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* [PATCH 22/22] gpio: mark unsafe gpio_chip manipulators as deprecated
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (20 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 21/22] gpio: remove the RW semaphore from the GPIO device Bartosz Golaszewski
@ 2024-01-30 12:48 ` Bartosz Golaszewski
  2024-01-31 20:29   ` Linus Walleij
  2024-01-31 20:32 ` [PATCH 00/22] gpio: rework locking and object life-time control Linus Walleij
  22 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-30 12:48 UTC (permalink / raw)
  To: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang
  Cc: linux-gpio, linux-kernel, Bartosz Golaszewski

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

We still have some functions that return the address of the GPIO chip
associated with the GPIO device. This is dangerous and the users should
find a better solution. Let's add appropriate comments to the kernel
docs.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/gpio/gpiolib.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5741bbfdc178..7ecdd8cc39c5 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -211,6 +211,11 @@ EXPORT_SYMBOL_GPL(desc_to_gpio);
 /**
  * gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs
  * @desc:	descriptor to return the chip of
+ *
+ * *DEPRECATED*
+ * This function is unsafe and should not be used. Using the chip address
+ * without taking the SRCU read lock may result in dereferencing a dangling
+ * pointer.
  */
 struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
 {
@@ -275,6 +280,7 @@ EXPORT_SYMBOL(gpio_device_get_label);
  * Returns:
  * Address of the GPIO chip backing this device.
  *
+ * *DEPRECATED*
  * Until we can get rid of all non-driver users of struct gpio_chip, we must
  * provide a way of retrieving the pointer to it from struct gpio_device. This
  * is *NOT* safe as the GPIO API is considered to be hot-unpluggable and the
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-30 12:48 ` [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU Bartosz Golaszewski
@ 2024-01-31  0:41   ` kernel test robot
  2024-01-31  8:15     ` Bartosz Golaszewski
  2024-01-31  2:20   ` kernel test robot
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 66+ messages in thread
From: kernel test robot @ 2024-01-31  0:41 UTC (permalink / raw)
  To: Bartosz Golaszewski, Linus Walleij, Kent Gibson, Alex Elder,
	Geert Uytterhoeven, Paul E . McKenney, Andy Shevchenko,
	Wolfram Sang
  Cc: llvm, oe-kbuild-all, linux-gpio, linux-kernel, Bartosz Golaszewski

Hi Bartosz,

kernel test robot noticed the following build errors:

[auto build test ERROR on brgl/gpio/for-next]
[also build test ERROR on linus/master v6.8-rc2 next-20240130]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
config: x86_64-buildonly-randconfig-004-20240131 (https://download.01.org/0day-ci/archive/20240131/202401310855.aA6wzlm2-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401310855.aA6wzlm2-lkp@intel.com/reproduce)

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-kbuild-all/202401310855.aA6wzlm2-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/gpio/gpiolib-sysfs.c:481:3: error: cannot jump from this goto statement to its label
     481 |                 goto done;
         |                 ^
   drivers/gpio/gpiolib-sysfs.c:490:25: note: jump bypasses initialization of variable with __attribute__((cleanup))
     490 |         CLASS(gpio_chip_guard, guard)(desc);
         |                                ^
   1 error generated.


vim +481 drivers/gpio/gpiolib-sysfs.c

0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  464  
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  465  /*
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  466   * /sys/class/gpio/export ... write-only
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  467   *	integer N ... number of GPIO to export (full access)
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  468   * /sys/class/gpio/unexport ... write-only
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  469   *	integer N ... number of GPIO to unexport
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  470   */
75a2d4226b5371 Greg Kroah-Hartman  2023-03-25  471  static ssize_t export_store(const struct class *class,
75a2d4226b5371 Greg Kroah-Hartman  2023-03-25  472  				const struct class_attribute *attr,
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  473  				const char *buf, size_t len)
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  474  {
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  475  	struct gpio_desc *desc;
513246a34b8dc5 Bartosz Golaszewski 2023-12-21  476  	int status, offset;
513246a34b8dc5 Bartosz Golaszewski 2023-12-21  477  	long gpio;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  478  
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  479  	status = kstrtol(buf, 0, &gpio);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  480  	if (status < 0)
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01 @481  		goto done;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  482  
f13a0b0bb46f07 Linus Walleij       2018-09-13  483  	desc = gpio_to_desc(gpio);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  484  	/* reject invalid GPIOs */
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  485  	if (!desc) {
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  486  		pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  487  		return -EINVAL;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  488  	}
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  489  
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  490  	CLASS(gpio_chip_guard, guard)(desc);
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  491  	if (!guard.gc)
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  492  		return -ENODEV;
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  493  
23cf00ddd2e1aa Matti Vaittinen     2021-03-29  494  	offset = gpio_chip_hwgpio(desc);
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  495  	if (!gpiochip_line_is_valid(guard.gc, offset)) {
23cf00ddd2e1aa Matti Vaittinen     2021-03-29  496  		pr_warn("%s: GPIO %ld masked\n", __func__, gpio);
23cf00ddd2e1aa Matti Vaittinen     2021-03-29  497  		return -EINVAL;
23cf00ddd2e1aa Matti Vaittinen     2021-03-29  498  	}
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  499  
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  500  	/* No extra locking here; FLAG_SYSFS just signifies that the
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  501  	 * request and export were done by on behalf of userspace, so
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  502  	 * they may be undone on its behalf too.
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  503  	 */
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  504  
95a4eed7dd5b7c Andy Shevchenko     2022-02-01  505  	status = gpiod_request_user(desc, "sysfs");
95a4eed7dd5b7c Andy Shevchenko     2022-02-01  506  	if (status)
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  507  		goto done;
e10f72bf4b3e88 Andrew Jeffery      2017-11-30  508  
e10f72bf4b3e88 Andrew Jeffery      2017-11-30  509  	status = gpiod_set_transitory(desc, false);
95dd1e34ff5bbe Boerge Struempfel   2023-11-29  510  	if (status) {
95dd1e34ff5bbe Boerge Struempfel   2023-11-29  511  		gpiod_free(desc);
95dd1e34ff5bbe Boerge Struempfel   2023-11-29  512  		goto done;
95dd1e34ff5bbe Boerge Struempfel   2023-11-29  513  	}
95dd1e34ff5bbe Boerge Struempfel   2023-11-29  514  
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  515  	status = gpiod_export(desc, true);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  516  	if (status < 0)
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  517  		gpiod_free(desc);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  518  	else
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  519  		set_bit(FLAG_SYSFS, &desc->flags);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  520  
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  521  done:
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  522  	if (status)
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  523  		pr_debug("%s: status %d\n", __func__, status);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  524  	return status ? : len;
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  525  }
d83bb159f4c6af Greg Kroah-Hartman  2017-06-08  526  static CLASS_ATTR_WO(export);
0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  527  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-30 12:48 ` [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU Bartosz Golaszewski
  2024-01-31  0:41   ` kernel test robot
@ 2024-01-31  2:20   ` kernel test robot
  2024-01-31  9:02     ` Bartosz Golaszewski
  2024-01-31 20:23   ` Linus Walleij
  2024-02-01  5:03   ` Dan Carpenter
  3 siblings, 1 reply; 66+ messages in thread
From: kernel test robot @ 2024-01-31  2:20 UTC (permalink / raw)
  To: Bartosz Golaszewski, Linus Walleij, Kent Gibson, Alex Elder,
	Geert Uytterhoeven, Paul E . McKenney, Andy Shevchenko,
	Wolfram Sang
  Cc: oe-kbuild-all, linux-gpio, linux-kernel, Bartosz Golaszewski

Hi Bartosz,

kernel test robot noticed the following build warnings:

[auto build test WARNING on brgl/gpio/for-next]
[also build test WARNING on linus/master v6.8-rc2 next-20240130]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
config: x86_64-randconfig-122-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/reproduce)

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-kbuild-all/202401311050.YNdm98Hv-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/gpio/gpiolib.c:444:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip *
   drivers/gpio/gpiolib.c:1103:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip *
   drivers/gpio/gpiolib.c:1182:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip *
   drivers/gpio/gpiolib.c:2970:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip *
   drivers/gpio/gpiolib.c:3004:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip *
   drivers/gpio/gpiolib.c:3585:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip *
   drivers/gpio/gpiolib.c:4772:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip *
   drivers/gpio/gpiolib.c:4846:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip *
   drivers/gpio/gpiolib.c: note: in included file:
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
   drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *

vim +444 drivers/gpio/gpiolib.c

   422	
   423	/*
   424	 * Convert a GPIO name to its descriptor
   425	 * Note that there is no guarantee that GPIO names are globally unique!
   426	 * Hence this function will return, if it exists, a reference to the first GPIO
   427	 * line found that matches the given name.
   428	 */
   429	static struct gpio_desc *gpio_name_to_desc(const char * const name)
   430	{
   431		struct gpio_device *gdev;
   432		struct gpio_desc *desc;
   433		struct gpio_chip *gc;
   434	
   435		if (!name)
   436			return NULL;
   437	
   438		guard(srcu)(&gpio_devices_srcu);
   439	
   440		list_for_each_entry_srcu(gdev, &gpio_devices, list,
   441					 srcu_read_lock_held(&gpio_devices_srcu)) {
   442			guard(srcu)(&gdev->srcu);
   443	
 > 444			gc = rcu_dereference(gdev->chip);
   445			if (!gc)
   446				continue;
   447	
   448			for_each_gpio_desc(gc, desc) {
   449				if (desc->name && !strcmp(desc->name, name))
   450					return desc;
   451			}
   452		}
   453	
   454		return NULL;
   455	}
   456	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-31  0:41   ` kernel test robot
@ 2024-01-31  8:15     ` Bartosz Golaszewski
  0 siblings, 0 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-31  8:15 UTC (permalink / raw)
  To: kernel test robot
  Cc: llvm, oe-kbuild-all, linux-gpio, linux-kernel,
	Bartosz Golaszewski, Bartosz Golaszewski, Linus Walleij,
	Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang

On Wed, 31 Jan 2024 01:41:11 +0100, kernel test robot <lkp@intel.com> said:
> Hi Bartosz,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on brgl/gpio/for-next]
> [also build test ERROR on linus/master v6.8-rc2 next-20240130]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
> patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
> patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
> config: x86_64-buildonly-randconfig-004-20240131 (https://download.01.org/0day-ci/archive/20240131/202401310855.aA6wzlm2-lkp@intel.com/config)
> compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401310855.aA6wzlm2-lkp@intel.com/reproduce)
>
> 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-kbuild-all/202401310855.aA6wzlm2-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
>>> drivers/gpio/gpiolib-sysfs.c:481:3: error: cannot jump from this goto statement to its label
>      481 |                 goto done;
>          |                 ^
>    drivers/gpio/gpiolib-sysfs.c:490:25: note: jump bypasses initialization of variable with __attribute__((cleanup))
>      490 |         CLASS(gpio_chip_guard, guard)(desc);
>          |                                ^
>    1 error generated.
>

I fixed it up like this:

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index c45b71adff2c..6a421309319e 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -477,8 +477,8 @@ static ssize_t export_store(const struct class *class,
 	long gpio;

 	status = kstrtol(buf, 0, &gpio);
-	if (status < 0)
-		goto done;
+	if (status)
+		return status;

 	desc = gpio_to_desc(gpio);
 	/* reject invalid GPIOs */

There's no reason to jump to done here only to print the error code.

Bart

>
> vim +481 drivers/gpio/gpiolib-sysfs.c
>
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  464
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  465  /*
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  466   * /sys/class/gpio/export ... write-only
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  467   *	integer N ... number of GPIO to export (full access)
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  468   * /sys/class/gpio/unexport ... write-only
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  469   *	integer N ... number of GPIO to unexport
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  470   */
> 75a2d4226b5371 Greg Kroah-Hartman  2023-03-25  471  static ssize_t export_store(const struct class *class,
> 75a2d4226b5371 Greg Kroah-Hartman  2023-03-25  472  				const struct class_attribute *attr,
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  473  				const char *buf, size_t len)
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  474  {
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  475  	struct gpio_desc *desc;
> 513246a34b8dc5 Bartosz Golaszewski 2023-12-21  476  	int status, offset;
> 513246a34b8dc5 Bartosz Golaszewski 2023-12-21  477  	long gpio;
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  478
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  479  	status = kstrtol(buf, 0, &gpio);
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  480  	if (status < 0)
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01 @481  		goto done;
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  482
> f13a0b0bb46f07 Linus Walleij       2018-09-13  483  	desc = gpio_to_desc(gpio);
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  484  	/* reject invalid GPIOs */
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  485  	if (!desc) {
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  486  		pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  487  		return -EINVAL;
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  488  	}
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  489
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  490  	CLASS(gpio_chip_guard, guard)(desc);
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  491  	if (!guard.gc)
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  492  		return -ENODEV;
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  493
> 23cf00ddd2e1aa Matti Vaittinen     2021-03-29  494  	offset = gpio_chip_hwgpio(desc);
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  495  	if (!gpiochip_line_is_valid(guard.gc, offset)) {
> 23cf00ddd2e1aa Matti Vaittinen     2021-03-29  496  		pr_warn("%s: GPIO %ld masked\n", __func__, gpio);
> 23cf00ddd2e1aa Matti Vaittinen     2021-03-29  497  		return -EINVAL;
> 23cf00ddd2e1aa Matti Vaittinen     2021-03-29  498  	}
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  499
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  500  	/* No extra locking here; FLAG_SYSFS just signifies that the
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  501  	 * request and export were done by on behalf of userspace, so
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  502  	 * they may be undone on its behalf too.
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  503  	 */
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  504
> 95a4eed7dd5b7c Andy Shevchenko     2022-02-01  505  	status = gpiod_request_user(desc, "sysfs");
> 95a4eed7dd5b7c Andy Shevchenko     2022-02-01  506  	if (status)
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  507  		goto done;
> e10f72bf4b3e88 Andrew Jeffery      2017-11-30  508
> e10f72bf4b3e88 Andrew Jeffery      2017-11-30  509  	status = gpiod_set_transitory(desc, false);
> 95dd1e34ff5bbe Boerge Struempfel   2023-11-29  510  	if (status) {
> 95dd1e34ff5bbe Boerge Struempfel   2023-11-29  511  		gpiod_free(desc);
> 95dd1e34ff5bbe Boerge Struempfel   2023-11-29  512  		goto done;
> 95dd1e34ff5bbe Boerge Struempfel   2023-11-29  513  	}
> 95dd1e34ff5bbe Boerge Struempfel   2023-11-29  514
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  515  	status = gpiod_export(desc, true);
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  516  	if (status < 0)
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  517  		gpiod_free(desc);
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  518  	else
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  519  		set_bit(FLAG_SYSFS, &desc->flags);
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  520
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  521  done:
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  522  	if (status)
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  523  		pr_debug("%s: status %d\n", __func__, status);
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  524  	return status ? : len;
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  525  }
> d83bb159f4c6af Greg Kroah-Hartman  2017-06-08  526  static CLASS_ATTR_WO(export);
> 0eb4c6c2671ca0 Alexandre Courbot   2014-07-01  527
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki
>

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-31  2:20   ` kernel test robot
@ 2024-01-31  9:02     ` Bartosz Golaszewski
  2024-01-31  9:24       ` Paul E. McKenney
  0 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-31  9:02 UTC (permalink / raw)
  To: Paul E . McKenney
  Cc: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Andy Shevchenko, Wolfram Sang, oe-kbuild-all, linux-gpio,
	linux-kernel, Bartosz Golaszewski

On Wed, Jan 31, 2024 at 3:21 AM kernel test robot <lkp@intel.com> wrote:
>
> Hi Bartosz,
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on brgl/gpio/for-next]
> [also build test WARNING on linus/master v6.8-rc2 next-20240130]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
> patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
> patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
> config: x86_64-randconfig-122-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/config)
> compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/reproduce)
>
> 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-kbuild-all/202401311050.YNdm98Hv-lkp@intel.com/
>
> sparse warnings: (new ones prefixed by >>)
> >> drivers/gpio/gpiolib.c:444:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip *
>    drivers/gpio/gpiolib.c:1103:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip *
>    drivers/gpio/gpiolib.c:1182:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip *
>    drivers/gpio/gpiolib.c:2970:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip *
>    drivers/gpio/gpiolib.c:3004:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip *
>    drivers/gpio/gpiolib.c:3585:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip *
>    drivers/gpio/gpiolib.c:4772:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip *
>    drivers/gpio/gpiolib.c:4846:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip *
>    drivers/gpio/gpiolib.c: note: in included file:
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>
> vim +444 drivers/gpio/gpiolib.c
>
>    422
>    423  /*
>    424   * Convert a GPIO name to its descriptor
>    425   * Note that there is no guarantee that GPIO names are globally unique!
>    426   * Hence this function will return, if it exists, a reference to the first GPIO
>    427   * line found that matches the given name.
>    428   */
>    429  static struct gpio_desc *gpio_name_to_desc(const char * const name)
>    430  {
>    431          struct gpio_device *gdev;
>    432          struct gpio_desc *desc;
>    433          struct gpio_chip *gc;
>    434
>    435          if (!name)
>    436                  return NULL;
>    437
>    438          guard(srcu)(&gpio_devices_srcu);
>    439
>    440          list_for_each_entry_srcu(gdev, &gpio_devices, list,
>    441                                   srcu_read_lock_held(&gpio_devices_srcu)) {
>    442                  guard(srcu)(&gdev->srcu);
>    443
>  > 444                  gc = rcu_dereference(gdev->chip);
>    445                  if (!gc)
>    446                          continue;
>    447
>    448                  for_each_gpio_desc(gc, desc) {
>    449                          if (desc->name && !strcmp(desc->name, name))
>    450                                  return desc;
>    451                  }
>    452          }
>    453
>    454          return NULL;
>    455  }
>    456
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki

Paul,

Should I care about these warnings? They seem to be emitted for a lot
of RCU code already upstream. I'm not even sure how I'd go about
addressing them honestly.

Bart

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-31  9:02     ` Bartosz Golaszewski
@ 2024-01-31  9:24       ` Paul E. McKenney
  2024-01-31  9:28         ` Bartosz Golaszewski
  0 siblings, 1 reply; 66+ messages in thread
From: Paul E. McKenney @ 2024-01-31  9:24 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Andy Shevchenko, Wolfram Sang, oe-kbuild-all, linux-gpio,
	linux-kernel, Bartosz Golaszewski

On Wed, Jan 31, 2024 at 10:02:40AM +0100, Bartosz Golaszewski wrote:
> On Wed, Jan 31, 2024 at 3:21 AM kernel test robot <lkp@intel.com> wrote:
> >
> > Hi Bartosz,
> >
> > kernel test robot noticed the following build warnings:
> >
> > [auto build test WARNING on brgl/gpio/for-next]
> > [also build test WARNING on linus/master v6.8-rc2 next-20240130]
> > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > And when submitting patch, we suggest to use '--base' as documented in
> > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> >
> > url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
> > base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
> > patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
> > patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
> > config: x86_64-randconfig-122-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/config)
> > compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
> > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/reproduce)
> >
> > 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-kbuild-all/202401311050.YNdm98Hv-lkp@intel.com/
> >
> > sparse warnings: (new ones prefixed by >>)
> > >> drivers/gpio/gpiolib.c:444:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip *
> >    drivers/gpio/gpiolib.c:1103:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip *
> >    drivers/gpio/gpiolib.c:1182:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip *
> >    drivers/gpio/gpiolib.c:2970:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip *
> >    drivers/gpio/gpiolib.c:3004:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip *
> >    drivers/gpio/gpiolib.c:3585:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip *
> >    drivers/gpio/gpiolib.c:4772:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip *
> >    drivers/gpio/gpiolib.c:4846:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip *
> >    drivers/gpio/gpiolib.c: note: in included file:
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >
> > vim +444 drivers/gpio/gpiolib.c
> >
> >    422
> >    423  /*
> >    424   * Convert a GPIO name to its descriptor
> >    425   * Note that there is no guarantee that GPIO names are globally unique!
> >    426   * Hence this function will return, if it exists, a reference to the first GPIO
> >    427   * line found that matches the given name.
> >    428   */
> >    429  static struct gpio_desc *gpio_name_to_desc(const char * const name)
> >    430  {
> >    431          struct gpio_device *gdev;
> >    432          struct gpio_desc *desc;
> >    433          struct gpio_chip *gc;
> >    434
> >    435          if (!name)
> >    436                  return NULL;
> >    437
> >    438          guard(srcu)(&gpio_devices_srcu);
> >    439
> >    440          list_for_each_entry_srcu(gdev, &gpio_devices, list,
> >    441                                   srcu_read_lock_held(&gpio_devices_srcu)) {
> >    442                  guard(srcu)(&gdev->srcu);
> >    443
> >  > 444                  gc = rcu_dereference(gdev->chip);
> >    445                  if (!gc)
> >    446                          continue;
> >    447
> >    448                  for_each_gpio_desc(gc, desc) {
> >    449                          if (desc->name && !strcmp(desc->name, name))
> >    450                                  return desc;
> >    451                  }
> >    452          }
> >    453
> >    454          return NULL;
> >    455  }
> >    456
> >
> > --
> > 0-DAY CI Kernel Test Service
> > https://github.com/intel/lkp-tests/wiki
> 
> Paul,
> 
> Should I care about these warnings? They seem to be emitted for a lot
> of RCU code already upstream. I'm not even sure how I'd go about
> addressing them honestly.

This is maintainer's choice.

The fix would be to apply __rcu to the definition of ->chip.  The benefit
is that it finds bugs where rcu-protected pointers are used without RCU
primitives and vice versa.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-31  9:24       ` Paul E. McKenney
@ 2024-01-31  9:28         ` Bartosz Golaszewski
  2024-01-31  9:41           ` Bartosz Golaszewski
  2024-01-31  9:42           ` Paul E. McKenney
  0 siblings, 2 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-31  9:28 UTC (permalink / raw)
  To: paulmck
  Cc: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Andy Shevchenko, Wolfram Sang, oe-kbuild-all, linux-gpio,
	linux-kernel, Bartosz Golaszewski

On Wed, Jan 31, 2024 at 10:24 AM Paul E. McKenney <paulmck@kernel.org> wrote:
>
> On Wed, Jan 31, 2024 at 10:02:40AM +0100, Bartosz Golaszewski wrote:
> > On Wed, Jan 31, 2024 at 3:21 AM kernel test robot <lkp@intel.com> wrote:
> > >
> > > Hi Bartosz,
> > >
> > > kernel test robot noticed the following build warnings:
> > >
> > > [auto build test WARNING on brgl/gpio/for-next]
> > > [also build test WARNING on linus/master v6.8-rc2 next-20240130]
> > > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > > And when submitting patch, we suggest to use '--base' as documented in
> > > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> > >
> > > url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
> > > base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
> > > patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
> > > patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
> > > config: x86_64-randconfig-122-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/config)
> > > compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
> > > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/reproduce)
> > >
> > > 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-kbuild-all/202401311050.YNdm98Hv-lkp@intel.com/
> > >
> > > sparse warnings: (new ones prefixed by >>)
> > > >> drivers/gpio/gpiolib.c:444:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip *
> > >    drivers/gpio/gpiolib.c:1103:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip *
> > >    drivers/gpio/gpiolib.c:1182:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip *
> > >    drivers/gpio/gpiolib.c:2970:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip *
> > >    drivers/gpio/gpiolib.c:3004:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip *
> > >    drivers/gpio/gpiolib.c:3585:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip *
> > >    drivers/gpio/gpiolib.c:4772:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip *
> > >    drivers/gpio/gpiolib.c:4846:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip *
> > >    drivers/gpio/gpiolib.c: note: in included file:
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >
> > > vim +444 drivers/gpio/gpiolib.c
> > >
> > >    422
> > >    423  /*
> > >    424   * Convert a GPIO name to its descriptor
> > >    425   * Note that there is no guarantee that GPIO names are globally unique!
> > >    426   * Hence this function will return, if it exists, a reference to the first GPIO
> > >    427   * line found that matches the given name.
> > >    428   */
> > >    429  static struct gpio_desc *gpio_name_to_desc(const char * const name)
> > >    430  {
> > >    431          struct gpio_device *gdev;
> > >    432          struct gpio_desc *desc;
> > >    433          struct gpio_chip *gc;
> > >    434
> > >    435          if (!name)
> > >    436                  return NULL;
> > >    437
> > >    438          guard(srcu)(&gpio_devices_srcu);
> > >    439
> > >    440          list_for_each_entry_srcu(gdev, &gpio_devices, list,
> > >    441                                   srcu_read_lock_held(&gpio_devices_srcu)) {
> > >    442                  guard(srcu)(&gdev->srcu);
> > >    443
> > >  > 444                  gc = rcu_dereference(gdev->chip);
> > >    445                  if (!gc)
> > >    446                          continue;
> > >    447
> > >    448                  for_each_gpio_desc(gc, desc) {
> > >    449                          if (desc->name && !strcmp(desc->name, name))
> > >    450                                  return desc;
> > >    451                  }
> > >    452          }
> > >    453
> > >    454          return NULL;
> > >    455  }
> > >    456
> > >
> > > --
> > > 0-DAY CI Kernel Test Service
> > > https://github.com/intel/lkp-tests/wiki
> >
> > Paul,
> >
> > Should I care about these warnings? They seem to be emitted for a lot
> > of RCU code already upstream. I'm not even sure how I'd go about
> > addressing them honestly.
>
> This is maintainer's choice.
>
> The fix would be to apply __rcu to the definition of ->chip.  The benefit
> is that it finds bugs where rcu-protected pointers are used without RCU
> primitives and vice versa.
>
>                                                         Thanx, Paul

Ah, good point. I marked the other RCU-protected fields like
descriptor label but forgot this one.

It also seems like I need to use __rcu for all function arguments
taking an RCU-protected pointer as argument?

Bart

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU
  2024-01-30 12:48 ` [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU Bartosz Golaszewski
@ 2024-01-31  9:34   ` kernel test robot
  2024-01-31 12:45     ` Bartosz Golaszewski
  2024-01-31 15:01   ` Linus Walleij
  1 sibling, 1 reply; 66+ messages in thread
From: kernel test robot @ 2024-01-31  9:34 UTC (permalink / raw)
  To: Bartosz Golaszewski, Linus Walleij, Kent Gibson, Alex Elder,
	Geert Uytterhoeven, Paul E . McKenney, Andy Shevchenko,
	Wolfram Sang
  Cc: oe-kbuild-all, linux-gpio, linux-kernel, Bartosz Golaszewski

Hi Bartosz,

kernel test robot noticed the following build warnings:

[auto build test WARNING on brgl/gpio/for-next]
[also build test WARNING on linus/master v6.8-rc2 next-20240131]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
patch link:    https://lore.kernel.org/r/20240130124828.14678-2-brgl%40bgdev.pl
patch subject: [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU
config: i386-randconfig-141-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311746.be3dlVTg-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)

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-kbuild-all/202401311746.be3dlVTg-lkp@intel.com/

New smatch warnings:
drivers/gpio/gpiolib.c:4167 gpiod_find_and_request() error: uninitialized symbol 'ret'.
drivers/gpio/gpiolib.c:4181 gpiod_find_and_request() error: uninitialized symbol 'desc'.

Old smatch warnings:
drivers/gpio/gpiolib.c:4184 gpiod_find_and_request() error: uninitialized symbol 'desc'.

vim +/ret +4167 drivers/gpio/gpiolib.c

0eadd36d9123745 Dmitry Torokhov     2022-09-03  4128  
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4129  static struct gpio_desc *gpiod_find_and_request(struct device *consumer,
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4130  						struct fwnode_handle *fwnode,
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4131  						const char *con_id,
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4132  						unsigned int idx,
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4133  						enum gpiod_flags flags,
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4134  						const char *label,
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4135  						bool platform_lookup_allowed)
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4136  {
ba2dc1cb5491712 Hans de Goede       2022-12-29  4137  	unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT;
c122f461ccac0e7 Andy Shevchenko     2023-03-09  4138  	struct gpio_desc *desc;
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4139  	int ret;
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4140  
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4141  	scoped_guard(srcu, &gpio_devices_srcu) {
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4142  		desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx,
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4143  					    &flags, &lookupflags);
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4144  		if (gpiod_not_found(desc) && platform_lookup_allowed) {
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4145  			/*
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4146  			 * Either we are not using DT or ACPI, or their lookup
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4147  			 * did not return a result. In that case, use platform
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4148  			 * lookup as a fallback.
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4149  			 */
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4150  			dev_dbg(consumer,
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4151  				"using lookup tables for GPIO lookup\n");
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4152  			desc = gpiod_find(consumer, con_id, idx, &lookupflags);
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4153  		}
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4154  
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4155  		if (IS_ERR(desc)) {
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4156  			dev_dbg(consumer, "No GPIO consumer %s found\n",
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4157  				con_id);
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4158  			return desc;
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4159  		}
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4160  
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4161  		/*
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4162  		 * If a connection label was passed use that, else attempt to use
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4163  		 * the device name as label
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4164  		 */
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4165  		ret = gpiod_request(desc, label);
1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4166  	}
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11 @4167  	if (ret) {
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4168  		if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4169  			return ERR_PTR(ret);
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4170  
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4171  		/*
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4172  		 * This happens when there are several consumers for
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4173  		 * the same GPIO line: we just return here without
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4174  		 * further initialization. It is a bit of a hack.
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4175  		 * This is necessary to support fixed regulators.
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4176  		 *
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4177  		 * FIXME: Make this more sane and safe.
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4178  		 */
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4179  		dev_info(consumer,
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4180  			 "nonexclusive access to GPIO for %s\n", con_id);
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11 @4181  		return desc;
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4182  	}
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4183  
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4184  	ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4185  	if (ret < 0) {
8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4186  		dev_dbg(consumer, "setup of GPIO %s failed\n", con_id);
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4187  		gpiod_put(desc);
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4188  		return ERR_PTR(ret);
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4189  	}
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4190  
9ce4ed5b4db1363 Bartosz Golaszewski 2023-08-21  4191  	gpiod_line_state_notify(desc, GPIOLINE_CHANGED_REQUESTED);
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4192  
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4193  	return desc;
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4194  }
0eadd36d9123745 Dmitry Torokhov     2022-09-03  4195  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-31  9:28         ` Bartosz Golaszewski
@ 2024-01-31  9:41           ` Bartosz Golaszewski
  2024-01-31  9:42           ` Paul E. McKenney
  1 sibling, 0 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-31  9:41 UTC (permalink / raw)
  To: paulmck
  Cc: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Andy Shevchenko, Wolfram Sang, oe-kbuild-all, linux-gpio,
	linux-kernel, Bartosz Golaszewski

On Wed, Jan 31, 2024 at 10:28 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> On Wed, Jan 31, 2024 at 10:24 AM Paul E. McKenney <paulmck@kernel.org> wrote:
> >
> > On Wed, Jan 31, 2024 at 10:02:40AM +0100, Bartosz Golaszewski wrote:
> > > On Wed, Jan 31, 2024 at 3:21 AM kernel test robot <lkp@intel.com> wrote:
> > > >
> > > > Hi Bartosz,
> > > >
> > > > kernel test robot noticed the following build warnings:
> > > >
> > > > [auto build test WARNING on brgl/gpio/for-next]
> > > > [also build test WARNING on linus/master v6.8-rc2 next-20240130]
> > > > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > > > And when submitting patch, we suggest to use '--base' as documented in
> > > > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> > > >
> > > > url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
> > > > base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
> > > > patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
> > > > patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
> > > > config: x86_64-randconfig-122-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/config)
> > > > compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
> > > > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/reproduce)
> > > >
> > > > 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-kbuild-all/202401311050.YNdm98Hv-lkp@intel.com/
> > > >
> > > > sparse warnings: (new ones prefixed by >>)
> > > > >> drivers/gpio/gpiolib.c:444:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:1103:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:1182:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:2970:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:3004:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:3585:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:4772:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:4846:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c: note: in included file:
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >
> > > > vim +444 drivers/gpio/gpiolib.c
> > > >
> > > >    422
> > > >    423  /*
> > > >    424   * Convert a GPIO name to its descriptor
> > > >    425   * Note that there is no guarantee that GPIO names are globally unique!
> > > >    426   * Hence this function will return, if it exists, a reference to the first GPIO
> > > >    427   * line found that matches the given name.
> > > >    428   */
> > > >    429  static struct gpio_desc *gpio_name_to_desc(const char * const name)
> > > >    430  {
> > > >    431          struct gpio_device *gdev;
> > > >    432          struct gpio_desc *desc;
> > > >    433          struct gpio_chip *gc;
> > > >    434
> > > >    435          if (!name)
> > > >    436                  return NULL;
> > > >    437
> > > >    438          guard(srcu)(&gpio_devices_srcu);
> > > >    439
> > > >    440          list_for_each_entry_srcu(gdev, &gpio_devices, list,
> > > >    441                                   srcu_read_lock_held(&gpio_devices_srcu)) {
> > > >    442                  guard(srcu)(&gdev->srcu);
> > > >    443
> > > >  > 444                  gc = rcu_dereference(gdev->chip);
> > > >    445                  if (!gc)
> > > >    446                          continue;
> > > >    447
> > > >    448                  for_each_gpio_desc(gc, desc) {
> > > >    449                          if (desc->name && !strcmp(desc->name, name))
> > > >    450                                  return desc;
> > > >    451                  }
> > > >    452          }
> > > >    453
> > > >    454          return NULL;
> > > >    455  }
> > > >    456
> > > >
> > > > --
> > > > 0-DAY CI Kernel Test Service
> > > > https://github.com/intel/lkp-tests/wiki
> > >
> > > Paul,
> > >
> > > Should I care about these warnings? They seem to be emitted for a lot
> > > of RCU code already upstream. I'm not even sure how I'd go about
> > > addressing them honestly.
> >
> > This is maintainer's choice.
> >
> > The fix would be to apply __rcu to the definition of ->chip.  The benefit
> > is that it finds bugs where rcu-protected pointers are used without RCU
> > primitives and vice versa.
> >
> >                                                         Thanx, Paul
>
> Ah, good point. I marked the other RCU-protected fields like
> descriptor label but forgot this one.
>
> It also seems like I need to use __rcu for all function arguments
> taking an RCU-protected pointer as argument?
>
> Bart

We have a deprecated, legacy function that returns the address of the
- now RCU-protected chip. This is of course dangerous but we have old
code using it. Can I somehow silence that warning as I don't want this
function to show that the returned pointer is marked with __rcu?

Bart

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-31  9:28         ` Bartosz Golaszewski
  2024-01-31  9:41           ` Bartosz Golaszewski
@ 2024-01-31  9:42           ` Paul E. McKenney
  2024-01-31 10:17             ` brgl
  1 sibling, 1 reply; 66+ messages in thread
From: Paul E. McKenney @ 2024-01-31  9:42 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Andy Shevchenko, Wolfram Sang, oe-kbuild-all, linux-gpio,
	linux-kernel, Bartosz Golaszewski

On Wed, Jan 31, 2024 at 10:28:19AM +0100, Bartosz Golaszewski wrote:
> On Wed, Jan 31, 2024 at 10:24 AM Paul E. McKenney <paulmck@kernel.org> wrote:
> >
> > On Wed, Jan 31, 2024 at 10:02:40AM +0100, Bartosz Golaszewski wrote:
> > > On Wed, Jan 31, 2024 at 3:21 AM kernel test robot <lkp@intel.com> wrote:
> > > >
> > > > Hi Bartosz,
> > > >
> > > > kernel test robot noticed the following build warnings:
> > > >
> > > > [auto build test WARNING on brgl/gpio/for-next]
> > > > [also build test WARNING on linus/master v6.8-rc2 next-20240130]
> > > > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > > > And when submitting patch, we suggest to use '--base' as documented in
> > > > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> > > >
> > > > url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
> > > > base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
> > > > patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
> > > > patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
> > > > config: x86_64-randconfig-122-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/config)
> > > > compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
> > > > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/reproduce)
> > > >
> > > > 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-kbuild-all/202401311050.YNdm98Hv-lkp@intel.com/
> > > >
> > > > sparse warnings: (new ones prefixed by >>)
> > > > >> drivers/gpio/gpiolib.c:444:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:1103:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:1182:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:2970:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:3004:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:3585:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:4772:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c:4846:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip *
> > > >    drivers/gpio/gpiolib.c: note: in included file:
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > > >
> > > > vim +444 drivers/gpio/gpiolib.c
> > > >
> > > >    422
> > > >    423  /*
> > > >    424   * Convert a GPIO name to its descriptor
> > > >    425   * Note that there is no guarantee that GPIO names are globally unique!
> > > >    426   * Hence this function will return, if it exists, a reference to the first GPIO
> > > >    427   * line found that matches the given name.
> > > >    428   */
> > > >    429  static struct gpio_desc *gpio_name_to_desc(const char * const name)
> > > >    430  {
> > > >    431          struct gpio_device *gdev;
> > > >    432          struct gpio_desc *desc;
> > > >    433          struct gpio_chip *gc;
> > > >    434
> > > >    435          if (!name)
> > > >    436                  return NULL;
> > > >    437
> > > >    438          guard(srcu)(&gpio_devices_srcu);
> > > >    439
> > > >    440          list_for_each_entry_srcu(gdev, &gpio_devices, list,
> > > >    441                                   srcu_read_lock_held(&gpio_devices_srcu)) {
> > > >    442                  guard(srcu)(&gdev->srcu);
> > > >    443
> > > >  > 444                  gc = rcu_dereference(gdev->chip);
> > > >    445                  if (!gc)
> > > >    446                          continue;
> > > >    447
> > > >    448                  for_each_gpio_desc(gc, desc) {
> > > >    449                          if (desc->name && !strcmp(desc->name, name))
> > > >    450                                  return desc;
> > > >    451                  }
> > > >    452          }
> > > >    453
> > > >    454          return NULL;
> > > >    455  }
> > > >    456
> > > >
> > > > --
> > > > 0-DAY CI Kernel Test Service
> > > > https://github.com/intel/lkp-tests/wiki
> > >
> > > Paul,
> > >
> > > Should I care about these warnings? They seem to be emitted for a lot
> > > of RCU code already upstream. I'm not even sure how I'd go about
> > > addressing them honestly.
> >
> > This is maintainer's choice.
> >
> > The fix would be to apply __rcu to the definition of ->chip.  The benefit
> > is that it finds bugs where rcu-protected pointers are used without RCU
> > primitives and vice versa.
> 
> Ah, good point. I marked the other RCU-protected fields like
> descriptor label but forgot this one.
> 
> It also seems like I need to use __rcu for all function arguments
> taking an RCU-protected pointer as argument?

Not if that argument gets its value from rcu_dereference(), which is
the usual pattern.

And if you are passing an RCU-protected pointer to a function *before*
passing it through rcu_dereference(), I would have some questions for you.

Or are you instead passing a pointer to an RCU-protected pointer as an
argument to your functions?

                                                        Thanx, Paul

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-31  9:42           ` Paul E. McKenney
@ 2024-01-31 10:17             ` brgl
  2024-01-31 11:00               ` Paul E. McKenney
  0 siblings, 1 reply; 66+ messages in thread
From: brgl @ 2024-01-31 10:17 UTC (permalink / raw)
  To: paulmck
  Cc: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Andy Shevchenko, Wolfram Sang, oe-kbuild-all, linux-gpio,
	linux-kernel, Bartosz Golaszewski, Bartosz Golaszewski

On Wed, 31 Jan 2024 10:42:20 +0100, "Paul E. McKenney"
<paulmck@kernel.org> said:
> On Wed, Jan 31, 2024 at 10:28:19AM +0100, Bartosz Golaszewski wrote:
>> On Wed, Jan 31, 2024 at 10:24 AM Paul E. McKenney <paulmck@kernel.org> wrote:
>> >
>> > On Wed, Jan 31, 2024 at 10:02:40AM +0100, Bartosz Golaszewski wrote:
>> > > On Wed, Jan 31, 2024 at 3:21 AM kernel test robot <lkp@intel.com> wrote:
>> > > >
>> > > > Hi Bartosz,
>> > > >
>> > > > kernel test robot noticed the following build warnings:
>> > > >
>> > > > [auto build test WARNING on brgl/gpio/for-next]
>> > > > [also build test WARNING on linus/master v6.8-rc2 next-20240130]
>> > > > [If your patch is applied to the wrong git tree, kindly drop us a note.
>> > > > And when submitting patch, we suggest to use '--base' as documented in
>> > > > https://git-scm.com/docs/git-format-patch#_base_tree_information]
>> > > >
>> > > > url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
>> > > > base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
>> > > > patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
>> > > > patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
>> > > > config: x86_64-randconfig-122-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/config)
>> > > > compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
>> > > > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/reproduce)
>> > > >
>> > > > 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-kbuild-all/202401311050.YNdm98Hv-lkp@intel.com/
>> > > >
>> > > > sparse warnings: (new ones prefixed by >>)
>> > > > >> drivers/gpio/gpiolib.c:444:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip *
>> > > >    drivers/gpio/gpiolib.c:1103:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip *
>> > > >    drivers/gpio/gpiolib.c:1182:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip *
>> > > >    drivers/gpio/gpiolib.c:2970:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip *
>> > > >    drivers/gpio/gpiolib.c:3004:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip *
>> > > >    drivers/gpio/gpiolib.c:3585:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip *
>> > > >    drivers/gpio/gpiolib.c:4772:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip *
>> > > >    drivers/gpio/gpiolib.c:4846:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip *
>> > > >    drivers/gpio/gpiolib.c: note: in included file:
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
>> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
>> > > >
>> > > > vim +444 drivers/gpio/gpiolib.c
>> > > >
>> > > >    422
>> > > >    423  /*
>> > > >    424   * Convert a GPIO name to its descriptor
>> > > >    425   * Note that there is no guarantee that GPIO names are globally unique!
>> > > >    426   * Hence this function will return, if it exists, a reference to the first GPIO
>> > > >    427   * line found that matches the given name.
>> > > >    428   */
>> > > >    429  static struct gpio_desc *gpio_name_to_desc(const char * const name)
>> > > >    430  {
>> > > >    431          struct gpio_device *gdev;
>> > > >    432          struct gpio_desc *desc;
>> > > >    433          struct gpio_chip *gc;
>> > > >    434
>> > > >    435          if (!name)
>> > > >    436                  return NULL;
>> > > >    437
>> > > >    438          guard(srcu)(&gpio_devices_srcu);
>> > > >    439
>> > > >    440          list_for_each_entry_srcu(gdev, &gpio_devices, list,
>> > > >    441                                   srcu_read_lock_held(&gpio_devices_srcu)) {
>> > > >    442                  guard(srcu)(&gdev->srcu);
>> > > >    443
>> > > >  > 444                  gc = rcu_dereference(gdev->chip);
>> > > >    445                  if (!gc)
>> > > >    446                          continue;
>> > > >    447
>> > > >    448                  for_each_gpio_desc(gc, desc) {
>> > > >    449                          if (desc->name && !strcmp(desc->name, name))
>> > > >    450                                  return desc;
>> > > >    451                  }
>> > > >    452          }
>> > > >    453
>> > > >    454          return NULL;
>> > > >    455  }
>> > > >    456
>> > > >
>> > > > --
>> > > > 0-DAY CI Kernel Test Service
>> > > > https://github.com/intel/lkp-tests/wiki
>> > >
>> > > Paul,
>> > >
>> > > Should I care about these warnings? They seem to be emitted for a lot
>> > > of RCU code already upstream. I'm not even sure how I'd go about
>> > > addressing them honestly.
>> >
>> > This is maintainer's choice.
>> >
>> > The fix would be to apply __rcu to the definition of ->chip.  The benefit
>> > is that it finds bugs where rcu-protected pointers are used without RCU
>> > primitives and vice versa.
>>
>> Ah, good point. I marked the other RCU-protected fields like
>> descriptor label but forgot this one.
>>
>> It also seems like I need to use __rcu for all function arguments
>> taking an RCU-protected pointer as argument?
>
> Not if that argument gets its value from rcu_dereference(), which is
> the usual pattern.
>
> And if you are passing an RCU-protected pointer to a function *before*
> passing it through rcu_dereference(), I would have some questions for you.
>
> Or are you instead passing a pointer to an RCU-protected pointer as an
> argument to your functions?
>
>                                                         Thanx, Paul
>

No, I'm not. Thanks for making it clear. With the following changes to the
series, the warnings are now gone:

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 6a421309319e..15349f92d0ec 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -762,7 +762,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;

@@ -775,6 +775,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.
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 7ecdd8cc39c5..ea0675514891 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -221,7 +221,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);

@@ -291,7 +291,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);

@@ -742,7 +742,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
 		goto err_remove_device;

 	dev_dbg(&gdev->dev, "registered GPIOs %d to %d on %s\n", gdev->base,
-		gdev->base + gdev->ngpio - 1, gdev->chip->label ? : "generic");
+		gdev->base + gdev->ngpio - 1, gdev->label);

 	return 0;

@@ -866,7 +866,7 @@ int gpiochip_add_data_with_key(struct gpio_chip
*gc, void *data,
 		return -ENOMEM;
 	gdev->dev.bus = &gpio_bus_type;
 	gdev->dev.parent = gc->parent;
-	WRITE_ONCE(gdev->chip, gc);
+	rcu_assign_pointer(gdev->chip, gc);

 	gc->gpiodev = gdev;
 	gpiochip_set_data(gc, data);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index c76acb8f95c6..07443d26cbca 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -59,7 +59,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;

Bartosz

^ permalink raw reply related	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-31 10:17             ` brgl
@ 2024-01-31 11:00               ` Paul E. McKenney
  2024-01-31 12:23                 ` Bartosz Golaszewski
  0 siblings, 1 reply; 66+ messages in thread
From: Paul E. McKenney @ 2024-01-31 11:00 UTC (permalink / raw)
  To: brgl
  Cc: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Andy Shevchenko, Wolfram Sang, oe-kbuild-all, linux-gpio,
	linux-kernel, Bartosz Golaszewski

On Wed, Jan 31, 2024 at 02:17:30AM -0800, brgl@bgdev.pl wrote:
> On Wed, 31 Jan 2024 10:42:20 +0100, "Paul E. McKenney"
> <paulmck@kernel.org> said:
> > On Wed, Jan 31, 2024 at 10:28:19AM +0100, Bartosz Golaszewski wrote:
> >> On Wed, Jan 31, 2024 at 10:24 AM Paul E. McKenney <paulmck@kernel.org> wrote:
> >> >
> >> > On Wed, Jan 31, 2024 at 10:02:40AM +0100, Bartosz Golaszewski wrote:
> >> > > On Wed, Jan 31, 2024 at 3:21 AM kernel test robot <lkp@intel.com> wrote:
> >> > > >
> >> > > > Hi Bartosz,
> >> > > >
> >> > > > kernel test robot noticed the following build warnings:
> >> > > >
> >> > > > [auto build test WARNING on brgl/gpio/for-next]
> >> > > > [also build test WARNING on linus/master v6.8-rc2 next-20240130]
> >> > > > [If your patch is applied to the wrong git tree, kindly drop us a note.
> >> > > > And when submitting patch, we suggest to use '--base' as documented in
> >> > > > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> >> > > >
> >> > > > url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
> >> > > > base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
> >> > > > patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
> >> > > > patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
> >> > > > config: x86_64-randconfig-122-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/config)
> >> > > > compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
> >> > > > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/reproduce)
> >> > > >
> >> > > > 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-kbuild-all/202401311050.YNdm98Hv-lkp@intel.com/
> >> > > >
> >> > > > sparse warnings: (new ones prefixed by >>)
> >> > > > >> drivers/gpio/gpiolib.c:444:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip *
> >> > > >    drivers/gpio/gpiolib.c:1103:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip *
> >> > > >    drivers/gpio/gpiolib.c:1182:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip *
> >> > > >    drivers/gpio/gpiolib.c:2970:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip *
> >> > > >    drivers/gpio/gpiolib.c:3004:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip *
> >> > > >    drivers/gpio/gpiolib.c:3585:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip *
> >> > > >    drivers/gpio/gpiolib.c:4772:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip *
> >> > > >    drivers/gpio/gpiolib.c:4846:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip *
> >> > > >    drivers/gpio/gpiolib.c: note: in included file:
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> >> > > >
> >> > > > vim +444 drivers/gpio/gpiolib.c
> >> > > >
> >> > > >    422
> >> > > >    423  /*
> >> > > >    424   * Convert a GPIO name to its descriptor
> >> > > >    425   * Note that there is no guarantee that GPIO names are globally unique!
> >> > > >    426   * Hence this function will return, if it exists, a reference to the first GPIO
> >> > > >    427   * line found that matches the given name.
> >> > > >    428   */
> >> > > >    429  static struct gpio_desc *gpio_name_to_desc(const char * const name)
> >> > > >    430  {
> >> > > >    431          struct gpio_device *gdev;
> >> > > >    432          struct gpio_desc *desc;
> >> > > >    433          struct gpio_chip *gc;
> >> > > >    434
> >> > > >    435          if (!name)
> >> > > >    436                  return NULL;
> >> > > >    437
> >> > > >    438          guard(srcu)(&gpio_devices_srcu);
> >> > > >    439
> >> > > >    440          list_for_each_entry_srcu(gdev, &gpio_devices, list,
> >> > > >    441                                   srcu_read_lock_held(&gpio_devices_srcu)) {
> >> > > >    442                  guard(srcu)(&gdev->srcu);
> >> > > >    443
> >> > > >  > 444                  gc = rcu_dereference(gdev->chip);
> >> > > >    445                  if (!gc)
> >> > > >    446                          continue;
> >> > > >    447
> >> > > >    448                  for_each_gpio_desc(gc, desc) {
> >> > > >    449                          if (desc->name && !strcmp(desc->name, name))
> >> > > >    450                                  return desc;
> >> > > >    451                  }
> >> > > >    452          }
> >> > > >    453
> >> > > >    454          return NULL;
> >> > > >    455  }
> >> > > >    456
> >> > > >
> >> > > > --
> >> > > > 0-DAY CI Kernel Test Service
> >> > > > https://github.com/intel/lkp-tests/wiki
> >> > >
> >> > > Paul,
> >> > >
> >> > > Should I care about these warnings? They seem to be emitted for a lot
> >> > > of RCU code already upstream. I'm not even sure how I'd go about
> >> > > addressing them honestly.
> >> >
> >> > This is maintainer's choice.
> >> >
> >> > The fix would be to apply __rcu to the definition of ->chip.  The benefit
> >> > is that it finds bugs where rcu-protected pointers are used without RCU
> >> > primitives and vice versa.
> >>
> >> Ah, good point. I marked the other RCU-protected fields like
> >> descriptor label but forgot this one.
> >>
> >> It also seems like I need to use __rcu for all function arguments
> >> taking an RCU-protected pointer as argument?
> >
> > Not if that argument gets its value from rcu_dereference(), which is
> > the usual pattern.
> >
> > And if you are passing an RCU-protected pointer to a function *before*
> > passing it through rcu_dereference(), I would have some questions for you.
> >
> > Or are you instead passing a pointer to an RCU-protected pointer as an
> > argument to your functions?
> 
> No, I'm not. Thanks for making it clear. With the following changes to the
> series, the warnings are now gone:
> 
> diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
> index 6a421309319e..15349f92d0ec 100644
> --- a/drivers/gpio/gpiolib-sysfs.c
> +++ b/drivers/gpio/gpiolib-sysfs.c
> @@ -762,7 +762,7 @@ EXPORT_SYMBOL_GPL(gpiod_unexport);
> 
>  int gpiochip_sysfs_register(struct gpio_device *gdev)
>  {
> -	struct gpio_chip *chip = gdev->chip;
> +	struct gpio_chip *chip;

This is protected by an update-side lock, correct?

>  	struct device *parent;
>  	struct device *dev;
> 
> @@ -775,6 +775,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 so, you rely on that lock's protection by replacing the above
two lines of code with something like this:

	chip = rcu_dereference_protected(gdev->chip,
					 lockdep_is_held(&my_lock));

> +	if (!chip)
> +		return -ENODEV;
> +
>  	/*
>  	 * For sysfs backward compatibility we need to preserve this
>  	 * preferred parenting to the gpio_chip parent field, if set.
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index 7ecdd8cc39c5..ea0675514891 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -221,7 +221,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);
> 
> @@ -291,7 +291,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);
> 
> @@ -742,7 +742,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
>  		goto err_remove_device;
> 
>  	dev_dbg(&gdev->dev, "registered GPIOs %d to %d on %s\n", gdev->base,
> -		gdev->base + gdev->ngpio - 1, gdev->chip->label ? : "generic");
> +		gdev->base + gdev->ngpio - 1, gdev->label);

I don't know enough to comment here, but the rest of the look good to me.

>  	return 0;
> 
> @@ -866,7 +866,7 @@ int gpiochip_add_data_with_key(struct gpio_chip
> *gc, void *data,
>  		return -ENOMEM;
>  	gdev->dev.bus = &gpio_bus_type;
>  	gdev->dev.parent = gc->parent;
> -	WRITE_ONCE(gdev->chip, gc);
> +	rcu_assign_pointer(gdev->chip, gc);
> 
>  	gc->gpiodev = gdev;
>  	gpiochip_set_data(gc, data);
> diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
> index c76acb8f95c6..07443d26cbca 100644
> --- a/drivers/gpio/gpiolib.h
> +++ b/drivers/gpio/gpiolib.h
> @@ -59,7 +59,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;
> 
> Bartosz

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-31 11:00               ` Paul E. McKenney
@ 2024-01-31 12:23                 ` Bartosz Golaszewski
  0 siblings, 0 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-31 12:23 UTC (permalink / raw)
  To: paulmck
  Cc: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Andy Shevchenko, Wolfram Sang, oe-kbuild-all, linux-gpio,
	linux-kernel, Bartosz Golaszewski

On Wed, Jan 31, 2024 at 12:00 PM Paul E. McKenney <paulmck@kernel.org> wrote:
>
> On Wed, Jan 31, 2024 at 02:17:30AM -0800, brgl@bgdev.pl wrote:
> > On Wed, 31 Jan 2024 10:42:20 +0100, "Paul E. McKenney"
> > <paulmck@kernel.org> said:
> > > On Wed, Jan 31, 2024 at 10:28:19AM +0100, Bartosz Golaszewski wrote:
> > >> On Wed, Jan 31, 2024 at 10:24 AM Paul E. McKenney <paulmck@kernel.org> wrote:
> > >> >
> > >> > On Wed, Jan 31, 2024 at 10:02:40AM +0100, Bartosz Golaszewski wrote:
> > >> > > On Wed, Jan 31, 2024 at 3:21 AM kernel test robot <lkp@intel.com> wrote:
> > >> > > >
> > >> > > > Hi Bartosz,
> > >> > > >
> > >> > > > kernel test robot noticed the following build warnings:
> > >> > > >
> > >> > > > [auto build test WARNING on brgl/gpio/for-next]
> > >> > > > [also build test WARNING on linus/master v6.8-rc2 next-20240130]
> > >> > > > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > >> > > > And when submitting patch, we suggest to use '--base' as documented in
> > >> > > > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> > >> > > >
> > >> > > > url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
> > >> > > > base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
> > >> > > > patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
> > >> > > > patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
> > >> > > > config: x86_64-randconfig-122-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/config)
> > >> > > > compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
> > >> > > > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240131/202401311050.YNdm98Hv-lkp@intel.com/reproduce)
> > >> > > >
> > >> > > > 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-kbuild-all/202401311050.YNdm98Hv-lkp@intel.com/
> > >> > > >
> > >> > > > sparse warnings: (new ones prefixed by >>)
> > >> > > > >> drivers/gpio/gpiolib.c:444:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.c:444:22: sparse:    struct gpio_chip *
> > >> > > >    drivers/gpio/gpiolib.c:1103:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.c:1103:9: sparse:    struct gpio_chip *
> > >> > > >    drivers/gpio/gpiolib.c:1182:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.c:1182:22: sparse:    struct gpio_chip *
> > >> > > >    drivers/gpio/gpiolib.c:2970:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.c:2970:14: sparse:    struct gpio_chip *
> > >> > > >    drivers/gpio/gpiolib.c:3004:22: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.c:3004:22: sparse:    struct gpio_chip *
> > >> > > >    drivers/gpio/gpiolib.c:3585:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.c:3585:14: sparse:    struct gpio_chip *
> > >> > > >    drivers/gpio/gpiolib.c:4772:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.c:4772:14: sparse:    struct gpio_chip *
> > >> > > >    drivers/gpio/gpiolib.c:4846:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.c:4846:14: sparse:    struct gpio_chip *
> > >> > > >    drivers/gpio/gpiolib.c: note: in included file:
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > > >> drivers/gpio/gpiolib.h:202:1: sparse: sparse: incompatible types in comparison expression (different address spaces):
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip [noderef] __rcu *
> > >> > > >    drivers/gpio/gpiolib.h:202:1: sparse:    struct gpio_chip *
> > >> > > >
> > >> > > > vim +444 drivers/gpio/gpiolib.c
> > >> > > >
> > >> > > >    422
> > >> > > >    423  /*
> > >> > > >    424   * Convert a GPIO name to its descriptor
> > >> > > >    425   * Note that there is no guarantee that GPIO names are globally unique!
> > >> > > >    426   * Hence this function will return, if it exists, a reference to the first GPIO
> > >> > > >    427   * line found that matches the given name.
> > >> > > >    428   */
> > >> > > >    429  static struct gpio_desc *gpio_name_to_desc(const char * const name)
> > >> > > >    430  {
> > >> > > >    431          struct gpio_device *gdev;
> > >> > > >    432          struct gpio_desc *desc;
> > >> > > >    433          struct gpio_chip *gc;
> > >> > > >    434
> > >> > > >    435          if (!name)
> > >> > > >    436                  return NULL;
> > >> > > >    437
> > >> > > >    438          guard(srcu)(&gpio_devices_srcu);
> > >> > > >    439
> > >> > > >    440          list_for_each_entry_srcu(gdev, &gpio_devices, list,
> > >> > > >    441                                   srcu_read_lock_held(&gpio_devices_srcu)) {
> > >> > > >    442                  guard(srcu)(&gdev->srcu);
> > >> > > >    443
> > >> > > >  > 444                  gc = rcu_dereference(gdev->chip);
> > >> > > >    445                  if (!gc)
> > >> > > >    446                          continue;
> > >> > > >    447
> > >> > > >    448                  for_each_gpio_desc(gc, desc) {
> > >> > > >    449                          if (desc->name && !strcmp(desc->name, name))
> > >> > > >    450                                  return desc;
> > >> > > >    451                  }
> > >> > > >    452          }
> > >> > > >    453
> > >> > > >    454          return NULL;
> > >> > > >    455  }
> > >> > > >    456
> > >> > > >
> > >> > > > --
> > >> > > > 0-DAY CI Kernel Test Service
> > >> > > > https://github.com/intel/lkp-tests/wiki
> > >> > >
> > >> > > Paul,
> > >> > >
> > >> > > Should I care about these warnings? They seem to be emitted for a lot
> > >> > > of RCU code already upstream. I'm not even sure how I'd go about
> > >> > > addressing them honestly.
> > >> >
> > >> > This is maintainer's choice.
> > >> >
> > >> > The fix would be to apply __rcu to the definition of ->chip.  The benefit
> > >> > is that it finds bugs where rcu-protected pointers are used without RCU
> > >> > primitives and vice versa.
> > >>
> > >> Ah, good point. I marked the other RCU-protected fields like
> > >> descriptor label but forgot this one.
> > >>
> > >> It also seems like I need to use __rcu for all function arguments
> > >> taking an RCU-protected pointer as argument?
> > >
> > > Not if that argument gets its value from rcu_dereference(), which is
> > > the usual pattern.
> > >
> > > And if you are passing an RCU-protected pointer to a function *before*
> > > passing it through rcu_dereference(), I would have some questions for you.
> > >
> > > Or are you instead passing a pointer to an RCU-protected pointer as an
> > > argument to your functions?
> >
> > No, I'm not. Thanks for making it clear. With the following changes to the
> > series, the warnings are now gone:
> >
> > diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
> > index 6a421309319e..15349f92d0ec 100644
> > --- a/drivers/gpio/gpiolib-sysfs.c
> > +++ b/drivers/gpio/gpiolib-sysfs.c
> > @@ -762,7 +762,7 @@ EXPORT_SYMBOL_GPL(gpiod_unexport);
> >
> >  int gpiochip_sysfs_register(struct gpio_device *gdev)
> >  {
> > -     struct gpio_chip *chip = gdev->chip;
> > +     struct gpio_chip *chip;
>
> This is protected by an update-side lock, correct?
>

No, it may be called from two places. One needs to be protected (it
isn't in my series but I'll fix it), the other does not as we are
holding the pointer to gdev already.

> >       struct device *parent;
> >       struct device *dev;
> >
> > @@ -775,6 +775,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 so, you rely on that lock's protection by replacing the above
> two lines of code with something like this:
>
>         chip = rcu_dereference_protected(gdev->chip,
>                                          lockdep_is_held(&my_lock));
>

Thanks, I'll see if I can use it elsewhere.

Bart

> > +     if (!chip)
> > +             return -ENODEV;
> > +
> >       /*
> >        * For sysfs backward compatibility we need to preserve this
> >        * preferred parenting to the gpio_chip parent field, if set.
> > diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> > index 7ecdd8cc39c5..ea0675514891 100644
> > --- a/drivers/gpio/gpiolib.c
> > +++ b/drivers/gpio/gpiolib.c
> > @@ -221,7 +221,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);
> >
> > @@ -291,7 +291,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);
> >
> > @@ -742,7 +742,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
> >               goto err_remove_device;
> >
> >       dev_dbg(&gdev->dev, "registered GPIOs %d to %d on %s\n", gdev->base,
> > -             gdev->base + gdev->ngpio - 1, gdev->chip->label ? : "generic");
> > +             gdev->base + gdev->ngpio - 1, gdev->label);
>
> I don't know enough to comment here, but the rest of the look good to me.
>
> >       return 0;
> >
> > @@ -866,7 +866,7 @@ int gpiochip_add_data_with_key(struct gpio_chip
> > *gc, void *data,
> >               return -ENOMEM;
> >       gdev->dev.bus = &gpio_bus_type;
> >       gdev->dev.parent = gc->parent;
> > -     WRITE_ONCE(gdev->chip, gc);
> > +     rcu_assign_pointer(gdev->chip, gc);
> >
> >       gc->gpiodev = gdev;
> >       gpiochip_set_data(gc, data);
> > diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
> > index c76acb8f95c6..07443d26cbca 100644
> > --- a/drivers/gpio/gpiolib.h
> > +++ b/drivers/gpio/gpiolib.h
> > @@ -59,7 +59,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;
> >
> > Bartosz

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU
  2024-01-31  9:34   ` kernel test robot
@ 2024-01-31 12:45     ` Bartosz Golaszewski
  0 siblings, 0 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-31 12:45 UTC (permalink / raw)
  To: kernel test robot
  Cc: Linus Walleij, Kent Gibson, Alex Elder, Geert Uytterhoeven,
	Paul E . McKenney, Andy Shevchenko, Wolfram Sang, oe-kbuild-all,
	linux-gpio, linux-kernel, Bartosz Golaszewski

On Wed, Jan 31, 2024 at 10:37 AM kernel test robot <lkp@intel.com> wrote:
>
> Hi Bartosz,
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on brgl/gpio/for-next]
> [also build test WARNING on linus/master v6.8-rc2 next-20240131]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
> patch link:    https://lore.kernel.org/r/20240130124828.14678-2-brgl%40bgdev.pl
> patch subject: [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU
> config: i386-randconfig-141-20240131 (https://download.01.org/0day-ci/archive/20240131/202401311746.be3dlVTg-lkp@intel.com/config)
> compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
>
> 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-kbuild-all/202401311746.be3dlVTg-lkp@intel.com/
>
> New smatch warnings:
> drivers/gpio/gpiolib.c:4167 gpiod_find_and_request() error: uninitialized symbol 'ret'.
> drivers/gpio/gpiolib.c:4181 gpiod_find_and_request() error: uninitialized symbol 'desc'.
>
> Old smatch warnings:
> drivers/gpio/gpiolib.c:4184 gpiod_find_and_request() error: uninitialized symbol 'desc'.
>
> vim +/ret +4167 drivers/gpio/gpiolib.c
>
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4128
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4129  static struct gpio_desc *gpiod_find_and_request(struct device *consumer,
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4130                                            struct fwnode_handle *fwnode,
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4131                                            const char *con_id,
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4132                                            unsigned int idx,
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4133                                            enum gpiod_flags flags,
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4134                                            const char *label,
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4135                                            bool platform_lookup_allowed)
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4136  {
> ba2dc1cb5491712 Hans de Goede       2022-12-29  4137    unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT;
> c122f461ccac0e7 Andy Shevchenko     2023-03-09  4138    struct gpio_desc *desc;
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4139    int ret;
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4140
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4141    scoped_guard(srcu, &gpio_devices_srcu) {
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4142            desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx,
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4143                                        &flags, &lookupflags);
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4144            if (gpiod_not_found(desc) && platform_lookup_allowed) {
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4145                    /*
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4146                     * Either we are not using DT or ACPI, or their lookup
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4147                     * did not return a result. In that case, use platform
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4148                     * lookup as a fallback.
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4149                     */
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4150                    dev_dbg(consumer,
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4151                            "using lookup tables for GPIO lookup\n");
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4152                    desc = gpiod_find(consumer, con_id, idx, &lookupflags);
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4153            }
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4154
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4155            if (IS_ERR(desc)) {
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4156                    dev_dbg(consumer, "No GPIO consumer %s found\n",
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4157                            con_id);
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4158                    return desc;
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4159            }
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4160
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4161            /*
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4162             * If a connection label was passed use that, else attempt to use
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4163             * the device name as label
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4164             */
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4165            ret = gpiod_request(desc, label);
> 1fe5210a1bfba00 Bartosz Golaszewski 2024-01-30  4166    }
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11 @4167    if (ret) {
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4168            if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4169                    return ERR_PTR(ret);
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4170
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4171            /*
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4172             * This happens when there are several consumers for
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4173             * the same GPIO line: we just return here without
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4174             * further initialization. It is a bit of a hack.
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4175             * This is necessary to support fixed regulators.
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4176             *
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4177             * FIXME: Make this more sane and safe.
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4178             */
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4179            dev_info(consumer,
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4180                     "nonexclusive access to GPIO for %s\n", con_id);
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11 @4181            return desc;
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4182    }
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4183
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4184    ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4185    if (ret < 0) {
> 8eb1f71e7acca4f Dmitry Torokhov     2022-11-11  4186            dev_dbg(consumer, "setup of GPIO %s failed\n", con_id);
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4187            gpiod_put(desc);
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4188            return ERR_PTR(ret);
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4189    }
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4190
> 9ce4ed5b4db1363 Bartosz Golaszewski 2023-08-21  4191    gpiod_line_state_notify(desc, GPIOLINE_CHANGED_REQUESTED);
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4192
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4193    return desc;
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4194  }
> 0eadd36d9123745 Dmitry Torokhov     2022-09-03  4195
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki

This is a false-positive coming from the fact the scoped_guard() is
implemented as a for loop. I will initialize the variables anyway to
make smatch happy.

Bart

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU
  2024-01-30 12:48 ` [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU Bartosz Golaszewski
  2024-01-31  9:34   ` kernel test robot
@ 2024-01-31 15:01   ` Linus Walleij
  1 sibling, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 15:01 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> We're working towards removing the "multi-function" GPIO spinlock that's
> implemented terribly wrong. We tried using an RW-semaphore to protect
> the list of GPIO devices but it turned out that we still have old code
> using legacy GPIO calls that need to translate the global GPIO number to
> the address of the associated descriptor and - to that end - traverse
> the list while holding the lock. If we change the spinlock to a sleeping
> lock then we'll end up with "scheduling while atomic" bugs.
>
> Let's allow lockless traversal of the list using SRCU and only use the
> mutex when modyfing the list.
>
> While at it: let's protect the period between when we start the lookup
> and when we finally request the descriptor (increasing the reference
> count of the GPIO device) with the SRCU read lock.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

This looks to be doing the right thing to my RCU-untrained eye, so:
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 02/22] gpio: of: assign and read the hog pointer atomically
  2024-01-30 12:48 ` [PATCH 02/22] gpio: of: assign and read the hog pointer atomically Bartosz Golaszewski
@ 2024-01-31 17:38   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 17:38 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> The device nodes representing GPIO hogs cannot be deleted without
> unregistering the GPIO chip so there's no need to serialize their access.
> However we must ensure that users can get the right address so write and
> read it atomically.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

So this would give barriers around desc->hog, so we are talking
SMP where the same hogs are added and removed on different
CPUs here I suppose? Seems a bit theoretical but OK.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 03/22] gpio: remove unused logging helpers
  2024-01-30 12:48 ` [PATCH 03/22] gpio: remove unused logging helpers Bartosz Golaszewski
@ 2024-01-31 17:39   ` Linus Walleij
  2024-01-31 18:08     ` Bartosz Golaszewski
  0 siblings, 1 reply; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 17:39 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> The general rule of the kernel is to not provide symbols that have no
> users upstream. Let's remove logging helpers that are not used anywhere.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Seems unrelated to the rest of the patches but OK.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 03/22] gpio: remove unused logging helpers
  2024-01-31 17:39   ` Linus Walleij
@ 2024-01-31 18:08     ` Bartosz Golaszewski
  2024-01-31 20:33       ` Linus Walleij
  0 siblings, 1 reply; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-01-31 18:08 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Wed, Jan 31, 2024 at 6:39 PM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > The general rule of the kernel is to not provide symbols that have no
> > users upstream. Let's remove logging helpers that are not used anywhere.
> >
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> Seems unrelated to the rest of the patches but OK.
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>
> Yours,
> Linus Walleij

It's kind of related because I'm later modifying the logging helpers
so I'm saving myself some work.

Bart

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 06/22] gpio: add SRCU infrastructure to struct gpio_desc
  2024-01-30 12:48 ` [PATCH 06/22] gpio: add SRCU infrastructure to struct gpio_desc Bartosz Golaszewski
@ 2024-01-31 19:35   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 19:35 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> Extend the GPIO descriptor with an SRCU structure in order to serialize
> the access to the label. Initialize and clean it up where applicable.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

I don't know the inner transcendental semantics of SRCU but the code
sure looks like it is doing the right thing.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 04/22] gpio: provide and use gpiod_get_label()
  2024-01-30 12:48 ` [PATCH 04/22] gpio: provide and use gpiod_get_label() Bartosz Golaszewski
@ 2024-01-31 19:36   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 19:36 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> We will soon serialize access to the descriptor label using SRCU. The
> write-side of the protection will require calling synchronize_srcu()
> which must not be called from atomic context. We have two irq helpers:
> gpiochip_lock_as_irq() and gpiochip_unlock_as_irq() that set the label
> if the GPIO is not requested but is being used as interrupt. They are
> called with a spinlock held from the interrupt subsystem.
>
> They must not do it if we are to use SRCU so instead let's move the
> special corner case to a dedicated getter.
>
> First: let's implement and use the getter where it's applicable.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

After seeing the clever trick in the next patch I realized why
you do this.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 05/22] gpio: don't set label from irq helpers
  2024-01-30 12:48 ` [PATCH 05/22] gpio: don't set label from irq helpers Bartosz Golaszewski
@ 2024-01-31 19:38   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 19:38 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> We will soon serialize access to the descriptor label using SRCU. The
> write-side of the protection will require calling synchronize_srcu()
> which must not be called from atomic context. We have two irq helpers:
> gpiochip_lock_as_irq() and gpiochip_unlock_as_irq() that set the label
> if the GPIO is not requested but is being used as interrupt. They are
> called with a spinlock held from the interrupt subsystem.
>
> They must not do it if we are to use SRCU so instead let's move the
> special corner case to a dedicated getter.
>
> Let's use the flags of the descriptor to figure out whether we should
> use the special "interrupt" label.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

I would refine the commit message: what you do IIUC is that you
simply avoid modifying a string, the label isn't set anymore,
instead a const string is returned and it is selected from the
state of an atomic variable (ha! smart!) and that is how the
atomicity is achieved.

Anyway:
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 07/22] gpio: protect the descriptor label with SRCU
  2024-01-30 12:48 ` [PATCH 07/22] gpio: protect the descriptor label with SRCU Bartosz Golaszewski
@ 2024-01-31 19:41   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 19:41 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> 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.
>
> 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>

And this conclude the previous patches by protecting the inevitable
label with SRCU, very clever. (I wouldn't have been able to come up
with it...)
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

> -#define gpiod_err(desc, fmt, ...)                                             \
> -       pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",  \
> -                ##__VA_ARGS__)
(...)

Now it is clear why you were minimizing these helpers.
(Maybe add to the commit message of that patch? "We do this
because all functions need to be changed later".)

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 08/22] gpio: sysfs: use gpio_device_find() to iterate over existing devices
  2024-01-30 12:48 ` [PATCH 08/22] gpio: sysfs: use gpio_device_find() to iterate over existing devices Bartosz Golaszewski
@ 2024-01-31 19:42   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 19:42 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> With the list of GPIO devices now protected with SRCU we can use
> gpio_device_find() to traverse it from sysfs.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

This is beautiful. And you can make the list private too.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 09/22] gpio: remove gpio_lock
  2024-01-30 12:48 ` [PATCH 09/22] gpio: remove gpio_lock Bartosz Golaszewski
@ 2024-01-31 19:51   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 19:51 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> The "multi-function" gpio_lock is pretty much useless with how it's used
> in GPIOLIB currently. Because many GPIO API calls can be called from all
> contexts but may also call into sleeping driver callbacks, there are
> many places with utterly broken workarounds like yielding the lock to
> call a possibly sleeping function and then re-acquiring it again without
> taking into account that the protected state may have changed.
>
> It was also used to protect several unrelated things: like individual
> descriptors AND the GPIO device list. We now serialize access to these
> two with SRCU and so can finally remove the spinlock.
>
> There is of course the question of consistency of lockless access to
> GPIO descriptors. Because we only support exclusive access to GPIOs
> (officially anyway, I'm looking at you broken
> GPIOD_FLAGS_BIT_NONEXCLUSIVE bit...) and the API contract with providers
> does not guarantee serialization, it's enough to ensure we cannot
> accidentally dereference an invalid pointer and that the state we present
> to both users and providers remains consistent. To achieve that: read the
> flags field atomically except for a few special cases. Read their current
> value before executing callback code and use this value for any subsequent
> logic. Modifying the flags depends on the particular use-case and can
> differ. For instance: when requesting a GPIO, we need to set the
> REQUESTED bit immediately so that the next user trying to request the
> same line sees -EBUSY.
>
> While at it: the allocations that used GFP_ATOMIC until this point can
> now switch to GFP_KERNEL.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Neat!
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

(I'm sorry about NONEXCLUSIVE, let's see what we can do about it...)

> @@ -578,6 +577,9 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
>                 return -EINVAL;
>         }
>
> +       if (!test_and_set_bit(FLAG_EXPORT, &desc->flags))
> +               return -EPERM;

This exit early split off from the big if() below (which is good) is
a new thing right? Maybe mention this in the commit message?

> -/* gpio_lock prevents conflicts during gpio_desc[] table updates.
> - * While any GPIO is requested, its gpio_chip is not removable;
> - * each GPIO's "requested" flag serves as a lock and refcount.
> - */
> -DEFINE_SPINLOCK(gpio_lock);

GOOD RIDDANCE.

> -               /* FIXME: make this GFP_KERNEL once the spinlock is out. */
> -               new = kstrdup_const(label, GFP_ATOMIC);
> +               new = kstrdup_const(label, GFP_KERNEL);

And all of this is neat as well.

Someone might complain about splitting that in a separate patch,
but not me because I don't care so much about such processy
things. (The patchset is already split enough as it is.)

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 10/22] gpio: reinforce desc->flags handling
  2024-01-30 12:48 ` [PATCH 10/22] gpio: reinforce desc->flags handling Bartosz Golaszewski
@ 2024-01-31 20:01   ` Linus Walleij
  2024-01-31 20:35     ` Linus Walleij
  0 siblings, 1 reply; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:01 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> We now removed the gpio_lock spinlock and modified the places
> previously protected by it to handle desc->flags access in a consistent
> way. Let's improve other places that were previously unprotected by
> reading the flags field of gpio_desc once and using the stored value for
> logic consistency. If we need to modify the field, let's also write it
> back once with a consistent value resulting from the function's logic.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
(...)

I have a trouble with this one:

gpiochip_find_base_unlocked()
> +       unsigned long flags;
(...)
> +       flags = READ_ONCE(desc->flags);
(...)
> +       if (test_bit(FLAG_OPEN_DRAIN, &flags) &&
> +           test_bit(FLAG_IS_OUT, &flags))
>                 return 0;
(...)
> +       assign_bit(FLAG_IS_OUT, &flags, !ret);
> +       WRITE_ONCE(desc->flags, flags);

I unerstand the atomicity of each operation here, but ... if what you want
to protect is modifications from other CPUs, how do we know that another
CPU isn't coming in and reading and modifying and assigning
another flag inbetween these operations while the value is only
stored in the CPU-local flags variable?

Same with gpiod_direction_output().

To me it seems like maybe you need to actually protect the desc->flags
with the SRCU struct in these cases? (and not only use it for the
label protection then).

An alternative is maybe to rewrite the code with test_and_set().

But as you say it is currently unprotected, I just wonder if this really
adds any protection.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 11/22] gpio: remove unneeded code from gpio_device_get_desc()
  2024-01-30 12:48 ` [PATCH 11/22] gpio: remove unneeded code from gpio_device_get_desc() Bartosz Golaszewski
@ 2024-01-31 20:02   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:02 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> The GPIO chip pointer is unused. Let's remove it.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Oups I think it was used at one point but we probably factored
ourselves away from using it.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 12/22] gpio: sysfs: extend the critical section for unregistering sysfs devices
  2024-01-30 12:48 ` [PATCH 12/22] gpio: sysfs: extend the critical section for unregistering sysfs devices Bartosz Golaszewski
@ 2024-01-31 20:06   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:06 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> Checking the gdev->mockdev pointer for NULL must be part of the critical
> section.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

(Unrelated: I don't quite understand why it has to be a member of the
gpio_device if mockdev/sysfs isn't enabled, something for us to fix
another day.)

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 13/22] gpio: sysfs: pass the GPIO device - not chip - to sysfs callbacks
  2024-01-30 12:48 ` [PATCH 13/22] gpio: sysfs: pass the GPIO device - not chip - to sysfs callbacks Bartosz Golaszewski
@ 2024-01-31 20:09   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:09 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> We're working towards protecting the chip pointer in struct gpio_device
> with SRCU. In order to use it in sysfs callbacks we must pass the pointer
> to the GPIO device that wraps the chip instead of the address of the
> chip itself as the user data.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 14/22] gpio: cdev: replace gpiochip_get_desc() with gpio_device_get_desc()
  2024-01-30 12:48 ` [PATCH 14/22] gpio: cdev: replace gpiochip_get_desc() with gpio_device_get_desc() Bartosz Golaszewski
@ 2024-01-31 20:10   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:10 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> gpio_device_get_desc() is the safer alternative to gpiochip_get_desc().
> As we don't really need to dereference the chip pointer to retrieve the
> descriptors in character device code, let's use it.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Excellent.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 15/22] gpio: cdev: don't access gdev->chip if it's not needed
  2024-01-30 12:48 ` [PATCH 15/22] gpio: cdev: don't access gdev->chip if it's not needed Bartosz Golaszewski
@ 2024-01-31 20:11   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:11 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> The variable holding the number of GPIO lines is duplicated in GPIO
> device so read it instead of unnecessarily dereferencing the chip
> pointer.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 16/22] gpio: reduce the functionality of validate_desc()
  2024-01-30 12:48 ` [PATCH 16/22] gpio: reduce the functionality of validate_desc() Bartosz Golaszewski
@ 2024-01-31 20:16   ` Linus Walleij
  2024-01-31 20:19     ` Linus Walleij
  0 siblings, 1 reply; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:16 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> Checking desc->gdev->chip for NULL without holding it in place with some
> serializing mechanism is pointless. Remove this check. Also don't check
> desc->gdev for NULL as it can never happen.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

I don't know if I agree that it is pointless. It will work on any single-CPU
system and 99.9% of other cases.

On the other hand: what it is supposed to protect against is userspace
doing calls to a gpio_device through the character device, while the
backing struct gpio_chip is gone (e.g. a GPIO expander on USB,
and someone pulled the cable), i.e. it became NULL, and this is why the
error message says "backing device is gone".

But I want to see where the series is going, maybe you fix this
problem in the end, so I can come back and ACK this.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 18/22] gpio: add the can_sleep flag to struct gpio_device
  2024-01-30 12:48 ` [PATCH 18/22] gpio: add the can_sleep flag to struct gpio_device Bartosz Golaszewski
@ 2024-01-31 20:17   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:17 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> Duplicating the can_sleep value in GPIO device will allow us to not
> needlessly dereference the chip pointer in several places and reduce the
> number of SRCU read-only critical sections.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 16/22] gpio: reduce the functionality of validate_desc()
  2024-01-31 20:16   ` Linus Walleij
@ 2024-01-31 20:19     ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:19 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Wed, Jan 31, 2024 at 9:16 PM Linus Walleij <linus.walleij@linaro.org> wrote:
> On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > Checking desc->gdev->chip for NULL without holding it in place with some
> > serializing mechanism is pointless. Remove this check. Also don't check
> > desc->gdev for NULL as it can never happen.
> >
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> I don't know if I agree that it is pointless. It will work on any single-CPU
> system and 99.9% of other cases.
>
> On the other hand: what it is supposed to protect against is userspace
> doing calls to a gpio_device through the character device, while the
> backing struct gpio_chip is gone (e.g. a GPIO expander on USB,
> and someone pulled the cable), i.e. it became NULL, and this is why the
> error message says "backing device is gone".
>
> But I want to see where the series is going, maybe you fix this
> problem in the end, so I can come back and ACK this.

Aha, it is fixed in patches 19+20. Maybe mention that we add a new
protection later in the series in the commit message?

Anyway, I get it now!

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-30 12:48 ` [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU Bartosz Golaszewski
  2024-01-31  0:41   ` kernel test robot
  2024-01-31  2:20   ` kernel test robot
@ 2024-01-31 20:23   ` Linus Walleij
  2024-02-01  5:03   ` Dan Carpenter
  3 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:23 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> Ensure we cannot crash if the GPIO device gets unregistered (and the
> chip pointer set to NULL) during any of the API calls.
>
> To that end: wait for all users of gdev->chip to exit their read-only
> SRCU critical sections in gpiochip_remove().
>
> For brevity: add a guard class which can be instantiated at the top of
> every function requiring read-only access to the chip pointer and use it
> in all API calls taking a GPIO descriptor as argument. In places where
> we only deal with the GPIO device - use regular guard() helpers and
> rcu_dereference() for chip access. Do the same in API calls taking a
> const pointer to gpio_desc.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

The way I read it after this the gpio character device is well protected
against the struct gpio_chip going away, good work!
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

I would perhaps slot in some documentation around
struct gpio_chip_guard explaining how this works and why it is needed.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 21/22] gpio: remove the RW semaphore from the GPIO device
  2024-01-30 12:48 ` [PATCH 21/22] gpio: remove the RW semaphore from the GPIO device Bartosz Golaszewski
@ 2024-01-31 20:24   ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:24 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> With all accesses to gdev->chip being protected with SRCU, we can now
> remove the RW-semaphore specific to the character device which
> fullfilled the same role up to this point.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 22/22] gpio: mark unsafe gpio_chip manipulators as deprecated
  2024-01-30 12:48 ` [PATCH 22/22] gpio: mark unsafe gpio_chip manipulators as deprecated Bartosz Golaszewski
@ 2024-01-31 20:29   ` Linus Walleij
  2024-02-01  9:14     ` Bartosz Golaszewski
  0 siblings, 1 reply; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:29 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:49 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> We still have some functions that return the address of the GPIO chip
> associated with the GPIO device. This is dangerous and the users should
> find a better solution. Let's add appropriate comments to the kernel
> docs.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

I'm not sure it's very easy to find a better solution for gpiod_to_chip(),
but perhaps also add this as a work item to the TODO file? We can certainly
try to get rid of <linux/gpio.h> before we need to look into fixing this...

gpiod_device_get_label() should be easy to fix:
linus@lino:~/linux$ git grep gpio_device_get_label
drivers/gpio/gpiolib.c: * gpio_device_get_label() - Get the label of
this GPIO device
drivers/gpio/gpiolib.c:const char *gpio_device_get_label(struct
gpio_device *gdev)
drivers/gpio/gpiolib.c:EXPORT_SYMBOL(gpio_device_get_label);
drivers/pinctrl/core.c:                            gpio_device_get_label(gdev));
include/linux/gpio/driver.h:const char *gpio_device_get_label(struct
gpio_device *gdev);

We only created that problem for ourselves... It should be removed
from <linux/gpio/driver.h>.

Anyway:
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 00/22] gpio: rework locking and object life-time control
  2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
                   ` (21 preceding siblings ...)
  2024-01-30 12:48 ` [PATCH 22/22] gpio: mark unsafe gpio_chip manipulators as deprecated Bartosz Golaszewski
@ 2024-01-31 20:32 ` Linus Walleij
  2024-02-01  8:43   ` Bartosz Golaszewski
  22 siblings, 1 reply; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:32 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> We do NOT serialize all API callbacks. This means that provider callbacks
> may be called simultaneously and GPIO drivers need to provide their own
> locking if needed. This is on purpose. First: we only support exclusive
> GPIO usage[1] so there's no risk of two drivers getting in each other's
> way over the same GPIO. Second: with this series, we ensure enough
> consistency to limit the chance of drivers or user-space users crashing
> the kernel. With additional improvements in handling the flags field in
> GPIO descriptors there's very little to gain, while bitbanging drivers
> may care about the increased performance of going lockless.

OK I read this before but didn't understand it, now I understand it.

The series:
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

I think you should merge it all soon so we get some time to shake
it out in linux-next, hopefully any remaining bugs and cleanups
can be done in-tree.

Excellent work, by the way.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 03/22] gpio: remove unused logging helpers
  2024-01-31 18:08     ` Bartosz Golaszewski
@ 2024-01-31 20:33       ` Linus Walleij
  0 siblings, 0 replies; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:33 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Wed, Jan 31, 2024 at 7:08 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> On Wed, Jan 31, 2024 at 6:39 PM Linus Walleij <linus.walleij@linaro.org> wrote:
> > On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >
> > > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > >
> > > The general rule of the kernel is to not provide symbols that have no
> > > users upstream. Let's remove logging helpers that are not used anywhere.
> > >
> > > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > Seems unrelated to the rest of the patches but OK.
> > Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> >
> > Yours,
> > Linus Walleij
>
> It's kind of related because I'm later modifying the logging helpers
> so I'm saving myself some work.

Yeah I realized that later. Maybe add to the commit message?
No big deal anyway.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 10/22] gpio: reinforce desc->flags handling
  2024-01-31 20:01   ` Linus Walleij
@ 2024-01-31 20:35     ` Linus Walleij
  2024-02-01 18:30       ` Bartosz Golaszewski
  0 siblings, 1 reply; 66+ messages in thread
From: Linus Walleij @ 2024-01-31 20:35 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Wed, Jan 31, 2024 at 9:01 PM Linus Walleij <linus.walleij@linaro.org> wrote:
> On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > We now removed the gpio_lock spinlock and modified the places
> > previously protected by it to handle desc->flags access in a consistent
> > way. Let's improve other places that were previously unprotected by
> > reading the flags field of gpio_desc once and using the stored value for
> > logic consistency. If we need to modify the field, let's also write it
> > back once with a consistent value resulting from the function's logic.
> >
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> (...)
>
> I have a trouble with this one:
>
> gpiochip_find_base_unlocked()
> > +       unsigned long flags;
> (...)
> > +       flags = READ_ONCE(desc->flags);
> (...)
> > +       if (test_bit(FLAG_OPEN_DRAIN, &flags) &&
> > +           test_bit(FLAG_IS_OUT, &flags))
> >                 return 0;
> (...)
> > +       assign_bit(FLAG_IS_OUT, &flags, !ret);
> > +       WRITE_ONCE(desc->flags, flags);
>
> I unerstand the atomicity of each operation here, but ... if what you want
> to protect is modifications from other CPUs, how do we know that another
> CPU isn't coming in and reading and modifying and assigning
> another flag inbetween these operations while the value is only
> stored in the CPU-local flags variable?
>
> Same with gpiod_direction_output().
>
> To me it seems like maybe you need to actually protect the desc->flags
> with the SRCU struct in these cases? (and not only use it for the
> label protection then).
>
> An alternative is maybe to rewrite the code with test_and_set().
>
> But as you say it is currently unprotected, I just wonder if this really
> adds any protection.

After re-reading the cover letter I'm fine with this, but I still wonder
if it buys us anything.

Maybe some words looped back from the
commit message that we are not really protecting the callbacks
because access is [predominantly] exclusive?

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-01-30 12:48 ` [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU Bartosz Golaszewski
                     ` (2 preceding siblings ...)
  2024-01-31 20:23   ` Linus Walleij
@ 2024-02-01  5:03   ` Dan Carpenter
  2024-02-01  7:57     ` Bartosz Golaszewski
  3 siblings, 1 reply; 66+ messages in thread
From: Dan Carpenter @ 2024-02-01  5:03 UTC (permalink / raw)
  To: oe-kbuild, Bartosz Golaszewski, Linus Walleij, Kent Gibson,
	Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang
  Cc: lkp, oe-kbuild-all, linux-gpio, linux-kernel, Bartosz Golaszewski

Hi Bartosz,

kernel test robot noticed the following build warnings:

https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
config: i386-randconfig-141-20240131 (https://download.01.org/0day-ci/archive/20240201/202402010641.idtEaO24-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)

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>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202402010641.idtEaO24-lkp@intel.com/

New smatch warnings:
drivers/gpio/gpiolib.c:4776 gpiolib_dbg_show() error: we previously assumed 'gc' could be null (see line 4773)


vim +/gc +4776 drivers/gpio/gpiolib.c

fdeb8e1547cb9d Linus Walleij       2016-02-10  4762  static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
d2876d08d86f22 David Brownell      2008-02-04  4763  {
0338f6a6fb659f Bartosz Golaszewski 2023-12-21  4764  	bool active_low, is_irq, is_out;
0338f6a6fb659f Bartosz Golaszewski 2023-12-21  4765  	unsigned int gpio = gdev->base;
3de69ae1c407da Andy Shevchenko     2022-04-08  4766  	struct gpio_desc *desc;
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4767  	struct gpio_chip *gc;
3de69ae1c407da Andy Shevchenko     2022-04-08  4768  	int value;
d2876d08d86f22 David Brownell      2008-02-04  4769  
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4770  	guard(srcu)(&gdev->srcu);
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4771  
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4772  	gc = rcu_dereference(gdev->chip);
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30 @4773  	if (!gc)
                                                            ^^^
The patch adds a NULL check

2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4774  		seq_puts(s, "Underlying GPIO chip is gone\n");
2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4775  
3de69ae1c407da Andy Shevchenko     2022-04-08 @4776  	for_each_gpio_desc(gc, desc) {
                                                                           ^^
But this dereference isn't checked...  Probably it should return after
the seq_puts().

bedc56b1695b27 Bartosz Golaszewski 2024-01-30  4777  		guard(srcu)(&desc->srcu);
3de69ae1c407da Andy Shevchenko     2022-04-08  4778  		if (test_bit(FLAG_REQUESTED, &desc->flags)) {
3de69ae1c407da Andy Shevchenko     2022-04-08  4779  			gpiod_get_direction(desc);
3de69ae1c407da Andy Shevchenko     2022-04-08  4780  			is_out = test_bit(FLAG_IS_OUT, &desc->flags);
234c52097ce416 Andy Shevchenko     2022-04-08  4781  			value = gpio_chip_get_value(gc, desc);
3de69ae1c407da Andy Shevchenko     2022-04-08  4782  			is_irq = test_bit(FLAG_USED_AS_IRQ, &desc->flags);
3de69ae1c407da Andy Shevchenko     2022-04-08  4783  			active_low = test_bit(FLAG_ACTIVE_LOW, &desc->flags);
3de69ae1c407da Andy Shevchenko     2022-04-08  4784  			seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s\n",
32648f473c7f46 Bartosz Golaszewski 2024-01-30  4785  				   gpio, desc->name ?: "", gpiod_get_label(desc),
d2876d08d86f22 David Brownell      2008-02-04  4786  				   is_out ? "out" : "in ",
3de69ae1c407da Andy Shevchenko     2022-04-08  4787  				   value >= 0 ? (value ? "hi" : "lo") : "?  ",
90fd227029a25b Linus Walleij       2018-10-01  4788  				   is_irq ? "IRQ " : "",
90fd227029a25b Linus Walleij       2018-10-01  4789  				   active_low ? "ACTIVE LOW" : "");
3de69ae1c407da Andy Shevchenko     2022-04-08  4790  		} else if (desc->name) {
3de69ae1c407da Andy Shevchenko     2022-04-08  4791  			seq_printf(s, " gpio-%-3d (%-20.20s)\n", gpio, desc->name);
3de69ae1c407da Andy Shevchenko     2022-04-08  4792  		}
3de69ae1c407da Andy Shevchenko     2022-04-08  4793  
3de69ae1c407da Andy Shevchenko     2022-04-08  4794  		gpio++;
d2876d08d86f22 David Brownell      2008-02-04  4795  	}
d2876d08d86f22 David Brownell      2008-02-04  4796  }

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
  2024-02-01  5:03   ` Dan Carpenter
@ 2024-02-01  7:57     ` Bartosz Golaszewski
  0 siblings, 0 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-02-01  7:57 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: oe-kbuild, Linus Walleij, Kent Gibson, Alex Elder,
	Geert Uytterhoeven, Paul E . McKenney, Andy Shevchenko,
	Wolfram Sang, lkp, oe-kbuild-all, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Thu, Feb 1, 2024 at 6:03 AM Dan Carpenter <dan.carpenter@linaro.org> wrote:
>
> Hi Bartosz,
>
> kernel test robot noticed the following build warnings:
>
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Bartosz-Golaszewski/gpio-protect-the-list-of-GPIO-devices-with-SRCU/20240130-205537
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next
> patch link:    https://lore.kernel.org/r/20240130124828.14678-21-brgl%40bgdev.pl
> patch subject: [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU
> config: i386-randconfig-141-20240131 (https://download.01.org/0day-ci/archive/20240201/202402010641.idtEaO24-lkp@intel.com/config)
> compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
>
> 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>
> | Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
> | Closes: https://lore.kernel.org/r/202402010641.idtEaO24-lkp@intel.com/
>
> New smatch warnings:
> drivers/gpio/gpiolib.c:4776 gpiolib_dbg_show() error: we previously assumed 'gc' could be null (see line 4773)
>
>
> vim +/gc +4776 drivers/gpio/gpiolib.c
>
> fdeb8e1547cb9d Linus Walleij       2016-02-10  4762  static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
> d2876d08d86f22 David Brownell      2008-02-04  4763  {
> 0338f6a6fb659f Bartosz Golaszewski 2023-12-21  4764     bool active_low, is_irq, is_out;
> 0338f6a6fb659f Bartosz Golaszewski 2023-12-21  4765     unsigned int gpio = gdev->base;
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4766     struct gpio_desc *desc;
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4767     struct gpio_chip *gc;
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4768     int value;
> d2876d08d86f22 David Brownell      2008-02-04  4769
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4770     guard(srcu)(&gdev->srcu);
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4771
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4772     gc = rcu_dereference(gdev->chip);
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30 @4773     if (!gc)
>                                                             ^^^
> The patch adds a NULL check
>
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4774             seq_puts(s, "Underlying GPIO chip is gone\n");
> 2796d5332f8ac8 Bartosz Golaszewski 2024-01-30  4775
> 3de69ae1c407da Andy Shevchenko     2022-04-08 @4776     for_each_gpio_desc(gc, desc) {
>                                                                            ^^
> But this dereference isn't checked...  Probably it should return after
> the seq_puts().
>

Of course it should. Thanks. I fixed it for v2.

Bart

> bedc56b1695b27 Bartosz Golaszewski 2024-01-30  4777             guard(srcu)(&desc->srcu);
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4778             if (test_bit(FLAG_REQUESTED, &desc->flags)) {
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4779                     gpiod_get_direction(desc);
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4780                     is_out = test_bit(FLAG_IS_OUT, &desc->flags);
> 234c52097ce416 Andy Shevchenko     2022-04-08  4781                     value = gpio_chip_get_value(gc, desc);
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4782                     is_irq = test_bit(FLAG_USED_AS_IRQ, &desc->flags);
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4783                     active_low = test_bit(FLAG_ACTIVE_LOW, &desc->flags);
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4784                     seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s\n",
> 32648f473c7f46 Bartosz Golaszewski 2024-01-30  4785                                gpio, desc->name ?: "", gpiod_get_label(desc),
> d2876d08d86f22 David Brownell      2008-02-04  4786                                is_out ? "out" : "in ",
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4787                                value >= 0 ? (value ? "hi" : "lo") : "?  ",
> 90fd227029a25b Linus Walleij       2018-10-01  4788                                is_irq ? "IRQ " : "",
> 90fd227029a25b Linus Walleij       2018-10-01  4789                                active_low ? "ACTIVE LOW" : "");
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4790             } else if (desc->name) {
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4791                     seq_printf(s, " gpio-%-3d (%-20.20s)\n", gpio, desc->name);
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4792             }
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4793
> 3de69ae1c407da Andy Shevchenko     2022-04-08  4794             gpio++;
> d2876d08d86f22 David Brownell      2008-02-04  4795     }
> d2876d08d86f22 David Brownell      2008-02-04  4796  }
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki
>

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 00/22] gpio: rework locking and object life-time control
  2024-01-31 20:32 ` [PATCH 00/22] gpio: rework locking and object life-time control Linus Walleij
@ 2024-02-01  8:43   ` Bartosz Golaszewski
  0 siblings, 0 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-02-01  8:43 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Wed, Jan 31, 2024 at 9:32 PM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> > We do NOT serialize all API callbacks. This means that provider callbacks
> > may be called simultaneously and GPIO drivers need to provide their own
> > locking if needed. This is on purpose. First: we only support exclusive
> > GPIO usage[1] so there's no risk of two drivers getting in each other's
> > way over the same GPIO. Second: with this series, we ensure enough
> > consistency to limit the chance of drivers or user-space users crashing
> > the kernel. With additional improvements in handling the flags field in
> > GPIO descriptors there's very little to gain, while bitbanging drivers
> > may care about the increased performance of going lockless.
>
> OK I read this before but didn't understand it, now I understand it.
>
> The series:
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>
> I think you should merge it all soon so we get some time to shake
> it out in linux-next, hopefully any remaining bugs and cleanups
> can be done in-tree.
>
> Excellent work, by the way.
>

Thanks. There are still a few issues here and there, so I'll be
sending a v2 next week.

Bart

> Yours,
> Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 22/22] gpio: mark unsafe gpio_chip manipulators as deprecated
  2024-01-31 20:29   ` Linus Walleij
@ 2024-02-01  9:14     ` Bartosz Golaszewski
  0 siblings, 0 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-02-01  9:14 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Wed, Jan 31, 2024 at 9:29 PM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> On Tue, Jan 30, 2024 at 1:49 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > We still have some functions that return the address of the GPIO chip
> > associated with the GPIO device. This is dangerous and the users should
> > find a better solution. Let's add appropriate comments to the kernel
> > docs.
> >
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
>
> I'm not sure it's very easy to find a better solution for gpiod_to_chip(),
> but perhaps also add this as a work item to the TODO file? We can certainly
> try to get rid of <linux/gpio.h> before we need to look into fixing this...

I will get to revising the TODO at some point hopefully.

>
> gpiod_device_get_label() should be easy to fix:

This is gone already! Check v6.8-rc1.

Bart

> linus@lino:~/linux$ git grep gpio_device_get_label
> drivers/gpio/gpiolib.c: * gpio_device_get_label() - Get the label of
> this GPIO device
> drivers/gpio/gpiolib.c:const char *gpio_device_get_label(struct
> gpio_device *gdev)
> drivers/gpio/gpiolib.c:EXPORT_SYMBOL(gpio_device_get_label);
> drivers/pinctrl/core.c:                            gpio_device_get_label(gdev));
> include/linux/gpio/driver.h:const char *gpio_device_get_label(struct
> gpio_device *gdev);
>
> We only created that problem for ourselves... It should be removed
> from <linux/gpio/driver.h>.
>
> Anyway:
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>
> Yours,
> Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

* Re: [PATCH 10/22] gpio: reinforce desc->flags handling
  2024-01-31 20:35     ` Linus Walleij
@ 2024-02-01 18:30       ` Bartosz Golaszewski
  0 siblings, 0 replies; 66+ messages in thread
From: Bartosz Golaszewski @ 2024-02-01 18:30 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Kent Gibson, Alex Elder, Geert Uytterhoeven, Paul E . McKenney,
	Andy Shevchenko, Wolfram Sang, linux-gpio, linux-kernel,
	Bartosz Golaszewski

On Wed, Jan 31, 2024 at 9:35 PM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> On Wed, Jan 31, 2024 at 9:01 PM Linus Walleij <linus.walleij@linaro.org> wrote:
> > On Tue, Jan 30, 2024 at 1:48 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> >
> > > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > >
> > > We now removed the gpio_lock spinlock and modified the places
> > > previously protected by it to handle desc->flags access in a consistent
> > > way. Let's improve other places that were previously unprotected by
> > > reading the flags field of gpio_desc once and using the stored value for
> > > logic consistency. If we need to modify the field, let's also write it
> > > back once with a consistent value resulting from the function's logic.
> > >
> > > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > (...)
> >
> > I have a trouble with this one:
> >
> > gpiochip_find_base_unlocked()
> > > +       unsigned long flags;
> > (...)
> > > +       flags = READ_ONCE(desc->flags);
> > (...)
> > > +       if (test_bit(FLAG_OPEN_DRAIN, &flags) &&
> > > +           test_bit(FLAG_IS_OUT, &flags))
> > >                 return 0;
> > (...)
> > > +       assign_bit(FLAG_IS_OUT, &flags, !ret);
> > > +       WRITE_ONCE(desc->flags, flags);
> >
> > I unerstand the atomicity of each operation here, but ... if what you want
> > to protect is modifications from other CPUs, how do we know that another
> > CPU isn't coming in and reading and modifying and assigning
> > another flag inbetween these operations while the value is only
> > stored in the CPU-local flags variable?
> >
> > Same with gpiod_direction_output().
> >
> > To me it seems like maybe you need to actually protect the desc->flags
> > with the SRCU struct in these cases? (and not only use it for the
> > label protection then).
> >
> > An alternative is maybe to rewrite the code with test_and_set().
> >
> > But as you say it is currently unprotected, I just wonder if this really
> > adds any protection.
>
> After re-reading the cover letter I'm fine with this, but I still wonder
> if it buys us anything.
>

This was a tough one...

I don't really see any way around it. SRCU is for pointers but even
then - we wouldn't get with SRCU anything more than what we're getting
with atomic reads and writes. As neither sleeping nor atomic locks
will work in the case of the GPIO subsystem, I figured that we should
strive for the maximum of coherence we can achieve - and for that I
figured that we should read the flags once, do our thing and then
write back a consistent result. If someone else comes around at the
same time and writes something else - well, he better be an
*exclusive*  user of that GPIO and know what they're doing. :)

Anyway, I think this series is already a big step forward and should
at least protect us from crashing. We can continue the work on
achieving full state consistency later.

Bart

> Maybe some words looped back from the
> commit message that we are not really protecting the callbacks
> because access is [predominantly] exclusive?
>
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
>
> Yours,
> Linus Walleij

^ permalink raw reply	[flat|nested] 66+ messages in thread

end of thread, other threads:[~2024-02-01 18:31 UTC | newest]

Thread overview: 66+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-30 12:48 [PATCH 00/22] gpio: rework locking and object life-time control Bartosz Golaszewski
2024-01-30 12:48 ` [PATCH 01/22] gpio: protect the list of GPIO devices with SRCU Bartosz Golaszewski
2024-01-31  9:34   ` kernel test robot
2024-01-31 12:45     ` Bartosz Golaszewski
2024-01-31 15:01   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 02/22] gpio: of: assign and read the hog pointer atomically Bartosz Golaszewski
2024-01-31 17:38   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 03/22] gpio: remove unused logging helpers Bartosz Golaszewski
2024-01-31 17:39   ` Linus Walleij
2024-01-31 18:08     ` Bartosz Golaszewski
2024-01-31 20:33       ` Linus Walleij
2024-01-30 12:48 ` [PATCH 04/22] gpio: provide and use gpiod_get_label() Bartosz Golaszewski
2024-01-31 19:36   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 05/22] gpio: don't set label from irq helpers Bartosz Golaszewski
2024-01-31 19:38   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 06/22] gpio: add SRCU infrastructure to struct gpio_desc Bartosz Golaszewski
2024-01-31 19:35   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 07/22] gpio: protect the descriptor label with SRCU Bartosz Golaszewski
2024-01-31 19:41   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 08/22] gpio: sysfs: use gpio_device_find() to iterate over existing devices Bartosz Golaszewski
2024-01-31 19:42   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 09/22] gpio: remove gpio_lock Bartosz Golaszewski
2024-01-31 19:51   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 10/22] gpio: reinforce desc->flags handling Bartosz Golaszewski
2024-01-31 20:01   ` Linus Walleij
2024-01-31 20:35     ` Linus Walleij
2024-02-01 18:30       ` Bartosz Golaszewski
2024-01-30 12:48 ` [PATCH 11/22] gpio: remove unneeded code from gpio_device_get_desc() Bartosz Golaszewski
2024-01-31 20:02   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 12/22] gpio: sysfs: extend the critical section for unregistering sysfs devices Bartosz Golaszewski
2024-01-31 20:06   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 13/22] gpio: sysfs: pass the GPIO device - not chip - to sysfs callbacks Bartosz Golaszewski
2024-01-31 20:09   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 14/22] gpio: cdev: replace gpiochip_get_desc() with gpio_device_get_desc() Bartosz Golaszewski
2024-01-31 20:10   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 15/22] gpio: cdev: don't access gdev->chip if it's not needed Bartosz Golaszewski
2024-01-31 20:11   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 16/22] gpio: reduce the functionality of validate_desc() Bartosz Golaszewski
2024-01-31 20:16   ` Linus Walleij
2024-01-31 20:19     ` Linus Walleij
2024-01-30 12:48 ` [PATCH 17/22] gpio: remove unnecessary checks from gpiod_to_chip() Bartosz Golaszewski
2024-01-30 12:48 ` [PATCH 18/22] gpio: add the can_sleep flag to struct gpio_device Bartosz Golaszewski
2024-01-31 20:17   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 19/22] gpio: add SRCU infrastructure " Bartosz Golaszewski
2024-01-30 12:48 ` [PATCH 20/22] gpio: protect the pointer to gpio_chip in gpio_device with SRCU Bartosz Golaszewski
2024-01-31  0:41   ` kernel test robot
2024-01-31  8:15     ` Bartosz Golaszewski
2024-01-31  2:20   ` kernel test robot
2024-01-31  9:02     ` Bartosz Golaszewski
2024-01-31  9:24       ` Paul E. McKenney
2024-01-31  9:28         ` Bartosz Golaszewski
2024-01-31  9:41           ` Bartosz Golaszewski
2024-01-31  9:42           ` Paul E. McKenney
2024-01-31 10:17             ` brgl
2024-01-31 11:00               ` Paul E. McKenney
2024-01-31 12:23                 ` Bartosz Golaszewski
2024-01-31 20:23   ` Linus Walleij
2024-02-01  5:03   ` Dan Carpenter
2024-02-01  7:57     ` Bartosz Golaszewski
2024-01-30 12:48 ` [PATCH 21/22] gpio: remove the RW semaphore from the GPIO device Bartosz Golaszewski
2024-01-31 20:24   ` Linus Walleij
2024-01-30 12:48 ` [PATCH 22/22] gpio: mark unsafe gpio_chip manipulators as deprecated Bartosz Golaszewski
2024-01-31 20:29   ` Linus Walleij
2024-02-01  9:14     ` Bartosz Golaszewski
2024-01-31 20:32 ` [PATCH 00/22] gpio: rework locking and object life-time control Linus Walleij
2024-02-01  8:43   ` Bartosz Golaszewski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).