aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Kondratyev <wulf@FreeBSD.org>2020-04-21 22:38:14 +0000
committerVladimir Kondratyev <wulf@FreeBSD.org>2021-01-07 23:18:42 +0000
commit3b8c8b35de3a1a8a24169d144189b6a4db82ce10 (patch)
tree0c4ab1221f08828654358da47415420372c48de7
parentd276eae674d22214d6a58d1f4871053ceb0cb9f5 (diff)
downloadsrc-3b8c8b35de3a1a8a24169d144189b6a4db82ce10.tar.gz
src-3b8c8b35de3a1a8a24169d144189b6a4db82ce10.zip
evdev: Allow open() handler to be interrupted by a signal
It is possible that the client list lock is taken by other process for too long due to e.g. IO timeouts. Allow user to terminate open() in this case. Reviewed by: markj (as part of D27865)
-rw-r--r--sys/dev/evdev/cdev.c11
-rw-r--r--sys/dev/evdev/evdev_private.h9
2 files changed, 15 insertions, 5 deletions
diff --git a/sys/dev/evdev/cdev.c b/sys/dev/evdev/cdev.c
index c4550362ebce..ec60a12dbf2d 100644
--- a/sys/dev/evdev/cdev.c
+++ b/sys/dev/evdev/cdev.c
@@ -126,19 +126,20 @@ evdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
mtx_init(&client->ec_buffer_mtx, "evclient", "evdev", MTX_DEF);
knlist_init_mtx(&client->ec_selp.si_note, &client->ec_buffer_mtx);
+ ret = EVDEV_LIST_LOCK_SIG(evdev);
+ if (ret != 0)
+ goto out;
/* Avoid race with evdev_unregister */
- EVDEV_LIST_LOCK(evdev);
if (dev->si_drv1 == NULL)
ret = ENODEV;
else
ret = evdev_register_client(evdev, client);
-
- if (ret != 0)
- evdev_revoke_client(client);
EVDEV_LIST_UNLOCK(evdev);
-
+out:
if (ret == 0)
ret = devfs_set_cdevpriv(client, evdev_dtor);
+ else
+ client->ec_revoked = true;
if (ret != 0) {
debugf(client, "cannot register evdev client");
diff --git a/sys/dev/evdev/evdev_private.h b/sys/dev/evdev/evdev_private.h
index 66a059c763bc..19636823b804 100644
--- a/sys/dev/evdev/evdev_private.h
+++ b/sys/dev/evdev/evdev_private.h
@@ -206,6 +206,15 @@ struct evdev_dev
else \
sx_assert(&(evdev)->ev_list_lock, MA_OWNED); \
} while (0)
+static inline int
+EVDEV_LIST_LOCK_SIG(struct evdev_dev *evdev)
+{
+ if (evdev->ev_lock_type == EV_LOCK_MTX) {
+ EVDEV_LOCK(evdev);
+ return (0);
+ }
+ return (sx_xlock_sig(&evdev->ev_list_lock));
+}
struct evdev_client
{