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.

Merge tag 'driver-core-6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core

Pull driver core and debugfs updates from Greg KH:
"Here is the big set of driver core and debugfs updates for 6.14-rc1.

Included in here is a bunch of driver core, PCI, OF, and platform rust
bindings (all acked by the different subsystem maintainers), hence the
merge conflict with the rust tree, and some driver core api updates to
mark things as const, which will also require some fixups due to new
stuff coming in through other trees in this merge window.

There are also a bunch of debugfs updates from Al, and there is at
least one user that does have a regression with these, but Al is
working on tracking down the fix for it. In my use (and everyone
else's linux-next use), it does not seem like a big issue at the
moment.

Here's a short list of the things in here:

- driver core rust bindings for PCI, platform, OF, and some i/o
functions.

We are almost at the "write a real driver in rust" stage now,
depending on what you want to do.

- misc device rust bindings and a sample driver to show how to use
them

- debugfs cleanups in the fs as well as the users of the fs api for
places where drivers got it wrong or were unnecessarily doing
things in complex ways.

- driver core const work, making more of the api take const * for
different parameters to make the rust bindings easier overall.

- other small fixes and updates

All of these have been in linux-next with all of the aforementioned
merge conflicts, and the one debugfs issue, which looks to be resolved
"soon""

* tag 'driver-core-6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (95 commits)
rust: device: Use as_char_ptr() to avoid explicit cast
rust: device: Replace CString with CStr in property_present()
devcoredump: Constify 'struct bin_attribute'
devcoredump: Define 'struct bin_attribute' through macro
rust: device: Add property_present()
saner replacement for debugfs_rename()
orangefs-debugfs: don't mess with ->d_name
octeontx2: don't mess with ->d_parent or ->d_parent->d_name
arm_scmi: don't mess with ->d_parent->d_name
slub: don't mess with ->d_name
sof-client-ipc-flood-test: don't mess with ->d_name
qat: don't mess with ->d_name
xhci: don't mess with ->d_iname
mtu3: don't mess wiht ->d_iname
greybus/camera - stop messing with ->d_iname
mediatek: stop messing with ->d_iname
netdevsim: don't embed file_operations into your structs
b43legacy: make use of debugfs_get_aux()
b43: stop embedding struct file_operations into their objects
carl9170: stop embedding file_operations into their objects
...

+3255 -995
+5 -7
Documentation/filesystems/debugfs.rst
··· 211 211 212 212 There are a couple of other directory-oriented helper functions:: 213 213 214 - struct dentry *debugfs_rename(struct dentry *old_dir, 215 - struct dentry *old_dentry, 216 - struct dentry *new_dir, 217 - const char *new_name); 214 + struct dentry *debugfs_change_name(struct dentry *dentry, 215 + const char *fmt, ...); 218 216 219 217 struct dentry *debugfs_create_symlink(const char *name, 220 218 struct dentry *parent, 221 219 const char *target); 222 220 223 - A call to debugfs_rename() will give a new name to an existing debugfs 224 - file, possibly in a different directory. The new_name must not exist prior 225 - to the call; the return value is old_dentry with updated information. 221 + A call to debugfs_change_name() will give a new name to an existing debugfs 222 + file, always in the same directory. The new_name must not exist prior 223 + to the call; the return value is 0 on success and -E... on failuer. 226 224 Symbolic links can be created with debugfs_create_symlink(). 227 225 228 226 There is one important thing that all debugfs users must take into account:
+1
Documentation/userspace-api/ioctl/ioctl-number.rst
··· 312 312 <mailto:oe@port.de> 313 313 'z' 10-4F drivers/s390/crypto/zcrypt_api.h conflict! 314 314 '|' 00-7F linux/media.h 315 + '|' 80-9F samples/ Any sample and example drivers 315 316 0x80 00-1F linux/fb.h 316 317 0x81 00-1F linux/vduse.h 317 318 0x89 00-06 arch/x86/include/asm/sockios.h
+12
MAINTAINERS
··· 5366 5366 F: drivers/char/ 5367 5367 F: drivers/misc/ 5368 5368 F: include/linux/miscdevice.h 5369 + F: samples/rust/rust_misc_device.rs 5369 5370 X: drivers/char/agp/ 5370 5371 X: drivers/char/hw_random/ 5371 5372 X: drivers/char/ipmi/ ··· 7092 7091 DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS 7093 7092 M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 7094 7093 R: "Rafael J. Wysocki" <rafael@kernel.org> 7094 + R: Danilo Krummrich <dakr@kernel.org> 7095 7095 S: Supported 7096 7096 T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git 7097 7097 F: Documentation/core-api/kobject.rst ··· 7103 7101 F: include/linux/fwnode.h 7104 7102 F: include/linux/kobj* 7105 7103 F: include/linux/property.h 7104 + F: include/linux/sysfs.h 7106 7105 F: lib/kobj* 7107 7106 F: rust/kernel/device.rs 7107 + F: rust/kernel/device_id.rs 7108 + F: rust/kernel/devres.rs 7109 + F: rust/kernel/driver.rs 7110 + F: rust/kernel/platform.rs 7111 + F: samples/rust/rust_driver_platform.rs 7108 7112 7109 7113 DRIVERS FOR OMAP ADAPTIVE VOLTAGE SCALING (AVS) 7110 7114 M: Nishanth Menon <nm@ti.com> ··· 17640 17632 F: Documentation/ABI/testing/sysfs-firmware-ofw 17641 17633 F: drivers/of/ 17642 17634 F: include/linux/of*.h 17635 + F: rust/kernel/of.rs 17643 17636 F: scripts/dtc/ 17644 17637 F: tools/testing/selftests/dt/ 17645 17638 K: of_overlay_notifier_ ··· 18241 18232 F: include/linux/of_pci.h 18242 18233 F: include/linux/pci* 18243 18234 F: include/uapi/linux/pci* 18235 + F: rust/kernel/pci.rs 18236 + F: samples/rust/rust_driver_pci.rs 18244 18237 18245 18238 PCIE BANDWIDTH CONTROLLER 18246 18239 M: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> ··· 19841 19830 F: Documentation/RCU/ 19842 19831 F: include/linux/rcu* 19843 19832 F: kernel/rcu/ 19833 + F: rust/kernel/sync/rcu.rs 19844 19834 X: Documentation/RCU/torture.rst 19845 19835 X: include/linux/srcu*.h 19846 19836 X: kernel/rcu/srcu*.c
+1 -1
arch/arm/include/asm/ecard.h
··· 195 195 unsigned long offset, unsigned long maxsize); 196 196 #define ecardm_iounmap(__ec, __addr) devm_iounmap(&(__ec)->dev, __addr) 197 197 198 - extern struct bus_type ecard_bus_type; 198 + extern const struct bus_type ecard_bus_type; 199 199 200 200 #define ECARD_DEV(_d) container_of((_d), struct expansion_card, dev) 201 201
+1 -1
arch/arm/mach-rpc/ecard.c
··· 1124 1124 return ret; 1125 1125 } 1126 1126 1127 - struct bus_type ecard_bus_type = { 1127 + const struct bus_type ecard_bus_type = { 1128 1128 .name = "ecard", 1129 1129 .dev_groups = ecard_dev_groups, 1130 1130 .match = ecard_match,
+1 -1
arch/powerpc/platforms/powernv/opal.c
··· 815 815 sysfs_bin_attr_init(attr); 816 816 attr->attr.name = name; 817 817 attr->attr.mode = 0400; 818 - attr->read = sysfs_bin_attr_simple_read; 818 + attr->read_new = sysfs_bin_attr_simple_read; 819 819 attr->private = __va(vals[0]); 820 820 attr->size = vals[1]; 821 821
+3 -3
arch/sparc/kernel/vio.c
··· 419 419 u64 node; 420 420 }; 421 421 422 - static int vio_md_node_match(struct device *dev, void *arg) 422 + static int vio_md_node_match(struct device *dev, const void *arg) 423 423 { 424 424 struct vio_dev *vdev = to_vio_dev(dev); 425 - struct vio_remove_node_data *node_data; 425 + const struct vio_remove_node_data *node_data; 426 426 u64 node; 427 427 428 - node_data = (struct vio_remove_node_data *)arg; 428 + node_data = (const struct vio_remove_node_data *)arg; 429 429 430 430 node = vio_vdev_node(node_data->hp, vdev); 431 431
+1
block/blk-cgroup.c
··· 1138 1138 blkg_iostat_set(&blkg->iostat.cur, &tmp); 1139 1139 u64_stats_update_end_irqrestore(&blkg->iostat.sync, flags); 1140 1140 } 1141 + class_dev_iter_exit(&iter); 1141 1142 } 1142 1143 1143 1144 static void blkcg_print_one_stat(struct blkcg_gq *blkg, struct seq_file *s)
+6 -3
drivers/base/bus.c
··· 354 354 * count in the supplied callback. 355 355 */ 356 356 int bus_for_each_dev(const struct bus_type *bus, struct device *start, 357 - void *data, int (*fn)(struct device *, void *)) 357 + void *data, device_iter_t fn) 358 358 { 359 359 struct subsys_private *sp = bus_to_subsys(bus); 360 360 struct klist_iter i; ··· 402 402 403 403 klist_iter_init_node(&sp->klist_devices, &i, 404 404 (start ? &start->p->knode_bus : NULL)); 405 - while ((dev = next_device(&i))) 406 - if (match(dev, data) && get_device(dev)) 405 + while ((dev = next_device(&i))) { 406 + if (match(dev, data)) { 407 + get_device(dev); 407 408 break; 409 + } 410 + } 408 411 klist_iter_exit(&i); 409 412 subsys_put(sp); 410 413 return dev;
+12 -30
drivers/base/class.c
··· 323 323 struct subsys_private *sp = class_to_subsys(class); 324 324 struct klist_node *start_knode = NULL; 325 325 326 - if (!sp) 326 + memset(iter, 0, sizeof(*iter)); 327 + if (!sp) { 328 + pr_crit("%s: class %p was not registered yet\n", 329 + __func__, class); 327 330 return; 331 + } 328 332 329 333 if (start) 330 334 start_knode = &start->p->knode_class; ··· 354 350 { 355 351 struct klist_node *knode; 356 352 struct device *dev; 353 + 354 + if (!iter->sp) 355 + return NULL; 357 356 358 357 while (1) { 359 358 knode = klist_next(&iter->ki); ··· 402 395 * code. There's no locking restriction. 403 396 */ 404 397 int class_for_each_device(const struct class *class, const struct device *start, 405 - void *data, int (*fn)(struct device *, void *)) 398 + void *data, device_iter_t fn) 406 399 { 407 400 struct subsys_private *sp = class_to_subsys(class); 408 401 struct class_dev_iter iter; ··· 601 594 * a bus device 602 595 * @cls: the compatibility class 603 596 * @dev: the target bus device 604 - * @device_link: an optional device to which a "device" link should be created 605 597 */ 606 - int class_compat_create_link(struct class_compat *cls, struct device *dev, 607 - struct device *device_link) 598 + int class_compat_create_link(struct class_compat *cls, struct device *dev) 608 599 { 609 - int error; 610 - 611 - error = sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev)); 612 - if (error) 613 - return error; 614 - 615 - /* 616 - * Optionally add a "device" link (typically to the parent), as a 617 - * class device would have one and we want to provide as much 618 - * backwards compatibility as possible. 619 - */ 620 - if (device_link) { 621 - error = sysfs_create_link(&dev->kobj, &device_link->kobj, 622 - "device"); 623 - if (error) 624 - sysfs_remove_link(cls->kobj, dev_name(dev)); 625 - } 626 - 627 - return error; 600 + return sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev)); 628 601 } 629 602 EXPORT_SYMBOL_GPL(class_compat_create_link); 630 603 ··· 613 626 * a bus device 614 627 * @cls: the compatibility class 615 628 * @dev: the target bus device 616 - * @device_link: an optional device to which a "device" link was previously 617 - * created 618 629 */ 619 - void class_compat_remove_link(struct class_compat *cls, struct device *dev, 620 - struct device *device_link) 630 + void class_compat_remove_link(struct class_compat *cls, struct device *dev) 621 631 { 622 - if (device_link) 623 - sysfs_remove_link(&dev->kobj, "device"); 624 632 sysfs_remove_link(cls->kobj, dev_name(dev)); 625 633 } 626 634 EXPORT_SYMBOL_GPL(class_compat_remove_link);
+22 -61
drivers/base/core.c
··· 3980 3980 * other than 0, we break out and return that value. 3981 3981 */ 3982 3982 int device_for_each_child(struct device *parent, void *data, 3983 - int (*fn)(struct device *dev, void *data)) 3983 + device_iter_t fn) 3984 3984 { 3985 3985 struct klist_iter i; 3986 3986 struct device *child; ··· 4010 4010 * other than 0, we break out and return that value. 4011 4011 */ 4012 4012 int device_for_each_child_reverse(struct device *parent, void *data, 4013 - int (*fn)(struct device *dev, void *data)) 4013 + device_iter_t fn) 4014 4014 { 4015 4015 struct klist_iter i; 4016 4016 struct device *child; ··· 4043 4043 * device_for_each_child_reverse_from(); 4044 4044 */ 4045 4045 int device_for_each_child_reverse_from(struct device *parent, 4046 - struct device *from, const void *data, 4047 - int (*fn)(struct device *, const void *)) 4046 + struct device *from, void *data, 4047 + device_iter_t fn) 4048 4048 { 4049 4049 struct klist_iter i; 4050 4050 struct device *child; 4051 4051 int error = 0; 4052 4052 4053 - if (!parent->p) 4053 + if (!parent || !parent->p) 4054 4054 return 0; 4055 4055 4056 4056 klist_iter_init_node(&parent->p->klist_children, &i, ··· 4079 4079 * 4080 4080 * NOTE: you will need to drop the reference with put_device() after use. 4081 4081 */ 4082 - struct device *device_find_child(struct device *parent, void *data, 4083 - int (*match)(struct device *dev, void *data)) 4082 + struct device *device_find_child(struct device *parent, const void *data, 4083 + device_match_t match) 4084 4084 { 4085 4085 struct klist_iter i; 4086 4086 struct device *child; ··· 4089 4089 return NULL; 4090 4090 4091 4091 klist_iter_init(&parent->p->klist_children, &i); 4092 - while ((child = next_device(&i))) 4093 - if (match(child, data) && get_device(child)) 4092 + while ((child = next_device(&i))) { 4093 + if (match(child, data)) { 4094 + get_device(child); 4094 4095 break; 4096 + } 4097 + } 4095 4098 klist_iter_exit(&i); 4096 4099 return child; 4097 4100 } 4098 4101 EXPORT_SYMBOL_GPL(device_find_child); 4099 - 4100 - /** 4101 - * device_find_child_by_name - device iterator for locating a child device. 4102 - * @parent: parent struct device 4103 - * @name: name of the child device 4104 - * 4105 - * This is similar to the device_find_child() function above, but it 4106 - * returns a reference to a device that has the name @name. 4107 - * 4108 - * NOTE: you will need to drop the reference with put_device() after use. 4109 - */ 4110 - struct device *device_find_child_by_name(struct device *parent, 4111 - const char *name) 4112 - { 4113 - struct klist_iter i; 4114 - struct device *child; 4115 - 4116 - if (!parent) 4117 - return NULL; 4118 - 4119 - klist_iter_init(&parent->p->klist_children, &i); 4120 - while ((child = next_device(&i))) 4121 - if (sysfs_streq(dev_name(child), name) && get_device(child)) 4122 - break; 4123 - klist_iter_exit(&i); 4124 - return child; 4125 - } 4126 - EXPORT_SYMBOL_GPL(device_find_child_by_name); 4127 - 4128 - static int match_any(struct device *dev, void *unused) 4129 - { 4130 - return 1; 4131 - } 4132 - 4133 - /** 4134 - * device_find_any_child - device iterator for locating a child device, if any. 4135 - * @parent: parent struct device 4136 - * 4137 - * This is similar to the device_find_child() function above, but it 4138 - * returns a reference to a child device, if any. 4139 - * 4140 - * NOTE: you will need to drop the reference with put_device() after use. 4141 - */ 4142 - struct device *device_find_any_child(struct device *parent) 4143 - { 4144 - return device_find_child(parent, NULL, match_any); 4145 - } 4146 - EXPORT_SYMBOL_GPL(device_find_any_child); 4147 4102 4148 4103 int __init devices_init(void) 4149 4104 { ··· 5199 5244 } 5200 5245 EXPORT_SYMBOL_GPL(device_match_name); 5201 5246 5247 + int device_match_type(struct device *dev, const void *type) 5248 + { 5249 + return dev->type == type; 5250 + } 5251 + EXPORT_SYMBOL_GPL(device_match_type); 5252 + 5202 5253 int device_match_of_node(struct device *dev, const void *np) 5203 5254 { 5204 - return dev->of_node == np; 5255 + return np && dev->of_node == np; 5205 5256 } 5206 5257 EXPORT_SYMBOL_GPL(device_match_of_node); 5207 5258 5208 5259 int device_match_fwnode(struct device *dev, const void *fwnode) 5209 5260 { 5210 - return dev_fwnode(dev) == fwnode; 5261 + return fwnode && dev_fwnode(dev) == fwnode; 5211 5262 } 5212 5263 EXPORT_SYMBOL_GPL(device_match_fwnode); 5213 5264 ··· 5225 5264 5226 5265 int device_match_acpi_dev(struct device *dev, const void *adev) 5227 5266 { 5228 - return ACPI_COMPANION(dev) == adev; 5267 + return adev && ACPI_COMPANION(dev) == adev; 5229 5268 } 5230 5269 EXPORT_SYMBOL(device_match_acpi_dev); 5231 5270 5232 5271 int device_match_acpi_handle(struct device *dev, const void *handle) 5233 5272 { 5234 - return ACPI_HANDLE(dev) == handle; 5273 + return handle && ACPI_HANDLE(dev) == handle; 5235 5274 } 5236 5275 EXPORT_SYMBOL(device_match_acpi_handle); 5237 5276
+10 -12
drivers/base/devcoredump.c
··· 106 106 } 107 107 108 108 static ssize_t devcd_data_read(struct file *filp, struct kobject *kobj, 109 - struct bin_attribute *bin_attr, 109 + const struct bin_attribute *bin_attr, 110 110 char *buffer, loff_t offset, size_t count) 111 111 { 112 112 struct device *dev = kobj_to_dev(kobj); ··· 116 116 } 117 117 118 118 static ssize_t devcd_data_write(struct file *filp, struct kobject *kobj, 119 - struct bin_attribute *bin_attr, 119 + const struct bin_attribute *bin_attr, 120 120 char *buffer, loff_t offset, size_t count) 121 121 { 122 122 struct device *dev = kobj_to_dev(kobj); ··· 132 132 return count; 133 133 } 134 134 135 - static struct bin_attribute devcd_attr_data = { 136 - .attr = { .name = "data", .mode = S_IRUSR | S_IWUSR, }, 137 - .size = 0, 138 - .read = devcd_data_read, 139 - .write = devcd_data_write, 140 - }; 135 + static const struct bin_attribute devcd_attr_data = 136 + __BIN_ATTR(data, 0600, devcd_data_read, devcd_data_write, 0); 141 137 142 - static struct bin_attribute *devcd_dev_bin_attrs[] = { 138 + static const struct bin_attribute *const devcd_dev_bin_attrs[] = { 143 139 &devcd_attr_data, NULL, 144 140 }; 145 141 146 142 static const struct attribute_group devcd_dev_group = { 147 - .bin_attrs = devcd_dev_bin_attrs, 143 + .bin_attrs_new = devcd_dev_bin_attrs, 148 144 }; 149 145 150 146 static const struct attribute_group *devcd_dev_groups[] = { ··· 182 186 * mutex_lock(&devcd->mutex); 183 187 * 184 188 * 185 - * In the above diagram, It looks like disabled_store() would be racing with parallely 189 + * In the above diagram, it looks like disabled_store() would be racing with parallelly 186 190 * running devcd_del() and result in memory abort while acquiring devcd->mutex which 187 - * is called after kfree of devcd memory after dropping its last reference with 191 + * is called after kfree of devcd memory after dropping its last reference with 188 192 * put_device(). However, this will not happens as fn(dev, data) runs 189 193 * with its own reference to device via klist_node so it is not its last reference. 190 194 * so, above situation would not occur. ··· 281 285 * @offset: start copy from @offset@ bytes from the head of the data 282 286 * in the given scatterlist 283 287 * @data_len: the length of the data in the sg_table 288 + * 289 + * Returns: the number of bytes copied 284 290 */ 285 291 static ssize_t devcd_read_from_sgtable(char *buffer, loff_t offset, 286 292 size_t buf_len, void *data,
+18 -5
drivers/base/devres.c
··· 750 750 EXPORT_SYMBOL_GPL(__devm_add_action); 751 751 752 752 /** 753 - * devm_remove_action() - removes previously added custom action 753 + * devm_remove_action_nowarn() - removes previously added custom action 754 754 * @dev: Device that owns the action 755 755 * @action: Function implementing the action 756 756 * @data: Pointer to data passed to @action implementation 757 757 * 758 758 * Removes instance of @action previously added by devm_add_action(). 759 759 * Both action and data should match one of the existing entries. 760 + * 761 + * In contrast to devm_remove_action(), this function does not WARN() if no 762 + * entry could have been found. 763 + * 764 + * This should only be used if the action is contained in an object with 765 + * independent lifetime management, e.g. the Devres rust abstraction. 766 + * 767 + * Causing the warning from regular driver code most likely indicates an abuse 768 + * of the devres API. 769 + * 770 + * Returns: 0 on success, -ENOENT if no entry could have been found. 760 771 */ 761 - void devm_remove_action(struct device *dev, void (*action)(void *), void *data) 772 + int devm_remove_action_nowarn(struct device *dev, 773 + void (*action)(void *), 774 + void *data) 762 775 { 763 776 struct action_devres devres = { 764 777 .data = data, 765 778 .action = action, 766 779 }; 767 780 768 - WARN_ON(devres_destroy(dev, devm_action_release, devm_action_match, 769 - &devres)); 781 + return devres_destroy(dev, devm_action_release, devm_action_match, 782 + &devres); 770 783 } 771 - EXPORT_SYMBOL_GPL(devm_remove_action); 784 + EXPORT_SYMBOL_GPL(devm_remove_action_nowarn); 772 785 773 786 /** 774 787 * devm_release_action() - release previously added custom action
+6 -3
drivers/base/driver.c
··· 115 115 * Iterate over the @drv's list of devices calling @fn for each one. 116 116 */ 117 117 int driver_for_each_device(struct device_driver *drv, struct device *start, 118 - void *data, int (*fn)(struct device *, void *)) 118 + void *data, device_iter_t fn) 119 119 { 120 120 struct klist_iter i; 121 121 struct device *dev; ··· 160 160 161 161 klist_iter_init_node(&drv->p->klist_devices, &i, 162 162 (start ? &start->p->knode_driver : NULL)); 163 - while ((dev = next_device(&i))) 164 - if (match(dev, data) && get_device(dev)) 163 + while ((dev = next_device(&i))) { 164 + if (match(dev, data)) { 165 + get_device(dev); 165 166 break; 167 + } 168 + } 166 169 klist_iter_exit(&i); 167 170 return dev; 168 171 }
+7 -7
drivers/base/firmware_loader/sysfs.c
··· 259 259 } 260 260 261 261 static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj, 262 - struct bin_attribute *bin_attr, 262 + const struct bin_attribute *bin_attr, 263 263 char *buffer, loff_t offset, size_t count) 264 264 { 265 265 struct device *dev = kobj_to_dev(kobj); ··· 316 316 * the driver as a firmware image. 317 317 **/ 318 318 static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj, 319 - struct bin_attribute *bin_attr, 319 + const struct bin_attribute *bin_attr, 320 320 char *buffer, loff_t offset, size_t count) 321 321 { 322 322 struct device *dev = kobj_to_dev(kobj); ··· 356 356 return retval; 357 357 } 358 358 359 - static struct bin_attribute firmware_attr_data = { 359 + static const struct bin_attribute firmware_attr_data = { 360 360 .attr = { .name = "data", .mode = 0644 }, 361 361 .size = 0, 362 - .read = firmware_data_read, 363 - .write = firmware_data_write, 362 + .read_new = firmware_data_read, 363 + .write_new = firmware_data_write, 364 364 }; 365 365 366 366 static struct attribute *fw_dev_attrs[] = { ··· 374 374 NULL 375 375 }; 376 376 377 - static struct bin_attribute *fw_dev_bin_attrs[] = { 377 + static const struct bin_attribute *const fw_dev_bin_attrs[] = { 378 378 &firmware_attr_data, 379 379 NULL 380 380 }; 381 381 382 382 static const struct attribute_group fw_dev_attr_group = { 383 383 .attrs = fw_dev_attrs, 384 - .bin_attrs = fw_dev_bin_attrs, 384 + .bin_attrs_new = fw_dev_bin_attrs, 385 385 #ifdef CONFIG_FW_UPLOAD 386 386 .is_visible = fw_upload_is_visible, 387 387 #endif
+1
drivers/base/test/Kconfig
··· 12 12 config DM_KUNIT_TEST 13 13 tristate "KUnit Tests for the device model" if !KUNIT_ALL_TESTS 14 14 depends on KUNIT 15 + default KUNIT_ALL_TESTS 15 16 16 17 config DRIVER_PE_KUNIT_TEST 17 18 tristate "KUnit Tests for property entry API" if !KUNIT_ALL_TESTS
+40 -1
drivers/base/test/platform-device-test.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 + #include <kunit/platform_device.h> 3 4 #include <kunit/resource.h> 4 5 5 6 #include <linux/device.h> 7 + #include <linux/device/bus.h> 8 + #include <linux/of_platform.h> 6 9 #include <linux/platform_device.h> 7 10 8 11 #define DEVICE_NAME "test" ··· 220 217 .test_cases = platform_device_devm_tests, 221 218 }; 222 219 223 - kunit_test_suite(platform_device_devm_test_suite); 220 + static void platform_device_find_by_null_test(struct kunit *test) 221 + { 222 + struct platform_device *pdev; 223 + int ret; 224 + 225 + pdev = kunit_platform_device_alloc(test, DEVICE_NAME, PLATFORM_DEVID_NONE); 226 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); 227 + 228 + ret = kunit_platform_device_add(test, pdev); 229 + KUNIT_ASSERT_EQ(test, ret, 0); 230 + 231 + KUNIT_EXPECT_PTR_EQ(test, of_find_device_by_node(NULL), NULL); 232 + 233 + KUNIT_EXPECT_PTR_EQ(test, bus_find_device_by_of_node(&platform_bus_type, NULL), NULL); 234 + KUNIT_EXPECT_PTR_EQ(test, bus_find_device_by_fwnode(&platform_bus_type, NULL), NULL); 235 + KUNIT_EXPECT_PTR_EQ(test, bus_find_device_by_acpi_dev(&platform_bus_type, NULL), NULL); 236 + 237 + KUNIT_EXPECT_FALSE(test, device_match_of_node(&pdev->dev, NULL)); 238 + KUNIT_EXPECT_FALSE(test, device_match_fwnode(&pdev->dev, NULL)); 239 + KUNIT_EXPECT_FALSE(test, device_match_acpi_dev(&pdev->dev, NULL)); 240 + KUNIT_EXPECT_FALSE(test, device_match_acpi_handle(&pdev->dev, NULL)); 241 + } 242 + 243 + static struct kunit_case platform_device_match_tests[] = { 244 + KUNIT_CASE(platform_device_find_by_null_test), 245 + {} 246 + }; 247 + 248 + static struct kunit_suite platform_device_match_test_suite = { 249 + .name = "platform-device-match", 250 + .test_cases = platform_device_match_tests, 251 + }; 252 + 253 + kunit_test_suites( 254 + &platform_device_devm_test_suite, 255 + &platform_device_match_test_suite, 256 + ); 224 257 225 258 MODULE_DESCRIPTION("Test module for platform devices"); 226 259 MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
+3 -3
drivers/block/sunvdc.c
··· 918 918 char *type; 919 919 }; 920 920 921 - static int vdc_device_probed(struct device *dev, void *arg) 921 + static int vdc_device_probed(struct device *dev, const void *arg) 922 922 { 923 923 struct vio_dev *vdev = to_vio_dev(dev); 924 - struct vdc_check_port_data *port_data; 924 + const struct vdc_check_port_data *port_data; 925 925 926 - port_data = (struct vdc_check_port_data *)arg; 926 + port_data = (const struct vdc_check_port_data *)arg; 927 927 928 928 if ((vdev->dev_no == port_data->dev_no) && 929 929 (!(strcmp((char *)&vdev->type, port_data->type))) &&
+4 -4
drivers/bus/fsl-mc/dprc-driver.c
··· 22 22 struct fsl_mc_obj_desc *child_array; 23 23 }; 24 24 25 - static bool fsl_mc_device_match(struct fsl_mc_device *mc_dev, 26 - struct fsl_mc_obj_desc *obj_desc) 25 + static bool fsl_mc_device_match(const struct fsl_mc_device *mc_dev, 26 + const struct fsl_mc_obj_desc *obj_desc) 27 27 { 28 28 return mc_dev->obj_desc.id == obj_desc->id && 29 29 strcmp(mc_dev->obj_desc.type, obj_desc->type) == 0; ··· 112 112 } 113 113 EXPORT_SYMBOL_GPL(dprc_remove_devices); 114 114 115 - static int __fsl_mc_device_match(struct device *dev, void *data) 115 + static int __fsl_mc_device_match(struct device *dev, const void *data) 116 116 { 117 - struct fsl_mc_obj_desc *obj_desc = data; 117 + const struct fsl_mc_obj_desc *obj_desc = data; 118 118 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 119 119 120 120 return fsl_mc_device_match(mc_dev, obj_desc);
+18 -18
drivers/bus/fsl-mc/fsl-mc-bus.c
··· 320 320 }; 321 321 EXPORT_SYMBOL_GPL(fsl_mc_bus_type); 322 322 323 - struct device_type fsl_mc_bus_dprc_type = { 323 + const struct device_type fsl_mc_bus_dprc_type = { 324 324 .name = "fsl_mc_bus_dprc" 325 325 }; 326 326 EXPORT_SYMBOL_GPL(fsl_mc_bus_dprc_type); 327 327 328 - struct device_type fsl_mc_bus_dpni_type = { 328 + const struct device_type fsl_mc_bus_dpni_type = { 329 329 .name = "fsl_mc_bus_dpni" 330 330 }; 331 331 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpni_type); 332 332 333 - struct device_type fsl_mc_bus_dpio_type = { 333 + const struct device_type fsl_mc_bus_dpio_type = { 334 334 .name = "fsl_mc_bus_dpio" 335 335 }; 336 336 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpio_type); 337 337 338 - struct device_type fsl_mc_bus_dpsw_type = { 338 + const struct device_type fsl_mc_bus_dpsw_type = { 339 339 .name = "fsl_mc_bus_dpsw" 340 340 }; 341 341 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpsw_type); 342 342 343 - struct device_type fsl_mc_bus_dpbp_type = { 343 + const struct device_type fsl_mc_bus_dpbp_type = { 344 344 .name = "fsl_mc_bus_dpbp" 345 345 }; 346 346 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpbp_type); 347 347 348 - struct device_type fsl_mc_bus_dpcon_type = { 348 + const struct device_type fsl_mc_bus_dpcon_type = { 349 349 .name = "fsl_mc_bus_dpcon" 350 350 }; 351 351 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpcon_type); 352 352 353 - struct device_type fsl_mc_bus_dpmcp_type = { 353 + const struct device_type fsl_mc_bus_dpmcp_type = { 354 354 .name = "fsl_mc_bus_dpmcp" 355 355 }; 356 356 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpmcp_type); 357 357 358 - struct device_type fsl_mc_bus_dpmac_type = { 358 + const struct device_type fsl_mc_bus_dpmac_type = { 359 359 .name = "fsl_mc_bus_dpmac" 360 360 }; 361 361 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpmac_type); 362 362 363 - struct device_type fsl_mc_bus_dprtc_type = { 363 + const struct device_type fsl_mc_bus_dprtc_type = { 364 364 .name = "fsl_mc_bus_dprtc" 365 365 }; 366 366 EXPORT_SYMBOL_GPL(fsl_mc_bus_dprtc_type); 367 367 368 - struct device_type fsl_mc_bus_dpseci_type = { 368 + const struct device_type fsl_mc_bus_dpseci_type = { 369 369 .name = "fsl_mc_bus_dpseci" 370 370 }; 371 371 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpseci_type); 372 372 373 - struct device_type fsl_mc_bus_dpdmux_type = { 373 + const struct device_type fsl_mc_bus_dpdmux_type = { 374 374 .name = "fsl_mc_bus_dpdmux" 375 375 }; 376 376 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdmux_type); 377 377 378 - struct device_type fsl_mc_bus_dpdcei_type = { 378 + const struct device_type fsl_mc_bus_dpdcei_type = { 379 379 .name = "fsl_mc_bus_dpdcei" 380 380 }; 381 381 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdcei_type); 382 382 383 - struct device_type fsl_mc_bus_dpaiop_type = { 383 + const struct device_type fsl_mc_bus_dpaiop_type = { 384 384 .name = "fsl_mc_bus_dpaiop" 385 385 }; 386 386 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpaiop_type); 387 387 388 - struct device_type fsl_mc_bus_dpci_type = { 388 + const struct device_type fsl_mc_bus_dpci_type = { 389 389 .name = "fsl_mc_bus_dpci" 390 390 }; 391 391 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpci_type); 392 392 393 - struct device_type fsl_mc_bus_dpdmai_type = { 393 + const struct device_type fsl_mc_bus_dpdmai_type = { 394 394 .name = "fsl_mc_bus_dpdmai" 395 395 }; 396 396 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdmai_type); 397 397 398 - struct device_type fsl_mc_bus_dpdbg_type = { 398 + const struct device_type fsl_mc_bus_dpdbg_type = { 399 399 .name = "fsl_mc_bus_dpdbg" 400 400 }; 401 401 EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdbg_type); 402 402 403 - static struct device_type *fsl_mc_get_device_type(const char *type) 403 + static const struct device_type *fsl_mc_get_device_type(const char *type) 404 404 { 405 405 static const struct { 406 - struct device_type *dev_type; 406 + const struct device_type *dev_type; 407 407 const char *type; 408 408 } dev_types[] = { 409 409 { &fsl_mc_bus_dprc_type, "dprc" },
+4 -32
drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.c
··· 473 473 } 474 474 DEFINE_SHOW_STORE_ATTRIBUTE(tl_control); 475 475 476 - static int get_rp_index_from_file(const struct file *f, u8 *rp_id, u8 rp_num) 477 - { 478 - char alpha; 479 - u8 index; 480 - int ret; 481 - 482 - ret = sscanf(f->f_path.dentry->d_name.name, ADF_TL_RP_REGS_FNAME, &alpha); 483 - if (ret != 1) 484 - return -EINVAL; 485 - 486 - index = ADF_TL_DBG_RP_INDEX_ALPHA(alpha); 487 - *rp_id = index; 488 - 489 - return 0; 490 - } 491 - 492 476 static int adf_tl_dbg_change_rp_index(struct adf_accel_dev *accel_dev, 493 477 unsigned int new_rp_num, 494 478 unsigned int rp_regs_index) ··· 595 611 { 596 612 struct adf_accel_dev *accel_dev = s->private; 597 613 u8 rp_regs_index; 598 - u8 max_rp; 599 - int ret; 600 614 601 615 if (!accel_dev) 602 616 return -EINVAL; 603 617 604 - max_rp = GET_TL_DATA(accel_dev).max_rp; 605 - ret = get_rp_index_from_file(s->file, &rp_regs_index, max_rp); 606 - if (ret) { 607 - dev_dbg(&GET_DEV(accel_dev), "invalid RP data file name\n"); 608 - return ret; 609 - } 618 + rp_regs_index = debugfs_get_aux_num(s->file); 610 619 611 620 return tl_print_rp_data(accel_dev, s, rp_regs_index); 612 621 } ··· 612 635 struct adf_telemetry *telemetry; 613 636 unsigned int new_rp_num; 614 637 u8 rp_regs_index; 615 - u8 max_rp; 616 638 int ret; 617 639 618 640 accel_dev = seq_f->private; ··· 619 643 return -EINVAL; 620 644 621 645 telemetry = accel_dev->telemetry; 622 - max_rp = GET_TL_DATA(accel_dev).max_rp; 623 646 624 647 mutex_lock(&telemetry->wr_lock); 625 648 626 - ret = get_rp_index_from_file(file, &rp_regs_index, max_rp); 627 - if (ret) { 628 - dev_dbg(&GET_DEV(accel_dev), "invalid RP data file name\n"); 629 - goto unlock_and_exit; 630 - } 649 + rp_regs_index = debugfs_get_aux_num(file); 631 650 632 651 ret = kstrtou32_from_user(userbuf, count, 10, &new_rp_num); 633 652 if (ret) ··· 660 689 for (i = 0; i < max_rp; i++) { 661 690 snprintf(name, sizeof(name), ADF_TL_RP_REGS_FNAME, 662 691 ADF_TL_DBG_RP_ALPHA_INDEX(i)); 663 - debugfs_create_file(name, 0644, dir, accel_dev, &tl_rp_data_fops); 692 + debugfs_create_file_aux_num(name, 0644, dir, accel_dev, i, 693 + &tl_rp_data_fops); 664 694 } 665 695 } 666 696
+1 -1
drivers/cxl/core/hdm.c
··· 703 703 return 0; 704 704 } 705 705 706 - static int commit_reap(struct device *dev, const void *data) 706 + static int commit_reap(struct device *dev, void *data) 707 707 { 708 708 struct cxl_port *port = to_cxl_port(dev->parent); 709 709 struct cxl_decoder *cxld;
+2 -2
drivers/cxl/core/pci.c
··· 252 252 } 253 253 254 254 /* require dvsec ranges to be covered by a locked platform window */ 255 - static int dvsec_range_allowed(struct device *dev, void *arg) 255 + static int dvsec_range_allowed(struct device *dev, const void *arg) 256 256 { 257 - struct range *dev_range = arg; 257 + const struct range *dev_range = arg; 258 258 struct cxl_decoder *cxld; 259 259 260 260 if (!is_root_decoder(dev))
+3 -12
drivers/cxl/core/pmem.c
··· 51 51 } 52 52 EXPORT_SYMBOL_NS_GPL(to_cxl_nvdimm_bridge, "CXL"); 53 53 54 - bool is_cxl_nvdimm_bridge(struct device *dev) 55 - { 56 - return dev->type == &cxl_nvdimm_bridge_type; 57 - } 58 - EXPORT_SYMBOL_NS_GPL(is_cxl_nvdimm_bridge, "CXL"); 59 - 60 - static int match_nvdimm_bridge(struct device *dev, void *data) 61 - { 62 - return is_cxl_nvdimm_bridge(dev); 63 - } 64 - 65 54 /** 66 55 * cxl_find_nvdimm_bridge() - find a bridge device relative to a port 67 56 * @port: any descendant port of an nvdimm-bridge associated ··· 64 75 if (!cxl_root) 65 76 return NULL; 66 77 67 - dev = device_find_child(&cxl_root->port.dev, NULL, match_nvdimm_bridge); 78 + dev = device_find_child(&cxl_root->port.dev, 79 + &cxl_nvdimm_bridge_type, 80 + device_match_type); 68 81 69 82 if (!dev) 70 83 return NULL;
+13 -10
drivers/cxl/core/region.c
··· 778 778 return rc; 779 779 } 780 780 781 - static int check_commit_order(struct device *dev, const void *data) 781 + static int check_commit_order(struct device *dev, void *data) 782 782 { 783 783 struct cxl_decoder *cxld = to_cxl_decoder(dev); 784 784 ··· 792 792 return 0; 793 793 } 794 794 795 - static int match_free_decoder(struct device *dev, void *data) 795 + static int match_free_decoder(struct device *dev, const void *data) 796 796 { 797 797 struct cxl_port *port = to_cxl_port(dev->parent); 798 798 struct cxl_decoder *cxld; ··· 824 824 return 1; 825 825 } 826 826 827 - static int match_auto_decoder(struct device *dev, void *data) 827 + static int match_auto_decoder(struct device *dev, const void *data) 828 828 { 829 - struct cxl_region_params *p = data; 829 + const struct cxl_region_params *p = data; 830 830 struct cxl_decoder *cxld; 831 831 struct range *r; 832 832 ··· 1733 1733 return port->parent_dport->port; 1734 1734 } 1735 1735 1736 - static int match_switch_decoder_by_range(struct device *dev, void *data) 1736 + static int match_switch_decoder_by_range(struct device *dev, 1737 + const void *data) 1737 1738 { 1738 1739 struct cxl_switch_decoder *cxlsd; 1739 - struct range *r1, *r2 = data; 1740 + const struct range *r1, *r2 = data; 1741 + 1740 1742 1741 1743 if (!is_switch_decoder(dev)) 1742 1744 return 0; ··· 3189 3187 return rc; 3190 3188 } 3191 3189 3192 - static int match_root_decoder_by_range(struct device *dev, void *data) 3190 + static int match_root_decoder_by_range(struct device *dev, 3191 + const void *data) 3193 3192 { 3194 - struct range *r1, *r2 = data; 3193 + const struct range *r1, *r2 = data; 3195 3194 struct cxl_root_decoder *cxlrd; 3196 3195 3197 3196 if (!is_root_decoder(dev)) ··· 3203 3200 return range_contains(r1, r2); 3204 3201 } 3205 3202 3206 - static int match_region_by_range(struct device *dev, void *data) 3203 + static int match_region_by_range(struct device *dev, const void *data) 3207 3204 { 3208 3205 struct cxl_region_params *p; 3209 3206 struct cxl_region *cxlr; 3210 - struct range *r = data; 3207 + const struct range *r = data; 3211 3208 int rc = 0; 3212 3209 3213 3210 if (!is_cxl_region(dev))
-1
drivers/cxl/cxl.h
··· 864 864 struct cxl_port *port); 865 865 struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev); 866 866 bool is_cxl_nvdimm(struct device *dev); 867 - bool is_cxl_nvdimm_bridge(struct device *dev); 868 867 int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd); 869 868 struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port); 870 869
+2 -2
drivers/firewire/core-device.c
··· 988 988 return 0; 989 989 } 990 990 991 - static int compare_configuration_rom(struct device *dev, void *data) 991 + static int compare_configuration_rom(struct device *dev, const void *data) 992 992 { 993 993 const struct fw_device *old = fw_device(dev); 994 994 const u32 *config_rom = data; ··· 1039 1039 // 1040 1040 // serialize config_rom access. 1041 1041 scoped_guard(rwsem_read, &fw_device_rwsem) { 1042 - found = device_find_child(card->device, (void *)device->config_rom, 1042 + found = device_find_child(card->device, device->config_rom, 1043 1043 compare_configuration_rom); 1044 1044 } 1045 1045 if (found) {
+2 -2
drivers/firmware/arm_scmi/bus.c
··· 238 238 return 0; 239 239 } 240 240 241 - static int scmi_match_by_id_table(struct device *dev, void *data) 241 + static int scmi_match_by_id_table(struct device *dev, const void *data) 242 242 { 243 243 struct scmi_device *sdev = to_scmi_dev(dev); 244 - struct scmi_device_id *id_table = data; 244 + const struct scmi_device_id *id_table = data; 245 245 246 246 return sdev->protocol_id == id_table->protocol_id && 247 247 (id_table->name && !strcmp(sdev->name, id_table->name));
+6 -6
drivers/firmware/arm_scmi/raw_mode.c
··· 886 886 887 887 static int scmi_dbg_raw_mode_open(struct inode *inode, struct file *filp) 888 888 { 889 - u8 id; 890 889 struct scmi_raw_mode_info *raw; 891 890 struct scmi_dbg_raw_data *rd; 892 - const char *id_str = filp->f_path.dentry->d_parent->d_name.name; 893 891 894 892 if (!inode->i_private) 895 893 return -ENODEV; ··· 913 915 } 914 916 915 917 /* Grab channel ID from debugfs entry naming if any */ 916 - if (!kstrtou8(id_str, 16, &id)) 917 - rd->chan_id = id; 918 + /* not set - reassing 0 we already had after kzalloc() */ 919 + rd->chan_id = debugfs_get_aux_num(filp); 918 920 919 921 rd->raw = raw; 920 922 filp->private_data = rd; ··· 1223 1225 snprintf(cdir, 8, "0x%02X", channels[i]); 1224 1226 chd = debugfs_create_dir(cdir, top_chans); 1225 1227 1226 - debugfs_create_file("message", 0600, chd, raw, 1228 + debugfs_create_file_aux_num("message", 0600, chd, 1229 + raw, channels[i], 1227 1230 &scmi_dbg_raw_mode_message_fops); 1228 1231 1229 - debugfs_create_file("message_async", 0600, chd, raw, 1232 + debugfs_create_file_aux_num("message_async", 0600, chd, 1233 + raw, channels[i], 1230 1234 &scmi_dbg_raw_mode_message_async_fops); 1231 1235 } 1232 1236 }
+2 -2
drivers/firmware/efi/dev-path-parser.c
··· 47 47 return 0; 48 48 } 49 49 50 - static int __init match_pci_dev(struct device *dev, void *data) 50 + static int __init match_pci_dev(struct device *dev, const void *data) 51 51 { 52 - unsigned int devfn = *(unsigned int *)data; 52 + unsigned int devfn = *(const unsigned int *)data; 53 53 54 54 return dev_is_pci(dev) && to_pci_dev(dev)->devfn == devfn; 55 55 }
+1 -6
drivers/gpio/gpio-sim.c
··· 413 413 return devm_add_action_or_reset(dev, gpio_sim_sysfs_remove, chip); 414 414 } 415 415 416 - static int gpio_sim_dev_match_fwnode(struct device *dev, void *data) 417 - { 418 - return device_match_fwnode(dev, data); 419 - } 420 - 421 416 static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) 422 417 { 423 418 struct gpio_sim_chip *chip; ··· 498 503 if (ret) 499 504 return ret; 500 505 501 - chip->dev = device_find_child(dev, swnode, gpio_sim_dev_match_fwnode); 506 + chip->dev = device_find_child(dev, swnode, device_match_fwnode); 502 507 if (!chip->dev) 503 508 return -ENODEV; 504 509
+1 -1
drivers/gpu/drm/mediatek/mtk_drm_drv.c
··· 358 358 }; 359 359 MODULE_DEVICE_TABLE(of, mtk_drm_of_ids); 360 360 361 - static int mtk_drm_match(struct device *dev, void *data) 361 + static int mtk_drm_match(struct device *dev, const void *data) 362 362 { 363 363 if (!strncmp(dev_name(dev), "mediatek-drm", sizeof("mediatek-drm") - 1)) 364 364 return true;
+1 -1
drivers/hwmon/hwmon.c
··· 332 332 333 333 static DEFINE_MUTEX(hwmon_pec_mutex); 334 334 335 - static int hwmon_match_device(struct device *dev, void *data) 335 + static int hwmon_match_device(struct device *dev, const void *data) 336 336 { 337 337 return dev->class == &hwmon_class; 338 338 }
+1 -1
drivers/i2c/i2c-core-base.c
··· 1310 1310 } 1311 1311 static DEVICE_ATTR_WO(new_device); 1312 1312 1313 - static int __i2c_find_user_addr(struct device *dev, void *addrp) 1313 + static int __i2c_find_user_addr(struct device *dev, const void *addrp) 1314 1314 { 1315 1315 struct i2c_client *client = i2c_verify_client(dev); 1316 1316 unsigned short addr = *(unsigned short *)addrp;
+1 -1
drivers/leds/leds-turris-omnia.c
··· 438 438 return reply; 439 439 } 440 440 441 - static int omnia_match_mcu_client(struct device *dev, void *data) 441 + static int omnia_match_mcu_client(struct device *dev, const void *data) 442 442 { 443 443 struct i2c_client *client; 444 444
+2 -2
drivers/media/pci/mgb4/mgb4_core.c
··· 125 125 }; 126 126 #endif 127 127 128 - static int match_i2c_adap(struct device *dev, void *data) 128 + static int match_i2c_adap(struct device *dev, const void *data) 129 129 { 130 130 return i2c_verify_adapter(dev) ? 1 : 0; 131 131 } ··· 141 141 return dev ? to_i2c_adapter(dev) : NULL; 142 142 } 143 143 144 - static int match_spi_adap(struct device *dev, void *data) 144 + static int match_spi_adap(struct device *dev, const void *data) 145 145 { 146 146 return to_spi_device(dev) ? 1 : 0; 147 147 }
+1 -1
drivers/mux/core.c
··· 42 42 unsigned int state; 43 43 }; 44 44 45 - static struct class mux_class = { 45 + static const struct class mux_class = { 46 46 .name = "mux", 47 47 }; 48 48
+2 -7
drivers/net/bonding/bond_debugfs.c
··· 63 63 64 64 void bond_debug_reregister(struct bonding *bond) 65 65 { 66 - struct dentry *d; 67 - 68 - d = debugfs_rename(bonding_debug_root, bond->debug_dir, 69 - bonding_debug_root, bond->dev->name); 70 - if (!IS_ERR(d)) { 71 - bond->debug_dir = d; 72 - } else { 66 + int err = debugfs_change_name(bond->debug_dir, "%s", bond->dev->name); 67 + if (err) { 73 68 netdev_warn(bond->dev, "failed to reregister, so just unregister old one\n"); 74 69 bond_debug_unregister(bond); 75 70 }
+2 -17
drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
··· 505 505 506 506 void xgbe_debugfs_rename(struct xgbe_prv_data *pdata) 507 507 { 508 - char *buf; 509 - 510 - if (!pdata->xgbe_debugfs) 511 - return; 512 - 513 - buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name); 514 - if (!buf) 515 - return; 516 - 517 - if (!strcmp(pdata->xgbe_debugfs->d_name.name, buf)) 518 - goto out; 519 - 520 - debugfs_rename(pdata->xgbe_debugfs->d_parent, pdata->xgbe_debugfs, 521 - pdata->xgbe_debugfs->d_parent, buf); 522 - 523 - out: 524 - kfree(buf); 508 + debugfs_change_name(pdata->xgbe_debugfs, 509 + "amd-xgbe-%s", pdata->netdev->name); 525 510 }
+24 -52
drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
··· 917 917 /* The 'qsize' entry dumps current Aura/Pool context Qsize 918 918 * and each context's current enable/disable status in a bitmap. 919 919 */ 920 - static int rvu_dbg_qsize_display(struct seq_file *filp, void *unsused, 920 + static int rvu_dbg_qsize_display(struct seq_file *s, void *unsused, 921 921 int blktype) 922 922 { 923 - void (*print_qsize)(struct seq_file *filp, 923 + void (*print_qsize)(struct seq_file *s, 924 924 struct rvu_pfvf *pfvf) = NULL; 925 - struct dentry *current_dir; 926 925 struct rvu_pfvf *pfvf; 927 926 struct rvu *rvu; 928 927 int qsize_id; 929 928 u16 pcifunc; 930 929 int blkaddr; 931 930 932 - rvu = filp->private; 931 + rvu = s->private; 933 932 switch (blktype) { 934 933 case BLKTYPE_NPA: 935 934 qsize_id = rvu->rvu_dbg.npa_qsize_id; ··· 944 945 return -EINVAL; 945 946 } 946 947 947 - if (blktype == BLKTYPE_NPA) { 948 + if (blktype == BLKTYPE_NPA) 948 949 blkaddr = BLKADDR_NPA; 949 - } else { 950 - current_dir = filp->file->f_path.dentry->d_parent; 951 - blkaddr = (!strcmp(current_dir->d_name.name, "nix1") ? 952 - BLKADDR_NIX1 : BLKADDR_NIX0); 953 - } 950 + else 951 + blkaddr = debugfs_get_aux_num(s->file); 954 952 955 953 if (!rvu_dbg_is_valid_lf(rvu, blkaddr, qsize_id, &pcifunc)) 956 954 return -EINVAL; 957 955 958 956 pfvf = rvu_get_pfvf(rvu, pcifunc); 959 - print_qsize(filp, pfvf); 957 + print_qsize(s, pfvf); 960 958 961 959 return 0; 962 960 } 963 961 964 - static ssize_t rvu_dbg_qsize_write(struct file *filp, 962 + static ssize_t rvu_dbg_qsize_write(struct file *file, 965 963 const char __user *buffer, size_t count, 966 964 loff_t *ppos, int blktype) 967 965 { 968 966 char *blk_string = (blktype == BLKTYPE_NPA) ? "npa" : "nix"; 969 - struct seq_file *seqfile = filp->private_data; 967 + struct seq_file *seqfile = file->private_data; 970 968 char *cmd_buf, *cmd_buf_tmp, *subtoken; 971 969 struct rvu *rvu = seqfile->private; 972 - struct dentry *current_dir; 973 970 int blkaddr; 974 971 u16 pcifunc; 975 972 int ret, lf; ··· 991 996 goto qsize_write_done; 992 997 } 993 998 994 - if (blktype == BLKTYPE_NPA) { 999 + if (blktype == BLKTYPE_NPA) 995 1000 blkaddr = BLKADDR_NPA; 996 - } else { 997 - current_dir = filp->f_path.dentry->d_parent; 998 - blkaddr = (!strcmp(current_dir->d_name.name, "nix1") ? 999 - BLKADDR_NIX1 : BLKADDR_NIX0); 1000 - } 1001 + else 1002 + blkaddr = debugfs_get_aux_num(file); 1001 1003 1002 1004 if (!rvu_dbg_is_valid_lf(rvu, blkaddr, lf, &pcifunc)) { 1003 1005 ret = -EINVAL; ··· 2696 2704 &rvu_dbg_nix_ndc_tx_hits_miss_fops); 2697 2705 debugfs_create_file("ndc_rx_hits_miss", 0600, rvu->rvu_dbg.nix, nix_hw, 2698 2706 &rvu_dbg_nix_ndc_rx_hits_miss_fops); 2699 - debugfs_create_file("qsize", 0600, rvu->rvu_dbg.nix, rvu, 2700 - &rvu_dbg_nix_qsize_fops); 2707 + debugfs_create_file_aux_num("qsize", 0600, rvu->rvu_dbg.nix, rvu, 2708 + blkaddr, &rvu_dbg_nix_qsize_fops); 2701 2709 debugfs_create_file("ingress_policer_ctx", 0600, rvu->rvu_dbg.nix, nix_hw, 2702 2710 &rvu_dbg_nix_band_prof_ctx_fops); 2703 2711 debugfs_create_file("ingress_policer_rsrc", 0600, rvu->rvu_dbg.nix, nix_hw, ··· 2846 2854 return err; 2847 2855 } 2848 2856 2849 - static int rvu_dbg_derive_lmacid(struct seq_file *filp, int *lmac_id) 2857 + static int rvu_dbg_derive_lmacid(struct seq_file *s) 2850 2858 { 2851 - struct dentry *current_dir; 2852 - char *buf; 2853 - 2854 - current_dir = filp->file->f_path.dentry->d_parent; 2855 - buf = strrchr(current_dir->d_name.name, 'c'); 2856 - if (!buf) 2857 - return -EINVAL; 2858 - 2859 - return kstrtoint(buf + 1, 10, lmac_id); 2859 + return debugfs_get_aux_num(s->file); 2860 2860 } 2861 2861 2862 - static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused) 2862 + static int rvu_dbg_cgx_stat_display(struct seq_file *s, void *unused) 2863 2863 { 2864 - int lmac_id, err; 2865 - 2866 - err = rvu_dbg_derive_lmacid(filp, &lmac_id); 2867 - if (!err) 2868 - return cgx_print_stats(filp, lmac_id); 2869 - 2870 - return err; 2864 + return cgx_print_stats(s, rvu_dbg_derive_lmacid(s)); 2871 2865 } 2872 2866 2873 2867 RVU_DEBUG_SEQ_FOPS(cgx_stat, cgx_stat_display, NULL); ··· 2911 2933 return 0; 2912 2934 } 2913 2935 2914 - static int rvu_dbg_cgx_dmac_flt_display(struct seq_file *filp, void *unused) 2936 + static int rvu_dbg_cgx_dmac_flt_display(struct seq_file *s, void *unused) 2915 2937 { 2916 - int err, lmac_id; 2917 - 2918 - err = rvu_dbg_derive_lmacid(filp, &lmac_id); 2919 - if (!err) 2920 - return cgx_print_dmac_flt(filp, lmac_id); 2921 - 2922 - return err; 2938 + return cgx_print_dmac_flt(s, rvu_dbg_derive_lmacid(s)); 2923 2939 } 2924 2940 2925 2941 RVU_DEBUG_SEQ_FOPS(cgx_dmac_flt, cgx_dmac_flt_display, NULL); ··· 2952 2980 rvu->rvu_dbg.lmac = 2953 2981 debugfs_create_dir(dname, rvu->rvu_dbg.cgx); 2954 2982 2955 - debugfs_create_file("stats", 0600, rvu->rvu_dbg.lmac, 2956 - cgx, &rvu_dbg_cgx_stat_fops); 2957 - debugfs_create_file("mac_filter", 0600, 2958 - rvu->rvu_dbg.lmac, cgx, 2983 + debugfs_create_file_aux_num("stats", 0600, rvu->rvu_dbg.lmac, 2984 + cgx, lmac_id, &rvu_dbg_cgx_stat_fops); 2985 + debugfs_create_file_aux_num("mac_filter", 0600, 2986 + rvu->rvu_dbg.lmac, cgx, lmac_id, 2959 2987 &rvu_dbg_cgx_dmac_flt_fops); 2960 2988 } 2961 2989 }
+1 -4
drivers/net/ethernet/marvell/skge.c
··· 3742 3742 skge = netdev_priv(dev); 3743 3743 switch (event) { 3744 3744 case NETDEV_CHANGENAME: 3745 - if (skge->debugfs) 3746 - skge->debugfs = debugfs_rename(skge_debug, 3747 - skge->debugfs, 3748 - skge_debug, dev->name); 3745 + debugfs_change_name(skge->debugfs, "%s", dev->name); 3749 3746 break; 3750 3747 3751 3748 case NETDEV_GOING_DOWN:
+1 -4
drivers/net/ethernet/marvell/sky2.c
··· 4494 4494 4495 4495 switch (event) { 4496 4496 case NETDEV_CHANGENAME: 4497 - if (sky2->debugfs) { 4498 - sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs, 4499 - sky2_debug, dev->name); 4500 - } 4497 + debugfs_change_name(sky2->debugfs, "%s", dev->name); 4501 4498 break; 4502 4499 4503 4500 case NETDEV_GOING_DOWN:
+1 -5
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
··· 6535 6535 6536 6536 switch (event) { 6537 6537 case NETDEV_CHANGENAME: 6538 - if (priv->dbgfs_dir) 6539 - priv->dbgfs_dir = debugfs_rename(stmmac_fs_dir, 6540 - priv->dbgfs_dir, 6541 - stmmac_fs_dir, 6542 - dev->name); 6538 + debugfs_change_name(priv->dbgfs_dir, "%s", dev->name); 6543 6539 break; 6544 6540 } 6545 6541 done:
+13 -16
drivers/net/netdevsim/hwstats.c
··· 331 331 }; 332 332 333 333 struct nsim_dev_hwstats_fops { 334 - const struct file_operations fops; 335 334 enum nsim_dev_hwstats_do action; 336 335 enum netdev_offload_xstats_type type; 337 336 }; ··· 341 342 size_t count, loff_t *ppos) 342 343 { 343 344 struct nsim_dev_hwstats *hwstats = file->private_data; 344 - struct nsim_dev_hwstats_fops *hwsfops; 345 + const struct nsim_dev_hwstats_fops *hwsfops; 345 346 struct list_head *hwsdev_list; 346 347 int ifindex; 347 348 int err; 348 349 349 - hwsfops = container_of(debugfs_real_fops(file), 350 - struct nsim_dev_hwstats_fops, fops); 350 + hwsfops = debugfs_get_aux(file); 351 351 352 352 err = kstrtoint_from_user(data, count, 0, &ifindex); 353 353 if (err) ··· 379 381 return count; 380 382 } 381 383 384 + static struct debugfs_short_fops debugfs_ops = { 385 + .write = nsim_dev_hwstats_do_write, 386 + .llseek = generic_file_llseek, 387 + }; 388 + 382 389 #define NSIM_DEV_HWSTATS_FOPS(ACTION, TYPE) \ 383 390 { \ 384 - .fops = { \ 385 - .open = simple_open, \ 386 - .write = nsim_dev_hwstats_do_write, \ 387 - .llseek = generic_file_llseek, \ 388 - .owner = THIS_MODULE, \ 389 - }, \ 390 391 .action = ACTION, \ 391 392 .type = TYPE, \ 392 393 } ··· 430 433 goto err_remove_hwstats_recursive; 431 434 } 432 435 433 - debugfs_create_file("enable_ifindex", 0200, hwstats->l3_ddir, hwstats, 434 - &nsim_dev_hwstats_l3_enable_fops.fops); 435 - debugfs_create_file("disable_ifindex", 0200, hwstats->l3_ddir, hwstats, 436 - &nsim_dev_hwstats_l3_disable_fops.fops); 437 - debugfs_create_file("fail_next_enable", 0200, hwstats->l3_ddir, hwstats, 438 - &nsim_dev_hwstats_l3_fail_fops.fops); 436 + debugfs_create_file_aux("enable_ifindex", 0200, hwstats->l3_ddir, hwstats, 437 + &nsim_dev_hwstats_l3_enable_fops, &debugfs_ops); 438 + debugfs_create_file_aux("disable_ifindex", 0200, hwstats->l3_ddir, hwstats, 439 + &nsim_dev_hwstats_l3_disable_fops, &debugfs_ops); 440 + debugfs_create_file_aux("fail_next_enable", 0200, hwstats->l3_ddir, hwstats, 441 + &nsim_dev_hwstats_l3_fail_fops, &debugfs_ops); 439 442 440 443 INIT_DELAYED_WORK(&hwstats->traffic_dw, 441 444 &nsim_dev_hwstats_traffic_work);
+12 -16
drivers/net/wireless/ath/carl9170/debug.c
··· 54 54 char *(*read)(struct ar9170 *ar, char *buf, size_t bufsize, 55 55 ssize_t *len); 56 56 ssize_t (*write)(struct ar9170 *aru, const char *buf, size_t size); 57 - const struct file_operations fops; 58 57 59 58 enum carl9170_device_state req_dev_state; 60 59 }; ··· 61 62 static ssize_t carl9170_debugfs_read(struct file *file, char __user *userbuf, 62 63 size_t count, loff_t *ppos) 63 64 { 64 - struct carl9170_debugfs_fops *dfops; 65 + const struct carl9170_debugfs_fops *dfops; 65 66 struct ar9170 *ar; 66 67 char *buf = NULL, *res_buf = NULL; 67 68 ssize_t ret = 0; ··· 74 75 75 76 if (!ar) 76 77 return -ENODEV; 77 - dfops = container_of(debugfs_real_fops(file), 78 - struct carl9170_debugfs_fops, fops); 78 + dfops = debugfs_get_aux(file); 79 79 80 80 if (!dfops->read) 81 81 return -ENOSYS; ··· 111 113 static ssize_t carl9170_debugfs_write(struct file *file, 112 114 const char __user *userbuf, size_t count, loff_t *ppos) 113 115 { 114 - struct carl9170_debugfs_fops *dfops; 116 + const struct carl9170_debugfs_fops *dfops; 115 117 struct ar9170 *ar; 116 118 char *buf = NULL; 117 119 int err = 0; ··· 126 128 127 129 if (!ar) 128 130 return -ENODEV; 129 - dfops = container_of(debugfs_real_fops(file), 130 - struct carl9170_debugfs_fops, fops); 131 + dfops = debugfs_get_aux(file); 131 132 132 133 if (!dfops->write) 133 134 return -ENOSYS; ··· 162 165 return err; 163 166 } 164 167 168 + static struct debugfs_short_fops debugfs_fops = { 169 + .read = carl9170_debugfs_read, 170 + .write = carl9170_debugfs_write, 171 + }; 172 + 165 173 #define __DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, \ 166 174 _attr, _dstate) \ 167 175 static const struct carl9170_debugfs_fops carl_debugfs_##name ##_ops = {\ ··· 175 173 .write = _write, \ 176 174 .attr = _attr, \ 177 175 .req_dev_state = _dstate, \ 178 - .fops = { \ 179 - .open = simple_open, \ 180 - .read = carl9170_debugfs_read, \ 181 - .write = carl9170_debugfs_write, \ 182 - .owner = THIS_MODULE \ 183 - }, \ 184 176 } 185 177 186 178 #define DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, _attr) \ ··· 812 816 ar->hw->wiphy->debugfsdir); 813 817 814 818 #define DEBUGFS_ADD(name) \ 815 - debugfs_create_file(#name, carl_debugfs_##name ##_ops.attr, \ 816 - ar->debug_dir, ar, \ 817 - &carl_debugfs_##name ## _ops.fops) 819 + debugfs_create_file_aux(#name, carl_debugfs_##name ##_ops.attr, \ 820 + ar->debug_dir, ar, &carl_debugfs_##name ## _ops, \ 821 + &debugfs_fops) 818 822 819 823 DEBUGFS_ADD(usb_tx_anch_urbs); 820 824 DEBUGFS_ADD(usb_rx_pool_urbs);
+12 -15
drivers/net/wireless/broadcom/b43/debugfs.c
··· 30 30 struct b43_debugfs_fops { 31 31 ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize); 32 32 int (*write)(struct b43_wldev *dev, const char *buf, size_t count); 33 - struct file_operations fops; 34 33 /* Offset of struct b43_dfs_file in struct b43_dfsentry */ 35 34 size_t file_struct_offset; 36 35 }; ··· 490 491 size_t count, loff_t *ppos) 491 492 { 492 493 struct b43_wldev *dev; 493 - struct b43_debugfs_fops *dfops; 494 + const struct b43_debugfs_fops *dfops; 494 495 struct b43_dfs_file *dfile; 495 496 ssize_t ret; 496 497 char *buf; ··· 510 511 goto out_unlock; 511 512 } 512 513 513 - dfops = container_of(debugfs_real_fops(file), 514 - struct b43_debugfs_fops, fops); 514 + dfops = debugfs_get_aux(file); 515 515 if (!dfops->read) { 516 516 err = -ENOSYS; 517 517 goto out_unlock; ··· 553 555 size_t count, loff_t *ppos) 554 556 { 555 557 struct b43_wldev *dev; 556 - struct b43_debugfs_fops *dfops; 558 + const struct b43_debugfs_fops *dfops; 557 559 char *buf; 558 560 int err = 0; 559 561 ··· 571 573 goto out_unlock; 572 574 } 573 575 574 - dfops = container_of(debugfs_real_fops(file), 575 - struct b43_debugfs_fops, fops); 576 + dfops = debugfs_get_aux(file); 576 577 if (!dfops->write) { 577 578 err = -ENOSYS; 578 579 goto out_unlock; ··· 599 602 } 600 603 601 604 605 + static struct debugfs_short_fops debugfs_ops = { 606 + .read = b43_debugfs_read, 607 + .write = b43_debugfs_write, 608 + .llseek = generic_file_llseek, 609 + }; 610 + 602 611 #define B43_DEBUGFS_FOPS(name, _read, _write) \ 603 612 static struct b43_debugfs_fops fops_##name = { \ 604 613 .read = _read, \ 605 614 .write = _write, \ 606 - .fops = { \ 607 - .open = simple_open, \ 608 - .read = b43_debugfs_read, \ 609 - .write = b43_debugfs_write, \ 610 - .llseek = generic_file_llseek, \ 611 - }, \ 612 615 .file_struct_offset = offsetof(struct b43_dfsentry, \ 613 616 file_##name), \ 614 617 } ··· 700 703 701 704 #define ADD_FILE(name, mode) \ 702 705 do { \ 703 - debugfs_create_file(__stringify(name), \ 706 + debugfs_create_file_aux(__stringify(name), \ 704 707 mode, e->subdir, dev, \ 705 - &fops_##name.fops); \ 708 + &fops_##name, &debugfs_ops); \ 706 709 } while (0) 707 710 708 711
+11 -15
drivers/net/wireless/broadcom/b43legacy/debugfs.c
··· 31 31 struct b43legacy_debugfs_fops { 32 32 ssize_t (*read)(struct b43legacy_wldev *dev, char *buf, size_t bufsize); 33 33 int (*write)(struct b43legacy_wldev *dev, const char *buf, size_t count); 34 - struct file_operations fops; 35 34 /* Offset of struct b43legacy_dfs_file in struct b43legacy_dfsentry */ 36 35 size_t file_struct_offset; 37 36 /* Take wl->irq_lock before calling read/write? */ ··· 187 188 size_t count, loff_t *ppos) 188 189 { 189 190 struct b43legacy_wldev *dev; 190 - struct b43legacy_debugfs_fops *dfops; 191 + const struct b43legacy_debugfs_fops *dfops; 191 192 struct b43legacy_dfs_file *dfile; 192 193 ssize_t ret; 193 194 char *buf; ··· 207 208 goto out_unlock; 208 209 } 209 210 210 - dfops = container_of(debugfs_real_fops(file), 211 - struct b43legacy_debugfs_fops, fops); 211 + dfops = debugfs_get_aux(file); 212 212 if (!dfops->read) { 213 213 err = -ENOSYS; 214 214 goto out_unlock; ··· 255 257 size_t count, loff_t *ppos) 256 258 { 257 259 struct b43legacy_wldev *dev; 258 - struct b43legacy_debugfs_fops *dfops; 260 + const struct b43legacy_debugfs_fops *dfops; 259 261 char *buf; 260 262 int err = 0; 261 263 ··· 273 275 goto out_unlock; 274 276 } 275 277 276 - dfops = container_of(debugfs_real_fops(file), 277 - struct b43legacy_debugfs_fops, fops); 278 + dfops = debugfs_get_aux(file); 278 279 if (!dfops->write) { 279 280 err = -ENOSYS; 280 281 goto out_unlock; ··· 305 308 return err ? err : count; 306 309 } 307 310 311 + static struct debugfs_short_fops debugfs_ops = { 312 + .read = b43legacy_debugfs_read, 313 + .write = b43legacy_debugfs_write, 314 + .llseek = generic_file_llseek 315 + }; 308 316 309 317 #define B43legacy_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ 310 318 static struct b43legacy_debugfs_fops fops_##name = { \ 311 319 .read = _read, \ 312 320 .write = _write, \ 313 - .fops = { \ 314 - .open = simple_open, \ 315 - .read = b43legacy_debugfs_read, \ 316 - .write = b43legacy_debugfs_write, \ 317 - .llseek = generic_file_llseek, \ 318 - }, \ 319 321 .file_struct_offset = offsetof(struct b43legacy_dfsentry, \ 320 322 file_##name), \ 321 323 .take_irqlock = _take_irqlock, \ ··· 382 386 383 387 #define ADD_FILE(name, mode) \ 384 388 do { \ 385 - debugfs_create_file(__stringify(name), mode, \ 389 + debugfs_create_file_aux(__stringify(name), mode, \ 386 390 e->subdir, dev, \ 387 - &fops_##name.fops); \ 391 + &fops_##name, &debugfs_ops); \ 388 392 } while (0) 389 393 390 394
+1 -1
drivers/nvdimm/bus.c
··· 1212 1212 DIMM_IOCTL, 1213 1213 }; 1214 1214 1215 - static int match_dimm(struct device *dev, void *data) 1215 + static int match_dimm(struct device *dev, const void *data) 1216 1216 { 1217 1217 long id = (long) data; 1218 1218
+1 -8
drivers/nvdimm/claim.c
··· 67 67 return claimed; 68 68 } 69 69 70 - static int namespace_match(struct device *dev, void *data) 71 - { 72 - char *name = data; 73 - 74 - return strcmp(name, dev_name(dev)) == 0; 75 - } 76 - 77 70 static bool is_idle(struct device *dev, struct nd_namespace_common *ndns) 78 71 { 79 72 struct nd_region *nd_region = to_nd_region(dev->parent); ··· 161 168 goto out; 162 169 } 163 170 164 - found = device_find_child(dev->parent, name, namespace_match); 171 + found = device_find_child_by_name(dev->parent, name); 165 172 if (!found) { 166 173 dev_dbg(dev, "'%s' not found under %s\n", name, 167 174 dev_name(dev->parent));
+5
drivers/of/unittest-data/tests-platform.dtsi
··· 33 33 reg = <0x100>; 34 34 }; 35 35 }; 36 + 37 + test-device@2 { 38 + compatible = "test,rust-device"; 39 + reg = <0x2>; 40 + }; 36 41 }; 37 42 38 43 platform-tests-2 {
+4 -6
drivers/opp/debugfs.c
··· 217 217 { 218 218 struct opp_device *new_dev = NULL, *iter; 219 219 const struct device *dev; 220 - struct dentry *dentry; 220 + int err; 221 221 222 222 /* Look for next opp-dev */ 223 223 list_for_each_entry(iter, &opp_table->dev_list, node) ··· 234 234 235 235 opp_set_dev_name(dev, opp_table->dentry_name); 236 236 237 - dentry = debugfs_rename(rootdir, opp_dev->dentry, rootdir, 238 - opp_table->dentry_name); 239 - if (IS_ERR(dentry)) { 237 + err = debugfs_change_name(opp_dev->dentry, "%s", opp_table->dentry_name); 238 + if (err) { 240 239 dev_err(dev, "%s: Failed to rename link from: %s to %s\n", 241 240 __func__, dev_name(opp_dev->dev), dev_name(dev)); 242 241 return; 243 242 } 244 243 245 - new_dev->dentry = dentry; 246 - opp_table->dentry = dentry; 244 + new_dev->dentry = opp_table->dentry = opp_dev->dentry; 247 245 } 248 246 249 247 /**
+10 -30
drivers/phy/mediatek/phy-mtk-tphy.c
··· 381 381 static int u2_phy_params_show(struct seq_file *sf, void *unused) 382 382 { 383 383 struct mtk_phy_instance *inst = sf->private; 384 - const char *fname = file_dentry(sf->file)->d_iname; 385 384 struct u2phy_banks *u2_banks = &inst->u2_banks; 386 385 void __iomem *com = u2_banks->com; 387 386 u32 max = 0; 388 387 u32 tmp = 0; 389 388 u32 val = 0; 390 - int ret; 391 - 392 - ret = match_string(u2_phy_files, ARRAY_SIZE(u2_phy_files), fname); 393 - if (ret < 0) 394 - return ret; 389 + int ret = debugfs_get_aux_num(sf->file); 395 390 396 391 switch (ret) { 397 392 case U2P_EYE_VRT: ··· 433 438 break; 434 439 } 435 440 436 - seq_printf(sf, "%s : %d [0, %d]\n", fname, val, max); 441 + seq_printf(sf, "%s : %d [0, %d]\n", u2_phy_files[ret], val, max); 437 442 438 443 return 0; 439 444 } ··· 446 451 static ssize_t u2_phy_params_write(struct file *file, const char __user *ubuf, 447 452 size_t count, loff_t *ppos) 448 453 { 449 - const char *fname = file_dentry(file)->d_iname; 450 454 struct seq_file *sf = file->private_data; 451 455 struct mtk_phy_instance *inst = sf->private; 452 456 struct u2phy_banks *u2_banks = &inst->u2_banks; 453 457 void __iomem *com = u2_banks->com; 454 458 ssize_t rc; 455 459 u32 val; 456 - int ret; 460 + int ret = debugfs_get_aux_num(file); 457 461 458 462 rc = kstrtouint_from_user(ubuf, USER_BUF_LEN(count), 0, &val); 459 463 if (rc) 460 464 return rc; 461 - 462 - ret = match_string(u2_phy_files, ARRAY_SIZE(u2_phy_files), fname); 463 - if (ret < 0) 464 - return (ssize_t)ret; 465 465 466 466 switch (ret) { 467 467 case U2P_EYE_VRT: ··· 506 516 int i; 507 517 508 518 for (i = 0; i < count; i++) 509 - debugfs_create_file(u2_phy_files[i], 0644, inst->phy->debugfs, 510 - inst, &u2_phy_fops); 519 + debugfs_create_file_aux_num(u2_phy_files[i], 0644, inst->phy->debugfs, 520 + inst, i, &u2_phy_fops); 511 521 } 512 522 513 523 static int u3_phy_params_show(struct seq_file *sf, void *unused) 514 524 { 515 525 struct mtk_phy_instance *inst = sf->private; 516 - const char *fname = file_dentry(sf->file)->d_iname; 517 526 struct u3phy_banks *u3_banks = &inst->u3_banks; 518 527 u32 val = 0; 519 528 u32 max = 0; 520 529 u32 tmp; 521 - int ret; 522 - 523 - ret = match_string(u3_phy_files, ARRAY_SIZE(u3_phy_files), fname); 524 - if (ret < 0) 525 - return ret; 530 + int ret = debugfs_get_aux_num(sf->file); 526 531 527 532 switch (ret) { 528 533 case U3P_EFUSE_EN: ··· 549 564 break; 550 565 } 551 566 552 - seq_printf(sf, "%s : %d [0, %d]\n", fname, val, max); 567 + seq_printf(sf, "%s : %d [0, %d]\n", u3_phy_files[ret], val, max); 553 568 554 569 return 0; 555 570 } ··· 562 577 static ssize_t u3_phy_params_write(struct file *file, const char __user *ubuf, 563 578 size_t count, loff_t *ppos) 564 579 { 565 - const char *fname = file_dentry(file)->d_iname; 566 580 struct seq_file *sf = file->private_data; 567 581 struct mtk_phy_instance *inst = sf->private; 568 582 struct u3phy_banks *u3_banks = &inst->u3_banks; 569 583 void __iomem *phyd = u3_banks->phyd; 570 584 ssize_t rc; 571 585 u32 val; 572 - int ret; 586 + int ret = debugfs_get_aux_num(sf->file); 573 587 574 588 rc = kstrtouint_from_user(ubuf, USER_BUF_LEN(count), 0, &val); 575 589 if (rc) 576 590 return rc; 577 - 578 - ret = match_string(u3_phy_files, ARRAY_SIZE(u3_phy_files), fname); 579 - if (ret < 0) 580 - return (ssize_t)ret; 581 591 582 592 switch (ret) { 583 593 case U3P_EFUSE_EN: ··· 616 636 int i; 617 637 618 638 for (i = 0; i < count; i++) 619 - debugfs_create_file(u3_phy_files[i], 0644, inst->phy->debugfs, 620 - inst, &u3_phy_fops); 639 + debugfs_create_file_aux_num(u3_phy_files[i], 0644, inst->phy->debugfs, 640 + inst, i, &u3_phy_fops); 621 641 } 622 642 623 643 static int phy_type_show(struct seq_file *sf, void *unused)
+1 -1
drivers/pwm/core.c
··· 1285 1285 return 0; 1286 1286 } 1287 1287 1288 - static int pwm_unexport_match(struct device *pwm_dev, void *data) 1288 + static int pwm_unexport_match(struct device *pwm_dev, const void *data) 1289 1289 { 1290 1290 return pwm_from_dev(pwm_dev) == data; 1291 1291 }
+2 -2
drivers/rpmsg/rpmsg_core.c
··· 377 377 * this is used to make sure we're not creating rpmsg devices for channels 378 378 * that already exist. 379 379 */ 380 - static int rpmsg_device_match(struct device *dev, void *data) 380 + static int rpmsg_device_match(struct device *dev, const void *data) 381 381 { 382 - struct rpmsg_channel_info *chinfo = data; 382 + const struct rpmsg_channel_info *chinfo = data; 383 383 struct rpmsg_device *rpdev = to_rpmsg_device(dev); 384 384 385 385 if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src)
+14 -14
drivers/s390/cio/chp.c
··· 128 128 * Channel measurement related functions 129 129 */ 130 130 static ssize_t measurement_chars_read(struct file *filp, struct kobject *kobj, 131 - struct bin_attribute *bin_attr, 131 + const struct bin_attribute *bin_attr, 132 132 char *buf, loff_t off, size_t count) 133 133 { 134 134 struct channel_path *chp; ··· 142 142 return memory_read_from_buffer(buf, count, &off, &chp->cmg_chars, 143 143 sizeof(chp->cmg_chars)); 144 144 } 145 - static BIN_ATTR_ADMIN_RO(measurement_chars, sizeof(struct cmg_chars)); 145 + static const BIN_ATTR_ADMIN_RO(measurement_chars, sizeof(struct cmg_chars)); 146 146 147 147 static ssize_t measurement_chars_full_read(struct file *filp, 148 148 struct kobject *kobj, 149 - struct bin_attribute *bin_attr, 149 + const struct bin_attribute *bin_attr, 150 150 char *buf, loff_t off, size_t count) 151 151 { 152 152 struct channel_path *chp = to_channelpath(kobj_to_dev(kobj)); ··· 196 196 } 197 197 198 198 static ssize_t measurement_read(struct file *filp, struct kobject *kobj, 199 - struct bin_attribute *bin_attr, 199 + const struct bin_attribute *bin_attr, 200 200 char *buf, loff_t off, size_t count) 201 201 { 202 202 return chp_measurement_copy_block(buf, off, count, kobj, false); 203 203 } 204 - static BIN_ATTR_ADMIN_RO(measurement, sizeof(struct cmg_entry)); 204 + static const BIN_ATTR_ADMIN_RO(measurement, sizeof(struct cmg_entry)); 205 205 206 206 static ssize_t ext_measurement_read(struct file *filp, struct kobject *kobj, 207 - struct bin_attribute *bin_attr, 207 + const struct bin_attribute *bin_attr, 208 208 char *buf, loff_t off, size_t count) 209 209 { 210 210 return chp_measurement_copy_block(buf, off, count, kobj, true); 211 211 } 212 - static BIN_ATTR_ADMIN_RO(ext_measurement, sizeof(struct cmg_ext_entry)); 212 + static const BIN_ATTR_ADMIN_RO(ext_measurement, sizeof(struct cmg_ext_entry)); 213 213 214 - static struct bin_attribute *measurement_attrs[] = { 214 + static const struct bin_attribute *measurement_attrs[] = { 215 215 &bin_attr_measurement_chars, 216 216 &bin_attr_measurement_chars_full, 217 217 &bin_attr_measurement, ··· 435 435 static DEVICE_ATTR_RO(speed_bps); 436 436 437 437 static ssize_t util_string_read(struct file *filp, struct kobject *kobj, 438 - struct bin_attribute *attr, char *buf, 438 + const struct bin_attribute *attr, char *buf, 439 439 loff_t off, size_t count) 440 440 { 441 441 struct channel_path *chp = to_channelpath(kobj_to_dev(kobj)); ··· 448 448 449 449 return rc; 450 450 } 451 - static BIN_ATTR_RO(util_string, 452 - sizeof(((struct channel_path_desc_fmt3 *)0)->util_str)); 451 + static const BIN_ATTR_RO(util_string, 452 + sizeof(((struct channel_path_desc_fmt3 *)0)->util_str)); 453 453 454 - static struct bin_attribute *chp_bin_attrs[] = { 454 + static const struct bin_attribute *const chp_bin_attrs[] = { 455 455 &bin_attr_util_string, 456 456 NULL, 457 457 }; ··· 468 468 &dev_attr_speed_bps.attr, 469 469 NULL, 470 470 }; 471 - static struct attribute_group chp_attr_group = { 471 + static const struct attribute_group chp_attr_group = { 472 472 .attrs = chp_attrs, 473 - .bin_attrs = chp_bin_attrs, 473 + .bin_attrs_new = chp_bin_attrs, 474 474 }; 475 475 static const struct attribute_group *chp_attr_groups[] = { 476 476 &chp_attr_group,
+2 -1
drivers/scsi/qla4xxx/ql4_os.c
··· 7189 7189 * 1: if flashnode entry is non-persistent 7190 7190 * 0: if flashnode entry is persistent 7191 7191 **/ 7192 - static int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data) 7192 + static int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, 7193 + const void *data) 7193 7194 { 7194 7195 struct iscsi_bus_flash_session *fnode_sess; 7195 7196
+5 -5
drivers/scsi/scsi_transport_iscsi.c
··· 1324 1324 * 1 on success 1325 1325 * 0 on failure 1326 1326 */ 1327 - static int iscsi_is_flashnode_conn_dev(struct device *dev, void *data) 1327 + static int iscsi_is_flashnode_conn_dev(struct device *dev, const void *data) 1328 1328 { 1329 1329 return dev->bus == &iscsi_flashnode_bus; 1330 1330 } ··· 1335 1335 return 0; 1336 1336 } 1337 1337 1338 - static int flashnode_match_index(struct device *dev, void *data) 1338 + static int flashnode_match_index(struct device *dev, const void *data) 1339 1339 { 1340 1340 struct iscsi_bus_flash_session *fnode_sess = NULL; 1341 1341 int ret = 0; ··· 1344 1344 goto exit_match_index; 1345 1345 1346 1346 fnode_sess = iscsi_dev_to_flash_session(dev); 1347 - ret = (fnode_sess->target_id == *((int *)data)) ? 1 : 0; 1347 + ret = (fnode_sess->target_id == *((const int *)data)) ? 1 : 0; 1348 1348 1349 1349 exit_match_index: 1350 1350 return ret; ··· 1389 1389 * %NULL on failure 1390 1390 */ 1391 1391 struct device * 1392 - iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data, 1393 - int (*fn)(struct device *dev, void *data)) 1392 + iscsi_find_flashnode_sess(struct Scsi_Host *shost, const void *data, 1393 + device_match_t fn) 1394 1394 { 1395 1395 return device_find_child(&shost->shost_gendev, data, fn); 1396 1396 }
+5 -12
drivers/slimbus/core.c
··· 328 328 } 329 329 EXPORT_SYMBOL_GPL(slim_report_absent); 330 330 331 - static bool slim_eaddr_equal(struct slim_eaddr *a, struct slim_eaddr *b) 331 + static bool slim_eaddr_equal(const struct slim_eaddr *a, 332 + const struct slim_eaddr *b) 332 333 { 333 334 return (a->manf_id == b->manf_id && 334 335 a->prod_code == b->prod_code && ··· 337 336 a->instance == b->instance); 338 337 } 339 338 340 - static int slim_match_dev(struct device *dev, void *data) 339 + static int slim_match_dev(struct device *dev, const void *data) 341 340 { 342 - struct slim_eaddr *e_addr = data; 341 + const struct slim_eaddr *e_addr = data; 343 342 struct slim_device *sbdev = to_slim_device(dev); 344 343 345 344 return slim_eaddr_equal(&sbdev->e_addr, e_addr); ··· 385 384 } 386 385 EXPORT_SYMBOL_GPL(slim_get_device); 387 386 388 - static int of_slim_match_dev(struct device *dev, void *data) 389 - { 390 - struct device_node *np = data; 391 - struct slim_device *sbdev = to_slim_device(dev); 392 - 393 - return (sbdev->dev.of_node == np); 394 - } 395 - 396 387 static struct slim_device *of_find_slim_device(struct slim_controller *ctrl, 397 388 struct device_node *np) 398 389 { 399 390 struct slim_device *sbdev; 400 391 struct device *dev; 401 392 402 - dev = device_find_child(ctrl->dev, np, of_slim_match_dev); 393 + dev = device_find_child(ctrl->dev, np, device_match_of_node); 403 394 if (dev) { 404 395 sbdev = to_slim_device(dev); 405 396 return sbdev;
+3 -14
drivers/staging/greybus/camera.c
··· 1128 1128 1129 1129 static int gb_camera_debugfs_open(struct inode *inode, struct file *file) 1130 1130 { 1131 - unsigned int i; 1132 - 1133 - for (i = 0; i < ARRAY_SIZE(gb_camera_debugfs_entries); ++i) { 1134 - const struct gb_camera_debugfs_entry *entry = 1135 - &gb_camera_debugfs_entries[i]; 1136 - 1137 - if (!strcmp(file->f_path.dentry->d_iname, entry->name)) { 1138 - file->private_data = (void *)entry; 1139 - break; 1140 - } 1141 - } 1142 - 1131 + file->private_data = (void *)debugfs_get_aux(file); 1143 1132 return 0; 1144 1133 } 1145 1134 ··· 1164 1175 1165 1176 gcam->debugfs.buffers[i].length = 0; 1166 1177 1167 - debugfs_create_file(entry->name, entry->mask, 1168 - gcam->debugfs.root, gcam, 1178 + debugfs_create_file_aux(entry->name, entry->mask, 1179 + gcam->debugfs.root, gcam, entry, 1169 1180 &gb_camera_debugfs_ops); 1170 1181 } 1171 1182
+1 -1
drivers/thunderbolt/retimer.c
··· 472 472 u8 index; 473 473 }; 474 474 475 - static int retimer_match(struct device *dev, void *data) 475 + static int retimer_match(struct device *dev, const void *data) 476 476 { 477 477 const struct tb_retimer_lookup *lookup = data; 478 478 struct tb_retimer *rt = tb_to_retimer(dev);
+1 -1
drivers/thunderbolt/xdomain.c
··· 1026 1026 return 0; 1027 1027 } 1028 1028 1029 - static int find_service(struct device *dev, void *data) 1029 + static int find_service(struct device *dev, const void *data) 1030 1030 { 1031 1031 const struct tb_property *p = data; 1032 1032 struct tb_service *svc;
+2 -2
drivers/tty/serial/serial_core.c
··· 2349 2349 struct uart_driver *driver; 2350 2350 }; 2351 2351 2352 - static int serial_match_port(struct device *dev, void *data) 2352 + static int serial_match_port(struct device *dev, const void *data) 2353 2353 { 2354 - struct uart_match *match = data; 2354 + const struct uart_match *match = data; 2355 2355 struct tty_driver *tty_drv = match->driver->tty_driver; 2356 2356 dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) + 2357 2357 match->port->line;
+4 -21
drivers/usb/host/xhci-debugfs.c
··· 232 232 233 233 static int xhci_ring_open(struct inode *inode, struct file *file) 234 234 { 235 - int i; 236 - struct xhci_file_map *f_map; 237 - const char *file_name = file_dentry(file)->d_iname; 238 - 239 - for (i = 0; i < ARRAY_SIZE(ring_files); i++) { 240 - f_map = &ring_files[i]; 241 - 242 - if (strcmp(f_map->name, file_name) == 0) 243 - break; 244 - } 235 + const struct xhci_file_map *f_map = debugfs_get_aux(file); 245 236 246 237 return single_open(file, f_map->show, inode->i_private); 247 238 } ··· 309 318 310 319 static int xhci_context_open(struct inode *inode, struct file *file) 311 320 { 312 - int i; 313 - struct xhci_file_map *f_map; 314 - const char *file_name = file_dentry(file)->d_iname; 315 - 316 - for (i = 0; i < ARRAY_SIZE(context_files); i++) { 317 - f_map = &context_files[i]; 318 - 319 - if (strcmp(f_map->name, file_name) == 0) 320 - break; 321 - } 321 + const struct xhci_file_map *f_map = debugfs_get_aux(file); 322 322 323 323 return single_open(file, f_map->show, inode->i_private); 324 324 } ··· 392 410 int i; 393 411 394 412 for (i = 0; i < nentries; i++) 395 - debugfs_create_file(files[i].name, 0444, parent, data, fops); 413 + debugfs_create_file_aux(files[i].name, 0444, parent, 414 + data, &files[i], fops); 396 415 } 397 416 398 417 static struct dentry *xhci_debugfs_create_ring_dir(struct xhci_hcd *xhci,
+7 -33
drivers/usb/mtu3/mtu3_debugfs.c
··· 257 257 258 258 static int mtu3_ep_open(struct inode *inode, struct file *file) 259 259 { 260 - const char *file_name = file_dentry(file)->d_iname; 261 - const struct mtu3_file_map *f_map; 262 - int i; 263 - 264 - for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) { 265 - f_map = &mtu3_ep_files[i]; 266 - 267 - if (strcmp(f_map->name, file_name) == 0) 268 - break; 269 - } 260 + const struct mtu3_file_map *f_map = debugfs_get_aux(file); 270 261 271 262 return single_open(file, f_map->show, inode->i_private); 272 263 } ··· 280 289 281 290 static int mtu3_probe_show(struct seq_file *sf, void *unused) 282 291 { 283 - const char *file_name = file_dentry(sf->file)->d_iname; 284 292 struct mtu3 *mtu = sf->private; 285 - const struct debugfs_reg32 *regs; 286 - int i; 287 - 288 - for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) { 289 - regs = &mtu3_prb_regs[i]; 290 - 291 - if (strcmp(regs->name, file_name) == 0) 292 - break; 293 - } 293 + const struct debugfs_reg32 *regs = debugfs_get_aux(sf->file); 294 294 295 295 seq_printf(sf, "0x%04x - 0x%08x\n", (u32)regs->offset, 296 296 mtu3_readl(mtu->ippc_base, (u32)regs->offset)); ··· 297 315 static ssize_t mtu3_probe_write(struct file *file, const char __user *ubuf, 298 316 size_t count, loff_t *ppos) 299 317 { 300 - const char *file_name = file_dentry(file)->d_iname; 301 318 struct seq_file *sf = file->private_data; 302 319 struct mtu3 *mtu = sf->private; 303 - const struct debugfs_reg32 *regs; 320 + const struct debugfs_reg32 *regs = debugfs_get_aux(file); 304 321 char buf[32]; 305 322 u32 val; 306 - int i; 307 323 308 324 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 309 325 return -EFAULT; ··· 309 329 if (kstrtou32(buf, 0, &val)) 310 330 return -EINVAL; 311 331 312 - for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) { 313 - regs = &mtu3_prb_regs[i]; 314 - 315 - if (strcmp(regs->name, file_name) == 0) 316 - break; 317 - } 318 332 mtu3_writel(mtu->ippc_base, (u32)regs->offset, val); 319 333 320 334 return count; ··· 333 359 334 360 for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) { 335 361 regs = &mtu3_prb_regs[i]; 336 - debugfs_create_file(regs->name, 0644, dir_prb, 337 - mtu, &mtu3_probe_fops); 362 + debugfs_create_file_aux(regs->name, 0644, dir_prb, 363 + mtu, regs, &mtu3_probe_fops); 338 364 } 339 365 340 366 mtu3_debugfs_regset(mtu, mtu->ippc_base, mtu3_prb_regs, ··· 354 380 for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) { 355 381 files = &mtu3_ep_files[i]; 356 382 357 - debugfs_create_file(files->name, 0444, dir_ep, 358 - mep, &mtu3_ep_fops); 383 + debugfs_create_file_aux(files->name, 0444, dir_ep, 384 + mep, files, &mtu3_ep_fops); 359 385 } 360 386 } 361 387
+14 -17
drivers/usb/typec/class.c
··· 230 230 /* ------------------------------------------------------------------------- */ 231 231 /* Alternate Modes */ 232 232 233 - static int altmode_match(struct device *dev, void *data) 233 + static int altmode_match(struct device *dev, const void *data) 234 234 { 235 235 struct typec_altmode *adev = to_typec_altmode(dev); 236 - struct typec_device_id *id = data; 236 + const struct typec_device_id *id = data; 237 237 238 238 if (!is_typec_altmode(dev)) 239 239 return 0; ··· 1284 1284 .release = typec_cable_release, 1285 1285 }; 1286 1286 1287 - static int cable_match(struct device *dev, void *data) 1288 - { 1289 - return is_typec_cable(dev); 1290 - } 1291 - 1292 1287 /** 1293 1288 * typec_cable_get - Get a reference to the USB Type-C cable 1294 1289 * @port: The USB Type-C Port the cable is connected to ··· 1295 1300 { 1296 1301 struct device *dev; 1297 1302 1298 - dev = device_find_child(&port->dev, NULL, cable_match); 1303 + dev = device_find_child(&port->dev, &typec_cable_dev_type, 1304 + device_match_type); 1299 1305 if (!dev) 1300 1306 return NULL; 1301 1307 ··· 2026 2030 /* --------------------------------------- */ 2027 2031 /* Driver callbacks to report role updates */ 2028 2032 2029 - static int partner_match(struct device *dev, void *data) 2030 - { 2031 - return is_typec_partner(dev); 2032 - } 2033 - 2034 2033 static struct typec_partner *typec_get_partner(struct typec_port *port) 2035 2034 { 2036 2035 struct device *dev; 2037 2036 2038 - dev = device_find_child(&port->dev, NULL, partner_match); 2037 + dev = device_find_child(&port->dev, &typec_partner_dev_type, 2038 + device_match_type); 2039 2039 if (!dev) 2040 2040 return NULL; 2041 2041 ··· 2164 2172 sysfs_notify(&port->dev.kobj, NULL, "power_operation_mode"); 2165 2173 kobject_uevent(&port->dev.kobj, KOBJ_CHANGE); 2166 2174 2167 - partner_dev = device_find_child(&port->dev, NULL, partner_match); 2175 + partner_dev = device_find_child(&port->dev, 2176 + &typec_partner_dev_type, 2177 + device_match_type); 2168 2178 if (partner_dev) { 2169 2179 struct typec_partner *partner = to_typec_partner(partner_dev); 2170 2180 ··· 2330 2336 enum usb_pd_svdm_ver svdm_version; 2331 2337 struct device *partner_dev; 2332 2338 2333 - partner_dev = device_find_child(&port->dev, NULL, partner_match); 2339 + partner_dev = device_find_child(&port->dev, 2340 + &typec_partner_dev_type, 2341 + device_match_type); 2334 2342 if (!partner_dev) 2335 2343 return -ENODEV; 2336 2344 ··· 2359 2363 enum usb_pd_svdm_ver svdm_version; 2360 2364 struct device *cable_dev; 2361 2365 2362 - cable_dev = device_find_child(&port->dev, NULL, cable_match); 2366 + cable_dev = device_find_child(&port->dev, &typec_cable_dev_type, 2367 + device_match_type); 2363 2368 if (!cable_dev) 2364 2369 return -ENODEV; 2365 2370
+2 -2
drivers/vfio/mdev/mdev_core.c
··· 76 76 if (ret) 77 77 return ret; 78 78 79 - ret = class_compat_create_link(mdev_bus_compat_class, dev, NULL); 79 + ret = class_compat_create_link(mdev_bus_compat_class, dev); 80 80 if (ret) 81 81 dev_warn(dev, "Failed to create compatibility class link\n"); 82 82 ··· 98 98 dev_info(parent->dev, "MDEV: Unregistering\n"); 99 99 100 100 down_write(&parent->unreg_sem); 101 - class_compat_remove_link(mdev_bus_compat_class, parent->dev, NULL); 101 + class_compat_remove_link(mdev_bus_compat_class, parent->dev); 102 102 device_for_each_child(parent->dev, NULL, mdev_device_remove_cb); 103 103 parent_remove_sysfs_files(parent); 104 104 up_write(&parent->unreg_sem);
+80 -85
fs/debugfs/file.c
··· 47 47 48 48 #define F_DENTRY(filp) ((filp)->f_path.dentry) 49 49 50 + const void *debugfs_get_aux(const struct file *file) 51 + { 52 + return DEBUGFS_I(file_inode(file))->aux; 53 + } 54 + EXPORT_SYMBOL_GPL(debugfs_get_aux); 55 + 50 56 const struct file_operations *debugfs_real_fops(const struct file *filp) 51 57 { 52 58 struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; 53 59 54 - if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) { 60 + if (!fsd) { 55 61 /* 56 62 * Urgh, we've been called w/o a protecting 57 63 * debugfs_file_get(). ··· 90 84 return -EINVAL; 91 85 92 86 d_fsd = READ_ONCE(dentry->d_fsdata); 93 - if (!((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) { 87 + if (d_fsd) { 94 88 fsd = d_fsd; 95 89 } else { 90 + struct inode *inode = dentry->d_inode; 91 + 96 92 if (WARN_ON(mode == DBGFS_GET_ALREADY)) 97 93 return -EINVAL; 98 94 ··· 103 95 return -ENOMEM; 104 96 105 97 if (mode == DBGFS_GET_SHORT) { 106 - fsd->real_fops = NULL; 107 - fsd->short_fops = (void *)((unsigned long)d_fsd & 108 - ~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); 98 + const struct debugfs_short_fops *ops; 99 + ops = fsd->short_fops = DEBUGFS_I(inode)->short_fops; 100 + if (ops->llseek) 101 + fsd->methods |= HAS_LSEEK; 102 + if (ops->read) 103 + fsd->methods |= HAS_READ; 104 + if (ops->write) 105 + fsd->methods |= HAS_WRITE; 109 106 } else { 110 - fsd->real_fops = (void *)((unsigned long)d_fsd & 111 - ~DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); 112 - fsd->short_fops = NULL; 107 + const struct file_operations *ops; 108 + ops = fsd->real_fops = DEBUGFS_I(inode)->real_fops; 109 + if (ops->llseek) 110 + fsd->methods |= HAS_LSEEK; 111 + if (ops->read) 112 + fsd->methods |= HAS_READ; 113 + if (ops->write) 114 + fsd->methods |= HAS_WRITE; 115 + if (ops->unlocked_ioctl) 116 + fsd->methods |= HAS_IOCTL; 117 + if (ops->poll) 118 + fsd->methods |= HAS_POLL; 113 119 } 114 120 refcount_set(&fsd->active_users, 1); 115 121 init_completion(&fsd->active_users_drained); 116 122 INIT_LIST_HEAD(&fsd->cancellations); 117 123 mutex_init(&fsd->cancellations_mtx); 118 124 119 - if (cmpxchg(&dentry->d_fsdata, d_fsd, fsd) != d_fsd) { 125 + d_fsd = cmpxchg(&dentry->d_fsdata, NULL, fsd); 126 + if (d_fsd) { 120 127 mutex_destroy(&fsd->cancellations_mtx); 121 128 kfree(fsd); 122 - fsd = READ_ONCE(dentry->d_fsdata); 129 + fsd = d_fsd; 123 130 } 124 131 } 125 132 ··· 231 208 return; 232 209 233 210 fsd = READ_ONCE(dentry->d_fsdata); 234 - if (WARN_ON(!fsd || 235 - ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT))) 211 + if (WARN_ON(!fsd)) 236 212 return; 237 213 238 214 mutex_lock(&fsd->cancellations_mtx); ··· 262 240 return; 263 241 264 242 fsd = READ_ONCE(dentry->d_fsdata); 265 - if (WARN_ON(!fsd || 266 - ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT))) 243 + if (WARN_ON(!fsd)) 267 244 return; 268 245 269 246 mutex_lock(&fsd->cancellations_mtx); ··· 343 322 #define PROTO(args...) args 344 323 #define ARGS(args...) args 345 324 346 - #define FULL_PROXY_FUNC(name, ret_type, filp, proto, args) \ 325 + #define FULL_PROXY_FUNC(name, ret_type, filp, proto, args, bit, ret) \ 347 326 static ret_type full_proxy_ ## name(proto) \ 348 327 { \ 349 - struct dentry *dentry = F_DENTRY(filp); \ 328 + struct dentry *dentry = F_DENTRY(filp); \ 329 + struct debugfs_fsdata *fsd = dentry->d_fsdata; \ 350 330 const struct file_operations *real_fops; \ 351 331 ret_type r; \ 352 332 \ 333 + if (!(fsd->methods & bit)) \ 334 + return ret; \ 353 335 r = debugfs_file_get(dentry); \ 354 336 if (unlikely(r)) \ 355 337 return r; \ ··· 362 338 return r; \ 363 339 } 364 340 365 - #define FULL_PROXY_FUNC_BOTH(name, ret_type, filp, proto, args) \ 341 + #define FULL_PROXY_FUNC_BOTH(name, ret_type, filp, proto, args, bit, ret) \ 366 342 static ret_type full_proxy_ ## name(proto) \ 367 343 { \ 368 344 struct dentry *dentry = F_DENTRY(filp); \ 369 - struct debugfs_fsdata *fsd; \ 345 + struct debugfs_fsdata *fsd = dentry->d_fsdata; \ 370 346 ret_type r; \ 371 347 \ 348 + if (!(fsd->methods & bit)) \ 349 + return ret; \ 372 350 r = debugfs_file_get(dentry); \ 373 351 if (unlikely(r)) \ 374 352 return r; \ 375 - fsd = dentry->d_fsdata; \ 376 353 if (fsd->real_fops) \ 377 354 r = fsd->real_fops->name(args); \ 378 355 else \ ··· 384 359 385 360 FULL_PROXY_FUNC_BOTH(llseek, loff_t, filp, 386 361 PROTO(struct file *filp, loff_t offset, int whence), 387 - ARGS(filp, offset, whence)); 362 + ARGS(filp, offset, whence), HAS_LSEEK, -ESPIPE); 388 363 389 364 FULL_PROXY_FUNC_BOTH(read, ssize_t, filp, 390 365 PROTO(struct file *filp, char __user *buf, size_t size, 391 366 loff_t *ppos), 392 - ARGS(filp, buf, size, ppos)); 367 + ARGS(filp, buf, size, ppos), HAS_READ, -EINVAL); 393 368 394 369 FULL_PROXY_FUNC_BOTH(write, ssize_t, filp, 395 370 PROTO(struct file *filp, const char __user *buf, 396 371 size_t size, loff_t *ppos), 397 - ARGS(filp, buf, size, ppos)); 372 + ARGS(filp, buf, size, ppos), HAS_WRITE, -EINVAL); 398 373 399 374 FULL_PROXY_FUNC(unlocked_ioctl, long, filp, 400 375 PROTO(struct file *filp, unsigned int cmd, unsigned long arg), 401 - ARGS(filp, cmd, arg)); 376 + ARGS(filp, cmd, arg), HAS_IOCTL, -ENOTTY); 402 377 403 378 static __poll_t full_proxy_poll(struct file *filp, 404 379 struct poll_table_struct *wait) 405 380 { 406 381 struct dentry *dentry = F_DENTRY(filp); 382 + struct debugfs_fsdata *fsd = dentry->d_fsdata; 407 383 __poll_t r = 0; 408 384 const struct file_operations *real_fops; 409 385 386 + if (!(fsd->methods & HAS_POLL)) 387 + return DEFAULT_POLLMASK; 410 388 if (debugfs_file_get(dentry)) 411 389 return EPOLLHUP; 412 390 ··· 421 393 422 394 static int full_proxy_release(struct inode *inode, struct file *filp) 423 395 { 424 - const struct dentry *dentry = F_DENTRY(filp); 425 396 const struct file_operations *real_fops = debugfs_real_fops(filp); 426 - const struct file_operations *proxy_fops = filp->f_op; 427 397 int r = 0; 428 398 429 399 /* ··· 430 404 * not to leak any resources. Releasers must not assume that 431 405 * ->i_private is still being meaningful here. 432 406 */ 433 - if (real_fops && real_fops->release) 407 + if (real_fops->release) 434 408 r = real_fops->release(inode, filp); 435 409 436 - replace_fops(filp, d_inode(dentry)->i_fop); 437 - kfree(proxy_fops); 438 410 fops_put(real_fops); 439 411 return r; 440 412 } 441 413 442 - static void __full_proxy_fops_init(struct file_operations *proxy_fops, 443 - struct debugfs_fsdata *fsd) 444 - { 445 - proxy_fops->release = full_proxy_release; 446 - 447 - if ((fsd->real_fops && fsd->real_fops->llseek) || 448 - (fsd->short_fops && fsd->short_fops->llseek)) 449 - proxy_fops->llseek = full_proxy_llseek; 450 - 451 - if ((fsd->real_fops && fsd->real_fops->read) || 452 - (fsd->short_fops && fsd->short_fops->read)) 453 - proxy_fops->read = full_proxy_read; 454 - 455 - if ((fsd->real_fops && fsd->real_fops->write) || 456 - (fsd->short_fops && fsd->short_fops->write)) 457 - proxy_fops->write = full_proxy_write; 458 - 459 - if (fsd->real_fops && fsd->real_fops->poll) 460 - proxy_fops->poll = full_proxy_poll; 461 - 462 - if (fsd->real_fops && fsd->real_fops->unlocked_ioctl) 463 - proxy_fops->unlocked_ioctl = full_proxy_unlocked_ioctl; 464 - } 465 - 466 - static int full_proxy_open(struct inode *inode, struct file *filp, 467 - enum dbgfs_get_mode mode) 414 + static int full_proxy_open_regular(struct inode *inode, struct file *filp) 468 415 { 469 416 struct dentry *dentry = F_DENTRY(filp); 470 417 const struct file_operations *real_fops; 471 - struct file_operations *proxy_fops = NULL; 472 418 struct debugfs_fsdata *fsd; 473 419 int r; 474 420 475 - r = __debugfs_file_get(dentry, mode); 421 + r = __debugfs_file_get(dentry, DBGFS_GET_REGULAR); 476 422 if (r) 477 423 return r == -EIO ? -ENOENT : r; 478 424 ··· 454 456 if (r) 455 457 goto out; 456 458 457 - if (real_fops && !fops_get(real_fops)) { 459 + if (!fops_get(real_fops)) { 458 460 #ifdef CONFIG_MODULES 459 461 if (real_fops->owner && 460 462 real_fops->owner->state == MODULE_STATE_GOING) { ··· 470 472 goto out; 471 473 } 472 474 473 - proxy_fops = kzalloc(sizeof(*proxy_fops), GFP_KERNEL); 474 - if (!proxy_fops) { 475 - r = -ENOMEM; 476 - goto free_proxy; 477 - } 478 - __full_proxy_fops_init(proxy_fops, fsd); 479 - replace_fops(filp, proxy_fops); 480 - 481 - if (!real_fops || real_fops->open) { 482 - if (real_fops) 483 - r = real_fops->open(inode, filp); 484 - else 485 - r = simple_open(inode, filp); 475 + if (real_fops->open) { 476 + r = real_fops->open(inode, filp); 486 477 if (r) { 487 - replace_fops(filp, d_inode(dentry)->i_fop); 488 - goto free_proxy; 489 - } else if (filp->f_op != proxy_fops) { 478 + fops_put(real_fops); 479 + } else if (filp->f_op != &debugfs_full_proxy_file_operations) { 490 480 /* No protection against file removal anymore. */ 491 481 WARN(1, "debugfs file owner replaced proxy fops: %pd", 492 482 dentry); 493 - goto free_proxy; 483 + fops_put(real_fops); 494 484 } 495 485 } 496 - 497 - goto out; 498 - free_proxy: 499 - kfree(proxy_fops); 500 - fops_put(real_fops); 501 486 out: 502 487 debugfs_file_put(dentry); 503 488 return r; 504 489 } 505 490 506 - static int full_proxy_open_regular(struct inode *inode, struct file *filp) 507 - { 508 - return full_proxy_open(inode, filp, DBGFS_GET_REGULAR); 509 - } 510 - 511 491 const struct file_operations debugfs_full_proxy_file_operations = { 512 492 .open = full_proxy_open_regular, 493 + .release = full_proxy_release, 494 + .llseek = full_proxy_llseek, 495 + .read = full_proxy_read, 496 + .write = full_proxy_write, 497 + .poll = full_proxy_poll, 498 + .unlocked_ioctl = full_proxy_unlocked_ioctl 513 499 }; 514 500 515 501 static int full_proxy_open_short(struct inode *inode, struct file *filp) 516 502 { 517 - return full_proxy_open(inode, filp, DBGFS_GET_SHORT); 503 + struct dentry *dentry = F_DENTRY(filp); 504 + int r; 505 + 506 + r = __debugfs_file_get(dentry, DBGFS_GET_SHORT); 507 + if (r) 508 + return r == -EIO ? -ENOENT : r; 509 + r = debugfs_locked_down(inode, filp, NULL); 510 + if (!r) 511 + r = simple_open(inode, filp); 512 + debugfs_file_put(dentry); 513 + return r; 518 514 } 519 515 520 516 const struct file_operations debugfs_full_short_proxy_file_operations = { 521 517 .open = full_proxy_open_short, 518 + .llseek = full_proxy_llseek, 519 + .read = full_proxy_read, 520 + .write = full_proxy_write, 522 521 }; 523 522 524 523 ssize_t debugfs_attr_read(struct file *file, char __user *buf,
+101 -101
fs/debugfs/inode.c
··· 208 208 return 0; 209 209 } 210 210 211 + static struct kmem_cache *debugfs_inode_cachep __ro_after_init; 212 + 213 + static void init_once(void *foo) 214 + { 215 + struct debugfs_inode_info *info = foo; 216 + inode_init_once(&info->vfs_inode); 217 + } 218 + 219 + static struct inode *debugfs_alloc_inode(struct super_block *sb) 220 + { 221 + struct debugfs_inode_info *info; 222 + info = alloc_inode_sb(sb, debugfs_inode_cachep, GFP_KERNEL); 223 + if (!info) 224 + return NULL; 225 + return &info->vfs_inode; 226 + } 227 + 211 228 static void debugfs_free_inode(struct inode *inode) 212 229 { 213 230 if (S_ISLNK(inode->i_mode)) 214 231 kfree(inode->i_link); 215 - free_inode_nonrcu(inode); 232 + kmem_cache_free(debugfs_inode_cachep, DEBUGFS_I(inode)); 216 233 } 217 234 218 235 static const struct super_operations debugfs_super_operations = { 219 236 .statfs = simple_statfs, 220 237 .show_options = debugfs_show_options, 238 + .alloc_inode = debugfs_alloc_inode, 221 239 .free_inode = debugfs_free_inode, 222 240 }; 223 241 ··· 243 225 { 244 226 struct debugfs_fsdata *fsd = dentry->d_fsdata; 245 227 246 - if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) 247 - return; 248 - 249 - /* check it wasn't a dir (no fsdata) or automount (no real_fops) */ 250 - if (fsd && (fsd->real_fops || fsd->short_fops)) { 228 + if (fsd) { 251 229 WARN_ON(!list_empty(&fsd->cancellations)); 252 230 mutex_destroy(&fsd->cancellations_mtx); 253 231 } 254 - 255 232 kfree(fsd); 256 233 } 257 234 258 235 static struct vfsmount *debugfs_automount(struct path *path) 259 236 { 260 - struct debugfs_fsdata *fsd = path->dentry->d_fsdata; 237 + struct inode *inode = path->dentry->d_inode; 261 238 262 - return fsd->automount(path->dentry, d_inode(path->dentry)->i_private); 239 + return DEBUGFS_I(inode)->automount(path->dentry, inode->i_private); 263 240 } 264 241 265 242 static const struct dentry_operations debugfs_dops = { ··· 424 411 425 412 static struct dentry *__debugfs_create_file(const char *name, umode_t mode, 426 413 struct dentry *parent, void *data, 414 + const void *aux, 427 415 const struct file_operations *proxy_fops, 428 416 const void *real_fops) 429 417 { ··· 455 441 inode->i_private = data; 456 442 457 443 inode->i_op = &debugfs_file_inode_operations; 444 + if (!real_fops) 445 + proxy_fops = &debugfs_noop_file_operations; 458 446 inode->i_fop = proxy_fops; 459 - dentry->d_fsdata = (void *)((unsigned long)real_fops | 460 - DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); 447 + DEBUGFS_I(inode)->raw = real_fops; 448 + DEBUGFS_I(inode)->aux = aux; 461 449 462 450 d_instantiate(dentry, inode); 463 451 fsnotify_create(d_inode(dentry->d_parent), dentry); ··· 468 452 469 453 struct dentry *debugfs_create_file_full(const char *name, umode_t mode, 470 454 struct dentry *parent, void *data, 455 + const void *aux, 471 456 const struct file_operations *fops) 472 457 { 473 - if (WARN_ON((unsigned long)fops & 474 - DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) 475 - return ERR_PTR(-EINVAL); 476 - 477 - return __debugfs_create_file(name, mode, parent, data, 478 - fops ? &debugfs_full_proxy_file_operations : 479 - &debugfs_noop_file_operations, 458 + return __debugfs_create_file(name, mode, parent, data, aux, 459 + &debugfs_full_proxy_file_operations, 480 460 fops); 481 461 } 482 462 EXPORT_SYMBOL_GPL(debugfs_create_file_full); 483 463 484 464 struct dentry *debugfs_create_file_short(const char *name, umode_t mode, 485 - struct dentry *parent, void *data, 486 - const struct debugfs_short_fops *fops) 465 + struct dentry *parent, void *data, 466 + const void *aux, 467 + const struct debugfs_short_fops *fops) 487 468 { 488 - if (WARN_ON((unsigned long)fops & 489 - DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) 490 - return ERR_PTR(-EINVAL); 491 - 492 - return __debugfs_create_file(name, mode, parent, data, 493 - fops ? &debugfs_full_short_proxy_file_operations : 494 - &debugfs_noop_file_operations, 469 + return __debugfs_create_file(name, mode, parent, data, aux, 470 + &debugfs_full_short_proxy_file_operations, 495 471 fops); 496 472 } 497 473 EXPORT_SYMBOL_GPL(debugfs_create_file_short); ··· 520 512 const struct file_operations *fops) 521 513 { 522 514 523 - return __debugfs_create_file(name, mode, parent, data, 524 - fops ? &debugfs_open_proxy_file_operations : 525 - &debugfs_noop_file_operations, 515 + return __debugfs_create_file(name, mode, parent, data, NULL, 516 + &debugfs_open_proxy_file_operations, 526 517 fops); 527 518 } 528 519 EXPORT_SYMBOL_GPL(debugfs_create_file_unsafe); ··· 631 624 void *data) 632 625 { 633 626 struct dentry *dentry = start_creating(name, parent); 634 - struct debugfs_fsdata *fsd; 635 627 struct inode *inode; 636 628 637 629 if (IS_ERR(dentry)) 638 630 return dentry; 639 631 640 - fsd = kzalloc(sizeof(*fsd), GFP_KERNEL); 641 - if (!fsd) { 642 - failed_creating(dentry); 643 - return ERR_PTR(-ENOMEM); 644 - } 645 - 646 - fsd->automount = f; 647 - 648 632 if (!(debugfs_allow & DEBUGFS_ALLOW_API)) { 649 633 failed_creating(dentry); 650 - kfree(fsd); 651 634 return ERR_PTR(-EPERM); 652 635 } 653 636 ··· 645 648 if (unlikely(!inode)) { 646 649 pr_err("out of free dentries, can not create automount '%s'\n", 647 650 name); 648 - kfree(fsd); 649 651 return failed_creating(dentry); 650 652 } 651 653 652 654 make_empty_dir_inode(inode); 653 655 inode->i_flags |= S_AUTOMOUNT; 654 656 inode->i_private = data; 655 - dentry->d_fsdata = fsd; 657 + DEBUGFS_I(inode)->automount = f; 656 658 /* directory inodes start off with i_nlink == 2 (for "." entry) */ 657 659 inc_nlink(inode); 658 660 d_instantiate(dentry, inode); ··· 726 730 */ 727 731 smp_mb(); 728 732 fsd = READ_ONCE(dentry->d_fsdata); 729 - if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) 733 + if (!fsd) 730 734 return; 731 735 732 736 /* if this was the last reference, we're done */ ··· 830 834 EXPORT_SYMBOL_GPL(debugfs_lookup_and_remove); 831 835 832 836 /** 833 - * debugfs_rename - rename a file/directory in the debugfs filesystem 834 - * @old_dir: a pointer to the parent dentry for the renamed object. This 835 - * should be a directory dentry. 836 - * @old_dentry: dentry of an object to be renamed. 837 - * @new_dir: a pointer to the parent dentry where the object should be 838 - * moved. This should be a directory dentry. 839 - * @new_name: a pointer to a string containing the target name. 837 + * debugfs_change_name - rename a file/directory in the debugfs filesystem 838 + * @dentry: dentry of an object to be renamed. 839 + * @fmt: format for new name 840 840 * 841 841 * This function renames a file/directory in debugfs. The target must not 842 842 * exist for rename to succeed. 843 843 * 844 - * This function will return a pointer to old_dentry (which is updated to 845 - * reflect renaming) if it succeeds. If an error occurs, ERR_PTR(-ERROR) 846 - * will be returned. 844 + * This function will return 0 on success and -E... on failure. 847 845 * 848 846 * If debugfs is not enabled in the kernel, the value -%ENODEV will be 849 847 * returned. 850 848 */ 851 - struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, 852 - struct dentry *new_dir, const char *new_name) 849 + int __printf(2, 3) debugfs_change_name(struct dentry *dentry, const char *fmt, ...) 853 850 { 854 - int error; 855 - struct dentry *dentry = NULL, *trap; 851 + int error = 0; 852 + const char *new_name; 856 853 struct name_snapshot old_name; 854 + struct dentry *parent, *target; 855 + struct inode *dir; 856 + va_list ap; 857 857 858 - if (IS_ERR(old_dir)) 859 - return old_dir; 860 - if (IS_ERR(new_dir)) 861 - return new_dir; 862 - if (IS_ERR_OR_NULL(old_dentry)) 863 - return old_dentry; 858 + if (IS_ERR_OR_NULL(dentry)) 859 + return 0; 864 860 865 - trap = lock_rename(new_dir, old_dir); 866 - /* Source or destination directories don't exist? */ 867 - if (d_really_is_negative(old_dir) || d_really_is_negative(new_dir)) 868 - goto exit; 869 - /* Source does not exist, cyclic rename, or mountpoint? */ 870 - if (d_really_is_negative(old_dentry) || old_dentry == trap || 871 - d_mountpoint(old_dentry)) 872 - goto exit; 873 - dentry = lookup_one_len(new_name, new_dir, strlen(new_name)); 874 - /* Lookup failed, cyclic rename or target exists? */ 875 - if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry)) 876 - goto exit; 861 + va_start(ap, fmt); 862 + new_name = kvasprintf_const(GFP_KERNEL, fmt, ap); 863 + va_end(ap); 864 + if (!new_name) 865 + return -ENOMEM; 877 866 878 - take_dentry_name_snapshot(&old_name, old_dentry); 867 + parent = dget_parent(dentry); 868 + dir = d_inode(parent); 869 + inode_lock(dir); 879 870 880 - error = simple_rename(&nop_mnt_idmap, d_inode(old_dir), old_dentry, 881 - d_inode(new_dir), dentry, 0); 882 - if (error) { 883 - release_dentry_name_snapshot(&old_name); 884 - goto exit; 871 + take_dentry_name_snapshot(&old_name, dentry); 872 + 873 + if (WARN_ON_ONCE(dentry->d_parent != parent)) { 874 + error = -EINVAL; 875 + goto out; 885 876 } 886 - d_move(old_dentry, dentry); 887 - fsnotify_move(d_inode(old_dir), d_inode(new_dir), &old_name.name, 888 - d_is_dir(old_dentry), 889 - NULL, old_dentry); 877 + if (strcmp(old_name.name.name, new_name) == 0) 878 + goto out; 879 + target = lookup_one_len(new_name, parent, strlen(new_name)); 880 + if (IS_ERR(target)) { 881 + error = PTR_ERR(target); 882 + goto out; 883 + } 884 + if (d_really_is_positive(target)) { 885 + dput(target); 886 + error = -EINVAL; 887 + goto out; 888 + } 889 + simple_rename_timestamp(dir, dentry, dir, target); 890 + d_move(dentry, target); 891 + dput(target); 892 + fsnotify_move(dir, dir, &old_name.name, d_is_dir(dentry), NULL, dentry); 893 + out: 890 894 release_dentry_name_snapshot(&old_name); 891 - unlock_rename(new_dir, old_dir); 892 - dput(dentry); 893 - return old_dentry; 894 - exit: 895 - if (dentry && !IS_ERR(dentry)) 896 - dput(dentry); 897 - unlock_rename(new_dir, old_dir); 898 - if (IS_ERR(dentry)) 899 - return dentry; 900 - return ERR_PTR(-EINVAL); 895 + inode_unlock(dir); 896 + dput(parent); 897 + kfree_const(new_name); 898 + return error; 901 899 } 902 - EXPORT_SYMBOL_GPL(debugfs_rename); 900 + EXPORT_SYMBOL_GPL(debugfs_change_name); 903 901 904 902 /** 905 903 * debugfs_initialized - Tells whether debugfs has been registered ··· 929 939 if (retval) 930 940 return retval; 931 941 932 - retval = register_filesystem(&debug_fs_type); 933 - if (retval) 942 + debugfs_inode_cachep = kmem_cache_create("debugfs_inode_cache", 943 + sizeof(struct debugfs_inode_info), 0, 944 + SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT, 945 + init_once); 946 + if (debugfs_inode_cachep == NULL) { 934 947 sysfs_remove_mount_point(kernel_kobj, "debug"); 935 - else 936 - debugfs_registered = true; 948 + return -ENOMEM; 949 + } 937 950 938 - return retval; 951 + retval = register_filesystem(&debug_fs_type); 952 + if (retval) { // Really not going to happen 953 + sysfs_remove_mount_point(kernel_kobj, "debug"); 954 + kmem_cache_destroy(debugfs_inode_cachep); 955 + return retval; 956 + } 957 + debugfs_registered = true; 958 + return 0; 939 959 } 940 960 core_initcall(debugfs_init);
+30 -18
fs/debugfs/internal.h
··· 11 11 12 12 struct file_operations; 13 13 14 + struct debugfs_inode_info { 15 + struct inode vfs_inode; 16 + union { 17 + const void *raw; 18 + const struct file_operations *real_fops; 19 + const struct debugfs_short_fops *short_fops; 20 + debugfs_automount_t automount; 21 + }; 22 + const void *aux; 23 + }; 24 + 25 + static inline struct debugfs_inode_info *DEBUGFS_I(struct inode *inode) 26 + { 27 + return container_of(inode, struct debugfs_inode_info, vfs_inode); 28 + } 29 + 14 30 /* declared over in file.c */ 15 31 extern const struct file_operations debugfs_noop_file_operations; 16 32 extern const struct file_operations debugfs_open_proxy_file_operations; ··· 36 20 struct debugfs_fsdata { 37 21 const struct file_operations *real_fops; 38 22 const struct debugfs_short_fops *short_fops; 39 - union { 40 - /* automount_fn is used when real_fops is NULL */ 41 - debugfs_automount_t automount; 42 - struct { 43 - refcount_t active_users; 44 - struct completion active_users_drained; 23 + struct { 24 + refcount_t active_users; 25 + struct completion active_users_drained; 45 26 46 - /* protect cancellations */ 47 - struct mutex cancellations_mtx; 48 - struct list_head cancellations; 49 - }; 27 + /* protect cancellations */ 28 + struct mutex cancellations_mtx; 29 + struct list_head cancellations; 30 + unsigned int methods; 50 31 }; 51 32 }; 52 33 53 - /* 54 - * A dentry's ->d_fsdata either points to the real fops or to a 55 - * dynamically allocated debugfs_fsdata instance. 56 - * In order to distinguish between these two cases, a real fops 57 - * pointer gets its lowest bit set. 58 - */ 59 - #define DEBUGFS_FSDATA_IS_REAL_FOPS_BIT BIT(0) 34 + enum { 35 + HAS_READ = 1, 36 + HAS_WRITE = 2, 37 + HAS_LSEEK = 4, 38 + HAS_POLL = 8, 39 + HAS_IOCTL = 16 40 + }; 60 41 61 - /* Access BITS */ 62 42 #define DEBUGFS_ALLOW_API BIT(0) 63 43 #define DEBUGFS_ALLOW_MOUNT BIT(1) 64 44
+7 -9
fs/orangefs/orangefs-debugfs.c
··· 206 206 pr_info("%s: overflow 1!\n", __func__); 207 207 } 208 208 209 - debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE, 0444, debug_dir, k_buffer, 210 - &kernel_debug_fops); 209 + debugfs_create_file_aux_num(ORANGEFS_KMOD_DEBUG_FILE, 0444, debug_dir, k_buffer, 210 + 0, &kernel_debug_fops); 211 211 } 212 212 213 213 ··· 306 306 pr_info("%s: overflow! 2\n", __func__); 307 307 } 308 308 309 - client_debug_dentry = debugfs_create_file(ORANGEFS_CLIENT_DEBUG_FILE, 310 - 0444, 311 - debug_dir, 312 - c_buffer, 313 - &kernel_debug_fops); 309 + client_debug_dentry = debugfs_create_file_aux_num( 310 + ORANGEFS_CLIENT_DEBUG_FILE, 311 + 0444, debug_dir, c_buffer, 1, 312 + &kernel_debug_fops); 314 313 } 315 314 316 315 /* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/ ··· 417 418 * A service operation is required to set a new client-side 418 419 * debug mask. 419 420 */ 420 - if (!strcmp(file->f_path.dentry->d_name.name, 421 - ORANGEFS_KMOD_DEBUG_FILE)) { 421 + if (!debugfs_get_aux_num(file)) { // kernel-debug 422 422 debug_string_to_mask(buf, &orangefs_gossip_debug_mask, 0); 423 423 debug_mask_to_string(&orangefs_gossip_debug_mask, 0); 424 424 debug_string = kernel_debug_string;
+1 -1
fs/sysfs/file.c
··· 817 817 * Returns number of bytes written to @buf. 818 818 */ 819 819 ssize_t sysfs_bin_attr_simple_read(struct file *file, struct kobject *kobj, 820 - struct bin_attribute *attr, char *buf, 820 + const struct bin_attribute *attr, char *buf, 821 821 loff_t off, size_t count) 822 822 { 823 823 memcpy(buf, attr->private + off, count);
+34 -10
include/linux/debugfs.h
··· 67 67 68 68 typedef struct vfsmount *(*debugfs_automount_t)(struct dentry *, void *); 69 69 70 - #if defined(CONFIG_DEBUG_FS) 71 - 72 - struct dentry *debugfs_lookup(const char *name, struct dentry *parent); 73 - 74 70 struct debugfs_short_fops { 75 71 ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); 76 72 ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); 77 73 loff_t (*llseek) (struct file *, loff_t, int); 78 74 }; 79 75 76 + #if defined(CONFIG_DEBUG_FS) 77 + 78 + struct dentry *debugfs_lookup(const char *name, struct dentry *parent); 79 + 80 80 struct dentry *debugfs_create_file_full(const char *name, umode_t mode, 81 81 struct dentry *parent, void *data, 82 + const void *aux, 82 83 const struct file_operations *fops); 83 84 struct dentry *debugfs_create_file_short(const char *name, umode_t mode, 84 85 struct dentry *parent, void *data, 86 + const void *aux, 85 87 const struct debugfs_short_fops *fops); 86 88 87 89 /** ··· 128 126 const struct debugfs_short_fops *: debugfs_create_file_short, \ 129 127 struct file_operations *: debugfs_create_file_full, \ 130 128 struct debugfs_short_fops *: debugfs_create_file_short) \ 131 - (name, mode, parent, data, fops) 129 + (name, mode, parent, data, NULL, fops) 130 + 131 + #define debugfs_create_file_aux(name, mode, parent, data, aux, fops) \ 132 + _Generic(fops, \ 133 + const struct file_operations *: debugfs_create_file_full, \ 134 + const struct debugfs_short_fops *: debugfs_create_file_short, \ 135 + struct file_operations *: debugfs_create_file_full, \ 136 + struct debugfs_short_fops *: debugfs_create_file_short) \ 137 + (name, mode, parent, data, aux, fops) 132 138 133 139 struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode, 134 140 struct dentry *parent, void *data, ··· 163 153 void debugfs_lookup_and_remove(const char *name, struct dentry *parent); 164 154 165 155 const struct file_operations *debugfs_real_fops(const struct file *filp); 156 + const void *debugfs_get_aux(const struct file *file); 166 157 167 158 int debugfs_file_get(struct dentry *dentry); 168 159 void debugfs_file_put(struct dentry *dentry); ··· 175 164 ssize_t debugfs_attr_write_signed(struct file *file, const char __user *buf, 176 165 size_t len, loff_t *ppos); 177 166 178 - struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, 179 - struct dentry *new_dir, const char *new_name); 167 + int debugfs_change_name(struct dentry *dentry, const char *fmt, ...) __printf(2, 3); 180 168 181 169 void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, 182 170 u8 *value); ··· 269 259 return ERR_PTR(-ENODEV); 270 260 } 271 261 262 + static inline struct dentry *debugfs_create_file_aux(const char *name, 263 + umode_t mode, struct dentry *parent, 264 + void *data, void *aux, 265 + const void *fops) 266 + { 267 + return ERR_PTR(-ENODEV); 268 + } 269 + 272 270 static inline struct dentry *debugfs_create_file(const char *name, umode_t mode, 273 271 struct dentry *parent, void *data, 274 272 const void *fops) ··· 330 312 { } 331 313 332 314 const struct file_operations *debugfs_real_fops(const struct file *filp); 315 + void *debugfs_get_aux(const struct file *file); 333 316 334 317 static inline int debugfs_file_get(struct dentry *dentry) 335 318 { ··· 360 341 return -ENODEV; 361 342 } 362 343 363 - static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, 364 - struct dentry *new_dir, char *new_name) 344 + static inline int __printf(2, 3) debugfs_change_name(struct dentry *dentry, 345 + const char *fmt, ...) 365 346 { 366 - return ERR_PTR(-ENODEV); 347 + return -ENODEV; 367 348 } 368 349 369 350 static inline void debugfs_create_u8(const char *name, umode_t mode, ··· 470 451 } 471 452 472 453 #endif 454 + 455 + #define debugfs_create_file_aux_num(name, mode, parent, data, n, fops) \ 456 + debugfs_create_file_aux(name, mode, parent, data, \ 457 + (void *)(unsigned long)n, fops) 458 + #define debugfs_get_aux_num(f) (unsigned long)debugfs_get_aux(f) 473 459 474 460 /** 475 461 * debugfs_create_xul - create a debugfs file that is used to read and write an
+54 -12
include/linux/device.h
··· 399 399 #endif 400 400 401 401 /* allows to add/remove a custom action to devres stack */ 402 - void devm_remove_action(struct device *dev, void (*action)(void *), void *data); 402 + int devm_remove_action_nowarn(struct device *dev, void (*action)(void *), void *data); 403 + 404 + /** 405 + * devm_remove_action() - removes previously added custom action 406 + * @dev: Device that owns the action 407 + * @action: Function implementing the action 408 + * @data: Pointer to data passed to @action implementation 409 + * 410 + * Removes instance of @action previously added by devm_add_action(). 411 + * Both action and data should match one of the existing entries. 412 + */ 413 + static inline 414 + void devm_remove_action(struct device *dev, void (*action)(void *), void *data) 415 + { 416 + WARN_ON(devm_remove_action_nowarn(dev, action, data)); 417 + } 418 + 403 419 void devm_release_action(struct device *dev, void (*action)(void *), void *data); 404 420 405 421 int __devm_add_action(struct device *dev, void (*action)(void *), void *data, const char *name); ··· 1090 1074 1091 1075 DEFINE_FREE(device_del, struct device *, if (_T) device_del(_T)) 1092 1076 1093 - int device_for_each_child(struct device *dev, void *data, 1094 - int (*fn)(struct device *dev, void *data)); 1095 - int device_for_each_child_reverse(struct device *dev, void *data, 1096 - int (*fn)(struct device *dev, void *data)); 1077 + int device_for_each_child(struct device *parent, void *data, 1078 + device_iter_t fn); 1079 + int device_for_each_child_reverse(struct device *parent, void *data, 1080 + device_iter_t fn); 1097 1081 int device_for_each_child_reverse_from(struct device *parent, 1098 - struct device *from, const void *data, 1099 - int (*fn)(struct device *, const void *)); 1100 - struct device *device_find_child(struct device *dev, void *data, 1101 - int (*match)(struct device *dev, void *data)); 1102 - struct device *device_find_child_by_name(struct device *parent, 1103 - const char *name); 1104 - struct device *device_find_any_child(struct device *parent); 1082 + struct device *from, void *data, 1083 + device_iter_t fn); 1084 + struct device *device_find_child(struct device *parent, const void *data, 1085 + device_match_t match); 1086 + /** 1087 + * device_find_child_by_name - device iterator for locating a child device. 1088 + * @parent: parent struct device 1089 + * @name: name of the child device 1090 + * 1091 + * This is similar to the device_find_child() function above, but it 1092 + * returns a reference to a device that has the name @name. 1093 + * 1094 + * NOTE: you will need to drop the reference with put_device() after use. 1095 + */ 1096 + static inline struct device *device_find_child_by_name(struct device *parent, 1097 + const char *name) 1098 + { 1099 + return device_find_child(parent, name, device_match_name); 1100 + } 1101 + 1102 + /** 1103 + * device_find_any_child - device iterator for locating a child device, if any. 1104 + * @parent: parent struct device 1105 + * 1106 + * This is similar to the device_find_child() function above, but it 1107 + * returns a reference to a child device, if any. 1108 + * 1109 + * NOTE: you will need to drop the reference with put_device() after use. 1110 + */ 1111 + static inline struct device *device_find_any_child(struct device *parent) 1112 + { 1113 + return device_find_child(parent, NULL, device_match_any); 1114 + } 1105 1115 1106 1116 int device_rename(struct device *dev, const char *new_name); 1107 1117 int device_move(struct device *dev, struct device *new_parent,
+6 -2
include/linux/device/bus.h
··· 134 134 135 135 /* Generic device matching functions that all busses can use to match with */ 136 136 int device_match_name(struct device *dev, const void *name); 137 + int device_match_type(struct device *dev, const void *type); 137 138 int device_match_of_node(struct device *dev, const void *np); 138 139 int device_match_fwnode(struct device *dev, const void *fwnode); 139 140 int device_match_devt(struct device *dev, const void *pdevt); ··· 142 141 int device_match_acpi_handle(struct device *dev, const void *handle); 143 142 int device_match_any(struct device *dev, const void *unused); 144 143 144 + /* Device iterating function type for various driver core for_each APIs */ 145 + typedef int (*device_iter_t)(struct device *dev, void *data); 146 + 145 147 /* iterator helpers for buses */ 146 - int bus_for_each_dev(const struct bus_type *bus, struct device *start, void *data, 147 - int (*fn)(struct device *dev, void *data)); 148 + int bus_for_each_dev(const struct bus_type *bus, struct device *start, 149 + void *data, device_iter_t fn); 148 150 struct device *bus_find_device(const struct bus_type *bus, struct device *start, 149 151 const void *data, device_match_t match); 150 152 /**
+4 -6
include/linux/device/class.h
··· 82 82 struct class_compat; 83 83 struct class_compat *class_compat_register(const char *name); 84 84 void class_compat_unregister(struct class_compat *cls); 85 - int class_compat_create_link(struct class_compat *cls, struct device *dev, 86 - struct device *device_link); 87 - void class_compat_remove_link(struct class_compat *cls, struct device *dev, 88 - struct device *device_link); 85 + int class_compat_create_link(struct class_compat *cls, struct device *dev); 86 + void class_compat_remove_link(struct class_compat *cls, struct device *dev); 89 87 90 88 void class_dev_iter_init(struct class_dev_iter *iter, const struct class *class, 91 89 const struct device *start, const struct device_type *type); 92 90 struct device *class_dev_iter_next(struct class_dev_iter *iter); 93 91 void class_dev_iter_exit(struct class_dev_iter *iter); 94 92 95 - int class_for_each_device(const struct class *class, const struct device *start, void *data, 96 - int (*fn)(struct device *dev, void *data)); 93 + int class_for_each_device(const struct class *class, const struct device *start, 94 + void *data, device_iter_t fn); 97 95 struct device *class_find_device(const struct class *class, const struct device *start, 98 96 const void *data, device_match_t match); 99 97
+1 -1
include/linux/device/driver.h
··· 154 154 int driver_set_override(struct device *dev, const char **override, 155 155 const char *s, size_t len); 156 156 int __must_check driver_for_each_device(struct device_driver *drv, struct device *start, 157 - void *data, int (*fn)(struct device *dev, void *)); 157 + void *data, device_iter_t fn); 158 158 struct device *driver_find_device(const struct device_driver *drv, 159 159 struct device *start, const void *data, 160 160 device_match_t match);
+15 -15
include/linux/fsl/mc.h
··· 438 438 439 439 extern const struct bus_type fsl_mc_bus_type; 440 440 441 - extern struct device_type fsl_mc_bus_dprc_type; 442 - extern struct device_type fsl_mc_bus_dpni_type; 443 - extern struct device_type fsl_mc_bus_dpio_type; 444 - extern struct device_type fsl_mc_bus_dpsw_type; 445 - extern struct device_type fsl_mc_bus_dpbp_type; 446 - extern struct device_type fsl_mc_bus_dpcon_type; 447 - extern struct device_type fsl_mc_bus_dpmcp_type; 448 - extern struct device_type fsl_mc_bus_dpmac_type; 449 - extern struct device_type fsl_mc_bus_dprtc_type; 450 - extern struct device_type fsl_mc_bus_dpseci_type; 451 - extern struct device_type fsl_mc_bus_dpdmux_type; 452 - extern struct device_type fsl_mc_bus_dpdcei_type; 453 - extern struct device_type fsl_mc_bus_dpaiop_type; 454 - extern struct device_type fsl_mc_bus_dpci_type; 455 - extern struct device_type fsl_mc_bus_dpdmai_type; 441 + extern const struct device_type fsl_mc_bus_dprc_type; 442 + extern const struct device_type fsl_mc_bus_dpni_type; 443 + extern const struct device_type fsl_mc_bus_dpio_type; 444 + extern const struct device_type fsl_mc_bus_dpsw_type; 445 + extern const struct device_type fsl_mc_bus_dpbp_type; 446 + extern const struct device_type fsl_mc_bus_dpcon_type; 447 + extern const struct device_type fsl_mc_bus_dpmcp_type; 448 + extern const struct device_type fsl_mc_bus_dpmac_type; 449 + extern const struct device_type fsl_mc_bus_dprtc_type; 450 + extern const struct device_type fsl_mc_bus_dpseci_type; 451 + extern const struct device_type fsl_mc_bus_dpdmux_type; 452 + extern const struct device_type fsl_mc_bus_dpdcei_type; 453 + extern const struct device_type fsl_mc_bus_dpaiop_type; 454 + extern const struct device_type fsl_mc_bus_dpci_type; 455 + extern const struct device_type fsl_mc_bus_dpdmai_type; 456 456 457 457 static inline bool is_fsl_mc_bus_dprc(const struct fsl_mc_device *mc_dev) 458 458 {
-2
include/linux/kobject_ns.h
··· 52 52 53 53 bool kobj_ns_current_may_mount(enum kobj_ns_type type); 54 54 void *kobj_ns_grab_current(enum kobj_ns_type type); 55 - const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); 56 - const void *kobj_ns_initial(enum kobj_ns_type type); 57 55 void kobj_ns_drop(enum kobj_ns_type type, void *ns); 58 56 59 57 #endif /* _LINUX_KOBJECT_NS_H */
+3 -3
include/linux/sysfs.h
··· 293 293 294 294 #define BIN_ATTRIBUTE_GROUPS(_name) \ 295 295 static const struct attribute_group _name##_group = { \ 296 - .bin_attrs = _name##_attrs, \ 296 + .bin_attrs_new = _name##_attrs, \ 297 297 }; \ 298 298 __ATTRIBUTE_GROUPS(_name) 299 299 ··· 511 511 int sysfs_emit_at(char *buf, int at, const char *fmt, ...); 512 512 513 513 ssize_t sysfs_bin_attr_simple_read(struct file *file, struct kobject *kobj, 514 - struct bin_attribute *attr, char *buf, 514 + const struct bin_attribute *attr, char *buf, 515 515 loff_t off, size_t count); 516 516 517 517 #else /* CONFIG_SYSFS */ ··· 774 774 775 775 static inline ssize_t sysfs_bin_attr_simple_read(struct file *file, 776 776 struct kobject *kobj, 777 - struct bin_attribute *attr, 777 + const struct bin_attribute *attr, 778 778 char *buf, loff_t off, 779 779 size_t count) 780 780 {
+2 -2
include/scsi/scsi_transport_iscsi.h
··· 493 493 extern int iscsi_flashnode_bus_match(struct device *dev, 494 494 const struct device_driver *drv); 495 495 extern struct device * 496 - iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data, 497 - int (*fn)(struct device *dev, void *data)); 496 + iscsi_find_flashnode_sess(struct Scsi_Host *shost, const void *data, 497 + device_match_t fn); 498 498 extern struct device * 499 499 iscsi_find_flashnode_conn(struct iscsi_bus_flash_session *fnode_sess); 500 500
+2 -13
kernel/bpf/btf.c
··· 8001 8001 static LIST_HEAD(btf_modules); 8002 8002 static DEFINE_MUTEX(btf_module_mutex); 8003 8003 8004 - static ssize_t 8005 - btf_module_read(struct file *file, struct kobject *kobj, 8006 - struct bin_attribute *bin_attr, 8007 - char *buf, loff_t off, size_t len) 8008 - { 8009 - const struct btf *btf = bin_attr->private; 8010 - 8011 - memcpy(buf, btf->data + off, len); 8012 - return len; 8013 - } 8014 - 8015 8004 static void purge_cand_cache(struct btf *btf); 8016 8005 8017 8006 static int btf_module_notify(struct notifier_block *nb, unsigned long op, ··· 8061 8072 attr->attr.name = btf->name; 8062 8073 attr->attr.mode = 0444; 8063 8074 attr->size = btf->data_size; 8064 - attr->private = btf; 8065 - attr->read = btf_module_read; 8075 + attr->private = btf->data; 8076 + attr->read_new = sysfs_bin_attr_simple_read; 8066 8077 8067 8078 err = sysfs_create_bin_file(btf_kobj, attr); 8068 8079 if (err) {
+2 -10
kernel/bpf/sysfs_btf.c
··· 12 12 extern char __start_BTF[]; 13 13 extern char __stop_BTF[]; 14 14 15 - static ssize_t 16 - btf_vmlinux_read(struct file *file, struct kobject *kobj, 17 - struct bin_attribute *bin_attr, 18 - char *buf, loff_t off, size_t len) 19 - { 20 - memcpy(buf, __start_BTF + off, len); 21 - return len; 22 - } 23 - 24 15 static struct bin_attribute bin_attr_btf_vmlinux __ro_after_init = { 25 16 .attr = { .name = "vmlinux", .mode = 0444, }, 26 - .read = btf_vmlinux_read, 17 + .read_new = sysfs_bin_attr_simple_read, 27 18 }; 28 19 29 20 struct kobject *btf_kobj; 30 21 31 22 static int __init btf_vmlinux_init(void) 32 23 { 24 + bin_attr_btf_vmlinux.private = __start_BTF; 33 25 bin_attr_btf_vmlinux.size = __stop_BTF - __start_BTF; 34 26 35 27 if (bin_attr_btf_vmlinux.size == 0)
+3 -16
kernel/kheaders.c
··· 29 29 extern char kernel_headers_data[]; 30 30 extern char kernel_headers_data_end[]; 31 31 32 - static ssize_t 33 - ikheaders_read(struct file *file, struct kobject *kobj, 34 - struct bin_attribute *bin_attr, 35 - char *buf, loff_t off, size_t len) 36 - { 37 - memcpy(buf, &kernel_headers_data[off], len); 38 - return len; 39 - } 40 - 41 - static struct bin_attribute kheaders_attr __ro_after_init = { 42 - .attr = { 43 - .name = "kheaders.tar.xz", 44 - .mode = 0444, 45 - }, 46 - .read = &ikheaders_read, 47 - }; 32 + static struct bin_attribute kheaders_attr __ro_after_init = 33 + __BIN_ATTR_SIMPLE_RO(kheaders.tar.xz, 0444); 48 34 49 35 static int __init ikheaders_init(void) 50 36 { 37 + kheaders_attr.private = kernel_headers_data; 51 38 kheaders_attr.size = (kernel_headers_data_end - 52 39 kernel_headers_data); 53 40 return sysfs_create_bin_file(kernel_kobj, &kheaders_attr);
+4 -17
kernel/ksysfs.c
··· 239 239 extern const void __stop_notes; 240 240 #define notes_size (&__stop_notes - &__start_notes) 241 241 242 - static ssize_t notes_read(struct file *filp, struct kobject *kobj, 243 - struct bin_attribute *bin_attr, 244 - char *buf, loff_t off, size_t count) 245 - { 246 - memcpy(buf, &__start_notes + off, count); 247 - return count; 248 - } 249 - 250 - static struct bin_attribute notes_attr __ro_after_init = { 251 - .attr = { 252 - .name = "notes", 253 - .mode = S_IRUGO, 254 - }, 255 - .read = &notes_read, 256 - }; 242 + static __ro_after_init BIN_ATTR_SIMPLE_RO(notes); 257 243 258 244 struct kobject *kernel_kobj; 259 245 EXPORT_SYMBOL_GPL(kernel_kobj); ··· 293 307 goto kset_exit; 294 308 295 309 if (notes_size > 0) { 296 - notes_attr.size = notes_size; 297 - error = sysfs_create_bin_file(kernel_kobj, &notes_attr); 310 + bin_attr_notes.private = (void *)&__start_notes; 311 + bin_attr_notes.size = notes_size; 312 + error = sysfs_create_bin_file(kernel_kobj, &bin_attr_notes); 298 313 if (error) 299 314 goto group_exit; 300 315 }
+1 -1
kernel/module/sysfs.c
··· 190 190 nattr->attr.mode = 0444; 191 191 nattr->size = info->sechdrs[i].sh_size; 192 192 nattr->private = (void *)info->sechdrs[i].sh_addr; 193 - nattr->read = sysfs_bin_attr_simple_read; 193 + nattr->read_new = sysfs_bin_attr_simple_read; 194 194 *(gattr++) = nattr++; 195 195 } 196 196 ++loaded;
-24
lib/kobject.c
··· 1096 1096 } 1097 1097 EXPORT_SYMBOL_GPL(kobj_ns_grab_current); 1098 1098 1099 - const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk) 1100 - { 1101 - const void *ns = NULL; 1102 - 1103 - spin_lock(&kobj_ns_type_lock); 1104 - if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type]) 1105 - ns = kobj_ns_ops_tbl[type]->netlink_ns(sk); 1106 - spin_unlock(&kobj_ns_type_lock); 1107 - 1108 - return ns; 1109 - } 1110 - 1111 - const void *kobj_ns_initial(enum kobj_ns_type type) 1112 - { 1113 - const void *ns = NULL; 1114 - 1115 - spin_lock(&kobj_ns_type_lock); 1116 - if (kobj_ns_type_is_valid(type) && kobj_ns_ops_tbl[type]) 1117 - ns = kobj_ns_ops_tbl[type]->initial_ns(); 1118 - spin_unlock(&kobj_ns_type_lock); 1119 - 1120 - return ns; 1121 - } 1122 - 1123 1099 void kobj_ns_drop(enum kobj_ns_type type, void *ns) 1124 1100 { 1125 1101 spin_lock(&kobj_ns_type_lock);
+2 -14
mm/shrinker_debug.c
··· 195 195 196 196 int shrinker_debugfs_rename(struct shrinker *shrinker, const char *fmt, ...) 197 197 { 198 - struct dentry *entry; 199 - char buf[128]; 200 198 const char *new, *old; 201 199 va_list ap; 202 200 int ret = 0; ··· 211 213 old = shrinker->name; 212 214 shrinker->name = new; 213 215 214 - if (shrinker->debugfs_entry) { 215 - snprintf(buf, sizeof(buf), "%s-%d", shrinker->name, 216 - shrinker->debugfs_id); 217 - 218 - entry = debugfs_rename(shrinker_debugfs_root, 219 - shrinker->debugfs_entry, 220 - shrinker_debugfs_root, buf); 221 - if (IS_ERR(entry)) 222 - ret = PTR_ERR(entry); 223 - else 224 - shrinker->debugfs_entry = entry; 225 - } 216 + ret = debugfs_change_name(shrinker->debugfs_entry, "%s-%d", 217 + shrinker->name, shrinker->debugfs_id); 226 218 227 219 mutex_unlock(&shrinker_mutex); 228 220
+5 -8
mm/slub.c
··· 7509 7509 return -ENOMEM; 7510 7510 } 7511 7511 7512 - if (strcmp(filep->f_path.dentry->d_name.name, "alloc_traces") == 0) 7513 - alloc = TRACK_ALLOC; 7514 - else 7515 - alloc = TRACK_FREE; 7512 + alloc = debugfs_get_aux_num(filep); 7516 7513 7517 7514 if (!alloc_loc_track(t, PAGE_SIZE / sizeof(struct location), GFP_KERNEL)) { 7518 7515 bitmap_free(obj_map); ··· 7565 7568 7566 7569 slab_cache_dir = debugfs_create_dir(s->name, slab_debugfs_root); 7567 7570 7568 - debugfs_create_file("alloc_traces", 0400, 7569 - slab_cache_dir, s, &slab_debugfs_fops); 7571 + debugfs_create_file_aux_num("alloc_traces", 0400, slab_cache_dir, s, 7572 + TRACK_ALLOC, &slab_debugfs_fops); 7570 7573 7571 - debugfs_create_file("free_traces", 0400, 7572 - slab_cache_dir, s, &slab_debugfs_fops); 7574 + debugfs_create_file_aux_num("free_traces", 0400, slab_cache_dir, s, 7575 + TRACK_FREE, &slab_debugfs_fops); 7573 7576 } 7574 7577 7575 7578 void debugfs_slab_release(struct kmem_cache *s)
+1 -1
net/dsa/dsa.c
··· 1367 1367 return dsa_switch_parse_ports_of(ds, dn); 1368 1368 } 1369 1369 1370 - static int dev_is_class(struct device *dev, void *class) 1370 + static int dev_is_class(struct device *dev, const void *class) 1371 1371 { 1372 1372 if (dev->class != NULL && !strcmp(dev->class->name, class)) 1373 1373 return 1;
+3 -6
net/hsr/hsr_debugfs.c
··· 57 57 void hsr_debugfs_rename(struct net_device *dev) 58 58 { 59 59 struct hsr_priv *priv = netdev_priv(dev); 60 - struct dentry *d; 60 + int err; 61 61 62 - d = debugfs_rename(hsr_debugfs_root_dir, priv->node_tbl_root, 63 - hsr_debugfs_root_dir, dev->name); 64 - if (IS_ERR(d)) 62 + err = debugfs_change_name(priv->node_tbl_root, "%s", dev->name); 63 + if (err) 65 64 netdev_warn(dev, "failed to rename\n"); 66 - else 67 - priv->node_tbl_root = d; 68 65 } 69 66 70 67 /* hsr_debugfs_init - create hsr node_table file for dumping
+1 -10
net/mac80211/debugfs_netdev.c
··· 1025 1025 1026 1026 void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) 1027 1027 { 1028 - struct dentry *dir; 1029 - char buf[10 + IFNAMSIZ]; 1030 - 1031 - dir = sdata->vif.debugfs_dir; 1032 - 1033 - if (IS_ERR_OR_NULL(dir)) 1034 - return; 1035 - 1036 - sprintf(buf, "netdev:%s", sdata->name); 1037 - debugfs_rename(dir->d_parent, dir, dir->d_parent, buf); 1028 + debugfs_change_name(sdata->vif.debugfs_dir, "netdev:%s", sdata->name); 1038 1029 } 1039 1030 1040 1031 void ieee80211_debugfs_recreate_netdev(struct ieee80211_sub_if_data *sdata,
+1 -4
net/wireless/core.c
··· 143 143 if (result) 144 144 return result; 145 145 146 - if (!IS_ERR_OR_NULL(rdev->wiphy.debugfsdir)) 147 - debugfs_rename(rdev->wiphy.debugfsdir->d_parent, 148 - rdev->wiphy.debugfsdir, 149 - rdev->wiphy.debugfsdir->d_parent, newname); 146 + debugfs_change_name(rdev->wiphy.debugfsdir, "%s", newname); 150 147 151 148 nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); 152 149
+4
rust/bindings/bindings_helper.h
··· 20 20 #include <linux/jump_label.h> 21 21 #include <linux/mdio.h> 22 22 #include <linux/miscdevice.h> 23 + #include <linux/of_device.h> 24 + #include <linux/pci.h> 23 25 #include <linux/phy.h> 24 26 #include <linux/pid_namespace.h> 27 + #include <linux/platform_device.h> 25 28 #include <linux/poll.h> 29 + #include <linux/property.h> 26 30 #include <linux/refcount.h> 27 31 #include <linux/sched.h> 28 32 #include <linux/security.h>
+10
rust/helpers/device.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/device.h> 4 + 5 + int rust_helper_devm_add_action(struct device *dev, 6 + void (*action)(void *), 7 + void *data) 8 + { 9 + return devm_add_action(dev, action, data); 10 + }
+5
rust/helpers/helpers.c
··· 12 12 #include "build_assert.c" 13 13 #include "build_bug.c" 14 14 #include "cred.c" 15 + #include "device.c" 15 16 #include "err.c" 16 17 #include "fs.c" 18 + #include "io.c" 17 19 #include "jump_label.c" 18 20 #include "kunit.c" 19 21 #include "mutex.c" 20 22 #include "page.c" 23 + #include "platform.c" 24 + #include "pci.c" 21 25 #include "pid_namespace.c" 22 26 #include "rbtree.c" 27 + #include "rcu.c" 23 28 #include "refcount.c" 24 29 #include "security.c" 25 30 #include "signal.c"
+101
rust/helpers/io.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/io.h> 4 + 5 + void __iomem *rust_helper_ioremap(phys_addr_t offset, size_t size) 6 + { 7 + return ioremap(offset, size); 8 + } 9 + 10 + void rust_helper_iounmap(volatile void __iomem *addr) 11 + { 12 + iounmap(addr); 13 + } 14 + 15 + u8 rust_helper_readb(const volatile void __iomem *addr) 16 + { 17 + return readb(addr); 18 + } 19 + 20 + u16 rust_helper_readw(const volatile void __iomem *addr) 21 + { 22 + return readw(addr); 23 + } 24 + 25 + u32 rust_helper_readl(const volatile void __iomem *addr) 26 + { 27 + return readl(addr); 28 + } 29 + 30 + #ifdef CONFIG_64BIT 31 + u64 rust_helper_readq(const volatile void __iomem *addr) 32 + { 33 + return readq(addr); 34 + } 35 + #endif 36 + 37 + void rust_helper_writeb(u8 value, volatile void __iomem *addr) 38 + { 39 + writeb(value, addr); 40 + } 41 + 42 + void rust_helper_writew(u16 value, volatile void __iomem *addr) 43 + { 44 + writew(value, addr); 45 + } 46 + 47 + void rust_helper_writel(u32 value, volatile void __iomem *addr) 48 + { 49 + writel(value, addr); 50 + } 51 + 52 + #ifdef CONFIG_64BIT 53 + void rust_helper_writeq(u64 value, volatile void __iomem *addr) 54 + { 55 + writeq(value, addr); 56 + } 57 + #endif 58 + 59 + u8 rust_helper_readb_relaxed(const volatile void __iomem *addr) 60 + { 61 + return readb_relaxed(addr); 62 + } 63 + 64 + u16 rust_helper_readw_relaxed(const volatile void __iomem *addr) 65 + { 66 + return readw_relaxed(addr); 67 + } 68 + 69 + u32 rust_helper_readl_relaxed(const volatile void __iomem *addr) 70 + { 71 + return readl_relaxed(addr); 72 + } 73 + 74 + #ifdef CONFIG_64BIT 75 + u64 rust_helper_readq_relaxed(const volatile void __iomem *addr) 76 + { 77 + return readq_relaxed(addr); 78 + } 79 + #endif 80 + 81 + void rust_helper_writeb_relaxed(u8 value, volatile void __iomem *addr) 82 + { 83 + writeb_relaxed(value, addr); 84 + } 85 + 86 + void rust_helper_writew_relaxed(u16 value, volatile void __iomem *addr) 87 + { 88 + writew_relaxed(value, addr); 89 + } 90 + 91 + void rust_helper_writel_relaxed(u32 value, volatile void __iomem *addr) 92 + { 93 + writel_relaxed(value, addr); 94 + } 95 + 96 + #ifdef CONFIG_64BIT 97 + void rust_helper_writeq_relaxed(u64 value, volatile void __iomem *addr) 98 + { 99 + writeq_relaxed(value, addr); 100 + } 101 + #endif
+18
rust/helpers/pci.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/pci.h> 4 + 5 + void rust_helper_pci_set_drvdata(struct pci_dev *pdev, void *data) 6 + { 7 + pci_set_drvdata(pdev, data); 8 + } 9 + 10 + void *rust_helper_pci_get_drvdata(struct pci_dev *pdev) 11 + { 12 + return pci_get_drvdata(pdev); 13 + } 14 + 15 + resource_size_t rust_helper_pci_resource_len(struct pci_dev *pdev, int bar) 16 + { 17 + return pci_resource_len(pdev, bar); 18 + }
+13
rust/helpers/platform.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/platform_device.h> 4 + 5 + void *rust_helper_platform_get_drvdata(const struct platform_device *pdev) 6 + { 7 + return platform_get_drvdata(pdev); 8 + } 9 + 10 + void rust_helper_platform_set_drvdata(struct platform_device *pdev, void *data) 11 + { 12 + platform_set_drvdata(pdev, data); 13 + }
+13
rust/helpers/rcu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/rcupdate.h> 4 + 5 + void rust_helper_rcu_read_lock(void) 6 + { 7 + rcu_read_lock(); 8 + } 9 + 10 + void rust_helper_rcu_read_unlock(void) 11 + { 12 + rcu_read_unlock(); 13 + }
+7
rust/kernel/device.rs
··· 6 6 7 7 use crate::{ 8 8 bindings, 9 + str::CStr, 9 10 types::{ARef, Opaque}, 10 11 }; 11 12 use core::{fmt, ptr}; ··· 180 179 &msg as *const _ as *const crate::ffi::c_void, 181 180 ) 182 181 }; 182 + } 183 + 184 + /// Checks if property is present or not. 185 + pub fn property_present(&self, name: &CStr) -> bool { 186 + // SAFETY: By the invariant of `CStr`, `name` is null-terminated. 187 + unsafe { bindings::device_property_present(self.as_raw().cast_const(), name.as_char_ptr()) } 183 188 } 184 189 } 185 190
+165
rust/kernel/device_id.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Generic implementation of device IDs. 4 + //! 5 + //! Each bus / subsystem that matches device and driver through a bus / subsystem specific ID is 6 + //! expected to implement [`RawDeviceId`]. 7 + 8 + use core::mem::MaybeUninit; 9 + 10 + /// Marker trait to indicate a Rust device ID type represents a corresponding C device ID type. 11 + /// 12 + /// This is meant to be implemented by buses/subsystems so that they can use [`IdTable`] to 13 + /// guarantee (at compile-time) zero-termination of device id tables provided by drivers. 14 + /// 15 + /// # Safety 16 + /// 17 + /// Implementers must ensure that: 18 + /// - `Self` is layout-compatible with [`RawDeviceId::RawType`]; i.e. it's safe to transmute to 19 + /// `RawDeviceId`. 20 + /// 21 + /// This requirement is needed so `IdArray::new` can convert `Self` to `RawType` when building 22 + /// the ID table. 23 + /// 24 + /// Ideally, this should be achieved using a const function that does conversion instead of 25 + /// transmute; however, const trait functions relies on `const_trait_impl` unstable feature, 26 + /// which is broken/gone in Rust 1.73. 27 + /// 28 + /// - `DRIVER_DATA_OFFSET` is the offset of context/data field of the device ID (usually named 29 + /// `driver_data`) of the device ID, the field is suitable sized to write a `usize` value. 30 + /// 31 + /// Similar to the previous requirement, the data should ideally be added during `Self` to 32 + /// `RawType` conversion, but there's currently no way to do it when using traits in const. 33 + pub unsafe trait RawDeviceId { 34 + /// The raw type that holds the device id. 35 + /// 36 + /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array. 37 + type RawType: Copy; 38 + 39 + /// The offset to the context/data field. 40 + const DRIVER_DATA_OFFSET: usize; 41 + 42 + /// The index stored at `DRIVER_DATA_OFFSET` of the implementor of the [`RawDeviceId`] trait. 43 + fn index(&self) -> usize; 44 + } 45 + 46 + /// A zero-terminated device id array. 47 + #[repr(C)] 48 + pub struct RawIdArray<T: RawDeviceId, const N: usize> { 49 + ids: [T::RawType; N], 50 + sentinel: MaybeUninit<T::RawType>, 51 + } 52 + 53 + impl<T: RawDeviceId, const N: usize> RawIdArray<T, N> { 54 + #[doc(hidden)] 55 + pub const fn size(&self) -> usize { 56 + core::mem::size_of::<Self>() 57 + } 58 + } 59 + 60 + /// A zero-terminated device id array, followed by context data. 61 + #[repr(C)] 62 + pub struct IdArray<T: RawDeviceId, U, const N: usize> { 63 + raw_ids: RawIdArray<T, N>, 64 + id_infos: [U; N], 65 + } 66 + 67 + impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> { 68 + /// Creates a new instance of the array. 69 + /// 70 + /// The contents are derived from the given identifiers and context information. 71 + pub const fn new(ids: [(T, U); N]) -> Self { 72 + let mut raw_ids = [const { MaybeUninit::<T::RawType>::uninit() }; N]; 73 + let mut infos = [const { MaybeUninit::uninit() }; N]; 74 + 75 + let mut i = 0usize; 76 + while i < N { 77 + // SAFETY: by the safety requirement of `RawDeviceId`, we're guaranteed that `T` is 78 + // layout-wise compatible with `RawType`. 79 + raw_ids[i] = unsafe { core::mem::transmute_copy(&ids[i].0) }; 80 + // SAFETY: by the safety requirement of `RawDeviceId`, this would be effectively 81 + // `raw_ids[i].driver_data = i;`. 82 + unsafe { 83 + raw_ids[i] 84 + .as_mut_ptr() 85 + .byte_offset(T::DRIVER_DATA_OFFSET as _) 86 + .cast::<usize>() 87 + .write(i); 88 + } 89 + 90 + // SAFETY: this is effectively a move: `infos[i] = ids[i].1`. We make a copy here but 91 + // later forget `ids`. 92 + infos[i] = MaybeUninit::new(unsafe { core::ptr::read(&ids[i].1) }); 93 + i += 1; 94 + } 95 + 96 + core::mem::forget(ids); 97 + 98 + Self { 99 + raw_ids: RawIdArray { 100 + // SAFETY: this is effectively `array_assume_init`, which is unstable, so we use 101 + // `transmute_copy` instead. We have initialized all elements of `raw_ids` so this 102 + // `array_assume_init` is safe. 103 + ids: unsafe { core::mem::transmute_copy(&raw_ids) }, 104 + sentinel: MaybeUninit::zeroed(), 105 + }, 106 + // SAFETY: We have initialized all elements of `infos` so this `array_assume_init` is 107 + // safe. 108 + id_infos: unsafe { core::mem::transmute_copy(&infos) }, 109 + } 110 + } 111 + 112 + /// Reference to the contained [`RawIdArray`]. 113 + pub const fn raw_ids(&self) -> &RawIdArray<T, N> { 114 + &self.raw_ids 115 + } 116 + } 117 + 118 + /// A device id table. 119 + /// 120 + /// This trait is only implemented by `IdArray`. 121 + /// 122 + /// The purpose of this trait is to allow `&'static dyn IdArray<T, U>` to be in context when `N` in 123 + /// `IdArray` doesn't matter. 124 + pub trait IdTable<T: RawDeviceId, U> { 125 + /// Obtain the pointer to the ID table. 126 + fn as_ptr(&self) -> *const T::RawType; 127 + 128 + /// Obtain the pointer to the bus specific device ID from an index. 129 + fn id(&self, index: usize) -> &T::RawType; 130 + 131 + /// Obtain the pointer to the driver-specific information from an index. 132 + fn info(&self, index: usize) -> &U; 133 + } 134 + 135 + impl<T: RawDeviceId, U, const N: usize> IdTable<T, U> for IdArray<T, U, N> { 136 + fn as_ptr(&self) -> *const T::RawType { 137 + // This cannot be `self.ids.as_ptr()`, as the return pointer must have correct provenance 138 + // to access the sentinel. 139 + (self as *const Self).cast() 140 + } 141 + 142 + fn id(&self, index: usize) -> &T::RawType { 143 + &self.raw_ids.ids[index] 144 + } 145 + 146 + fn info(&self, index: usize) -> &U { 147 + &self.id_infos[index] 148 + } 149 + } 150 + 151 + /// Create device table alias for modpost. 152 + #[macro_export] 153 + macro_rules! module_device_table { 154 + ($table_type: literal, $module_table_name:ident, $table_name:ident) => { 155 + #[rustfmt::skip] 156 + #[export_name = 157 + concat!("__mod_device_table__", $table_type, 158 + "__", module_path!(), 159 + "_", line!(), 160 + "_", stringify!($table_name)) 161 + ] 162 + static $module_table_name: [core::mem::MaybeUninit<u8>; $table_name.raw_ids().size()] = 163 + unsafe { core::mem::transmute_copy($table_name.raw_ids()) }; 164 + }; 165 + }
+201
rust/kernel/devres.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Devres abstraction 4 + //! 5 + //! [`Devres`] represents an abstraction for the kernel devres (device resource management) 6 + //! implementation. 7 + 8 + use crate::{ 9 + alloc::Flags, 10 + bindings, 11 + device::Device, 12 + error::{Error, Result}, 13 + ffi::c_void, 14 + prelude::*, 15 + revocable::Revocable, 16 + sync::Arc, 17 + types::ARef, 18 + }; 19 + 20 + use core::ops::Deref; 21 + 22 + #[pin_data] 23 + struct DevresInner<T> { 24 + dev: ARef<Device>, 25 + callback: unsafe extern "C" fn(*mut c_void), 26 + #[pin] 27 + data: Revocable<T>, 28 + } 29 + 30 + /// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to 31 + /// manage their lifetime. 32 + /// 33 + /// [`Device`] bound resources should be freed when either the resource goes out of scope or the 34 + /// [`Device`] is unbound respectively, depending on what happens first. 35 + /// 36 + /// To achieve that [`Devres`] registers a devres callback on creation, which is called once the 37 + /// [`Device`] is unbound, revoking access to the encapsulated resource (see also [`Revocable`]). 38 + /// 39 + /// After the [`Devres`] has been unbound it is not possible to access the encapsulated resource 40 + /// anymore. 41 + /// 42 + /// [`Devres`] users should make sure to simply free the corresponding backing resource in `T`'s 43 + /// [`Drop`] implementation. 44 + /// 45 + /// # Example 46 + /// 47 + /// ```no_run 48 + /// # use kernel::{bindings, c_str, device::Device, devres::Devres, io::{Io, IoRaw}}; 49 + /// # use core::ops::Deref; 50 + /// 51 + /// // See also [`pci::Bar`] for a real example. 52 + /// struct IoMem<const SIZE: usize>(IoRaw<SIZE>); 53 + /// 54 + /// impl<const SIZE: usize> IoMem<SIZE> { 55 + /// /// # Safety 56 + /// /// 57 + /// /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs 58 + /// /// virtual address space. 59 + /// unsafe fn new(paddr: usize) -> Result<Self>{ 60 + /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is 61 + /// // valid for `ioremap`. 62 + /// let addr = unsafe { bindings::ioremap(paddr as _, SIZE as _) }; 63 + /// if addr.is_null() { 64 + /// return Err(ENOMEM); 65 + /// } 66 + /// 67 + /// Ok(IoMem(IoRaw::new(addr as _, SIZE)?)) 68 + /// } 69 + /// } 70 + /// 71 + /// impl<const SIZE: usize> Drop for IoMem<SIZE> { 72 + /// fn drop(&mut self) { 73 + /// // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`. 74 + /// unsafe { bindings::iounmap(self.0.addr() as _); }; 75 + /// } 76 + /// } 77 + /// 78 + /// impl<const SIZE: usize> Deref for IoMem<SIZE> { 79 + /// type Target = Io<SIZE>; 80 + /// 81 + /// fn deref(&self) -> &Self::Target { 82 + /// // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`. 83 + /// unsafe { Io::from_raw(&self.0) } 84 + /// } 85 + /// } 86 + /// # fn no_run() -> Result<(), Error> { 87 + /// # // SAFETY: Invalid usage; just for the example to get an `ARef<Device>` instance. 88 + /// # let dev = unsafe { Device::get_device(core::ptr::null_mut()) }; 89 + /// 90 + /// // SAFETY: Invalid usage for example purposes. 91 + /// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? }; 92 + /// let devres = Devres::new(&dev, iomem, GFP_KERNEL)?; 93 + /// 94 + /// let res = devres.try_access().ok_or(ENXIO)?; 95 + /// res.writel(0x42, 0x0); 96 + /// # Ok(()) 97 + /// # } 98 + /// ``` 99 + pub struct Devres<T>(Arc<DevresInner<T>>); 100 + 101 + impl<T> DevresInner<T> { 102 + fn new(dev: &Device, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> { 103 + let inner = Arc::pin_init( 104 + pin_init!( DevresInner { 105 + dev: dev.into(), 106 + callback: Self::devres_callback, 107 + data <- Revocable::new(data), 108 + }), 109 + flags, 110 + )?; 111 + 112 + // Convert `Arc<DevresInner>` into a raw pointer and make devres own this reference until 113 + // `Self::devres_callback` is called. 114 + let data = inner.clone().into_raw(); 115 + 116 + // SAFETY: `devm_add_action` guarantees to call `Self::devres_callback` once `dev` is 117 + // detached. 118 + let ret = 119 + unsafe { bindings::devm_add_action(dev.as_raw(), Some(inner.callback), data as _) }; 120 + 121 + if ret != 0 { 122 + // SAFETY: We just created another reference to `inner` in order to pass it to 123 + // `bindings::devm_add_action`. If `bindings::devm_add_action` fails, we have to drop 124 + // this reference accordingly. 125 + let _ = unsafe { Arc::from_raw(data) }; 126 + return Err(Error::from_errno(ret)); 127 + } 128 + 129 + Ok(inner) 130 + } 131 + 132 + fn as_ptr(&self) -> *const Self { 133 + self as _ 134 + } 135 + 136 + fn remove_action(this: &Arc<Self>) { 137 + // SAFETY: 138 + // - `self.inner.dev` is a valid `Device`, 139 + // - the `action` and `data` pointers are the exact same ones as given to devm_add_action() 140 + // previously, 141 + // - `self` is always valid, even if the action has been released already. 142 + let ret = unsafe { 143 + bindings::devm_remove_action_nowarn( 144 + this.dev.as_raw(), 145 + Some(this.callback), 146 + this.as_ptr() as _, 147 + ) 148 + }; 149 + 150 + if ret == 0 { 151 + // SAFETY: We leaked an `Arc` reference to devm_add_action() in `DevresInner::new`; if 152 + // devm_remove_action_nowarn() was successful we can (and have to) claim back ownership 153 + // of this reference. 154 + let _ = unsafe { Arc::from_raw(this.as_ptr()) }; 155 + } 156 + } 157 + 158 + #[allow(clippy::missing_safety_doc)] 159 + unsafe extern "C" fn devres_callback(ptr: *mut kernel::ffi::c_void) { 160 + let ptr = ptr as *mut DevresInner<T>; 161 + // Devres owned this memory; now that we received the callback, drop the `Arc` and hence the 162 + // reference. 163 + // SAFETY: Safe, since we leaked an `Arc` reference to devm_add_action() in 164 + // `DevresInner::new`. 165 + let inner = unsafe { Arc::from_raw(ptr) }; 166 + 167 + inner.data.revoke(); 168 + } 169 + } 170 + 171 + impl<T> Devres<T> { 172 + /// Creates a new [`Devres`] instance of the given `data`. The `data` encapsulated within the 173 + /// returned `Devres` instance' `data` will be revoked once the device is detached. 174 + pub fn new(dev: &Device, data: T, flags: Flags) -> Result<Self> { 175 + let inner = DevresInner::new(dev, data, flags)?; 176 + 177 + Ok(Devres(inner)) 178 + } 179 + 180 + /// Same as [`Devres::new`], but does not return a `Devres` instance. Instead the given `data` 181 + /// is owned by devres and will be revoked / dropped, once the device is detached. 182 + pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -> Result { 183 + let _ = DevresInner::new(dev, data, flags)?; 184 + 185 + Ok(()) 186 + } 187 + } 188 + 189 + impl<T> Deref for Devres<T> { 190 + type Target = Revocable<T>; 191 + 192 + fn deref(&self) -> &Self::Target { 193 + &self.0.data 194 + } 195 + } 196 + 197 + impl<T> Drop for Devres<T> { 198 + fn drop(&mut self) { 199 + DevresInner::remove_action(&self.0); 200 + } 201 + }
+188
rust/kernel/driver.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.). 4 + //! 5 + //! Each bus / subsystem is expected to implement [`RegistrationOps`], which allows drivers to 6 + //! register using the [`Registration`] class. 7 + 8 + use crate::error::{Error, Result}; 9 + use crate::{device, init::PinInit, of, str::CStr, try_pin_init, types::Opaque, ThisModule}; 10 + use core::pin::Pin; 11 + use macros::{pin_data, pinned_drop}; 12 + 13 + /// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, 14 + /// Amba, etc.) to provide the corresponding subsystem specific implementation to register / 15 + /// unregister a driver of the particular type (`RegType`). 16 + /// 17 + /// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call 18 + /// `bindings::__pci_register_driver` from `RegistrationOps::register` and 19 + /// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. 20 + /// 21 + /// # Safety 22 + /// 23 + /// A call to [`RegistrationOps::unregister`] for a given instance of `RegType` is only valid if a 24 + /// preceding call to [`RegistrationOps::register`] has been successful. 25 + pub unsafe trait RegistrationOps { 26 + /// The type that holds information about the registration. This is typically a struct defined 27 + /// by the C portion of the kernel. 28 + type RegType: Default; 29 + 30 + /// Registers a driver. 31 + /// 32 + /// # Safety 33 + /// 34 + /// On success, `reg` must remain pinned and valid until the matching call to 35 + /// [`RegistrationOps::unregister`]. 36 + unsafe fn register( 37 + reg: &Opaque<Self::RegType>, 38 + name: &'static CStr, 39 + module: &'static ThisModule, 40 + ) -> Result; 41 + 42 + /// Unregisters a driver previously registered with [`RegistrationOps::register`]. 43 + /// 44 + /// # Safety 45 + /// 46 + /// Must only be called after a preceding successful call to [`RegistrationOps::register`] for 47 + /// the same `reg`. 48 + unsafe fn unregister(reg: &Opaque<Self::RegType>); 49 + } 50 + 51 + /// A [`Registration`] is a generic type that represents the registration of some driver type (e.g. 52 + /// `bindings::pci_driver`). Therefore a [`Registration`] must be initialized with a type that 53 + /// implements the [`RegistrationOps`] trait, such that the generic `T::register` and 54 + /// `T::unregister` calls result in the subsystem specific registration calls. 55 + /// 56 + ///Once the `Registration` structure is dropped, the driver is unregistered. 57 + #[pin_data(PinnedDrop)] 58 + pub struct Registration<T: RegistrationOps> { 59 + #[pin] 60 + reg: Opaque<T::RegType>, 61 + } 62 + 63 + // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to 64 + // share references to it with multiple threads as nothing can be done. 65 + unsafe impl<T: RegistrationOps> Sync for Registration<T> {} 66 + 67 + // SAFETY: Both registration and unregistration are implemented in C and safe to be performed from 68 + // any thread, so `Registration` is `Send`. 69 + unsafe impl<T: RegistrationOps> Send for Registration<T> {} 70 + 71 + impl<T: RegistrationOps> Registration<T> { 72 + /// Creates a new instance of the registration object. 73 + pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> { 74 + try_pin_init!(Self { 75 + reg <- Opaque::try_ffi_init(|ptr: *mut T::RegType| { 76 + // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write. 77 + unsafe { ptr.write(T::RegType::default()) }; 78 + 79 + // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write, and it has 80 + // just been initialised above, so it's also valid for read. 81 + let drv = unsafe { &*(ptr as *const Opaque<T::RegType>) }; 82 + 83 + // SAFETY: `drv` is guaranteed to be pinned until `T::unregister`. 84 + unsafe { T::register(drv, name, module) } 85 + }), 86 + }) 87 + } 88 + } 89 + 90 + #[pinned_drop] 91 + impl<T: RegistrationOps> PinnedDrop for Registration<T> { 92 + fn drop(self: Pin<&mut Self>) { 93 + // SAFETY: The existence of `self` guarantees that `self.reg` has previously been 94 + // successfully registered with `T::register` 95 + unsafe { T::unregister(&self.reg) }; 96 + } 97 + } 98 + 99 + /// Declares a kernel module that exposes a single driver. 100 + /// 101 + /// It is meant to be used as a helper by other subsystems so they can more easily expose their own 102 + /// macros. 103 + #[macro_export] 104 + macro_rules! module_driver { 105 + (<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => { 106 + type Ops<$gen_type> = $driver_ops; 107 + 108 + #[$crate::prelude::pin_data] 109 + struct DriverModule { 110 + #[pin] 111 + _driver: $crate::driver::Registration<Ops<$type>>, 112 + } 113 + 114 + impl $crate::InPlaceModule for DriverModule { 115 + fn init( 116 + module: &'static $crate::ThisModule 117 + ) -> impl $crate::init::PinInit<Self, $crate::error::Error> { 118 + $crate::try_pin_init!(Self { 119 + _driver <- $crate::driver::Registration::new( 120 + <Self as $crate::ModuleMetadata>::NAME, 121 + module, 122 + ), 123 + }) 124 + } 125 + } 126 + 127 + $crate::prelude::module! { 128 + type: DriverModule, 129 + $($f)* 130 + } 131 + } 132 + } 133 + 134 + /// The bus independent adapter to match a drivers and a devices. 135 + /// 136 + /// This trait should be implemented by the bus specific adapter, which represents the connection 137 + /// of a device and a driver. 138 + /// 139 + /// It provides bus independent functions for device / driver interactions. 140 + pub trait Adapter { 141 + /// The type holding driver private data about each device id supported by the driver. 142 + type IdInfo: 'static; 143 + 144 + /// The [`of::IdTable`] of the corresponding driver. 145 + fn of_id_table() -> Option<of::IdTable<Self::IdInfo>>; 146 + 147 + /// Returns the driver's private data from the matching entry in the [`of::IdTable`], if any. 148 + /// 149 + /// If this returns `None`, it means there is no match with an entry in the [`of::IdTable`]. 150 + #[cfg(CONFIG_OF)] 151 + fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { 152 + let table = Self::of_id_table()?; 153 + 154 + // SAFETY: 155 + // - `table` has static lifetime, hence it's valid for read, 156 + // - `dev` is guaranteed to be valid while it's alive, and so is `pdev.as_ref().as_raw()`. 157 + let raw_id = unsafe { bindings::of_match_device(table.as_ptr(), dev.as_raw()) }; 158 + 159 + if raw_id.is_null() { 160 + None 161 + } else { 162 + // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct of_device_id` and 163 + // does not add additional invariants, so it's safe to transmute. 164 + let id = unsafe { &*raw_id.cast::<of::DeviceId>() }; 165 + 166 + Some(table.info(<of::DeviceId as crate::device_id::RawDeviceId>::index(id))) 167 + } 168 + } 169 + 170 + #[cfg(not(CONFIG_OF))] 171 + #[allow(missing_docs)] 172 + fn of_id_info(_dev: &device::Device) -> Option<&'static Self::IdInfo> { 173 + None 174 + } 175 + 176 + /// Returns the driver's private data from the matching entry of any of the ID tables, if any. 177 + /// 178 + /// If this returns `None`, it means that there is no match in any of the ID tables directly 179 + /// associated with a [`device::Device`]. 180 + fn id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { 181 + let id = Self::of_id_info(dev); 182 + if id.is_some() { 183 + return id; 184 + } 185 + 186 + None 187 + } 188 + }
+260
rust/kernel/io.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Memory-mapped IO. 4 + //! 5 + //! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.h) 6 + 7 + use crate::error::{code::EINVAL, Result}; 8 + use crate::{bindings, build_assert}; 9 + 10 + /// Raw representation of an MMIO region. 11 + /// 12 + /// By itself, the existence of an instance of this structure does not provide any guarantees that 13 + /// the represented MMIO region does exist or is properly mapped. 14 + /// 15 + /// Instead, the bus specific MMIO implementation must convert this raw representation into an `Io` 16 + /// instance providing the actual memory accessors. Only by the conversion into an `Io` structure 17 + /// any guarantees are given. 18 + pub struct IoRaw<const SIZE: usize = 0> { 19 + addr: usize, 20 + maxsize: usize, 21 + } 22 + 23 + impl<const SIZE: usize> IoRaw<SIZE> { 24 + /// Returns a new `IoRaw` instance on success, an error otherwise. 25 + pub fn new(addr: usize, maxsize: usize) -> Result<Self> { 26 + if maxsize < SIZE { 27 + return Err(EINVAL); 28 + } 29 + 30 + Ok(Self { addr, maxsize }) 31 + } 32 + 33 + /// Returns the base address of the MMIO region. 34 + #[inline] 35 + pub fn addr(&self) -> usize { 36 + self.addr 37 + } 38 + 39 + /// Returns the maximum size of the MMIO region. 40 + #[inline] 41 + pub fn maxsize(&self) -> usize { 42 + self.maxsize 43 + } 44 + } 45 + 46 + /// IO-mapped memory, starting at the base address @addr and spanning @maxlen bytes. 47 + /// 48 + /// The creator (usually a subsystem / bus such as PCI) is responsible for creating the 49 + /// mapping, performing an additional region request etc. 50 + /// 51 + /// # Invariant 52 + /// 53 + /// `addr` is the start and `maxsize` the length of valid I/O mapped memory region of size 54 + /// `maxsize`. 55 + /// 56 + /// # Examples 57 + /// 58 + /// ```no_run 59 + /// # use kernel::{bindings, io::{Io, IoRaw}}; 60 + /// # use core::ops::Deref; 61 + /// 62 + /// // See also [`pci::Bar`] for a real example. 63 + /// struct IoMem<const SIZE: usize>(IoRaw<SIZE>); 64 + /// 65 + /// impl<const SIZE: usize> IoMem<SIZE> { 66 + /// /// # Safety 67 + /// /// 68 + /// /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs 69 + /// /// virtual address space. 70 + /// unsafe fn new(paddr: usize) -> Result<Self>{ 71 + /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is 72 + /// // valid for `ioremap`. 73 + /// let addr = unsafe { bindings::ioremap(paddr as _, SIZE as _) }; 74 + /// if addr.is_null() { 75 + /// return Err(ENOMEM); 76 + /// } 77 + /// 78 + /// Ok(IoMem(IoRaw::new(addr as _, SIZE)?)) 79 + /// } 80 + /// } 81 + /// 82 + /// impl<const SIZE: usize> Drop for IoMem<SIZE> { 83 + /// fn drop(&mut self) { 84 + /// // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`. 85 + /// unsafe { bindings::iounmap(self.0.addr() as _); }; 86 + /// } 87 + /// } 88 + /// 89 + /// impl<const SIZE: usize> Deref for IoMem<SIZE> { 90 + /// type Target = Io<SIZE>; 91 + /// 92 + /// fn deref(&self) -> &Self::Target { 93 + /// // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`. 94 + /// unsafe { Io::from_raw(&self.0) } 95 + /// } 96 + /// } 97 + /// 98 + ///# fn no_run() -> Result<(), Error> { 99 + /// // SAFETY: Invalid usage for example purposes. 100 + /// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? }; 101 + /// iomem.writel(0x42, 0x0); 102 + /// assert!(iomem.try_writel(0x42, 0x0).is_ok()); 103 + /// assert!(iomem.try_writel(0x42, 0x4).is_err()); 104 + /// # Ok(()) 105 + /// # } 106 + /// ``` 107 + #[repr(transparent)] 108 + pub struct Io<const SIZE: usize = 0>(IoRaw<SIZE>); 109 + 110 + macro_rules! define_read { 111 + ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => { 112 + /// Read IO data from a given offset known at compile time. 113 + /// 114 + /// Bound checks are performed on compile time, hence if the offset is not known at compile 115 + /// time, the build will fail. 116 + $(#[$attr])* 117 + #[inline] 118 + pub fn $name(&self, offset: usize) -> $type_name { 119 + let addr = self.io_addr_assert::<$type_name>(offset); 120 + 121 + // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 122 + unsafe { bindings::$name(addr as _) } 123 + } 124 + 125 + /// Read IO data from a given offset. 126 + /// 127 + /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is 128 + /// out of bounds. 129 + $(#[$attr])* 130 + pub fn $try_name(&self, offset: usize) -> Result<$type_name> { 131 + let addr = self.io_addr::<$type_name>(offset)?; 132 + 133 + // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 134 + Ok(unsafe { bindings::$name(addr as _) }) 135 + } 136 + }; 137 + } 138 + 139 + macro_rules! define_write { 140 + ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => { 141 + /// Write IO data from a given offset known at compile time. 142 + /// 143 + /// Bound checks are performed on compile time, hence if the offset is not known at compile 144 + /// time, the build will fail. 145 + $(#[$attr])* 146 + #[inline] 147 + pub fn $name(&self, value: $type_name, offset: usize) { 148 + let addr = self.io_addr_assert::<$type_name>(offset); 149 + 150 + // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 151 + unsafe { bindings::$name(value, addr as _, ) } 152 + } 153 + 154 + /// Write IO data from a given offset. 155 + /// 156 + /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is 157 + /// out of bounds. 158 + $(#[$attr])* 159 + pub fn $try_name(&self, value: $type_name, offset: usize) -> Result { 160 + let addr = self.io_addr::<$type_name>(offset)?; 161 + 162 + // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 163 + unsafe { bindings::$name(value, addr as _) } 164 + Ok(()) 165 + } 166 + }; 167 + } 168 + 169 + impl<const SIZE: usize> Io<SIZE> { 170 + /// Converts an `IoRaw` into an `Io` instance, providing the accessors to the MMIO mapping. 171 + /// 172 + /// # Safety 173 + /// 174 + /// Callers must ensure that `addr` is the start of a valid I/O mapped memory region of size 175 + /// `maxsize`. 176 + pub unsafe fn from_raw(raw: &IoRaw<SIZE>) -> &Self { 177 + // SAFETY: `Io` is a transparent wrapper around `IoRaw`. 178 + unsafe { &*core::ptr::from_ref(raw).cast() } 179 + } 180 + 181 + /// Returns the base address of this mapping. 182 + #[inline] 183 + pub fn addr(&self) -> usize { 184 + self.0.addr() 185 + } 186 + 187 + /// Returns the maximum size of this mapping. 188 + #[inline] 189 + pub fn maxsize(&self) -> usize { 190 + self.0.maxsize() 191 + } 192 + 193 + #[inline] 194 + const fn offset_valid<U>(offset: usize, size: usize) -> bool { 195 + let type_size = core::mem::size_of::<U>(); 196 + if let Some(end) = offset.checked_add(type_size) { 197 + end <= size && offset % type_size == 0 198 + } else { 199 + false 200 + } 201 + } 202 + 203 + #[inline] 204 + fn io_addr<U>(&self, offset: usize) -> Result<usize> { 205 + if !Self::offset_valid::<U>(offset, self.maxsize()) { 206 + return Err(EINVAL); 207 + } 208 + 209 + // Probably no need to check, since the safety requirements of `Self::new` guarantee that 210 + // this can't overflow. 211 + self.addr().checked_add(offset).ok_or(EINVAL) 212 + } 213 + 214 + #[inline] 215 + fn io_addr_assert<U>(&self, offset: usize) -> usize { 216 + build_assert!(Self::offset_valid::<U>(offset, SIZE)); 217 + 218 + self.addr() + offset 219 + } 220 + 221 + define_read!(readb, try_readb, u8); 222 + define_read!(readw, try_readw, u16); 223 + define_read!(readl, try_readl, u32); 224 + define_read!( 225 + #[cfg(CONFIG_64BIT)] 226 + readq, 227 + try_readq, 228 + u64 229 + ); 230 + 231 + define_read!(readb_relaxed, try_readb_relaxed, u8); 232 + define_read!(readw_relaxed, try_readw_relaxed, u16); 233 + define_read!(readl_relaxed, try_readl_relaxed, u32); 234 + define_read!( 235 + #[cfg(CONFIG_64BIT)] 236 + readq_relaxed, 237 + try_readq_relaxed, 238 + u64 239 + ); 240 + 241 + define_write!(writeb, try_writeb, u8); 242 + define_write!(writew, try_writew, u16); 243 + define_write!(writel, try_writel, u32); 244 + define_write!( 245 + #[cfg(CONFIG_64BIT)] 246 + writeq, 247 + try_writeq, 248 + u64 249 + ); 250 + 251 + define_write!(writeb_relaxed, try_writeb_relaxed, u8); 252 + define_write!(writew_relaxed, try_writew_relaxed, u16); 253 + define_write!(writel_relaxed, try_writel_relaxed, u32); 254 + define_write!( 255 + #[cfg(CONFIG_64BIT)] 256 + writeq_relaxed, 257 + try_writeq_relaxed, 258 + u64 259 + ); 260 + }
+20
rust/kernel/lib.rs
··· 19 19 #![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(unsize))] 20 20 #![feature(inline_const)] 21 21 #![feature(lint_reasons)] 22 + // Stable in Rust 1.83 23 + #![feature(const_maybe_uninit_as_mut_ptr)] 24 + #![feature(const_mut_refs)] 25 + #![feature(const_ptr_write)] 26 + #![feature(const_refs_to_cell)] 22 27 23 28 // Ensure conditional compilation based on the kernel configuration works; 24 29 // otherwise we may silently break things like initcall handling. ··· 42 37 pub mod build_assert; 43 38 pub mod cred; 44 39 pub mod device; 40 + pub mod device_id; 41 + pub mod devres; 42 + pub mod driver; 45 43 pub mod error; 46 44 #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)] 47 45 pub mod firmware; 48 46 pub mod fs; 49 47 pub mod init; 48 + pub mod io; 50 49 pub mod ioctl; 51 50 pub mod jump_label; 52 51 #[cfg(CONFIG_KUNIT)] ··· 59 50 pub mod miscdevice; 60 51 #[cfg(CONFIG_NET)] 61 52 pub mod net; 53 + pub mod of; 62 54 pub mod page; 55 + #[cfg(CONFIG_PCI)] 56 + pub mod pci; 63 57 pub mod pid_namespace; 58 + pub mod platform; 64 59 pub mod prelude; 65 60 pub mod print; 66 61 pub mod rbtree; 62 + pub mod revocable; 67 63 pub mod security; 68 64 pub mod seq_file; 69 65 pub mod sizes; ··· 127 113 // SAFETY: On success, `initer` always fully initialises an instance of `Self`. 128 114 unsafe { init::pin_init_from_closure(initer) } 129 115 } 116 + } 117 + 118 + /// Metadata attached to a [`Module`] or [`InPlaceModule`]. 119 + pub trait ModuleMetadata { 120 + /// The name of the module as specified in the `module!` macro. 121 + const NAME: &'static crate::str::CStr; 130 122 } 131 123 132 124 /// Equivalent to `THIS_MODULE` in the C API.
+89 -11
rust/kernel/miscdevice.rs
··· 10 10 11 11 use crate::{ 12 12 bindings, 13 + device::Device, 13 14 error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR}, 14 15 ffi::{c_int, c_long, c_uint, c_ulong}, 16 + fs::File, 15 17 prelude::*, 18 + seq_file::SeqFile, 16 19 str::CStr, 17 20 types::{ForeignOwnable, Opaque}, 18 21 }; ··· 83 80 pub fn as_raw(&self) -> *mut bindings::miscdevice { 84 81 self.inner.get() 85 82 } 83 + 84 + /// Access the `this_device` field. 85 + pub fn device(&self) -> &Device { 86 + // SAFETY: This can only be called after a successful register(), which always 87 + // initialises `this_device` with a valid device. Furthermore, the signature of this 88 + // function tells the borrow-checker that the `&Device` reference must not outlive the 89 + // `&MiscDeviceRegistration<T>` used to obtain it, so the last use of the reference must be 90 + // before the underlying `struct miscdevice` is destroyed. 91 + unsafe { Device::as_ref((*self.as_raw()).this_device) } 92 + } 86 93 } 87 94 88 95 #[pinned_drop] ··· 105 92 106 93 /// Trait implemented by the private data of an open misc device. 107 94 #[vtable] 108 - pub trait MiscDevice { 95 + pub trait MiscDevice: Sized { 109 96 /// What kind of pointer should `Self` be wrapped in. 110 97 type Ptr: ForeignOwnable + Send + Sync; 111 98 112 99 /// Called when the misc device is opened. 113 100 /// 114 101 /// The returned pointer will be stored as the private data for the file. 115 - fn open() -> Result<Self::Ptr>; 102 + fn open(_file: &File, _misc: &MiscDeviceRegistration<Self>) -> Result<Self::Ptr>; 116 103 117 104 /// Called when the misc device is released. 118 - fn release(device: Self::Ptr) { 105 + fn release(device: Self::Ptr, _file: &File) { 119 106 drop(device); 120 107 } 121 108 ··· 126 113 /// [`kernel::ioctl`]: mod@crate::ioctl 127 114 fn ioctl( 128 115 _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>, 116 + _file: &File, 129 117 _cmd: u32, 130 118 _arg: usize, 131 119 ) -> Result<isize> { ··· 143 129 #[cfg(CONFIG_COMPAT)] 144 130 fn compat_ioctl( 145 131 _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>, 132 + _file: &File, 146 133 _cmd: u32, 147 134 _arg: usize, 148 135 ) -> Result<isize> { 136 + build_error!(VTABLE_DEFAULT_ERROR) 137 + } 138 + 139 + /// Show info for this fd. 140 + fn show_fdinfo( 141 + _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>, 142 + _m: &SeqFile, 143 + _file: &File, 144 + ) { 149 145 build_error!(VTABLE_DEFAULT_ERROR) 150 146 } 151 147 } ··· 185 161 } else { 186 162 None 187 163 }, 164 + show_fdinfo: maybe_fn(T::HAS_SHOW_FDINFO, fops_show_fdinfo::<T>), 188 165 // SAFETY: All zeros is a valid value for `bindings::file_operations`. 189 166 ..unsafe { MaybeUninit::zeroed().assume_init() } 190 167 }; ··· 200 175 /// The file must be associated with a `MiscDeviceRegistration<T>`. 201 176 unsafe extern "C" fn fops_open<T: MiscDevice>( 202 177 inode: *mut bindings::inode, 203 - file: *mut bindings::file, 178 + raw_file: *mut bindings::file, 204 179 ) -> c_int { 205 180 // SAFETY: The pointers are valid and for a file being opened. 206 - let ret = unsafe { bindings::generic_file_open(inode, file) }; 181 + let ret = unsafe { bindings::generic_file_open(inode, raw_file) }; 207 182 if ret != 0 { 208 183 return ret; 209 184 } 210 185 211 - let ptr = match T::open() { 186 + // SAFETY: The open call of a file can access the private data. 187 + let misc_ptr = unsafe { (*raw_file).private_data }; 188 + 189 + // SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the 190 + // associated `struct miscdevice` before calling into this method. Furthermore, `misc_open()` 191 + // ensures that the miscdevice can't be unregistered and freed during this call to `fops_open`. 192 + let misc = unsafe { &*misc_ptr.cast::<MiscDeviceRegistration<T>>() }; 193 + 194 + // SAFETY: 195 + // * This underlying file is valid for (much longer than) the duration of `T::open`. 196 + // * There is no active fdget_pos region on the file on this thread. 197 + let file = unsafe { File::from_raw_file(raw_file) }; 198 + 199 + let ptr = match T::open(file, misc) { 212 200 Ok(ptr) => ptr, 213 201 Err(err) => return err.to_errno(), 214 202 }; 215 203 216 - // SAFETY: The open call of a file owns the private data. 217 - unsafe { (*file).private_data = ptr.into_foreign() }; 204 + // This overwrites the private data with the value specified by the user, changing the type of 205 + // this file's private data. All future accesses to the private data is performed by other 206 + // fops_* methods in this file, which all correctly cast the private data to the new type. 207 + // 208 + // SAFETY: The open call of a file can access the private data. 209 + unsafe { (*raw_file).private_data = ptr.into_foreign() }; 218 210 219 211 0 220 212 } ··· 249 207 // SAFETY: The release call of a file owns the private data. 250 208 let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) }; 251 209 252 - T::release(ptr); 210 + // SAFETY: 211 + // * The file is valid for the duration of this call. 212 + // * There is no active fdget_pos region on the file on this thread. 213 + T::release(ptr, unsafe { File::from_raw_file(file) }); 253 214 254 215 0 255 216 } ··· 270 225 // SAFETY: Ioctl calls can borrow the private data of the file. 271 226 let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; 272 227 273 - match T::ioctl(device, cmd, arg) { 228 + // SAFETY: 229 + // * The file is valid for the duration of this call. 230 + // * There is no active fdget_pos region on the file on this thread. 231 + let file = unsafe { File::from_raw_file(file) }; 232 + 233 + match T::ioctl(device, file, cmd, arg) { 274 234 Ok(ret) => ret as c_long, 275 235 Err(err) => err.to_errno() as c_long, 276 236 } ··· 295 245 // SAFETY: Ioctl calls can borrow the private data of the file. 296 246 let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; 297 247 298 - match T::compat_ioctl(device, cmd, arg) { 248 + // SAFETY: 249 + // * The file is valid for the duration of this call. 250 + // * There is no active fdget_pos region on the file on this thread. 251 + let file = unsafe { File::from_raw_file(file) }; 252 + 253 + match T::compat_ioctl(device, file, cmd, arg) { 299 254 Ok(ret) => ret as c_long, 300 255 Err(err) => err.to_errno() as c_long, 301 256 } 257 + } 258 + 259 + /// # Safety 260 + /// 261 + /// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. 262 + /// - `seq_file` must be a valid `struct seq_file` that we can write to. 263 + unsafe extern "C" fn fops_show_fdinfo<T: MiscDevice>( 264 + seq_file: *mut bindings::seq_file, 265 + file: *mut bindings::file, 266 + ) { 267 + // SAFETY: The release call of a file owns the private data. 268 + let private = unsafe { (*file).private_data }; 269 + // SAFETY: Ioctl calls can borrow the private data of the file. 270 + let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; 271 + // SAFETY: 272 + // * The file is valid for the duration of this call. 273 + // * There is no active fdget_pos region on the file on this thread. 274 + let file = unsafe { File::from_raw_file(file) }; 275 + // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in which 276 + // this method is called. 277 + let m = unsafe { SeqFile::from_raw(seq_file) }; 278 + 279 + T::show_fdinfo(device, m, file); 302 280 }
+60
rust/kernel/of.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Device Tree / Open Firmware abstractions. 4 + 5 + use crate::{bindings, device_id::RawDeviceId, prelude::*}; 6 + 7 + /// IdTable type for OF drivers. 8 + pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>; 9 + 10 + /// An open firmware device id. 11 + #[repr(transparent)] 12 + #[derive(Clone, Copy)] 13 + pub struct DeviceId(bindings::of_device_id); 14 + 15 + // SAFETY: 16 + // * `DeviceId` is a `#[repr(transparent)` wrapper of `struct of_device_id` and does not add 17 + // additional invariants, so it's safe to transmute to `RawType`. 18 + // * `DRIVER_DATA_OFFSET` is the offset to the `data` field. 19 + unsafe impl RawDeviceId for DeviceId { 20 + type RawType = bindings::of_device_id; 21 + 22 + const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::of_device_id, data); 23 + 24 + fn index(&self) -> usize { 25 + self.0.data as _ 26 + } 27 + } 28 + 29 + impl DeviceId { 30 + /// Create a new device id from an OF 'compatible' string. 31 + pub const fn new(compatible: &'static CStr) -> Self { 32 + let src = compatible.as_bytes_with_nul(); 33 + // Replace with `bindings::of_device_id::default()` once stabilized for `const`. 34 + // SAFETY: FFI type is valid to be zero-initialized. 35 + let mut of: bindings::of_device_id = unsafe { core::mem::zeroed() }; 36 + 37 + // TODO: Use `clone_from_slice` once the corresponding types do match. 38 + let mut i = 0; 39 + while i < src.len() { 40 + of.compatible[i] = src[i] as _; 41 + i += 1; 42 + } 43 + 44 + Self(of) 45 + } 46 + } 47 + 48 + /// Create an OF `IdTable` with an "alias" for modpost. 49 + #[macro_export] 50 + macro_rules! of_device_table { 51 + ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { 52 + const $table_name: $crate::device_id::IdArray< 53 + $crate::of::DeviceId, 54 + $id_info_type, 55 + { $table_data.len() }, 56 + > = $crate::device_id::IdArray::new($table_data); 57 + 58 + $crate::module_device_table!("of", $module_table_name, $table_name); 59 + }; 60 + }
+434
rust/kernel/pci.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Abstractions for the PCI bus. 4 + //! 5 + //! C header: [`include/linux/pci.h`](srctree/include/linux/pci.h) 6 + 7 + use crate::{ 8 + alloc::flags::*, 9 + bindings, container_of, device, 10 + device_id::RawDeviceId, 11 + devres::Devres, 12 + driver, 13 + error::{to_result, Result}, 14 + io::Io, 15 + io::IoRaw, 16 + str::CStr, 17 + types::{ARef, ForeignOwnable, Opaque}, 18 + ThisModule, 19 + }; 20 + use core::{ops::Deref, ptr::addr_of_mut}; 21 + use kernel::prelude::*; 22 + 23 + /// An adapter for the registration of PCI drivers. 24 + pub struct Adapter<T: Driver>(T); 25 + 26 + // SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if 27 + // a preceding call to `register` has been successful. 28 + unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { 29 + type RegType = bindings::pci_driver; 30 + 31 + unsafe fn register( 32 + pdrv: &Opaque<Self::RegType>, 33 + name: &'static CStr, 34 + module: &'static ThisModule, 35 + ) -> Result { 36 + // SAFETY: It's safe to set the fields of `struct pci_driver` on initialization. 37 + unsafe { 38 + (*pdrv.get()).name = name.as_char_ptr(); 39 + (*pdrv.get()).probe = Some(Self::probe_callback); 40 + (*pdrv.get()).remove = Some(Self::remove_callback); 41 + (*pdrv.get()).id_table = T::ID_TABLE.as_ptr(); 42 + } 43 + 44 + // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. 45 + to_result(unsafe { 46 + bindings::__pci_register_driver(pdrv.get(), module.0, name.as_char_ptr()) 47 + }) 48 + } 49 + 50 + unsafe fn unregister(pdrv: &Opaque<Self::RegType>) { 51 + // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. 52 + unsafe { bindings::pci_unregister_driver(pdrv.get()) } 53 + } 54 + } 55 + 56 + impl<T: Driver + 'static> Adapter<T> { 57 + extern "C" fn probe_callback( 58 + pdev: *mut bindings::pci_dev, 59 + id: *const bindings::pci_device_id, 60 + ) -> kernel::ffi::c_int { 61 + // SAFETY: The PCI bus only ever calls the probe callback with a valid pointer to a 62 + // `struct pci_dev`. 63 + let dev = unsafe { device::Device::get_device(addr_of_mut!((*pdev).dev)) }; 64 + // SAFETY: `dev` is guaranteed to be embedded in a valid `struct pci_dev` by the call 65 + // above. 66 + let mut pdev = unsafe { Device::from_dev(dev) }; 67 + 68 + // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct pci_device_id` and 69 + // does not add additional invariants, so it's safe to transmute. 70 + let id = unsafe { &*id.cast::<DeviceId>() }; 71 + let info = T::ID_TABLE.info(id.index()); 72 + 73 + match T::probe(&mut pdev, info) { 74 + Ok(data) => { 75 + // Let the `struct pci_dev` own a reference of the driver's private data. 76 + // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a 77 + // `struct pci_dev`. 78 + unsafe { bindings::pci_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; 79 + } 80 + Err(err) => return Error::to_errno(err), 81 + } 82 + 83 + 0 84 + } 85 + 86 + extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) { 87 + // SAFETY: The PCI bus only ever calls the remove callback with a valid pointer to a 88 + // `struct pci_dev`. 89 + let ptr = unsafe { bindings::pci_get_drvdata(pdev) }; 90 + 91 + // SAFETY: `remove_callback` is only ever called after a successful call to 92 + // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized 93 + // `KBox<T>` pointer created through `KBox::into_foreign`. 94 + let _ = unsafe { KBox::<T>::from_foreign(ptr) }; 95 + } 96 + } 97 + 98 + /// Declares a kernel module that exposes a single PCI driver. 99 + /// 100 + /// # Example 101 + /// 102 + ///```ignore 103 + /// kernel::module_pci_driver! { 104 + /// type: MyDriver, 105 + /// name: "Module name", 106 + /// author: "Author name", 107 + /// description: "Description", 108 + /// license: "GPL v2", 109 + /// } 110 + ///``` 111 + #[macro_export] 112 + macro_rules! module_pci_driver { 113 + ($($f:tt)*) => { 114 + $crate::module_driver!(<T>, $crate::pci::Adapter<T>, { $($f)* }); 115 + }; 116 + } 117 + 118 + /// Abstraction for bindings::pci_device_id. 119 + #[repr(transparent)] 120 + #[derive(Clone, Copy)] 121 + pub struct DeviceId(bindings::pci_device_id); 122 + 123 + impl DeviceId { 124 + const PCI_ANY_ID: u32 = !0; 125 + 126 + /// Equivalent to C's `PCI_DEVICE` macro. 127 + /// 128 + /// Create a new `pci::DeviceId` from a vendor and device ID number. 129 + pub const fn from_id(vendor: u32, device: u32) -> Self { 130 + Self(bindings::pci_device_id { 131 + vendor, 132 + device, 133 + subvendor: DeviceId::PCI_ANY_ID, 134 + subdevice: DeviceId::PCI_ANY_ID, 135 + class: 0, 136 + class_mask: 0, 137 + driver_data: 0, 138 + override_only: 0, 139 + }) 140 + } 141 + 142 + /// Equivalent to C's `PCI_DEVICE_CLASS` macro. 143 + /// 144 + /// Create a new `pci::DeviceId` from a class number and mask. 145 + pub const fn from_class(class: u32, class_mask: u32) -> Self { 146 + Self(bindings::pci_device_id { 147 + vendor: DeviceId::PCI_ANY_ID, 148 + device: DeviceId::PCI_ANY_ID, 149 + subvendor: DeviceId::PCI_ANY_ID, 150 + subdevice: DeviceId::PCI_ANY_ID, 151 + class, 152 + class_mask, 153 + driver_data: 0, 154 + override_only: 0, 155 + }) 156 + } 157 + } 158 + 159 + // SAFETY: 160 + // * `DeviceId` is a `#[repr(transparent)` wrapper of `pci_device_id` and does not add 161 + // additional invariants, so it's safe to transmute to `RawType`. 162 + // * `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. 163 + unsafe impl RawDeviceId for DeviceId { 164 + type RawType = bindings::pci_device_id; 165 + 166 + const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::pci_device_id, driver_data); 167 + 168 + fn index(&self) -> usize { 169 + self.0.driver_data as _ 170 + } 171 + } 172 + 173 + /// IdTable type for PCI 174 + pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>; 175 + 176 + /// Create a PCI `IdTable` with its alias for modpost. 177 + #[macro_export] 178 + macro_rules! pci_device_table { 179 + ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { 180 + const $table_name: $crate::device_id::IdArray< 181 + $crate::pci::DeviceId, 182 + $id_info_type, 183 + { $table_data.len() }, 184 + > = $crate::device_id::IdArray::new($table_data); 185 + 186 + $crate::module_device_table!("pci", $module_table_name, $table_name); 187 + }; 188 + } 189 + 190 + /// The PCI driver trait. 191 + /// 192 + /// # Example 193 + /// 194 + ///``` 195 + /// # use kernel::{bindings, pci}; 196 + /// 197 + /// struct MyDriver; 198 + /// 199 + /// kernel::pci_device_table!( 200 + /// PCI_TABLE, 201 + /// MODULE_PCI_TABLE, 202 + /// <MyDriver as pci::Driver>::IdInfo, 203 + /// [ 204 + /// (pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, bindings::PCI_ANY_ID as _), ()) 205 + /// ] 206 + /// ); 207 + /// 208 + /// impl pci::Driver for MyDriver { 209 + /// type IdInfo = (); 210 + /// const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; 211 + /// 212 + /// fn probe( 213 + /// _pdev: &mut pci::Device, 214 + /// _id_info: &Self::IdInfo, 215 + /// ) -> Result<Pin<KBox<Self>>> { 216 + /// Err(ENODEV) 217 + /// } 218 + /// } 219 + ///``` 220 + /// Drivers must implement this trait in order to get a PCI driver registered. Please refer to the 221 + /// `Adapter` documentation for an example. 222 + pub trait Driver { 223 + /// The type holding information about each device id supported by the driver. 224 + /// 225 + /// TODO: Use associated_type_defaults once stabilized: 226 + /// 227 + /// type IdInfo: 'static = (); 228 + type IdInfo: 'static; 229 + 230 + /// The table of device ids supported by the driver. 231 + const ID_TABLE: IdTable<Self::IdInfo>; 232 + 233 + /// PCI driver probe. 234 + /// 235 + /// Called when a new platform device is added or discovered. 236 + /// Implementers should attempt to initialize the device here. 237 + fn probe(dev: &mut Device, id_info: &Self::IdInfo) -> Result<Pin<KBox<Self>>>; 238 + } 239 + 240 + /// The PCI device representation. 241 + /// 242 + /// A PCI device is based on an always reference counted `device:Device` instance. Cloning a PCI 243 + /// device, hence, also increments the base device' reference count. 244 + /// 245 + /// # Invariants 246 + /// 247 + /// `Device` hold a valid reference of `ARef<device::Device>` whose underlying `struct device` is a 248 + /// member of a `struct pci_dev`. 249 + #[derive(Clone)] 250 + pub struct Device(ARef<device::Device>); 251 + 252 + /// A PCI BAR to perform I/O-Operations on. 253 + /// 254 + /// # Invariants 255 + /// 256 + /// `Bar` always holds an `IoRaw` inststance that holds a valid pointer to the start of the I/O 257 + /// memory mapped PCI bar and its size. 258 + pub struct Bar<const SIZE: usize = 0> { 259 + pdev: Device, 260 + io: IoRaw<SIZE>, 261 + num: i32, 262 + } 263 + 264 + impl<const SIZE: usize> Bar<SIZE> { 265 + fn new(pdev: Device, num: u32, name: &CStr) -> Result<Self> { 266 + let len = pdev.resource_len(num)?; 267 + if len == 0 { 268 + return Err(ENOMEM); 269 + } 270 + 271 + // Convert to `i32`, since that's what all the C bindings use. 272 + let num = i32::try_from(num)?; 273 + 274 + // SAFETY: 275 + // `pdev` is valid by the invariants of `Device`. 276 + // `num` is checked for validity by a previous call to `Device::resource_len`. 277 + // `name` is always valid. 278 + let ret = unsafe { bindings::pci_request_region(pdev.as_raw(), num, name.as_char_ptr()) }; 279 + if ret != 0 { 280 + return Err(EBUSY); 281 + } 282 + 283 + // SAFETY: 284 + // `pdev` is valid by the invariants of `Device`. 285 + // `num` is checked for validity by a previous call to `Device::resource_len`. 286 + // `name` is always valid. 287 + let ioptr: usize = unsafe { bindings::pci_iomap(pdev.as_raw(), num, 0) } as usize; 288 + if ioptr == 0 { 289 + // SAFETY: 290 + // `pdev` valid by the invariants of `Device`. 291 + // `num` is checked for validity by a previous call to `Device::resource_len`. 292 + unsafe { bindings::pci_release_region(pdev.as_raw(), num) }; 293 + return Err(ENOMEM); 294 + } 295 + 296 + let io = match IoRaw::new(ioptr, len as usize) { 297 + Ok(io) => io, 298 + Err(err) => { 299 + // SAFETY: 300 + // `pdev` is valid by the invariants of `Device`. 301 + // `ioptr` is guaranteed to be the start of a valid I/O mapped memory region. 302 + // `num` is checked for validity by a previous call to `Device::resource_len`. 303 + unsafe { Self::do_release(&pdev, ioptr, num) }; 304 + return Err(err); 305 + } 306 + }; 307 + 308 + Ok(Bar { pdev, io, num }) 309 + } 310 + 311 + /// # Safety 312 + /// 313 + /// `ioptr` must be a valid pointer to the memory mapped PCI bar number `num`. 314 + unsafe fn do_release(pdev: &Device, ioptr: usize, num: i32) { 315 + // SAFETY: 316 + // `pdev` is valid by the invariants of `Device`. 317 + // `ioptr` is valid by the safety requirements. 318 + // `num` is valid by the safety requirements. 319 + unsafe { 320 + bindings::pci_iounmap(pdev.as_raw(), ioptr as _); 321 + bindings::pci_release_region(pdev.as_raw(), num); 322 + } 323 + } 324 + 325 + fn release(&self) { 326 + // SAFETY: The safety requirements are guaranteed by the type invariant of `self.pdev`. 327 + unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) }; 328 + } 329 + } 330 + 331 + impl Bar { 332 + fn index_is_valid(index: u32) -> bool { 333 + // A `struct pci_dev` owns an array of resources with at most `PCI_NUM_RESOURCES` entries. 334 + index < bindings::PCI_NUM_RESOURCES 335 + } 336 + } 337 + 338 + impl<const SIZE: usize> Drop for Bar<SIZE> { 339 + fn drop(&mut self) { 340 + self.release(); 341 + } 342 + } 343 + 344 + impl<const SIZE: usize> Deref for Bar<SIZE> { 345 + type Target = Io<SIZE>; 346 + 347 + fn deref(&self) -> &Self::Target { 348 + // SAFETY: By the type invariant of `Self`, the MMIO range in `self.io` is properly mapped. 349 + unsafe { Io::from_raw(&self.io) } 350 + } 351 + } 352 + 353 + impl Device { 354 + /// Create a PCI Device instance from an existing `device::Device`. 355 + /// 356 + /// # Safety 357 + /// 358 + /// `dev` must be an `ARef<device::Device>` whose underlying `bindings::device` is a member of 359 + /// a `bindings::pci_dev`. 360 + pub unsafe fn from_dev(dev: ARef<device::Device>) -> Self { 361 + Self(dev) 362 + } 363 + 364 + fn as_raw(&self) -> *mut bindings::pci_dev { 365 + // SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device` 366 + // embedded in `struct pci_dev`. 367 + unsafe { container_of!(self.0.as_raw(), bindings::pci_dev, dev) as _ } 368 + } 369 + 370 + /// Returns the PCI vendor ID. 371 + pub fn vendor_id(&self) -> u16 { 372 + // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. 373 + unsafe { (*self.as_raw()).vendor } 374 + } 375 + 376 + /// Returns the PCI device ID. 377 + pub fn device_id(&self) -> u16 { 378 + // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`. 379 + unsafe { (*self.as_raw()).device } 380 + } 381 + 382 + /// Enable memory resources for this device. 383 + pub fn enable_device_mem(&self) -> Result { 384 + // SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`. 385 + let ret = unsafe { bindings::pci_enable_device_mem(self.as_raw()) }; 386 + if ret != 0 { 387 + Err(Error::from_errno(ret)) 388 + } else { 389 + Ok(()) 390 + } 391 + } 392 + 393 + /// Enable bus-mastering for this device. 394 + pub fn set_master(&self) { 395 + // SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`. 396 + unsafe { bindings::pci_set_master(self.as_raw()) }; 397 + } 398 + 399 + /// Returns the size of the given PCI bar resource. 400 + pub fn resource_len(&self, bar: u32) -> Result<bindings::resource_size_t> { 401 + if !Bar::index_is_valid(bar) { 402 + return Err(EINVAL); 403 + } 404 + 405 + // SAFETY: 406 + // - `bar` is a valid bar number, as guaranteed by the above call to `Bar::index_is_valid`, 407 + // - by its type invariant `self.as_raw` is always a valid pointer to a `struct pci_dev`. 408 + Ok(unsafe { bindings::pci_resource_len(self.as_raw(), bar.try_into()?) }) 409 + } 410 + 411 + /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks 412 + /// can be performed on compile time for offsets (plus the requested type size) < SIZE. 413 + pub fn iomap_region_sized<const SIZE: usize>( 414 + &self, 415 + bar: u32, 416 + name: &CStr, 417 + ) -> Result<Devres<Bar<SIZE>>> { 418 + let bar = Bar::<SIZE>::new(self.clone(), bar, name)?; 419 + let devres = Devres::new(self.as_ref(), bar, GFP_KERNEL)?; 420 + 421 + Ok(devres) 422 + } 423 + 424 + /// Mapps an entire PCI-BAR after performing a region-request on it. 425 + pub fn iomap_region(&self, bar: u32, name: &CStr) -> Result<Devres<Bar>> { 426 + self.iomap_region_sized::<0>(bar, name) 427 + } 428 + } 429 + 430 + impl AsRef<device::Device> for Device { 431 + fn as_ref(&self) -> &device::Device { 432 + &self.0 433 + } 434 + }
+200
rust/kernel/platform.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Abstractions for the platform bus. 4 + //! 5 + //! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h) 6 + 7 + use crate::{ 8 + bindings, container_of, device, driver, 9 + error::{to_result, Result}, 10 + of, 11 + prelude::*, 12 + str::CStr, 13 + types::{ARef, ForeignOwnable, Opaque}, 14 + ThisModule, 15 + }; 16 + 17 + use core::ptr::addr_of_mut; 18 + 19 + /// An adapter for the registration of platform drivers. 20 + pub struct Adapter<T: Driver>(T); 21 + 22 + // SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if 23 + // a preceding call to `register` has been successful. 24 + unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { 25 + type RegType = bindings::platform_driver; 26 + 27 + unsafe fn register( 28 + pdrv: &Opaque<Self::RegType>, 29 + name: &'static CStr, 30 + module: &'static ThisModule, 31 + ) -> Result { 32 + let of_table = match T::OF_ID_TABLE { 33 + Some(table) => table.as_ptr(), 34 + None => core::ptr::null(), 35 + }; 36 + 37 + // SAFETY: It's safe to set the fields of `struct platform_driver` on initialization. 38 + unsafe { 39 + (*pdrv.get()).driver.name = name.as_char_ptr(); 40 + (*pdrv.get()).probe = Some(Self::probe_callback); 41 + (*pdrv.get()).remove = Some(Self::remove_callback); 42 + (*pdrv.get()).driver.of_match_table = of_table; 43 + } 44 + 45 + // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. 46 + to_result(unsafe { bindings::__platform_driver_register(pdrv.get(), module.0) }) 47 + } 48 + 49 + unsafe fn unregister(pdrv: &Opaque<Self::RegType>) { 50 + // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. 51 + unsafe { bindings::platform_driver_unregister(pdrv.get()) }; 52 + } 53 + } 54 + 55 + impl<T: Driver + 'static> Adapter<T> { 56 + extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ffi::c_int { 57 + // SAFETY: The platform bus only ever calls the probe callback with a valid `pdev`. 58 + let dev = unsafe { device::Device::get_device(addr_of_mut!((*pdev).dev)) }; 59 + // SAFETY: `dev` is guaranteed to be embedded in a valid `struct platform_device` by the 60 + // call above. 61 + let mut pdev = unsafe { Device::from_dev(dev) }; 62 + 63 + let info = <Self as driver::Adapter>::id_info(pdev.as_ref()); 64 + match T::probe(&mut pdev, info) { 65 + Ok(data) => { 66 + // Let the `struct platform_device` own a reference of the driver's private data. 67 + // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a 68 + // `struct platform_device`. 69 + unsafe { bindings::platform_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; 70 + } 71 + Err(err) => return Error::to_errno(err), 72 + } 73 + 74 + 0 75 + } 76 + 77 + extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { 78 + // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. 79 + let ptr = unsafe { bindings::platform_get_drvdata(pdev) }; 80 + 81 + // SAFETY: `remove_callback` is only ever called after a successful call to 82 + // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized 83 + // `KBox<T>` pointer created through `KBox::into_foreign`. 84 + let _ = unsafe { KBox::<T>::from_foreign(ptr) }; 85 + } 86 + } 87 + 88 + impl<T: Driver + 'static> driver::Adapter for Adapter<T> { 89 + type IdInfo = T::IdInfo; 90 + 91 + fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> { 92 + T::OF_ID_TABLE 93 + } 94 + } 95 + 96 + /// Declares a kernel module that exposes a single platform driver. 97 + /// 98 + /// # Examples 99 + /// 100 + /// ```ignore 101 + /// kernel::module_platform_driver! { 102 + /// type: MyDriver, 103 + /// name: "Module name", 104 + /// author: "Author name", 105 + /// description: "Description", 106 + /// license: "GPL v2", 107 + /// } 108 + /// ``` 109 + #[macro_export] 110 + macro_rules! module_platform_driver { 111 + ($($f:tt)*) => { 112 + $crate::module_driver!(<T>, $crate::platform::Adapter<T>, { $($f)* }); 113 + }; 114 + } 115 + 116 + /// The platform driver trait. 117 + /// 118 + /// Drivers must implement this trait in order to get a platform driver registered. 119 + /// 120 + /// # Example 121 + /// 122 + ///``` 123 + /// # use kernel::{bindings, c_str, of, platform}; 124 + /// 125 + /// struct MyDriver; 126 + /// 127 + /// kernel::of_device_table!( 128 + /// OF_TABLE, 129 + /// MODULE_OF_TABLE, 130 + /// <MyDriver as platform::Driver>::IdInfo, 131 + /// [ 132 + /// (of::DeviceId::new(c_str!("test,device")), ()) 133 + /// ] 134 + /// ); 135 + /// 136 + /// impl platform::Driver for MyDriver { 137 + /// type IdInfo = (); 138 + /// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); 139 + /// 140 + /// fn probe( 141 + /// _pdev: &mut platform::Device, 142 + /// _id_info: Option<&Self::IdInfo>, 143 + /// ) -> Result<Pin<KBox<Self>>> { 144 + /// Err(ENODEV) 145 + /// } 146 + /// } 147 + ///``` 148 + pub trait Driver { 149 + /// The type holding driver private data about each device id supported by the driver. 150 + /// 151 + /// TODO: Use associated_type_defaults once stabilized: 152 + /// 153 + /// type IdInfo: 'static = (); 154 + type IdInfo: 'static; 155 + 156 + /// The table of OF device ids supported by the driver. 157 + const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>>; 158 + 159 + /// Platform driver probe. 160 + /// 161 + /// Called when a new platform device is added or discovered. 162 + /// Implementers should attempt to initialize the device here. 163 + fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Pin<KBox<Self>>>; 164 + } 165 + 166 + /// The platform device representation. 167 + /// 168 + /// A platform device is based on an always reference counted `device:Device` instance. Cloning a 169 + /// platform device, hence, also increments the base device' reference count. 170 + /// 171 + /// # Invariants 172 + /// 173 + /// `Device` holds a valid reference of `ARef<device::Device>` whose underlying `struct device` is a 174 + /// member of a `struct platform_device`. 175 + #[derive(Clone)] 176 + pub struct Device(ARef<device::Device>); 177 + 178 + impl Device { 179 + /// Convert a raw kernel device into a `Device` 180 + /// 181 + /// # Safety 182 + /// 183 + /// `dev` must be an `Aref<device::Device>` whose underlying `bindings::device` is a member of a 184 + /// `bindings::platform_device`. 185 + unsafe fn from_dev(dev: ARef<device::Device>) -> Self { 186 + Self(dev) 187 + } 188 + 189 + fn as_raw(&self) -> *mut bindings::platform_device { 190 + // SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device` 191 + // embedded in `struct platform_device`. 192 + unsafe { container_of!(self.0.as_raw(), bindings::platform_device, dev) }.cast_mut() 193 + } 194 + } 195 + 196 + impl AsRef<device::Device> for Device { 197 + fn as_ref(&self) -> &device::Device { 198 + &self.0 199 + } 200 + }
+219
rust/kernel/revocable.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Revocable objects. 4 + //! 5 + //! The [`Revocable`] type wraps other types and allows access to them to be revoked. The existence 6 + //! of a [`RevocableGuard`] ensures that objects remain valid. 7 + 8 + use crate::{bindings, prelude::*, sync::rcu, types::Opaque}; 9 + use core::{ 10 + marker::PhantomData, 11 + ops::Deref, 12 + ptr::drop_in_place, 13 + sync::atomic::{AtomicBool, Ordering}, 14 + }; 15 + 16 + /// An object that can become inaccessible at runtime. 17 + /// 18 + /// Once access is revoked and all concurrent users complete (i.e., all existing instances of 19 + /// [`RevocableGuard`] are dropped), the wrapped object is also dropped. 20 + /// 21 + /// # Examples 22 + /// 23 + /// ``` 24 + /// # use kernel::revocable::Revocable; 25 + /// 26 + /// struct Example { 27 + /// a: u32, 28 + /// b: u32, 29 + /// } 30 + /// 31 + /// fn add_two(v: &Revocable<Example>) -> Option<u32> { 32 + /// let guard = v.try_access()?; 33 + /// Some(guard.a + guard.b) 34 + /// } 35 + /// 36 + /// let v = KBox::pin_init(Revocable::new(Example { a: 10, b: 20 }), GFP_KERNEL).unwrap(); 37 + /// assert_eq!(add_two(&v), Some(30)); 38 + /// v.revoke(); 39 + /// assert_eq!(add_two(&v), None); 40 + /// ``` 41 + /// 42 + /// Sample example as above, but explicitly using the rcu read side lock. 43 + /// 44 + /// ``` 45 + /// # use kernel::revocable::Revocable; 46 + /// use kernel::sync::rcu; 47 + /// 48 + /// struct Example { 49 + /// a: u32, 50 + /// b: u32, 51 + /// } 52 + /// 53 + /// fn add_two(v: &Revocable<Example>) -> Option<u32> { 54 + /// let guard = rcu::read_lock(); 55 + /// let e = v.try_access_with_guard(&guard)?; 56 + /// Some(e.a + e.b) 57 + /// } 58 + /// 59 + /// let v = KBox::pin_init(Revocable::new(Example { a: 10, b: 20 }), GFP_KERNEL).unwrap(); 60 + /// assert_eq!(add_two(&v), Some(30)); 61 + /// v.revoke(); 62 + /// assert_eq!(add_two(&v), None); 63 + /// ``` 64 + #[pin_data(PinnedDrop)] 65 + pub struct Revocable<T> { 66 + is_available: AtomicBool, 67 + #[pin] 68 + data: Opaque<T>, 69 + } 70 + 71 + // SAFETY: `Revocable` is `Send` if the wrapped object is also `Send`. This is because while the 72 + // functionality exposed by `Revocable` can be accessed from any thread/CPU, it is possible that 73 + // this isn't supported by the wrapped object. 74 + unsafe impl<T: Send> Send for Revocable<T> {} 75 + 76 + // SAFETY: `Revocable` is `Sync` if the wrapped object is both `Send` and `Sync`. We require `Send` 77 + // from the wrapped object as well because of `Revocable::revoke`, which can trigger the `Drop` 78 + // implementation of the wrapped object from an arbitrary thread. 79 + unsafe impl<T: Sync + Send> Sync for Revocable<T> {} 80 + 81 + impl<T> Revocable<T> { 82 + /// Creates a new revocable instance of the given data. 83 + pub fn new(data: impl PinInit<T>) -> impl PinInit<Self> { 84 + pin_init!(Self { 85 + is_available: AtomicBool::new(true), 86 + data <- Opaque::pin_init(data), 87 + }) 88 + } 89 + 90 + /// Tries to access the revocable wrapped object. 91 + /// 92 + /// Returns `None` if the object has been revoked and is therefore no longer accessible. 93 + /// 94 + /// Returns a guard that gives access to the object otherwise; the object is guaranteed to 95 + /// remain accessible while the guard is alive. In such cases, callers are not allowed to sleep 96 + /// because another CPU may be waiting to complete the revocation of this object. 97 + pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> { 98 + let guard = rcu::read_lock(); 99 + if self.is_available.load(Ordering::Relaxed) { 100 + // Since `self.is_available` is true, data is initialised and has to remain valid 101 + // because the RCU read side lock prevents it from being dropped. 102 + Some(RevocableGuard::new(self.data.get(), guard)) 103 + } else { 104 + None 105 + } 106 + } 107 + 108 + /// Tries to access the revocable wrapped object. 109 + /// 110 + /// Returns `None` if the object has been revoked and is therefore no longer accessible. 111 + /// 112 + /// Returns a shared reference to the object otherwise; the object is guaranteed to 113 + /// remain accessible while the rcu read side guard is alive. In such cases, callers are not 114 + /// allowed to sleep because another CPU may be waiting to complete the revocation of this 115 + /// object. 116 + pub fn try_access_with_guard<'a>(&'a self, _guard: &'a rcu::Guard) -> Option<&'a T> { 117 + if self.is_available.load(Ordering::Relaxed) { 118 + // SAFETY: Since `self.is_available` is true, data is initialised and has to remain 119 + // valid because the RCU read side lock prevents it from being dropped. 120 + Some(unsafe { &*self.data.get() }) 121 + } else { 122 + None 123 + } 124 + } 125 + 126 + /// # Safety 127 + /// 128 + /// Callers must ensure that there are no more concurrent users of the revocable object. 129 + unsafe fn revoke_internal<const SYNC: bool>(&self) { 130 + if self.is_available.swap(false, Ordering::Relaxed) { 131 + if SYNC { 132 + // SAFETY: Just an FFI call, there are no further requirements. 133 + unsafe { bindings::synchronize_rcu() }; 134 + } 135 + 136 + // SAFETY: We know `self.data` is valid because only one CPU can succeed the 137 + // `compare_exchange` above that takes `is_available` from `true` to `false`. 138 + unsafe { drop_in_place(self.data.get()) }; 139 + } 140 + } 141 + 142 + /// Revokes access to and drops the wrapped object. 143 + /// 144 + /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`], 145 + /// expecting that there are no concurrent users of the object. 146 + /// 147 + /// # Safety 148 + /// 149 + /// Callers must ensure that there are no more concurrent users of the revocable object. 150 + pub unsafe fn revoke_nosync(&self) { 151 + // SAFETY: By the safety requirement of this function, the caller ensures that nobody is 152 + // accessing the data anymore and hence we don't have to wait for the grace period to 153 + // finish. 154 + unsafe { self.revoke_internal::<false>() } 155 + } 156 + 157 + /// Revokes access to and drops the wrapped object. 158 + /// 159 + /// Access to the object is revoked immediately to new callers of [`Revocable::try_access`]. 160 + /// 161 + /// If there are concurrent users of the object (i.e., ones that called 162 + /// [`Revocable::try_access`] beforehand and still haven't dropped the returned guard), this 163 + /// function waits for the concurrent access to complete before dropping the wrapped object. 164 + pub fn revoke(&self) { 165 + // SAFETY: By passing `true` we ask `revoke_internal` to wait for the grace period to 166 + // finish. 167 + unsafe { self.revoke_internal::<true>() } 168 + } 169 + } 170 + 171 + #[pinned_drop] 172 + impl<T> PinnedDrop for Revocable<T> { 173 + fn drop(self: Pin<&mut Self>) { 174 + // Drop only if the data hasn't been revoked yet (in which case it has already been 175 + // dropped). 176 + // SAFETY: We are not moving out of `p`, only dropping in place 177 + let p = unsafe { self.get_unchecked_mut() }; 178 + if *p.is_available.get_mut() { 179 + // SAFETY: We know `self.data` is valid because no other CPU has changed 180 + // `is_available` to `false` yet, and no other CPU can do it anymore because this CPU 181 + // holds the only reference (mutable) to `self` now. 182 + unsafe { drop_in_place(p.data.get()) }; 183 + } 184 + } 185 + } 186 + 187 + /// A guard that allows access to a revocable object and keeps it alive. 188 + /// 189 + /// CPUs may not sleep while holding on to [`RevocableGuard`] because it's in atomic context 190 + /// holding the RCU read-side lock. 191 + /// 192 + /// # Invariants 193 + /// 194 + /// The RCU read-side lock is held while the guard is alive. 195 + pub struct RevocableGuard<'a, T> { 196 + data_ref: *const T, 197 + _rcu_guard: rcu::Guard, 198 + _p: PhantomData<&'a ()>, 199 + } 200 + 201 + impl<T> RevocableGuard<'_, T> { 202 + fn new(data_ref: *const T, rcu_guard: rcu::Guard) -> Self { 203 + Self { 204 + data_ref, 205 + _rcu_guard: rcu_guard, 206 + _p: PhantomData, 207 + } 208 + } 209 + } 210 + 211 + impl<T> Deref for RevocableGuard<'_, T> { 212 + type Target = T; 213 + 214 + fn deref(&self) -> &Self::Target { 215 + // SAFETY: By the type invariants, we hold the rcu read-side lock, so the object is 216 + // guaranteed to remain valid. 217 + unsafe { &*self.data_ref } 218 + } 219 + }
+1
rust/kernel/sync.rs
··· 12 12 pub mod lock; 13 13 mod locked_by; 14 14 pub mod poll; 15 + pub mod rcu; 15 16 16 17 pub use arc::{Arc, ArcBorrow, UniqueArc}; 17 18 pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};
+47
rust/kernel/sync/rcu.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! RCU support. 4 + //! 5 + //! C header: [`include/linux/rcupdate.h`](srctree/include/linux/rcupdate.h) 6 + 7 + use crate::{bindings, types::NotThreadSafe}; 8 + 9 + /// Evidence that the RCU read side lock is held on the current thread/CPU. 10 + /// 11 + /// The type is explicitly not `Send` because this property is per-thread/CPU. 12 + /// 13 + /// # Invariants 14 + /// 15 + /// The RCU read side lock is actually held while instances of this guard exist. 16 + pub struct Guard(NotThreadSafe); 17 + 18 + impl Guard { 19 + /// Acquires the RCU read side lock and returns a guard. 20 + pub fn new() -> Self { 21 + // SAFETY: An FFI call with no additional requirements. 22 + unsafe { bindings::rcu_read_lock() }; 23 + // INVARIANT: The RCU read side lock was just acquired above. 24 + Self(NotThreadSafe) 25 + } 26 + 27 + /// Explicitly releases the RCU read side lock. 28 + pub fn unlock(self) {} 29 + } 30 + 31 + impl Default for Guard { 32 + fn default() -> Self { 33 + Self::new() 34 + } 35 + } 36 + 37 + impl Drop for Guard { 38 + fn drop(&mut self) { 39 + // SAFETY: By the type invariants, the RCU read side is locked, so it is ok to unlock it. 40 + unsafe { bindings::rcu_read_unlock() }; 41 + } 42 + } 43 + 44 + /// Acquires the RCU read side lock. 45 + pub fn read_lock() -> Guard { 46 + Guard::new() 47 + }
+11
rust/kernel/types.rs
··· 326 326 } 327 327 } 328 328 329 + /// Create an opaque pin-initializer from the given pin-initializer. 330 + pub fn pin_init(slot: impl PinInit<T>) -> impl PinInit<Self> { 331 + Self::ffi_init(|ptr: *mut T| { 332 + // SAFETY: 333 + // - `ptr` is a valid pointer to uninitialized memory, 334 + // - `slot` is not accessed on error; the call is infallible, 335 + // - `slot` is pinned in memory. 336 + let _ = unsafe { init::PinInit::<T>::__pinned_init(slot, ptr) }; 337 + }) 338 + } 339 + 329 340 /// Creates a pin-initializer from the given initializer closure. 330 341 /// 331 342 /// The returned initializer calls the given closure with the pointer to the inner `T` of this
+4
rust/macros/module.rs
··· 228 228 kernel::ThisModule::from_ptr(core::ptr::null_mut()) 229 229 }}; 230 230 231 + impl kernel::ModuleMetadata for {type_} {{ 232 + const NAME: &'static kernel::str::CStr = kernel::c_str!(\"{name}\"); 233 + }} 234 + 231 235 // Double nested modules, since then nobody can access the public items inside. 232 236 mod __module_init {{ 233 237 mod __module_init {{
+31
samples/rust/Kconfig
··· 20 20 21 21 If unsure, say N. 22 22 23 + config SAMPLE_RUST_MISC_DEVICE 24 + tristate "Misc device" 25 + help 26 + This option builds the Rust misc device. 27 + 28 + To compile this as a module, choose M here: 29 + the module will be called rust_misc_device. 30 + 31 + If unsure, say N. 32 + 23 33 config SAMPLE_RUST_PRINT 24 34 tristate "Printing macros" 25 35 help ··· 37 27 38 28 To compile this as a module, choose M here: 39 29 the module will be called rust_print. 30 + 31 + If unsure, say N. 32 + 33 + config SAMPLE_RUST_DRIVER_PCI 34 + tristate "PCI Driver" 35 + depends on PCI 36 + help 37 + This option builds the Rust PCI driver sample. 38 + 39 + To compile this as a module, choose M here: 40 + the module will be called driver_pci. 41 + 42 + If unsure, say N. 43 + 44 + config SAMPLE_RUST_DRIVER_PLATFORM 45 + tristate "Platform Driver" 46 + help 47 + This option builds the Rust Platform driver sample. 48 + 49 + To compile this as a module, choose M here: 50 + the module will be called rust_driver_platform. 40 51 41 52 If unsure, say N. 42 53
+3
samples/rust/Makefile
··· 2 2 ccflags-y += -I$(src) # needed for trace events 3 3 4 4 obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o 5 + obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) += rust_misc_device.o 5 6 obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o 7 + obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o 8 + obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o 6 9 7 10 rust_print-y := rust_print_main.o rust_print_events.o 8 11
+110
samples/rust/rust_driver_pci.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Rust PCI driver sample (based on QEMU's `pci-testdev`). 4 + //! 5 + //! To make this driver probe, QEMU must be run with `-device pci-testdev`. 6 + 7 + use kernel::{bindings, c_str, devres::Devres, pci, prelude::*}; 8 + 9 + struct Regs; 10 + 11 + impl Regs { 12 + const TEST: usize = 0x0; 13 + const OFFSET: usize = 0x4; 14 + const DATA: usize = 0x8; 15 + const COUNT: usize = 0xC; 16 + const END: usize = 0x10; 17 + } 18 + 19 + type Bar0 = pci::Bar<{ Regs::END }>; 20 + 21 + #[derive(Debug)] 22 + struct TestIndex(u8); 23 + 24 + impl TestIndex { 25 + const NO_EVENTFD: Self = Self(0); 26 + } 27 + 28 + struct SampleDriver { 29 + pdev: pci::Device, 30 + bar: Devres<Bar0>, 31 + } 32 + 33 + kernel::pci_device_table!( 34 + PCI_TABLE, 35 + MODULE_PCI_TABLE, 36 + <SampleDriver as pci::Driver>::IdInfo, 37 + [( 38 + pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5), 39 + TestIndex::NO_EVENTFD 40 + )] 41 + ); 42 + 43 + impl SampleDriver { 44 + fn testdev(index: &TestIndex, bar: &Bar0) -> Result<u32> { 45 + // Select the test. 46 + bar.writeb(index.0, Regs::TEST); 47 + 48 + let offset = u32::from_le(bar.readl(Regs::OFFSET)) as usize; 49 + let data = bar.readb(Regs::DATA); 50 + 51 + // Write `data` to `offset` to increase `count` by one. 52 + // 53 + // Note that we need `try_writeb`, since `offset` can't be checked at compile-time. 54 + bar.try_writeb(data, offset)?; 55 + 56 + Ok(bar.readl(Regs::COUNT)) 57 + } 58 + } 59 + 60 + impl pci::Driver for SampleDriver { 61 + type IdInfo = TestIndex; 62 + 63 + const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; 64 + 65 + fn probe(pdev: &mut pci::Device, info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> { 66 + dev_dbg!( 67 + pdev.as_ref(), 68 + "Probe Rust PCI driver sample (PCI ID: 0x{:x}, 0x{:x}).\n", 69 + pdev.vendor_id(), 70 + pdev.device_id() 71 + ); 72 + 73 + pdev.enable_device_mem()?; 74 + pdev.set_master(); 75 + 76 + let bar = pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci"))?; 77 + 78 + let drvdata = KBox::new( 79 + Self { 80 + pdev: pdev.clone(), 81 + bar, 82 + }, 83 + GFP_KERNEL, 84 + )?; 85 + 86 + let bar = drvdata.bar.try_access().ok_or(ENXIO)?; 87 + 88 + dev_info!( 89 + pdev.as_ref(), 90 + "pci-testdev data-match count: {}\n", 91 + Self::testdev(info, &bar)? 92 + ); 93 + 94 + Ok(drvdata.into()) 95 + } 96 + } 97 + 98 + impl Drop for SampleDriver { 99 + fn drop(&mut self) { 100 + dev_dbg!(self.pdev.as_ref(), "Remove Rust PCI driver sample.\n"); 101 + } 102 + } 103 + 104 + kernel::module_pci_driver! { 105 + type: SampleDriver, 106 + name: "rust_driver_pci", 107 + author: "Danilo Krummrich", 108 + description: "Rust PCI driver", 109 + license: "GPL v2", 110 + }
+49
samples/rust/rust_driver_platform.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Rust Platform driver sample. 4 + 5 + use kernel::{c_str, of, platform, prelude::*}; 6 + 7 + struct SampleDriver { 8 + pdev: platform::Device, 9 + } 10 + 11 + struct Info(u32); 12 + 13 + kernel::of_device_table!( 14 + OF_TABLE, 15 + MODULE_OF_TABLE, 16 + <SampleDriver as platform::Driver>::IdInfo, 17 + [(of::DeviceId::new(c_str!("test,rust-device")), Info(42))] 18 + ); 19 + 20 + impl platform::Driver for SampleDriver { 21 + type IdInfo = Info; 22 + const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); 23 + 24 + fn probe(pdev: &mut platform::Device, info: Option<&Self::IdInfo>) -> Result<Pin<KBox<Self>>> { 25 + dev_dbg!(pdev.as_ref(), "Probe Rust Platform driver sample.\n"); 26 + 27 + if let Some(info) = info { 28 + dev_info!(pdev.as_ref(), "Probed with info: '{}'.\n", info.0); 29 + } 30 + 31 + let drvdata = KBox::new(Self { pdev: pdev.clone() }, GFP_KERNEL)?; 32 + 33 + Ok(drvdata.into()) 34 + } 35 + } 36 + 37 + impl Drop for SampleDriver { 38 + fn drop(&mut self) { 39 + dev_dbg!(self.pdev.as_ref(), "Remove Rust Platform driver sample.\n"); 40 + } 41 + } 42 + 43 + kernel::module_platform_driver! { 44 + type: SampleDriver, 45 + name: "rust_driver_platform", 46 + author: "Danilo Krummrich", 47 + description: "Rust Platform driver", 48 + license: "GPL v2", 49 + }
+238
samples/rust/rust_misc_device.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + // Copyright (C) 2024 Google LLC. 4 + 5 + //! Rust misc device sample. 6 + 7 + /// Below is an example userspace C program that exercises this sample's functionality. 8 + /// 9 + /// ```c 10 + /// #include <stdio.h> 11 + /// #include <stdlib.h> 12 + /// #include <errno.h> 13 + /// #include <fcntl.h> 14 + /// #include <unistd.h> 15 + /// #include <sys/ioctl.h> 16 + /// 17 + /// #define RUST_MISC_DEV_FAIL _IO('|', 0) 18 + /// #define RUST_MISC_DEV_HELLO _IO('|', 0x80) 19 + /// #define RUST_MISC_DEV_GET_VALUE _IOR('|', 0x81, int) 20 + /// #define RUST_MISC_DEV_SET_VALUE _IOW('|', 0x82, int) 21 + /// 22 + /// int main() { 23 + /// int value, new_value; 24 + /// int fd, ret; 25 + /// 26 + /// // Open the device file 27 + /// printf("Opening /dev/rust-misc-device for reading and writing\n"); 28 + /// fd = open("/dev/rust-misc-device", O_RDWR); 29 + /// if (fd < 0) { 30 + /// perror("open"); 31 + /// return errno; 32 + /// } 33 + /// 34 + /// // Make call into driver to say "hello" 35 + /// printf("Calling Hello\n"); 36 + /// ret = ioctl(fd, RUST_MISC_DEV_HELLO, NULL); 37 + /// if (ret < 0) { 38 + /// perror("ioctl: Failed to call into Hello"); 39 + /// close(fd); 40 + /// return errno; 41 + /// } 42 + /// 43 + /// // Get initial value 44 + /// printf("Fetching initial value\n"); 45 + /// ret = ioctl(fd, RUST_MISC_DEV_GET_VALUE, &value); 46 + /// if (ret < 0) { 47 + /// perror("ioctl: Failed to fetch the initial value"); 48 + /// close(fd); 49 + /// return errno; 50 + /// } 51 + /// 52 + /// value++; 53 + /// 54 + /// // Set value to something different 55 + /// printf("Submitting new value (%d)\n", value); 56 + /// ret = ioctl(fd, RUST_MISC_DEV_SET_VALUE, &value); 57 + /// if (ret < 0) { 58 + /// perror("ioctl: Failed to submit new value"); 59 + /// close(fd); 60 + /// return errno; 61 + /// } 62 + /// 63 + /// // Ensure new value was applied 64 + /// printf("Fetching new value\n"); 65 + /// ret = ioctl(fd, RUST_MISC_DEV_GET_VALUE, &new_value); 66 + /// if (ret < 0) { 67 + /// perror("ioctl: Failed to fetch the new value"); 68 + /// close(fd); 69 + /// return errno; 70 + /// } 71 + /// 72 + /// if (value != new_value) { 73 + /// printf("Failed: Committed and retrieved values are different (%d - %d)\n", value, new_value); 74 + /// close(fd); 75 + /// return -1; 76 + /// } 77 + /// 78 + /// // Call the unsuccessful ioctl 79 + /// printf("Attempting to call in to an non-existent IOCTL\n"); 80 + /// ret = ioctl(fd, RUST_MISC_DEV_FAIL, NULL); 81 + /// if (ret < 0) { 82 + /// perror("ioctl: Succeeded to fail - this was expected"); 83 + /// } else { 84 + /// printf("ioctl: Failed to fail\n"); 85 + /// close(fd); 86 + /// return -1; 87 + /// } 88 + /// 89 + /// // Close the device file 90 + /// printf("Closing /dev/rust-misc-device\n"); 91 + /// close(fd); 92 + /// 93 + /// printf("Success\n"); 94 + /// return 0; 95 + /// } 96 + /// ``` 97 + use core::pin::Pin; 98 + 99 + use kernel::{ 100 + c_str, 101 + device::Device, 102 + fs::File, 103 + ioctl::{_IO, _IOC_SIZE, _IOR, _IOW}, 104 + miscdevice::{MiscDevice, MiscDeviceOptions, MiscDeviceRegistration}, 105 + new_mutex, 106 + prelude::*, 107 + sync::Mutex, 108 + types::ARef, 109 + uaccess::{UserSlice, UserSliceReader, UserSliceWriter}, 110 + }; 111 + 112 + const RUST_MISC_DEV_HELLO: u32 = _IO('|' as u32, 0x80); 113 + const RUST_MISC_DEV_GET_VALUE: u32 = _IOR::<i32>('|' as u32, 0x81); 114 + const RUST_MISC_DEV_SET_VALUE: u32 = _IOW::<i32>('|' as u32, 0x82); 115 + 116 + module! { 117 + type: RustMiscDeviceModule, 118 + name: "rust_misc_device", 119 + author: "Lee Jones", 120 + description: "Rust misc device sample", 121 + license: "GPL", 122 + } 123 + 124 + #[pin_data] 125 + struct RustMiscDeviceModule { 126 + #[pin] 127 + _miscdev: MiscDeviceRegistration<RustMiscDevice>, 128 + } 129 + 130 + impl kernel::InPlaceModule for RustMiscDeviceModule { 131 + fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> { 132 + pr_info!("Initialising Rust Misc Device Sample\n"); 133 + 134 + let options = MiscDeviceOptions { 135 + name: c_str!("rust-misc-device"), 136 + }; 137 + 138 + try_pin_init!(Self { 139 + _miscdev <- MiscDeviceRegistration::register(options), 140 + }) 141 + } 142 + } 143 + 144 + struct Inner { 145 + value: i32, 146 + } 147 + 148 + #[pin_data(PinnedDrop)] 149 + struct RustMiscDevice { 150 + #[pin] 151 + inner: Mutex<Inner>, 152 + dev: ARef<Device>, 153 + } 154 + 155 + #[vtable] 156 + impl MiscDevice for RustMiscDevice { 157 + type Ptr = Pin<KBox<Self>>; 158 + 159 + fn open(_file: &File, misc: &MiscDeviceRegistration<Self>) -> Result<Pin<KBox<Self>>> { 160 + let dev = ARef::from(misc.device()); 161 + 162 + dev_info!(dev, "Opening Rust Misc Device Sample\n"); 163 + 164 + KBox::try_pin_init( 165 + try_pin_init! { 166 + RustMiscDevice { 167 + inner <- new_mutex!( Inner{ value: 0_i32 } ), 168 + dev: dev, 169 + } 170 + }, 171 + GFP_KERNEL, 172 + ) 173 + } 174 + 175 + fn ioctl(me: Pin<&RustMiscDevice>, _file: &File, cmd: u32, arg: usize) -> Result<isize> { 176 + dev_info!(me.dev, "IOCTLing Rust Misc Device Sample\n"); 177 + 178 + let size = _IOC_SIZE(cmd); 179 + 180 + match cmd { 181 + RUST_MISC_DEV_GET_VALUE => me.get_value(UserSlice::new(arg, size).writer())?, 182 + RUST_MISC_DEV_SET_VALUE => me.set_value(UserSlice::new(arg, size).reader())?, 183 + RUST_MISC_DEV_HELLO => me.hello()?, 184 + _ => { 185 + dev_err!(me.dev, "-> IOCTL not recognised: {}\n", cmd); 186 + return Err(ENOTTY); 187 + } 188 + }; 189 + 190 + Ok(0) 191 + } 192 + } 193 + 194 + #[pinned_drop] 195 + impl PinnedDrop for RustMiscDevice { 196 + fn drop(self: Pin<&mut Self>) { 197 + dev_info!(self.dev, "Exiting the Rust Misc Device Sample\n"); 198 + } 199 + } 200 + 201 + impl RustMiscDevice { 202 + fn set_value(&self, mut reader: UserSliceReader) -> Result<isize> { 203 + let new_value = reader.read::<i32>()?; 204 + let mut guard = self.inner.lock(); 205 + 206 + dev_info!( 207 + self.dev, 208 + "-> Copying data from userspace (value: {})\n", 209 + new_value 210 + ); 211 + 212 + guard.value = new_value; 213 + Ok(0) 214 + } 215 + 216 + fn get_value(&self, mut writer: UserSliceWriter) -> Result<isize> { 217 + let guard = self.inner.lock(); 218 + let value = guard.value; 219 + 220 + // Free-up the lock and use our locally cached instance from here 221 + drop(guard); 222 + 223 + dev_info!( 224 + self.dev, 225 + "-> Copying data to userspace (value: {})\n", 226 + &value 227 + ); 228 + 229 + writer.write::<i32>(&value)?; 230 + Ok(0) 231 + } 232 + 233 + fn hello(&self) -> Result<isize> { 234 + dev_info!(self.dev, "-> Hello from the Rust Misc Device\n"); 235 + 236 + Ok(0) 237 + } 238 + }
+12 -27
sound/soc/sof/sof-client-ipc-flood-test.c
··· 158 158 unsigned long ipc_duration_ms = 0; 159 159 bool flood_duration_test = false; 160 160 unsigned long ipc_count = 0; 161 - struct dentry *dentry; 162 161 int err; 163 162 char *string; 164 163 int ret; ··· 181 182 * ipc_duration_ms test floods the DSP for the time specified 182 183 * in the debugfs entry. 183 184 */ 184 - dentry = file->f_path.dentry; 185 - if (strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_COUNT) && 186 - strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION)) { 187 - ret = -EINVAL; 188 - goto out; 189 - } 190 - 191 - if (!strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION)) 185 + if (debugfs_get_aux_num(file)) 192 186 flood_duration_test = true; 193 187 194 188 /* test completion criterion */ ··· 244 252 struct sof_ipc_flood_priv *priv = cdev->data; 245 253 size_t size_ret; 246 254 247 - struct dentry *dentry; 255 + if (*ppos) 256 + return 0; 248 257 249 - dentry = file->f_path.dentry; 250 - if (!strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_COUNT) || 251 - !strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION)) { 252 - if (*ppos) 253 - return 0; 258 + count = min_t(size_t, count, strlen(priv->buf)); 259 + size_ret = copy_to_user(buffer, priv->buf, count); 260 + if (size_ret) 261 + return -EFAULT; 254 262 255 - count = min_t(size_t, count, strlen(priv->buf)); 256 - size_ret = copy_to_user(buffer, priv->buf, count); 257 - if (size_ret) 258 - return -EFAULT; 259 - 260 - *ppos += count; 261 - return count; 262 - } 263 + *ppos += count; 263 264 return count; 264 265 } 265 266 ··· 305 320 priv->dfs_root = debugfs_create_dir(dev_name(dev), debugfs_root); 306 321 if (!IS_ERR_OR_NULL(priv->dfs_root)) { 307 322 /* create read-write ipc_flood_count debugfs entry */ 308 - debugfs_create_file(DEBUGFS_IPC_FLOOD_COUNT, 0644, priv->dfs_root, 309 - cdev, &sof_ipc_flood_fops); 323 + debugfs_create_file_aux_num(DEBUGFS_IPC_FLOOD_COUNT, 0644, 324 + priv->dfs_root, cdev, 0, &sof_ipc_flood_fops); 310 325 311 326 /* create read-write ipc_flood_duration_ms debugfs entry */ 312 - debugfs_create_file(DEBUGFS_IPC_FLOOD_DURATION, 0644, 313 - priv->dfs_root, cdev, &sof_ipc_flood_fops); 327 + debugfs_create_file_aux_num(DEBUGFS_IPC_FLOOD_DURATION, 0644, 328 + priv->dfs_root, cdev, 1, &sof_ipc_flood_fops); 314 329 315 330 if (auxdev->id == 0) { 316 331 /*
+1 -1
tools/testing/cxl/test/cxl.c
··· 725 725 cxld->reset = mock_decoder_reset; 726 726 } 727 727 728 - static int first_decoder(struct device *dev, void *data) 728 + static int first_decoder(struct device *dev, const void *data) 729 729 { 730 730 struct cxl_decoder *cxld; 731 731