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

cxl/acpi: Add root device lockdep validation

The CXL "root" device, ACPI0017, is an attach point for coordinating
platform level CXL resources and is the parent device for a CXL port
topology tree. As such it has distinct locking rules relative to other
CXL subsystem objects, but because it is an ACPI device the lock class
is established well before it is given to the cxl_acpi driver.

However, the lockdep API does support changing the lock class "live" for
situations like this. Add a device_lock_set_class() helper that a driver
can use in ->probe() to set a custom lock class, and
device_lock_reset_class() to return to the default "no validate" class
before the custom lock class key goes out of scope after ->remove().

Note the helpers are all macros to support dead code elimination in the
CONFIG_PROVE_LOCKING=n case, however device_set_lock_class() still needs
#ifdef CONFIG_PROVE_LOCKING since lockdep_match_class() explicitly does
not have a helper in the CONFIG_PROVE_LOCKING=n case (see comment in
lockdep.h). The lockdep API needs 2 small tweaks to prevent "unused"
warnings for the @key argument to lock_set_class(), and a new
lock_set_novalidate_class() is added to supplement
lockdep_set_novalidate_class() in the cases where the lock class is
converted while the lock is held.

Suggested-by: Peter Zijlstra <peterz@infradead.org>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Will Deacon <will@kernel.org>
Cc: Waiman Long <longman@redhat.com>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Alison Schofield <alison.schofield@intel.com>
Cc: Vishal Verma <vishal.l.verma@intel.com>
Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Link: https://lore.kernel.org/r/165100081305.1528964.11138612430659737238.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+61 -1
+13
drivers/cxl/acpi.c
··· 275 275 return 1; 276 276 } 277 277 278 + static struct lock_class_key cxl_root_key; 279 + 280 + static void cxl_acpi_lock_reset_class(void *dev) 281 + { 282 + device_lock_reset_class(dev); 283 + } 284 + 278 285 static int cxl_acpi_probe(struct platform_device *pdev) 279 286 { 280 287 int rc; ··· 289 282 struct device *host = &pdev->dev; 290 283 struct acpi_device *adev = ACPI_COMPANION(host); 291 284 struct cxl_cfmws_context ctx; 285 + 286 + device_lock_set_class(&pdev->dev, &cxl_root_key); 287 + rc = devm_add_action_or_reset(&pdev->dev, cxl_acpi_lock_reset_class, 288 + &pdev->dev); 289 + if (rc) 290 + return rc; 292 291 293 292 root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL); 294 293 if (IS_ERR(root_port))
+43
include/linux/device.h
··· 850 850 return dev->bus && dev->bus->offline && dev->bus->online; 851 851 } 852 852 853 + #define __device_lock_set_class(dev, name, key) \ 854 + do { \ 855 + struct device *__d2 __maybe_unused = dev; \ 856 + lock_set_class(&__d2->mutex.dep_map, name, key, 0, _THIS_IP_); \ 857 + } while (0) 858 + 859 + /** 860 + * device_lock_set_class - Specify a temporary lock class while a device 861 + * is attached to a driver 862 + * @dev: device to modify 863 + * @key: lock class key data 864 + * 865 + * This must be called with the device_lock() already held, for example 866 + * from driver ->probe(). Take care to only override the default 867 + * lockdep_no_validate class. 868 + */ 869 + #ifdef CONFIG_LOCKDEP 870 + #define device_lock_set_class(dev, key) \ 871 + do { \ 872 + struct device *__d = dev; \ 873 + dev_WARN_ONCE(__d, !lockdep_match_class(&__d->mutex, \ 874 + &__lockdep_no_validate__), \ 875 + "overriding existing custom lock class\n"); \ 876 + __device_lock_set_class(__d, #key, key); \ 877 + } while (0) 878 + #else 879 + #define device_lock_set_class(dev, key) __device_lock_set_class(dev, #key, key) 880 + #endif 881 + 882 + /** 883 + * device_lock_reset_class - Return a device to the default lockdep novalidate state 884 + * @dev: device to modify 885 + * 886 + * This must be called with the device_lock() already held, for example 887 + * from driver ->remove(). 888 + */ 889 + #define device_lock_reset_class(dev) \ 890 + do { \ 891 + struct device *__d __maybe_unused = dev; \ 892 + lock_set_novalidate_class(&__d->mutex.dep_map, "&dev->mutex", \ 893 + _THIS_IP_); \ 894 + } while (0) 895 + 853 896 void lock_device_hotplug(void); 854 897 void unlock_device_hotplug(void); 855 898 int lock_device_hotplug_sysfs(void);
+5 -1
include/linux/lockdep.h
··· 290 290 struct lock_class_key *key, unsigned int subclass, 291 291 unsigned long ip); 292 292 293 + #define lock_set_novalidate_class(l, n, i) \ 294 + lock_set_class(l, n, &__lockdep_no_validate__, 0, i) 295 + 293 296 static inline void lock_set_subclass(struct lockdep_map *lock, 294 297 unsigned int subclass, unsigned long ip) 295 298 { ··· 360 357 # define lock_acquire(l, s, t, r, c, n, i) do { } while (0) 361 358 # define lock_release(l, i) do { } while (0) 362 359 # define lock_downgrade(l, i) do { } while (0) 363 - # define lock_set_class(l, n, k, s, i) do { } while (0) 360 + # define lock_set_class(l, n, key, s, i) do { (void)(key); } while (0) 361 + # define lock_set_novalidate_class(l, n, i) do { } while (0) 364 362 # define lock_set_subclass(l, s, i) do { } while (0) 365 363 # define lockdep_init() do { } while (0) 366 364 # define lockdep_init_map_type(lock, name, key, sub, inner, outer, type) \