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)
This commit is contained in:
Vladimir Kondratyev 2020-04-22 01:38:14 +03:00
parent d276eae674
commit 3b8c8b35de
2 changed files with 15 additions and 5 deletions

View File

@ -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");

View File

@ -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
{