Skip to content

Commit d29edf9

Browse files
kennylevinsenkakra
authored andcommitted
ZEN: Input: evdev - use call_rcu when detaching client
Significant time was spent on synchronize_rcu in evdev_detach_client when applications closed evdev devices. Switching VT away from a graphical environment commonly leads to mass input device closures, which could lead to noticable delays on systems with many input devices. Replace synchronize_rcu with call_rcu, deferring reclaim of the evdev client struct till after the RCU grace period instead of blocking the calling application. While this does not solve all slow evdev fd closures, it takes care of a good portion of them, including this simple test: #include <fcntl.h> #include <unistd.h> int main(int argc, char *argv[]) { int idx, fd; const char *path = "/dev/input/event0"; for (idx = 0; idx < 1000; idx++) { if ((fd = open(path, O_RDWR)) == -1) { return -1; } close(fd); } return 0; } Time to completion of above test when run locally: Before: 0m27.111s After: 0m0.018s Signed-off-by: Kenny Levinsen <kl@kl.wtf>
1 parent 0ef35bd commit d29edf9

1 file changed

Lines changed: 11 additions & 8 deletions

File tree

drivers/input/evdev.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ struct evdev_client {
4646
struct fasync_struct *fasync;
4747
struct evdev *evdev;
4848
struct list_head node;
49+
struct rcu_head rcu;
4950
enum input_clock_type clk_type;
5051
bool revoked;
5152
unsigned long *evmasks[EV_CNT];
@@ -377,13 +378,22 @@ static void evdev_attach_client(struct evdev *evdev,
377378
spin_unlock(&evdev->client_lock);
378379
}
379380

381+
static void evdev_reclaim_client(struct rcu_head *rp)
382+
{
383+
struct evdev_client *client = container_of(rp, struct evdev_client, rcu);
384+
unsigned int i;
385+
for (i = 0; i < EV_CNT; ++i)
386+
bitmap_free(client->evmasks[i]);
387+
kvfree(client);
388+
}
389+
380390
static void evdev_detach_client(struct evdev *evdev,
381391
struct evdev_client *client)
382392
{
383393
spin_lock(&evdev->client_lock);
384394
list_del_rcu(&client->node);
385395
spin_unlock(&evdev->client_lock);
386-
synchronize_rcu();
396+
call_rcu(&client->rcu, evdev_reclaim_client);
387397
}
388398

389399
static int evdev_open_device(struct evdev *evdev)
@@ -436,7 +446,6 @@ static int evdev_release(struct inode *inode, struct file *file)
436446
{
437447
struct evdev_client *client = file->private_data;
438448
struct evdev *evdev = client->evdev;
439-
unsigned int i;
440449

441450
mutex_lock(&evdev->mutex);
442451

@@ -448,11 +457,6 @@ static int evdev_release(struct inode *inode, struct file *file)
448457

449458
evdev_detach_client(evdev, client);
450459

451-
for (i = 0; i < EV_CNT; ++i)
452-
bitmap_free(client->evmasks[i]);
453-
454-
kvfree(client);
455-
456460
evdev_close_device(evdev);
457461

458462
return 0;
@@ -495,7 +499,6 @@ static int evdev_open(struct inode *inode, struct file *file)
495499

496500
err_free_client:
497501
evdev_detach_client(evdev, client);
498-
kvfree(client);
499502
return error;
500503
}
501504

0 commit comments

Comments
 (0)