Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

hwmon: Serialize accesses in hwmon core

Implement locking in the hardware monitoring core for drivers using
the _with_info() API functions.

Most hardware monitoring drivers need to support locking to protect
against parallel accesses from userspace. With older API functions, such
locking had to be implemented in the driver code since sysfs attributes
were created by the driver. However, the _with_info() API creates sysfs
attributes in the hardware monitoring core. This makes it easy to move
the locking primitives into that code. This has the benefit of simplifying
driver code while at the same time reducing the risk of incomplete of bad
locking implementations in hardware monitoring drivers.

While this means that all accesses are forced to be synchronized, this
has little if any practical impact since accesses are expected to be low
frequency and are typically synchronized from userspace anyway since
only a single process is accessing the data. On top of that, many drivers
use regmap, which also has its own locking scheme and already serializes
accesses.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>

+48 -7
+10
Documentation/hwmon/hwmon-kernel-api.rst
··· 42 42 43 43 char *devm_hwmon_sanitize_name(struct device *dev, const char *name); 44 44 45 + void hwmon_lock(struct device *dev); 46 + void hwmon_unlock(struct device *dev); 47 + 45 48 hwmon_device_register_with_info registers a hardware monitoring device. 46 49 It creates the standard sysfs attributes in the hardware monitoring core, 47 50 letting the driver focus on reading from and writing to the chip instead ··· 81 78 devm_hwmon_sanitize_name is the resource managed version of 82 79 hwmon_sanitize_name; the memory will be freed automatically on device 83 80 removal. 81 + 82 + When using ``[devm_]hwmon_device_register_with_info()`` to register the 83 + hardware monitoring device, accesses using the associated access functions 84 + are serialised by the hardware monitoring core. If a driver needs locking 85 + for other functions such as interrupt handlers or for attributes which are 86 + fully implemented in the driver, hwmon_lock() and hwmon_unlock() can be used 87 + to ensure that calls to those functions are serialized. 84 88 85 89 Using devm_hwmon_device_register_with_info() 86 90 --------------------------------------------
+35 -7
drivers/hwmon/hwmon.c
··· 19 19 #include <linux/kstrtox.h> 20 20 #include <linux/list.h> 21 21 #include <linux/module.h> 22 + #include <linux/mutex.h> 22 23 #include <linux/pci.h> 23 24 #include <linux/property.h> 24 25 #include <linux/slab.h> ··· 37 36 const char *label; 38 37 struct device dev; 39 38 const struct hwmon_chip_info *chip; 39 + struct mutex lock; 40 40 struct list_head tzdata; 41 41 struct attribute_group group; 42 42 const struct attribute_group **groups; ··· 167 165 int ret; 168 166 long t; 169 167 168 + guard(mutex)(&hwdev->lock); 169 + 170 170 ret = hwdev->chip->ops->read(tdata->dev, hwmon_temp, hwmon_temp_input, 171 171 tdata->index, &t); 172 172 if (ret < 0) ··· 196 192 197 193 if (!info[i]) 198 194 return 0; 195 + 196 + guard(mutex)(&hwdev->lock); 199 197 200 198 if (info[i]->config[tdata->index] & HWMON_T_MIN) { 201 199 err = chip->ops->write(tdata->dev, hwmon_temp, ··· 336 330 * attached to an i2c client device. 337 331 */ 338 332 339 - static DEFINE_MUTEX(hwmon_pec_mutex); 340 - 341 333 static int hwmon_match_device(struct device *dev, const void *data) 342 334 { 343 335 return dev->class == &hwmon_class; ··· 366 362 if (!hdev) 367 363 return -ENODEV; 368 364 369 - mutex_lock(&hwmon_pec_mutex); 370 - 371 365 /* 372 366 * If there is no write function, we assume that chip specific 373 367 * handling is not required. 374 368 */ 375 369 hwdev = to_hwmon_device(hdev); 370 + guard(mutex)(&hwdev->lock); 376 371 if (hwdev->chip->ops->write) { 377 372 err = hwdev->chip->ops->write(hdev, hwmon_chip, hwmon_chip_pec, 0, val); 378 373 if (err && err != -EOPNOTSUPP) 379 - goto unlock; 374 + goto put; 380 375 } 381 376 382 377 if (!val) ··· 384 381 client->flags |= I2C_CLIENT_PEC; 385 382 386 383 err = count; 387 - unlock: 388 - mutex_unlock(&hwmon_pec_mutex); 384 + put: 389 385 put_device(hdev); 390 386 391 387 return err; ··· 428 426 struct device_attribute *devattr, char *buf) 429 427 { 430 428 struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); 429 + struct hwmon_device *hwdev = to_hwmon_device(dev); 431 430 s64 val64; 432 431 long val; 433 432 int ret; 433 + 434 + guard(mutex)(&hwdev->lock); 434 435 435 436 ret = hattr->ops->read(dev, hattr->type, hattr->attr, hattr->index, 436 437 (hattr->type == hwmon_energy64) ? (long *)&val64 : &val); ··· 454 449 char *buf) 455 450 { 456 451 struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); 452 + struct hwmon_device *hwdev = to_hwmon_device(dev); 457 453 enum hwmon_sensor_types type = hattr->type; 458 454 const char *s; 459 455 int ret; 456 + 457 + guard(mutex)(&hwdev->lock); 460 458 461 459 ret = hattr->ops->read_string(dev, hattr->type, hattr->attr, 462 460 hattr->index, &s); ··· 477 469 const char *buf, size_t count) 478 470 { 479 471 struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); 472 + struct hwmon_device *hwdev = to_hwmon_device(dev); 480 473 long val; 481 474 int ret; 482 475 483 476 ret = kstrtol(buf, 10, &val); 484 477 if (ret < 0) 485 478 return ret; 479 + 480 + guard(mutex)(&hwdev->lock); 486 481 487 482 ret = hattr->ops->write(dev, hattr->type, hattr->attr, hattr->index, 488 483 val); ··· 802 791 } 803 792 EXPORT_SYMBOL_GPL(hwmon_notify_event); 804 793 794 + void hwmon_lock(struct device *dev) 795 + { 796 + struct hwmon_device *hwdev = to_hwmon_device(dev); 797 + 798 + mutex_lock(&hwdev->lock); 799 + } 800 + EXPORT_SYMBOL_GPL(hwmon_lock); 801 + 802 + void hwmon_unlock(struct device *dev) 803 + { 804 + struct hwmon_device *hwdev = to_hwmon_device(dev); 805 + 806 + mutex_unlock(&hwdev->lock); 807 + } 808 + EXPORT_SYMBOL_GPL(hwmon_unlock); 809 + 805 810 static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info) 806 811 { 807 812 int i, n; ··· 978 951 tdev = tdev->parent; 979 952 hdev->of_node = tdev ? tdev->of_node : NULL; 980 953 hwdev->chip = chip; 954 + mutex_init(&hwdev->lock); 981 955 dev_set_drvdata(hdev, drvdata); 982 956 dev_set_name(hdev, HWMON_ID_FORMAT, id); 983 957 err = device_register(hdev);
+3
include/linux/hwmon.h
··· 492 492 char *hwmon_sanitize_name(const char *name); 493 493 char *devm_hwmon_sanitize_name(struct device *dev, const char *name); 494 494 495 + void hwmon_lock(struct device *dev); 496 + void hwmon_unlock(struct device *dev); 497 + 495 498 /** 496 499 * hwmon_is_bad_char - Is the char invalid in a hwmon name 497 500 * @ch: the char to be considered