[PATCH v2 4/5] gpiolib: don't overwrite the entire flags field in gpiod_free_commit()
From: Bartosz Golaszewski
Date: Mon Nov 09 2026 - 05:30:42 EST
Use gpiod_update_flags() to clear all request-related flags in one go
instead of risking racing with concurrent users and overwriting any
changes they could have done between READ_ONCE() and WRITE_ONCE().
Cc: stable@xxxxxxxxxxxxxxx
Fixes: 35b545332b80 ("gpio: remove gpio_lock")
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxxxxxxxx>
---
drivers/gpio/gpiolib.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index af2d67d977f4925558ab77c34b37c3c29bd12a6f..4c9c524389ca13e422bca8c217b7f47477cc0dd4 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3,6 +3,7 @@
#include <linux/acpi.h>
#include <linux/array_size.h>
#include <linux/bitmap.h>
+#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/compat.h>
#include <linux/debugfs.h>
@@ -2696,24 +2697,23 @@ void gpiod_free_commit(struct gpio_desc *desc)
#ifdef CONFIG_GPIO_CDEV
WRITE_ONCE(desc->debounce_period_us, 0);
#endif
-
- clear_bit(GPIOD_FLAG_ACTIVE_LOW, &flags);
- clear_bit(GPIOD_FLAG_REQUESTED, &flags);
- clear_bit(GPIOD_FLAG_OPEN_DRAIN, &flags);
- clear_bit(GPIOD_FLAG_OPEN_SOURCE, &flags);
- clear_bit(GPIOD_FLAG_PULL_UP, &flags);
- clear_bit(GPIOD_FLAG_PULL_DOWN, &flags);
- clear_bit(GPIOD_FLAG_BIAS_DISABLE, &flags);
- clear_bit(GPIOD_FLAG_EDGE_RISING, &flags);
- clear_bit(GPIOD_FLAG_EDGE_FALLING, &flags);
- clear_bit(GPIOD_FLAG_EVENT_CLOCK_REALTIME, &flags);
- clear_bit(GPIOD_FLAG_EVENT_CLOCK_HTE, &flags);
- clear_bit(GPIOD_FLAG_IS_HOGGED, &flags);
#ifdef CONFIG_OF_DYNAMIC
WRITE_ONCE(desc->hog, NULL);
#endif
desc_set_label(desc, NULL);
- WRITE_ONCE(desc->flags, flags);
+ set_mask_bits(&desc->flags,
+ BIT(GPIOD_FLAG_ACTIVE_LOW) |
+ BIT(GPIOD_FLAG_REQUESTED) |
+ BIT(GPIOD_FLAG_OPEN_DRAIN) |
+ BIT(GPIOD_FLAG_OPEN_SOURCE) |
+ BIT(GPIOD_FLAG_PULL_UP) |
+ BIT(GPIOD_FLAG_PULL_DOWN) |
+ BIT(GPIOD_FLAG_BIAS_DISABLE) |
+ BIT(GPIOD_FLAG_EDGE_RISING) |
+ BIT(GPIOD_FLAG_EDGE_FALLING) |
+ BIT(GPIOD_FLAG_EVENT_CLOCK_REALTIME) |
+ BIT(GPIOD_FLAG_EVENT_CLOCK_HTE) |
+ BIT(GPIOD_FLAG_IS_HOGGED), 0);
gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_RELEASED);
}
}
--
2.47.3