Skip to content

Commit 8590222

Browse files
andrealmeidbentiss
authored andcommitted
HID: hidraw: Replace hidraw device table mutex with a rwsem
Currently, the table that stores information about the connected hidraw devices has a mutex to prevent concurrent hidraw users to manipulate the hidraw table (e.g. delete an entry) while someone is trying to use the table (e.g. issuing an ioctl to the device), preventing the kernel to referencing a NULL pointer. However, since that every user that wants to access the table for both manipulating it and reading it content, this prevents concurrent access to the table for read-only operations for different or the same device (e.g. two hidraw ioctls can't happen at the same time, even if they are completely unrelated). This proves to be a bottleneck and gives performance issues when using multiple HID devices at same time, like VR kits where one can have two controllers, the headset and some tracking sensors. To improve the performance, replace the table mutex with a read-write semaphore, enabling multiple threads to issue parallel syscalls to multiple devices at the same time while protecting the table for concurrent modifications. Signed-off-by: André Almeida <andrealmeid@collabora.com> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Link: https://lore.kernel.org/r/20211130132957.8480-2-andrealmeid@collabora.com
1 parent 03090cc commit 8590222

1 file changed

Lines changed: 17 additions & 17 deletions

File tree

drivers/hid/hidraw.c

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static int hidraw_major;
3434
static struct cdev hidraw_cdev;
3535
static struct class *hidraw_class;
3636
static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
37-
static DEFINE_MUTEX(minors_lock);
37+
static DECLARE_RWSEM(minors_rwsem);
3838

3939
static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
4040
{
@@ -107,7 +107,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
107107
__u8 *buf;
108108
int ret = 0;
109109

110-
lockdep_assert_held(&minors_lock);
110+
lockdep_assert_held(&minors_rwsem);
111111

112112
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
113113
ret = -ENODEV;
@@ -160,9 +160,9 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
160160
static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
161161
{
162162
ssize_t ret;
163-
mutex_lock(&minors_lock);
163+
down_read(&minors_rwsem);
164164
ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
165-
mutex_unlock(&minors_lock);
165+
up_read(&minors_rwsem);
166166
return ret;
167167
}
168168

@@ -182,7 +182,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
182182
int ret = 0, len;
183183
unsigned char report_number;
184184

185-
lockdep_assert_held(&minors_lock);
185+
lockdep_assert_held(&minors_rwsem);
186186

187187
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
188188
ret = -ENODEV;
@@ -272,7 +272,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
272272
goto out;
273273
}
274274

275-
mutex_lock(&minors_lock);
275+
down_read(&minors_rwsem);
276276
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
277277
err = -ENODEV;
278278
goto out_unlock;
@@ -301,7 +301,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
301301
spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
302302
file->private_data = list;
303303
out_unlock:
304-
mutex_unlock(&minors_lock);
304+
up_read(&minors_rwsem);
305305
out:
306306
if (err < 0)
307307
kfree(list);
@@ -347,7 +347,7 @@ static int hidraw_release(struct inode * inode, struct file * file)
347347
struct hidraw_list *list = file->private_data;
348348
unsigned long flags;
349349

350-
mutex_lock(&minors_lock);
350+
down_write(&minors_rwsem);
351351

352352
spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
353353
list_del(&list->node);
@@ -356,7 +356,7 @@ static int hidraw_release(struct inode * inode, struct file * file)
356356

357357
drop_ref(hidraw_table[minor], 0);
358358

359-
mutex_unlock(&minors_lock);
359+
up_write(&minors_rwsem);
360360
return 0;
361361
}
362362

@@ -369,7 +369,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
369369
struct hidraw *dev;
370370
void __user *user_arg = (void __user*) arg;
371371

372-
mutex_lock(&minors_lock);
372+
down_read(&minors_rwsem);
373373
dev = hidraw_table[minor];
374374
if (!dev || !dev->exist) {
375375
ret = -ENODEV;
@@ -487,7 +487,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
487487
ret = -ENOTTY;
488488
}
489489
out:
490-
mutex_unlock(&minors_lock);
490+
up_read(&minors_rwsem);
491491
return ret;
492492
}
493493

@@ -546,7 +546,7 @@ int hidraw_connect(struct hid_device *hid)
546546

547547
result = -EINVAL;
548548

549-
mutex_lock(&minors_lock);
549+
down_write(&minors_rwsem);
550550

551551
for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
552552
if (hidraw_table[minor])
@@ -557,7 +557,7 @@ int hidraw_connect(struct hid_device *hid)
557557
}
558558

559559
if (result) {
560-
mutex_unlock(&minors_lock);
560+
up_write(&minors_rwsem);
561561
kfree(dev);
562562
goto out;
563563
}
@@ -567,7 +567,7 @@ int hidraw_connect(struct hid_device *hid)
567567

568568
if (IS_ERR(dev->dev)) {
569569
hidraw_table[minor] = NULL;
570-
mutex_unlock(&minors_lock);
570+
up_write(&minors_rwsem);
571571
result = PTR_ERR(dev->dev);
572572
kfree(dev);
573573
goto out;
@@ -583,7 +583,7 @@ int hidraw_connect(struct hid_device *hid)
583583
dev->exist = 1;
584584
hid->hidraw = dev;
585585

586-
mutex_unlock(&minors_lock);
586+
up_write(&minors_rwsem);
587587
out:
588588
return result;
589589

@@ -594,11 +594,11 @@ void hidraw_disconnect(struct hid_device *hid)
594594
{
595595
struct hidraw *hidraw = hid->hidraw;
596596

597-
mutex_lock(&minors_lock);
597+
down_write(&minors_rwsem);
598598

599599
drop_ref(hidraw, 1);
600600

601-
mutex_unlock(&minors_lock);
601+
up_write(&minors_rwsem);
602602
}
603603
EXPORT_SYMBOL_GPL(hidraw_disconnect);
604604

0 commit comments

Comments
 (0)