Re: [PATCH 1/1] HID: hidraw: Replace hidraw device table mutex with a rwsem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Nov 30, 2021 at 2:36 PM André Almeida <andrealmeid@xxxxxxxxxxxxx> wrote:
>
> 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@xxxxxxxxxxxxx>
> ---

Patch looks good to me.

Applied to for-5.17/hidraw.

Thanks!

Cheers,
Benjamin

>  drivers/hid/hidraw.c | 34 +++++++++++++++++-----------------
>  1 file changed, 17 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
> index 79faac87a06f..681614a8302a 100644
> --- a/drivers/hid/hidraw.c
> +++ b/drivers/hid/hidraw.c
> @@ -34,7 +34,7 @@ static int hidraw_major;
>  static struct cdev hidraw_cdev;
>  static struct class *hidraw_class;
>  static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
> -static DEFINE_MUTEX(minors_lock);
> +static DECLARE_RWSEM(minors_rwsem);
>
>  static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
>  {
> @@ -107,7 +107,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
>         __u8 *buf;
>         int ret = 0;
>
> -       lockdep_assert_held(&minors_lock);
> +       lockdep_assert_held(&minors_rwsem);
>
>         if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
>                 ret = -ENODEV;
> @@ -160,9 +160,9 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
>  static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
>  {
>         ssize_t ret;
> -       mutex_lock(&minors_lock);
> +       down_read(&minors_rwsem);
>         ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
> -       mutex_unlock(&minors_lock);
> +       up_read(&minors_rwsem);
>         return ret;
>  }
>
> @@ -182,7 +182,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
>         int ret = 0, len;
>         unsigned char report_number;
>
> -       lockdep_assert_held(&minors_lock);
> +       lockdep_assert_held(&minors_rwsem);
>
>         if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
>                 ret = -ENODEV;
> @@ -272,7 +272,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
>                 goto out;
>         }
>
> -       mutex_lock(&minors_lock);
> +       down_read(&minors_rwsem);
>         if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
>                 err = -ENODEV;
>                 goto out_unlock;
> @@ -301,7 +301,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
>         spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
>         file->private_data = list;
>  out_unlock:
> -       mutex_unlock(&minors_lock);
> +       up_read(&minors_rwsem);
>  out:
>         if (err < 0)
>                 kfree(list);
> @@ -347,7 +347,7 @@ static int hidraw_release(struct inode * inode, struct file * file)
>         struct hidraw_list *list = file->private_data;
>         unsigned long flags;
>
> -       mutex_lock(&minors_lock);
> +       down_write(&minors_rwsem);
>
>         spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
>         list_del(&list->node);
> @@ -356,7 +356,7 @@ static int hidraw_release(struct inode * inode, struct file * file)
>
>         drop_ref(hidraw_table[minor], 0);
>
> -       mutex_unlock(&minors_lock);
> +       up_write(&minors_rwsem);
>         return 0;
>  }
>
> @@ -369,7 +369,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
>         struct hidraw *dev;
>         void __user *user_arg = (void __user*) arg;
>
> -       mutex_lock(&minors_lock);
> +       down_read(&minors_rwsem);
>         dev = hidraw_table[minor];
>         if (!dev || !dev->exist) {
>                 ret = -ENODEV;
> @@ -487,7 +487,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
>                 ret = -ENOTTY;
>         }
>  out:
> -       mutex_unlock(&minors_lock);
> +       up_read(&minors_rwsem);
>         return ret;
>  }
>
> @@ -546,7 +546,7 @@ int hidraw_connect(struct hid_device *hid)
>
>         result = -EINVAL;
>
> -       mutex_lock(&minors_lock);
> +       down_write(&minors_rwsem);
>
>         for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
>                 if (hidraw_table[minor])
> @@ -557,7 +557,7 @@ int hidraw_connect(struct hid_device *hid)
>         }
>
>         if (result) {
> -               mutex_unlock(&minors_lock);
> +               up_write(&minors_rwsem);
>                 kfree(dev);
>                 goto out;
>         }
> @@ -567,7 +567,7 @@ int hidraw_connect(struct hid_device *hid)
>
>         if (IS_ERR(dev->dev)) {
>                 hidraw_table[minor] = NULL;
> -               mutex_unlock(&minors_lock);
> +               up_write(&minors_rwsem);
>                 result = PTR_ERR(dev->dev);
>                 kfree(dev);
>                 goto out;
> @@ -583,7 +583,7 @@ int hidraw_connect(struct hid_device *hid)
>         dev->exist = 1;
>         hid->hidraw = dev;
>
> -       mutex_unlock(&minors_lock);
> +       up_write(&minors_rwsem);
>  out:
>         return result;
>
> @@ -594,11 +594,11 @@ void hidraw_disconnect(struct hid_device *hid)
>  {
>         struct hidraw *hidraw = hid->hidraw;
>
> -       mutex_lock(&minors_lock);
> +       down_write(&minors_rwsem);
>
>         drop_ref(hidraw, 1);
>
> -       mutex_unlock(&minors_lock);
> +       up_write(&minors_rwsem);
>  }
>  EXPORT_SYMBOL_GPL(hidraw_disconnect);
>
> --
> 2.34.1
>





[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux