From: Jonas Malaco <jonas@protocubo.io>
To: Jean Delvare <jdelvare@suse.com>, Guenter Roeck <linux@roeck-us.net>
Cc: Jonas Malaco <jonas@protocubo.io>,
linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] hwmon: (nzxt-kraken2) mark and order concurrent accesses
Date: Mon, 29 Mar 2021 05:22:01 -0300 [thread overview]
Message-ID: <20210329082211.86716-1-jonas@protocubo.io> (raw)
To avoid a spinlock, the driver explores concurrent memory accesses
between _raw_event and _read, having the former updating fields on a
data structure while the latter could be reading from them. Because
these are "plain" accesses, those are data races according to the Linux
kernel memory model (LKMM).
Data races are undefined behavior in both C11 and LKMM. In practice,
the compiler is free to make optimizations assuming there is no data
race, including load tearing, load fusing and many others,[1] most of
which could result in corruption of the values reported to user-space.
Prevent undesirable optimizations to those concurrent accesses by
marking them with READ_ONCE() and WRITE_ONCE(). This also removes the
data races, according to the LKMM, because both loads and stores to each
location are now "marked" accesses.
As a special case, use smp_load_acquire() and smp_load_release() when
loading and storing ->updated, as it is used to track the validity of
the other values, and thus has to be stored after and loaded before
them. These imply READ_ONCE()/WRITE_ONCE() but also ensure the desired
order of memory accesses.
[1] https://lwn.net/Articles/793253/
Signed-off-by: Jonas Malaco <jonas@protocubo.io>
---
drivers/hwmon/nzxt-kraken2.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/hwmon/nzxt-kraken2.c b/drivers/hwmon/nzxt-kraken2.c
index 89f7ea4f42d4..f4fbc8771930 100644
--- a/drivers/hwmon/nzxt-kraken2.c
+++ b/drivers/hwmon/nzxt-kraken2.c
@@ -46,16 +46,22 @@ static int kraken2_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct kraken2_priv_data *priv = dev_get_drvdata(dev);
+ unsigned long expires;
- if (time_after(jiffies, priv->updated + STATUS_VALIDITY * HZ))
+ /*
+ * Order load from ->updated before the data it refers to.
+ */
+ expires = smp_load_acquire(&priv->updated) + STATUS_VALIDITY * HZ;
+
+ if (time_after(jiffies, expires))
return -ENODATA;
switch (type) {
case hwmon_temp:
- *val = priv->temp_input[channel];
+ *val = READ_ONCE(priv->temp_input[channel]);
break;
case hwmon_fan:
- *val = priv->fan_input[channel];
+ *val = READ_ONCE(priv->fan_input[channel]);
break;
default:
return -EOPNOTSUPP; /* unreachable */
@@ -119,12 +125,15 @@ static int kraken2_raw_event(struct hid_device *hdev,
* and that the missing steps are artifacts of how the firmware
* processes the raw sensor data.
*/
- priv->temp_input[0] = data[1] * 1000 + data[2] * 100;
+ WRITE_ONCE(priv->temp_input[0], data[1] * 1000 + data[2] * 100);
- priv->fan_input[0] = get_unaligned_be16(data + 3);
- priv->fan_input[1] = get_unaligned_be16(data + 5);
+ WRITE_ONCE(priv->fan_input[0], get_unaligned_be16(data + 3));
+ WRITE_ONCE(priv->fan_input[1], get_unaligned_be16(data + 5));
- priv->updated = jiffies;
+ /*
+ * Order store to ->updated after the data it refers to.
+ */
+ smp_store_release(&priv->updated, jiffies);
return 0;
}
base-commit: 644b9af5c605762feffac96bd7ea2499e0197656
--
2.31.1
next reply other threads:[~2021-03-29 8:38 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-03-29 8:22 Jonas Malaco [this message]
2021-03-29 21:53 ` Guenter Roeck
2021-03-30 0:21 ` Jonas Malaco
2021-03-30 1:01 ` Guenter Roeck
2021-03-30 3:16 ` Jonas Malaco
2021-03-30 5:43 ` Guenter Roeck
2021-03-30 6:27 ` Jonas Malaco
2021-03-30 10:51 ` Guenter Roeck
2021-03-30 17:53 ` Jonas Malaco
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210329082211.86716-1-jonas@protocubo.io \
--to=jonas@protocubo.io \
--cc=jdelvare@suse.com \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@roeck-us.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®