2021-11-20 17:03:44

by Armin Wolf

[permalink] [raw]
Subject: [PATCH 0/2] hwmon: (dell-smm) Improve ioctl handler

This patch series improves the ioctl handler in dell_smm_hwmon.
The first patch is simplifying the ioctl handler by removing
an unnecessary switch case, while the second patch is unifying
both i8k_ioctl() and i8k_ioctl_unlocked(), resulting in better
performance since i8k_mutex is only acquired when needed
(during fan status change) instead of being acquired for
every ioctl call.

Tested on a Dell Inspiron 3505.

Armin Wolf (2):
hwmon: (dell-smm) Simplify ioctl handler
hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()

drivers/hwmon/dell-smm-hwmon.c | 57 +++++++++++-----------------------
1 file changed, 18 insertions(+), 39 deletions(-)

--
2.30.2



2021-11-20 17:03:50

by Armin Wolf

[permalink] [raw]
Subject: [PATCH 1/2] hwmon: (dell-smm) Simplify ioctl handler

The second switch-case has no real purpose:

- for I8K_BIOS_VERSION, val does not represent a return value,
making the check for error values unnecessary.
- for I8K_MACHINE_ID, val remains zero, so the error check is
unnecessary too.

Remove the switch-case and move the calls to copy_to_user()
into the first switch-case for I8K_BIOS_VERSION/_MACHINE_ID.
Omit buff[] since data->machineid already contains the string
with the necessary zero padding.

Tested on a Dell Inspiron 3505.

Signed-off-by: Armin Wolf <[email protected]>
---
drivers/hwmon/dell-smm-hwmon.c | 30 +++++++++---------------------
1 file changed, 9 insertions(+), 21 deletions(-)

diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index 5596c211f38d..b5d1703faa62 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -454,7 +454,6 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
{
int val = 0;
int speed, err;
- unsigned char buff[16];
int __user *argp = (int __user *)arg;

if (!argp)
@@ -468,15 +467,19 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd

val = (data->bios_version[0] << 16) |
(data->bios_version[1] << 8) | data->bios_version[2];
- break;

+ if (copy_to_user(argp, &val, 4))
+ return -EFAULT;
+
+ return 0;
case I8K_MACHINE_ID:
if (restricted && !capable(CAP_SYS_ADMIN))
return -EPERM;

- strscpy_pad(buff, data->bios_machineid, sizeof(buff));
- break;
+ if (copy_to_user(argp, data->bios_machineid, 16))
+ return -EFAULT;

+ return 0;
case I8K_FN_STATUS:
val = i8k_get_fn_status();
break;
@@ -527,23 +530,8 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
if (val < 0)
return val;

- switch (cmd) {
- case I8K_BIOS_VERSION:
- if (copy_to_user(argp, &val, 4))
- return -EFAULT;
-
- break;
- case I8K_MACHINE_ID:
- if (copy_to_user(argp, buff, 16))
- return -EFAULT;
-
- break;
- default:
- if (copy_to_user(argp, &val, sizeof(int)))
- return -EFAULT;
-
- break;
- }
+ if (copy_to_user(argp, &val, sizeof(int)))
+ return -EFAULT;

return 0;
}
--
2.30.2


2021-11-20 17:03:50

by Armin Wolf

[permalink] [raw]
Subject: [PATCH 2/2] hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()

The only purpose of i8k_ioctl() is to call i8k_ioctl_unlocked()
with i8k_mutex held. Judging from the hwmon code, this mutex
only needs to be held when setting the fan speed/mode.
Unify both functions and reduce the locking of i8k_mutex
to I8K_SET_FAN.

Tested on a Dell Inspiron 3505.

Signed-off-by: Armin Wolf <[email protected]>
---
drivers/hwmon/dell-smm-hwmon.c | 27 +++++++++------------------
1 file changed, 9 insertions(+), 18 deletions(-)

diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index b5d1703faa62..e2d388f7360e 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -449,12 +449,12 @@ static int i8k_get_power_status(void)
* Procfs interface
*/

-static int
-i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd, unsigned long arg)
+static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
- int val = 0;
- int speed, err;
+ struct dell_smm_data *data = PDE_DATA(file_inode(fp));
int __user *argp = (int __user *)arg;
+ int speed, err;
+ int val = 0;

if (!argp)
return -EINVAL;
@@ -516,11 +516,14 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
if (copy_from_user(&speed, argp + 1, sizeof(int)))
return -EFAULT;

+ mutex_lock(&data->i8k_mutex);
err = i8k_set_fan(data, val, speed);
- if (err < 0)
+ if (err < 0) {
+ mutex_unlock(&data->i8k_mutex);
return err;
-
+ }
val = i8k_get_fan_status(data, val);
+ mutex_unlock(&data->i8k_mutex);
break;

default:
@@ -536,18 +539,6 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
return 0;
}

-static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
-{
- struct dell_smm_data *data = PDE_DATA(file_inode(fp));
- long ret;
-
- mutex_lock(&data->i8k_mutex);
- ret = i8k_ioctl_unlocked(fp, data, cmd, arg);
- mutex_unlock(&data->i8k_mutex);
-
- return ret;
-}
-
/*
* Print the information for /proc/i8k.
*/
--
2.30.2


2021-11-22 16:01:26

by Pali Rohár

[permalink] [raw]
Subject: Re: [PATCH 2/2] hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()

On Saturday 20 November 2021 18:03:19 Armin Wolf wrote:
> The only purpose of i8k_ioctl() is to call i8k_ioctl_unlocked()
> with i8k_mutex held. Judging from the hwmon code, this mutex
> only needs to be held when setting the fan speed/mode.

Really? I think that there is no difference between setting and getting
fan speed/mode. At least I do not see why 'set' needs mutex and 'get' do
not need it. Some more explanation is needed...

I'm not sure here but SMM call consist of two 'out' instructions and we
probably need to ensure that interrupt does not happen between them.

> Unify both functions and reduce the locking of i8k_mutex
> to I8K_SET_FAN.
>
> Tested on a Dell Inspiron 3505.
>
> Signed-off-by: Armin Wolf <[email protected]>
> ---
> drivers/hwmon/dell-smm-hwmon.c | 27 +++++++++------------------
> 1 file changed, 9 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
> index b5d1703faa62..e2d388f7360e 100644
> --- a/drivers/hwmon/dell-smm-hwmon.c
> +++ b/drivers/hwmon/dell-smm-hwmon.c
> @@ -449,12 +449,12 @@ static int i8k_get_power_status(void)
> * Procfs interface
> */
>
> -static int
> -i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd, unsigned long arg)
> +static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> {
> - int val = 0;
> - int speed, err;
> + struct dell_smm_data *data = PDE_DATA(file_inode(fp));
> int __user *argp = (int __user *)arg;
> + int speed, err;
> + int val = 0;
>
> if (!argp)
> return -EINVAL;
> @@ -516,11 +516,14 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
> if (copy_from_user(&speed, argp + 1, sizeof(int)))
> return -EFAULT;
>
> + mutex_lock(&data->i8k_mutex);
> err = i8k_set_fan(data, val, speed);
> - if (err < 0)
> + if (err < 0) {
> + mutex_unlock(&data->i8k_mutex);
> return err;
> -
> + }
> val = i8k_get_fan_status(data, val);
> + mutex_unlock(&data->i8k_mutex);
> break;
>
> default:
> @@ -536,18 +539,6 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
> return 0;
> }
>
> -static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> -{
> - struct dell_smm_data *data = PDE_DATA(file_inode(fp));
> - long ret;
> -
> - mutex_lock(&data->i8k_mutex);
> - ret = i8k_ioctl_unlocked(fp, data, cmd, arg);
> - mutex_unlock(&data->i8k_mutex);
> -
> - return ret;
> -}
> -
> /*
> * Print the information for /proc/i8k.
> */
> --
> 2.30.2
>

2021-11-22 17:55:36

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH 2/2] hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()

On 11/22/21 8:01 AM, Pali Rohár wrote:
> On Saturday 20 November 2021 18:03:19 Armin Wolf wrote:
>> The only purpose of i8k_ioctl() is to call i8k_ioctl_unlocked()
>> with i8k_mutex held. Judging from the hwmon code, this mutex
>> only needs to be held when setting the fan speed/mode.
>
> Really? I think that there is no difference between setting and getting
> fan speed/mode. At least I do not see why 'set' needs mutex and 'get' do
> not need it. Some more explanation is needed...
>
I8K_SET_FAN sets the fan speed and returns the current status. Without
locking, the returned status may not match or be associated with the previous
set operation.

Maybe that doesn't matter, and the synchronization is not needed. If so,
you can probably remove the locking entirely.

Guenter

2021-11-22 18:50:37

by Armin Wolf

[permalink] [raw]
Subject: Re: [PATCH 2/2] hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()


Am 22.11.21 um 18:55 schrieb Guenter Roeck:
> On 11/22/21 8:01 AM, Pali Rohár wrote:
>> On Saturday 20 November 2021 18:03:19 Armin Wolf wrote:
>>> The only purpose of i8k_ioctl() is to call i8k_ioctl_unlocked()
>>> with i8k_mutex held. Judging from the hwmon code, this mutex
>>> only needs to be held when setting the fan speed/mode.
>>
>> Really? I think that there is no difference between setting and getting
>> fan speed/mode. At least I do not see why 'set' needs mutex and 'get' do
>> not need it. Some more explanation is needed...
>>
> I8K_SET_FAN sets the fan speed and returns the current status. Without
> locking, the returned status may not match or be associated with the
> previous
> set operation.
>
> Maybe that doesn't matter, and the synchronization is not needed. If so,
> you can probably remove the locking entirely.
>
> Guenter

That is the reason i kept the locking code. Since i do not want to break
the ioctl interfacein any way, removing the locking code seems too risky
to me.

Armin


2021-11-22 19:10:16

by Pali Rohár

[permalink] [raw]
Subject: Re: [PATCH 2/2] hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()

On Monday 22 November 2021 19:50:14 Armin Wolf wrote:
> Am 22.11.21 um 18:55 schrieb Guenter Roeck:
> > On 11/22/21 8:01 AM, Pali Rohár wrote:
> > > On Saturday 20 November 2021 18:03:19 Armin Wolf wrote:
> > > > The only purpose of i8k_ioctl() is to call i8k_ioctl_unlocked()
> > > > with i8k_mutex held. Judging from the hwmon code, this mutex
> > > > only needs to be held when setting the fan speed/mode.
> > >
> > > Really? I think that there is no difference between setting and getting
> > > fan speed/mode. At least I do not see why 'set' needs mutex and 'get' do
> > > not need it. Some more explanation is needed...
> > >
> > I8K_SET_FAN sets the fan speed and returns the current status. Without
> > locking, the returned status may not match or be associated with the
> > previous
> > set operation.
> >
> > Maybe that doesn't matter, and the synchronization is not needed. If so,
> > you can probably remove the locking entirely.
> >
> > Guenter
>
> That is the reason i kept the locking code. Since i do not want to break
> the ioctl interfacein any way, removing the locking code seems too risky
> to me.

I see. That is a good point.

But there is same race condition also when at the same time going to
change speed via ioctl and also via hwmon sysfs.

2021-11-22 19:28:39

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH 2/2] hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()

On 11/22/21 11:10 AM, Pali Rohár wrote:
> On Monday 22 November 2021 19:50:14 Armin Wolf wrote:
>> Am 22.11.21 um 18:55 schrieb Guenter Roeck:
>>> On 11/22/21 8:01 AM, Pali Rohár wrote:
>>>> On Saturday 20 November 2021 18:03:19 Armin Wolf wrote:
>>>>> The only purpose of i8k_ioctl() is to call i8k_ioctl_unlocked()
>>>>> with i8k_mutex held. Judging from the hwmon code, this mutex
>>>>> only needs to be held when setting the fan speed/mode.
>>>>
>>>> Really? I think that there is no difference between setting and getting
>>>> fan speed/mode. At least I do not see why 'set' needs mutex and 'get' do
>>>> not need it. Some more explanation is needed...
>>>>
>>> I8K_SET_FAN sets the fan speed and returns the current status. Without
>>> locking, the returned status may not match or be associated with the
>>> previous
>>> set operation.
>>>
>>> Maybe that doesn't matter, and the synchronization is not needed. If so,
>>> you can probably remove the locking entirely.
>>>
>>> Guenter
>>
>> That is the reason i kept the locking code. Since i do not want to break
>> the ioctl interfacein any way, removing the locking code seems too risky
>> to me.
>
> I see. That is a good point.
>
> But there is same race condition also when at the same time going to
> change speed via ioctl and also via hwmon sysfs.
>

I thought the sysfs code does not change the fan speed and report the
fan status in the same request. Did I miss something ?

Guenter

2021-11-22 19:43:15

by Pali Rohár

[permalink] [raw]
Subject: Re: [PATCH 2/2] hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()

On Monday 22 November 2021 11:28:30 Guenter Roeck wrote:
> On 11/22/21 11:10 AM, Pali Rohár wrote:
> > On Monday 22 November 2021 19:50:14 Armin Wolf wrote:
> > > Am 22.11.21 um 18:55 schrieb Guenter Roeck:
> > > > On 11/22/21 8:01 AM, Pali Rohár wrote:
> > > > > On Saturday 20 November 2021 18:03:19 Armin Wolf wrote:
> > > > > > The only purpose of i8k_ioctl() is to call i8k_ioctl_unlocked()
> > > > > > with i8k_mutex held. Judging from the hwmon code, this mutex
> > > > > > only needs to be held when setting the fan speed/mode.
> > > > >
> > > > > Really? I think that there is no difference between setting and getting
> > > > > fan speed/mode. At least I do not see why 'set' needs mutex and 'get' do
> > > > > not need it. Some more explanation is needed...
> > > > >
> > > > I8K_SET_FAN sets the fan speed and returns the current status. Without
> > > > locking, the returned status may not match or be associated with the
> > > > previous
> > > > set operation.
> > > >
> > > > Maybe that doesn't matter, and the synchronization is not needed. If so,
> > > > you can probably remove the locking entirely.
> > > >
> > > > Guenter
> > >
> > > That is the reason i kept the locking code. Since i do not want to break
> > > the ioctl interfacein any way, removing the locking code seems too risky
> > > to me.
> >
> > I see. That is a good point.
> >
> > But there is same race condition also when at the same time going to
> > change speed via ioctl and also via hwmon sysfs.
> >
>
> I thought the sysfs code does not change the fan speed and report the
> fan status in the same request. Did I miss something ?

No. I mean something different. Let me to write trace call:

CPU 0: CPU 1:
1. dell_smm_write()
1. ioctl(I8K_SET_FAN)
2. i8k_set_fan()
2. i8k_set_fan()
3. i8k_get_fan_status()

So to ensure that i8k_get_fan_status() on CPU 0 returns value which
belongs to i8k_set_fan() from CPU 0 it is needed to still use mutex.

Armin is right here and I think that patch is correct.

2021-11-23 16:00:57

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH 2/2] hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()

On Mon, Nov 22, 2021 at 08:43:10PM +0100, Pali Roh?r wrote:
> On Monday 22 November 2021 11:28:30 Guenter Roeck wrote:
> > On 11/22/21 11:10 AM, Pali Roh?r wrote:
> > > On Monday 22 November 2021 19:50:14 Armin Wolf wrote:
> > > > Am 22.11.21 um 18:55 schrieb Guenter Roeck:
> > > > > On 11/22/21 8:01 AM, Pali Roh?r wrote:
> > > > > > On Saturday 20 November 2021 18:03:19 Armin Wolf wrote:
> > > > > > > The only purpose of i8k_ioctl() is to call i8k_ioctl_unlocked()
> > > > > > > with i8k_mutex held. Judging from the hwmon code, this mutex
> > > > > > > only needs to be held when setting the fan speed/mode.
> > > > > >
> > > > > > Really? I think that there is no difference between setting and getting
> > > > > > fan speed/mode. At least I do not see why 'set' needs mutex and 'get' do
> > > > > > not need it. Some more explanation is needed...
> > > > > >
> > > > > I8K_SET_FAN sets the fan speed and returns the current status. Without
> > > > > locking, the returned status may not match or be associated with the
> > > > > previous
> > > > > set operation.
> > > > >
> > > > > Maybe that doesn't matter, and the synchronization is not needed. If so,
> > > > > you can probably remove the locking entirely.
> > > > >
> > > > > Guenter
> > > >
> > > > That is the reason i kept the locking code. Since i do not want to break
> > > > the ioctl interfacein any way, removing the locking code seems too risky
> > > > to me.
> > >
> > > I see. That is a good point.
> > >
> > > But there is same race condition also when at the same time going to
> > > change speed via ioctl and also via hwmon sysfs.
> > >
> >
> > I thought the sysfs code does not change the fan speed and report the
> > fan status in the same request. Did I miss something ?
>
> No. I mean something different. Let me to write trace call:
>
> CPU 0: CPU 1:
> 1. dell_smm_write()
> 1. ioctl(I8K_SET_FAN)
> 2. i8k_set_fan()
> 2. i8k_set_fan()
> 3. i8k_get_fan_status()
>
> So to ensure that i8k_get_fan_status() on CPU 0 returns value which
> belongs to i8k_set_fan() from CPU 0 it is needed to still use mutex.
>
> Armin is right here and I think that patch is correct.

Quoting your earlier reply:

> Really? I think that there is no difference between setting and getting
> fan speed/mode. At least I do not see why 'set' needs mutex and 'get' do
> not need it. Some more explanation is needed...

This was the reason for my comment. Your latest reply is leaving me a bit
puzzled. If you are ok with the patch as-is, please provide a Reviewed-by:
or Acked-by: tag.

Thanks,
Guenter


2021-11-23 16:02:29

by Pali Rohár

[permalink] [raw]
Subject: Re: [PATCH 2/2] hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()

On Tuesday 23 November 2021 08:00:51 Guenter Roeck wrote:
> On Mon, Nov 22, 2021 at 08:43:10PM +0100, Pali Rohár wrote:
> > On Monday 22 November 2021 11:28:30 Guenter Roeck wrote:
> > > On 11/22/21 11:10 AM, Pali Rohár wrote:
> > > > On Monday 22 November 2021 19:50:14 Armin Wolf wrote:
> > > > > Am 22.11.21 um 18:55 schrieb Guenter Roeck:
> > > > > > On 11/22/21 8:01 AM, Pali Rohár wrote:
> > > > > > > On Saturday 20 November 2021 18:03:19 Armin Wolf wrote:
> > > > > > > > The only purpose of i8k_ioctl() is to call i8k_ioctl_unlocked()
> > > > > > > > with i8k_mutex held. Judging from the hwmon code, this mutex
> > > > > > > > only needs to be held when setting the fan speed/mode.
> > > > > > >
> > > > > > > Really? I think that there is no difference between setting and getting
> > > > > > > fan speed/mode. At least I do not see why 'set' needs mutex and 'get' do
> > > > > > > not need it. Some more explanation is needed...
> > > > > > >
> > > > > > I8K_SET_FAN sets the fan speed and returns the current status. Without
> > > > > > locking, the returned status may not match or be associated with the
> > > > > > previous
> > > > > > set operation.
> > > > > >
> > > > > > Maybe that doesn't matter, and the synchronization is not needed. If so,
> > > > > > you can probably remove the locking entirely.
> > > > > >
> > > > > > Guenter
> > > > >
> > > > > That is the reason i kept the locking code. Since i do not want to break
> > > > > the ioctl interfacein any way, removing the locking code seems too risky
> > > > > to me.
> > > >
> > > > I see. That is a good point.
> > > >
> > > > But there is same race condition also when at the same time going to
> > > > change speed via ioctl and also via hwmon sysfs.
> > > >
> > >
> > > I thought the sysfs code does not change the fan speed and report the
> > > fan status in the same request. Did I miss something ?
> >
> > No. I mean something different. Let me to write trace call:
> >
> > CPU 0: CPU 1:
> > 1. dell_smm_write()
> > 1. ioctl(I8K_SET_FAN)
> > 2. i8k_set_fan()
> > 2. i8k_set_fan()
> > 3. i8k_get_fan_status()
> >
> > So to ensure that i8k_get_fan_status() on CPU 0 returns value which
> > belongs to i8k_set_fan() from CPU 0 it is needed to still use mutex.
> >
> > Armin is right here and I think that patch is correct.
>
> Quoting your earlier reply:
>
> > Really? I think that there is no difference between setting and getting
> > fan speed/mode. At least I do not see why 'set' needs mutex and 'get' do
> > not need it. Some more explanation is needed...
>
> This was the reason for my comment. Your latest reply is leaving me a bit
> puzzled. If you are ok with the patch as-is, please provide a Reviewed-by:
> or Acked-by: tag.

Sorry for that. I should have explicitly wrote that I realized how it
works after Armin explained it.

2021-11-23 16:04:35

by Pali Rohár

[permalink] [raw]
Subject: Re: [PATCH 2/2] hwmon: (dell-smm) Unify i8k_ioctl() and i8k_ioctl_unlocked()

On Saturday 20 November 2021 18:03:19 Armin Wolf wrote:
> The only purpose of i8k_ioctl() is to call i8k_ioctl_unlocked()
> with i8k_mutex held. Judging from the hwmon code, this mutex
> only needs to be held when setting the fan speed/mode.
> Unify both functions and reduce the locking of i8k_mutex
> to I8K_SET_FAN.
>
> Tested on a Dell Inspiron 3505.
>
> Signed-off-by: Armin Wolf <[email protected]>

Maybe some more information in commit message could be useful, but now
it is in this email thread.

Anyway, change is correct, so:

Reviewed-by: Pali Rohár <[email protected]>

> ---
> drivers/hwmon/dell-smm-hwmon.c | 27 +++++++++------------------
> 1 file changed, 9 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
> index b5d1703faa62..e2d388f7360e 100644
> --- a/drivers/hwmon/dell-smm-hwmon.c
> +++ b/drivers/hwmon/dell-smm-hwmon.c
> @@ -449,12 +449,12 @@ static int i8k_get_power_status(void)
> * Procfs interface
> */
>
> -static int
> -i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd, unsigned long arg)
> +static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> {
> - int val = 0;
> - int speed, err;
> + struct dell_smm_data *data = PDE_DATA(file_inode(fp));
> int __user *argp = (int __user *)arg;
> + int speed, err;
> + int val = 0;
>
> if (!argp)
> return -EINVAL;
> @@ -516,11 +516,14 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
> if (copy_from_user(&speed, argp + 1, sizeof(int)))
> return -EFAULT;
>
> + mutex_lock(&data->i8k_mutex);
> err = i8k_set_fan(data, val, speed);
> - if (err < 0)
> + if (err < 0) {
> + mutex_unlock(&data->i8k_mutex);
> return err;
> -
> + }
> val = i8k_get_fan_status(data, val);
> + mutex_unlock(&data->i8k_mutex);
> break;
>
> default:
> @@ -536,18 +539,6 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
> return 0;
> }
>
> -static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
> -{
> - struct dell_smm_data *data = PDE_DATA(file_inode(fp));
> - long ret;
> -
> - mutex_lock(&data->i8k_mutex);
> - ret = i8k_ioctl_unlocked(fp, data, cmd, arg);
> - mutex_unlock(&data->i8k_mutex);
> -
> - return ret;
> -}
> -
> /*
> * Print the information for /proc/i8k.
> */
> --
> 2.30.2
>

2021-11-23 16:13:36

by Pali Rohár

[permalink] [raw]
Subject: Re: [PATCH 1/2] hwmon: (dell-smm) Simplify ioctl handler

On Saturday 20 November 2021 18:03:18 Armin Wolf wrote:
> The second switch-case has no real purpose:
>
> - for I8K_BIOS_VERSION, val does not represent a return value,
> making the check for error values unnecessary.
> - for I8K_MACHINE_ID, val remains zero, so the error check is
> unnecessary too.
>
> Remove the switch-case and move the calls to copy_to_user()
> into the first switch-case for I8K_BIOS_VERSION/_MACHINE_ID.
> Omit buff[] since data->machineid already contains the string

s/->machineid/->bios_machineid/

> with the necessary zero padding.

data is allocated by devm_kzalloc() so data->bios_machineid is really
zero padded.

> Tested on a Dell Inspiron 3505.
>
> Signed-off-by: Armin Wolf <[email protected]>
> ---
> drivers/hwmon/dell-smm-hwmon.c | 30 +++++++++---------------------
> 1 file changed, 9 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
> index 5596c211f38d..b5d1703faa62 100644
> --- a/drivers/hwmon/dell-smm-hwmon.c
> +++ b/drivers/hwmon/dell-smm-hwmon.c
> @@ -454,7 +454,6 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
> {
> int val = 0;
> int speed, err;
> - unsigned char buff[16];
> int __user *argp = (int __user *)arg;
>
> if (!argp)
> @@ -468,15 +467,19 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
>
> val = (data->bios_version[0] << 16) |
> (data->bios_version[1] << 8) | data->bios_version[2];
> - break;
>
> + if (copy_to_user(argp, &val, 4))
> + return -EFAULT;
> +
> + return 0;
> case I8K_MACHINE_ID:
> if (restricted && !capable(CAP_SYS_ADMIN))
> return -EPERM;
>
> - strscpy_pad(buff, data->bios_machineid, sizeof(buff));
> - break;
> + if (copy_to_user(argp, data->bios_machineid, 16))

What about usage of sizeof(data->bios_machineid) instead of hardcoded
constant 16? And maybe same for constant 4?

> + return -EFAULT;
>
> + return 0;
> case I8K_FN_STATUS:
> val = i8k_get_fn_status();
> break;
> @@ -527,23 +530,8 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
> if (val < 0)
> return val;
>
> - switch (cmd) {
> - case I8K_BIOS_VERSION:
> - if (copy_to_user(argp, &val, 4))
> - return -EFAULT;
> -
> - break;
> - case I8K_MACHINE_ID:
> - if (copy_to_user(argp, buff, 16))
> - return -EFAULT;
> -
> - break;
> - default:
> - if (copy_to_user(argp, &val, sizeof(int)))
> - return -EFAULT;
> -
> - break;
> - }
> + if (copy_to_user(argp, &val, sizeof(int)))
> + return -EFAULT;
>
> return 0;
> }
> --
> 2.30.2
>

2021-11-29 21:00:02

by Armin Wolf

[permalink] [raw]
Subject: Re: [PATCH 1/2] hwmon: (dell-smm) Simplify ioctl handler

Am 23.11.21 um 17:13 schrieb Pali Rohár:

> On Saturday 20 November 2021 18:03:18 Armin Wolf wrote:
>> The second switch-case has no real purpose:
>>
>> - for I8K_BIOS_VERSION, val does not represent a return value,
>> making the check for error values unnecessary.
>> - for I8K_MACHINE_ID, val remains zero, so the error check is
>> unnecessary too.
>>
>> Remove the switch-case and move the calls to copy_to_user()
>> into the first switch-case for I8K_BIOS_VERSION/_MACHINE_ID.
>> Omit buff[] since data->machineid already contains the string
> s/->machineid/->bios_machineid/
>
>> with the necessary zero padding.
> data is allocated by devm_kzalloc() so data->bios_machineid is really
> zero padded.
>
>> Tested on a Dell Inspiron 3505.
>>
>> Signed-off-by: Armin Wolf <[email protected]>
>> ---
>> drivers/hwmon/dell-smm-hwmon.c | 30 +++++++++---------------------
>> 1 file changed, 9 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
>> index 5596c211f38d..b5d1703faa62 100644
>> --- a/drivers/hwmon/dell-smm-hwmon.c
>> +++ b/drivers/hwmon/dell-smm-hwmon.c
>> @@ -454,7 +454,6 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
>> {
>> int val = 0;
>> int speed, err;
>> - unsigned char buff[16];
>> int __user *argp = (int __user *)arg;
>>
>> if (!argp)
>> @@ -468,15 +467,19 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
>>
>> val = (data->bios_version[0] << 16) |
>> (data->bios_version[1] << 8) | data->bios_version[2];
>> - break;
>>
>> + if (copy_to_user(argp, &val, 4))
>> + return -EFAULT;
>> +
>> + return 0;
>> case I8K_MACHINE_ID:
>> if (restricted && !capable(CAP_SYS_ADMIN))
>> return -EPERM;
>>
>> - strscpy_pad(buff, data->bios_machineid, sizeof(buff));
>> - break;
>> + if (copy_to_user(argp, data->bios_machineid, 16))
> What about usage of sizeof(data->bios_machineid) instead of hardcoded
> constant 16? And maybe same for constant 4?

For the string yes, but maybe i should change the int to an u32?

>> + return -EFAULT;
>>
>> + return 0;
>> case I8K_FN_STATUS:
>> val = i8k_get_fn_status();
>> break;
>> @@ -527,23 +530,8 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
>> if (val < 0)
>> return val;
>>
>> - switch (cmd) {
>> - case I8K_BIOS_VERSION:
>> - if (copy_to_user(argp, &val, 4))
>> - return -EFAULT;
>> -
>> - break;
>> - case I8K_MACHINE_ID:
>> - if (copy_to_user(argp, buff, 16))
>> - return -EFAULT;
>> -
>> - break;
>> - default:
>> - if (copy_to_user(argp, &val, sizeof(int)))
>> - return -EFAULT;
>> -
>> - break;
>> - }
>> + if (copy_to_user(argp, &val, sizeof(int)))
>> + return -EFAULT;
>>
>> return 0;
>> }
>> --
>> 2.30.2
>>

2021-12-09 16:52:16

by Pali Rohár

[permalink] [raw]
Subject: Re: [PATCH 1/2] hwmon: (dell-smm) Simplify ioctl handler

On Monday 29 November 2021 21:57:40 Armin Wolf wrote:
> Am 23.11.21 um 17:13 schrieb Pali Rohár:
>
> > On Saturday 20 November 2021 18:03:18 Armin Wolf wrote:
> > > The second switch-case has no real purpose:
> > >
> > > - for I8K_BIOS_VERSION, val does not represent a return value,
> > > making the check for error values unnecessary.
> > > - for I8K_MACHINE_ID, val remains zero, so the error check is
> > > unnecessary too.
> > >
> > > Remove the switch-case and move the calls to copy_to_user()
> > > into the first switch-case for I8K_BIOS_VERSION/_MACHINE_ID.
> > > Omit buff[] since data->machineid already contains the string
> > s/->machineid/->bios_machineid/
> >
> > > with the necessary zero padding.
> > data is allocated by devm_kzalloc() so data->bios_machineid is really
> > zero padded.
> >
> > > Tested on a Dell Inspiron 3505.
> > >
> > > Signed-off-by: Armin Wolf <[email protected]>
> > > ---
> > > drivers/hwmon/dell-smm-hwmon.c | 30 +++++++++---------------------
> > > 1 file changed, 9 insertions(+), 21 deletions(-)
> > >
> > > diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
> > > index 5596c211f38d..b5d1703faa62 100644
> > > --- a/drivers/hwmon/dell-smm-hwmon.c
> > > +++ b/drivers/hwmon/dell-smm-hwmon.c
> > > @@ -454,7 +454,6 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
> > > {
> > > int val = 0;
> > > int speed, err;
> > > - unsigned char buff[16];
> > > int __user *argp = (int __user *)arg;
> > >
> > > if (!argp)
> > > @@ -468,15 +467,19 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
> > >
> > > val = (data->bios_version[0] << 16) |
> > > (data->bios_version[1] << 8) | data->bios_version[2];
> > > - break;
> > >
> > > + if (copy_to_user(argp, &val, 4))
> > > + return -EFAULT;
> > > +
> > > + return 0;
> > > case I8K_MACHINE_ID:
> > > if (restricted && !capable(CAP_SYS_ADMIN))
> > > return -EPERM;
> > >
> > > - strscpy_pad(buff, data->bios_machineid, sizeof(buff));
> > > - break;
> > > + if (copy_to_user(argp, data->bios_machineid, 16))
> > What about usage of sizeof(data->bios_machineid) instead of hardcoded
> > constant 16? And maybe same for constant 4?
>
> For the string yes, but maybe i should change the int to an u32?

I do not know if changing int to u32 should be done or not...

> > > + return -EFAULT;
> > >
> > > + return 0;
> > > case I8K_FN_STATUS:
> > > val = i8k_get_fn_status();
> > > break;
> > > @@ -527,23 +530,8 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
> > > if (val < 0)
> > > return val;
> > >
> > > - switch (cmd) {
> > > - case I8K_BIOS_VERSION:
> > > - if (copy_to_user(argp, &val, 4))
> > > - return -EFAULT;
> > > -
> > > - break;
> > > - case I8K_MACHINE_ID:
> > > - if (copy_to_user(argp, buff, 16))
> > > - return -EFAULT;
> > > -
> > > - break;
> > > - default:
> > > - if (copy_to_user(argp, &val, sizeof(int)))
> > > - return -EFAULT;
> > > -
> > > - break;
> > > - }
> > > + if (copy_to_user(argp, &val, sizeof(int)))
> > > + return -EFAULT;
> > >
> > > return 0;
> > > }
> > > --
> > > 2.30.2
> > >