diff mbox series

[v2,4/6] gpio: cdev: wake up chardev poll() on device unbind

Message ID 20230817184958.25349-5-brgl@bgdev.pl
State New
Headers show
Series gpio: cdev: bail out of poll() if the device goes down | expand

Commit Message

Bartosz Golaszewski Aug. 17, 2023, 6:49 p.m. UTC
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

Add a notifier block to the gpio_chardev_data structure and register it
with the gpio_device's device notifier. Upon reception of an event, wake
up the wait queue so that the user-space be forced out of poll() and need
to go into a new system call which will then fail due to the chip being
gone.

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

Comments

Andy Shevchenko Aug. 18, 2023, 10:30 a.m. UTC | #1
On Thu, Aug 17, 2023 at 08:49:56PM +0200, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> 
> Add a notifier block to the gpio_chardev_data structure and register it
> with the gpio_device's device notifier. Upon reception of an event, wake
> up the wait queue so that the user-space be forced out of poll() and need
> to go into a new system call which will then fail due to the chip being
> gone.

...

> +	struct gpio_chardev_data *cdev = container_of(nb,
> +						      struct gpio_chardev_data,
> +						      device_unregistered_nb);

	struct gpio_chardev_data *cdev =
		container_of(nb, struct gpio_chardev_data, device_unregistered_nb);

?
Bartosz Golaszewski Aug. 21, 2023, 12:43 p.m. UTC | #2
On Fri, Aug 18, 2023 at 12:31 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Aug 17, 2023 at 08:49:56PM +0200, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > Add a notifier block to the gpio_chardev_data structure and register it
> > with the gpio_device's device notifier. Upon reception of an event, wake
> > up the wait queue so that the user-space be forced out of poll() and need
> > to go into a new system call which will then fail due to the chip being
> > gone.
>
> ...
>
> > +     struct gpio_chardev_data *cdev = container_of(nb,
> > +                                                   struct gpio_chardev_data,
> > +                                                   device_unregistered_nb);
>
>         struct gpio_chardev_data *cdev =
>                 container_of(nb, struct gpio_chardev_data, device_unregistered_nb);
>
> ?

I could live with the other version but sure, why not.

I will send a v3 with a helper wrapper around
blocking_notifier_call_chain() for more brevity.

Bart
Bartosz Golaszewski Aug. 21, 2023, 1:03 p.m. UTC | #3
On Mon, Aug 21, 2023 at 2:43 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> On Fri, Aug 18, 2023 at 12:31 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> >
> > On Thu, Aug 17, 2023 at 08:49:56PM +0200, Bartosz Golaszewski wrote:
> > > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > >
> > > Add a notifier block to the gpio_chardev_data structure and register it
> > > with the gpio_device's device notifier. Upon reception of an event, wake
> > > up the wait queue so that the user-space be forced out of poll() and need
> > > to go into a new system call which will then fail due to the chip being
> > > gone.
> >
> > ...
> >
> > > +     struct gpio_chardev_data *cdev = container_of(nb,
> > > +                                                   struct gpio_chardev_data,
> > > +                                                   device_unregistered_nb);
> >
> >         struct gpio_chardev_data *cdev =
> >                 container_of(nb, struct gpio_chardev_data, device_unregistered_nb);
> >
> > ?
>
> I could live with the other version but sure, why not.
>
> I will send a v3 with a helper wrapper around
> blocking_notifier_call_chain() for more brevity.
>

Scratch that, I need coffee. This was supposed to go under the line
state notifications patch.

Bart
Bartosz Golaszewski Aug. 21, 2023, 1:34 p.m. UTC | #4
On Fri, Aug 18, 2023 at 12:31 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Aug 17, 2023 at 08:49:56PM +0200, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> >
> > Add a notifier block to the gpio_chardev_data structure and register it
> > with the gpio_device's device notifier. Upon reception of an event, wake
> > up the wait queue so that the user-space be forced out of poll() and need
> > to go into a new system call which will then fail due to the chip being
> > gone.
>
> ...
>
> > +     struct gpio_chardev_data *cdev = container_of(nb,
> > +                                                   struct gpio_chardev_data,
> > +                                                   device_unregistered_nb);
>
>         struct gpio_chardev_data *cdev =
>                 container_of(nb, struct gpio_chardev_data, device_unregistered_nb);
>

Ah, this goes over 80 chars. I will leave it as it is, I will fix the
other one when applying.

Bart

> ?
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
diff mbox series

Patch

diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index f95e1b110311..8b081c9b8d27 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -2320,6 +2320,7 @@  struct gpio_chardev_data {
 	wait_queue_head_t wait;
 	DECLARE_KFIFO(events, struct gpio_v2_line_info_changed, 32);
 	struct notifier_block lineinfo_changed_nb;
+	struct notifier_block device_unregistered_nb;
 	unsigned long *watched_lines;
 #ifdef CONFIG_GPIO_CDEV_V1
 	atomic_t watch_abi_version;
@@ -2518,6 +2519,18 @@  static int lineinfo_changed_notify(struct notifier_block *nb,
 	return NOTIFY_OK;
 }
 
+static int gpio_device_unregistered_notify(struct notifier_block *nb,
+					   unsigned long action, void *data)
+{
+	struct gpio_chardev_data *cdev = container_of(nb,
+						      struct gpio_chardev_data,
+						      device_unregistered_nb);
+
+	wake_up_poll(&cdev->wait, EPOLLIN | EPOLLERR);
+
+	return NOTIFY_OK;
+}
+
 static __poll_t lineinfo_watch_poll_unlocked(struct file *file,
 					     struct poll_table_struct *pollt)
 {
@@ -2672,17 +2685,27 @@  static int gpio_chrdev_open(struct inode *inode, struct file *file)
 	if (ret)
 		goto out_free_bitmap;
 
+	cdev->device_unregistered_nb.notifier_call =
+					gpio_device_unregistered_notify;
+	ret = blocking_notifier_chain_register(&gdev->device_notifier,
+					       &cdev->device_unregistered_nb);
+	if (ret)
+		goto out_unregister_line_notifier;
+
 	file->private_data = cdev;
 
 	ret = nonseekable_open(inode, file);
 	if (ret)
-		goto out_unregister_notifier;
+		goto out_unregister_device_notifier;
 
 	up_read(&gdev->sem);
 
 	return ret;
 
-out_unregister_notifier:
+out_unregister_device_notifier:
+	blocking_notifier_chain_unregister(&gdev->device_notifier,
+					   &cdev->device_unregistered_nb);
+out_unregister_line_notifier:
 	blocking_notifier_chain_unregister(&gdev->line_state_notifier,
 					   &cdev->lineinfo_changed_nb);
 out_free_bitmap:
@@ -2707,6 +2730,8 @@  static int gpio_chrdev_release(struct inode *inode, struct file *file)
 	struct gpio_device *gdev = cdev->gdev;
 
 	bitmap_free(cdev->watched_lines);
+	blocking_notifier_chain_unregister(&gdev->device_notifier,
+					   &cdev->device_unregistered_nb);
 	blocking_notifier_chain_unregister(&gdev->line_state_notifier,
 					   &cdev->lineinfo_changed_nb);
 	gpio_device_put(gdev);