sysfs and driver core patches for 2.6.22
Subsystems (43)
PATCH 1/1 sysfs and driver core patches for 2.6.22
Here are some driver core and sysfs patches against your 2.6.22 git tree.
The majority of the work here is a sysfs rework from Tejun that splits the dependency between sysfs and kobjecs apart, fixing loads of reference counting issues all at once. This rework is needed for his upcoming libata hotplug work.
DMI module autoloading is also added here, along with some power management core work.
Also some documentation about the future of sysfs has been added.
All of these patches have been in the -mm tree for a few months.
Please pull from:
master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6.git/
Patches will be sent as a follow-on to this message to lkml for people to see.
thanks,
greg k-h
.../firmware_sample_firmware_class.c | 2 + Documentation/sysfs-rules.txt | 166 +++ arch/arm/common/locomo.c | 11 +- arch/arm/common/sa1111.c | 13 +- arch/arm/mach-sa1100/neponset.c | 15 +- arch/ppc/syslib/mv64x60.c | 1 - arch/s390/kernel/ipl.c | 2 - drivers/base/attribute_container.c | 1 + drivers/base/base.h | 2 +- drivers/base/bus.c | 24 +- drivers/base/class.c | 46 +- drivers/base/core.c | 58 +- drivers/base/dd.c | 21 +- drivers/base/devres.c | 2 + drivers/base/firmware_class.c | 6 +- drivers/base/power/main.c | 44 +- drivers/base/power/power.h | 4 +- drivers/base/power/resume.c | 23 +- drivers/base/power/runtime.c | 12 +- drivers/base/power/suspend.c | 72 +- drivers/base/sys.c | 24 +- drivers/block/pktcdvd.c | 3 +- drivers/char/ipmi/ipmi_msghandler.c | 10 - drivers/cpufreq/cpufreq_stats.c | 3 +- drivers/cpufreq/cpufreq_userspace.c | 2 +- drivers/cpufreq/freq_table.c | 1 - drivers/firmware/Kconfig | 9 + drivers/firmware/Makefile | 1 + drivers/firmware/dcdbas.c | 10 +- drivers/firmware/dcdbas.h | 3 +- drivers/firmware/dell_rbu.c | 31 +- drivers/firmware/dmi-id.c | 222 ++++ drivers/firmware/dmi_scan.c | 73 +- drivers/firmware/edd.c | 2 +- drivers/firmware/efivars.c | 6 +- drivers/i2c/chips/eeprom.c | 4 +- drivers/i2c/chips/max6875.c | 6 +- drivers/infiniband/core/sysfs.c | 1 - drivers/input/mouse/psmouse.h | 1 - drivers/macintosh/windfarm_core.c | 2 - drivers/misc/asus-laptop.c | 3 +- drivers/misc/msi-laptop.c | 44 +- drivers/net/ibmveth.c | 2 +- drivers/parisc/pdc_stable.c | 4 +- drivers/pci/hotplug/acpiphp_ibm.c | 7 +- drivers/pci/pci-sysfs.c | 22 +- drivers/pci/probe.c | 2 - drivers/pcmcia/socket_sysfs.c | 10 +- drivers/rapidio/rio-sysfs.c | 7 +- drivers/rtc/rtc-ds1553.c | 11 +- drivers/rtc/rtc-ds1742.c | 11 +- drivers/s390/cio/chp.c | 12 +- drivers/s390/net/qeth_sys.c | 2 +- drivers/scsi/arcmsr/arcmsr_attr.c | 18 +- drivers/scsi/ipr.c | 18 +- drivers/scsi/libsas/sas_expander.c | 17 +- drivers/scsi/lpfc/lpfc_attr.c | 14 +- drivers/scsi/qla2xxx/qla_attr.c | 56 +- drivers/spi/at25.c | 7 +- drivers/usb/core/hub.c | 5 - drivers/video/aty/radeon_base.c | 10 +- drivers/video/backlight/backlight.c | 2 +- drivers/video/backlight/lcd.c | 2 +- drivers/w1/slaves/w1_ds2433.c | 11 +- drivers/w1/slaves/w1_therm.c | 8 +- drivers/w1/w1.c | 14 +- drivers/zorro/zorro-sysfs.c | 6 +- fs/debugfs/inode.c | 63 + fs/ecryptfs/main.c | 2 - fs/ocfs2/cluster/masklog.c | 1 - fs/partitions/check.c | 1 - fs/sysfs/bin.c | 195 ++-- fs/sysfs/dir.c | 1297 ++++++++++++++------ fs/sysfs/file.c | 379 +++---- fs/sysfs/group.c | 55 +- fs/sysfs/inode.c | 221 +--- fs/sysfs/mount.c | 36 +- fs/sysfs/symlink.c | 150 ++-- fs/sysfs/sysfs.h | 169 ++-- include/linux/debugfs.h | 9 + include/linux/device.h | 5 - include/linux/dmi.h | 8 + include/linux/idr.h | 29 + include/linux/kobject.h | 9 +- include/linux/pm.h | 5 - include/linux/sysdev.h | 3 +- include/linux/sysfs.h | 43 +- kernel/module.c | 9 +- kernel/params.c | 1 - lib/idr.c | 332 +++++- lib/kobject.c | 19 +- net/bridge/br_sysfs_br.c | 8 +- net/bridge/br_sysfs_if.c | 3 +- 93 files changed, 2822 insertions(+), 1494 deletions(-) create mode 100644 Documentation/sysfs-rules.txt create mode 100644 drivers/firmware/dmi-id.c
---------------
Adrian Bunk (1):
Driver core: fix devres_release_all() return value
Cornelia Huck (1):
Driver core: coding style cleanup
Jan Kara (1):
debugfs: add rename for debugfs files
Kay Sievers (2):
Rules on how to use sysfs in userspace programs Driver core: add missing kset uevent
Lennart Poettering (1):
DMI-based module autoloading
Matthias Kaehlcke (2):
sysdev: use mutex instead of semaphore Power Management: use mutexes instead of semaphores
Michael S. Tsirkin (1):
Driver core: include linux/mutex.h from attribute_container.c
Rafael J. Wysocki (8):
PM: Remove pm_parent from struct dev_pm_info
PM: Remove saved_state from struct dev_pm_info
PM: Simplify suspend_device
PM: Remove prev_state from struct dev_pm_info
PM: Remove power_state.event checks from suspend core code
PM: Do not check parent state in suspend and resume core code
PM: do not use saved_state from struct dev_pm_info on ARM
sysfs: Fix oops in sysfs_drop_dentry on x86_64
Stefan Richter (2):
driver core: properly get driver in device_release_driver driver core: fix kernel doc of device_release_driver
Tejun Heo (41):
idr: fix obscure bug in allocation path
idr: separate out idr_mark_full()
ida: implement idr based id allocator
sysfs: move release_sysfs_dirent() to dir.c
sysfs: allocate inode number using ida
sysfs: make sysfs_put() ignore NULL sd
sysfs: fix error handling in binattr write()
sysfs: flatten cleanup paths in sysfs_add_link() and create_dir()
sysfs: flatten and fix sysfs_rename_dir() error handling
sysfs: consolidate sysfs_dirent creation functions
sysfs: add sysfs_dirent->s_parent
sysfs: add sysfs_dirent->s_name
sysfs: make sysfs_dirent->s_element a union
sysfs: implement kobj_sysfs_assoc_lock
sysfs: reimplement symlink using sysfs_dirent tree
sysfs: implement bin_buffer
sysfs: implement sysfs_dirent active reference and immediate disconnect
sysfs: kill attribute file orphaning
sysfs: separate out sysfs_attach_dentry()
sysfs: reimplement sysfs_drop_dentry()
sysfs: kill unnecessary attribute->owner
driver-core: make devt_attr and uevent_attr static
sysfs: make sysfs_alloc_ino() static
sysfs: fix parent refcounting during rename and move
sysfs: reorganize sysfs_new_indoe() and sysfs_create()
sysfs: use iget_locked() instead of new_inode()
sysfs: fix root sysfs_dirent -> root dentry association
sysfs: move s_active functions to fs/sysfs/dir.c
sysfs: slim down sysfs_dirent->s_active
sysfs: use singly-linked list for sysfs_dirent tree
sysfs: make sysfs_drop_dentry() access inodes using ilookup()
sysfs: rename sysfs_dirent->s_type to s_flags and make room for flags
sysfs: implement SYSFS_FLAG_REMOVED flag
sysfs: implement sysfs_find_dirent() and sysfs_get_dirent()
sysfs: make kobj point to sysfs_dirent instead of dentry
sysfs: consolidate sysfs spinlocks
sysfs: use sysfs_mutex to protect the sysfs_dirent tree
sysfs: restructure add/remove paths and fix inode update
sysfs: move sysfs_drop_dentry() to dir.c and make it static
sysfs: implement sysfs_get_dentry()
sysfs: make directory dentries and inodes reclaimable
Zhang Rui (1):
sysfs: add parameter "struct bin_attribute *" in .read/.write methods for sysfs binary attributes
PATCH 1/61 Rules on how to use sysfs in userspace programs
From: Kay Sievers <[email protected]>
Here's a document to help clear things up.
--- Documentation/sysfs-rules.txt | 166 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 166 insertions(+), 0 deletions(-) create mode 100644 Documentation/sysfs-rules.txt
Documentation/sysfs-rules.txt new file +166 -0
@@ -0,0 +1,166 @@ +Rules on how to access information in the Linux kernel sysfs + +The kernel exported sysfs exports internal kernel implementation-details +and depends on internal kernel structures and layout. It is agreed upon +by the kernel developers that the Linux kernel does not provide a stable +internal API. As sysfs is a direct export of kernel internal +structures, the sysfs interface can not provide a stable interface eighter, +it may always change along with internal kernel changes. + +To minimize the risk of breaking users of sysfs, which are in most cases +low-level userspace applications, with a new kernel release, the users +of sysfs must follow some rules to use an as abstract-as-possible way to +access this filesystem. The current udev and HAL programs already +implement this and users are encouraged to plug, if possible, into the +abstractions these programs provide instead of accessing sysfs +directly. + +But if you really do want or need to access sysfs directly, please follow +the following rules and then your programs should work with future +versions of the sysfs interface. + +- Do not use libsysfs + It makes assumptions about sysfs which are not true. Its API does not + offer any abstraction, it exposes all the kernel driver-core + implementation details in its own API. Therefore it is not better than + reading directories and opening the files yourself. + Also, it is not actively maintained, in the sense of reflecting the + current kernel-development. The goal of providing a stable interface + to sysfs has failed, it causes more problems, than it solves. It + violates many of the rules in this document. + +- sysfs is always at /sys + Parsing /proc/mounts is a waste of time. Other mount points are a + system configuration bug you should not try to solve. For test cases, + possibly support a SYSFS_PATH environment variable to overwrite the + applications behavior, but never try to search for sysfs. Never try + to mount it, if you are not an early boot script. + +- devices are only "devices" + There is no such thing like class-, bus-, physical devices, + interfaces, and such that you can rely on in userspace. Everything is + just simply a "device". Class-, bus-, physical, ... types are just + kernel implementation details, which should not be expected by + applications that look for devices in sysfs. + + The properties of a device are: + o devpath (/devices/pci0000:00/0000:00:1d.1/usb2/2-2/2-2:1.0) + - identical to the DEVPATH value in the event sent from the kernel + at device creation and removal + - the unique key to the device at that point in time + - the kernels path to the device-directory without the leading + /sys, and always starting with with a slash + - all elements of a devpath must be real directories. Symlinks + pointing to /sys/devices must always be resolved to their real + target, and the target path must be used to access the device. + That way the devpath to the device matches the devpath of the + kernel used at event time. + - using or exposing symlink values as elements in a devpath string + is a bug in the application + + o kernel name (sda, tty, 0000:00:1f.2, ...) + - a directory name, identical to the last element of the devpath + - applications need to handle spaces and characters like '!' in + the name + + o subsystem (block, tty, pci, ...) + - simple string, never a path or a link + - retrieved by reading the "subsystem"-link and using only the + last element of the target path + + o driver (tg3, ata_piix, uhci_hcd) + - a simple string, which may contain spaces, never a path or a + link + - it is retrieved by reading the "driver"-link and using only the + last element of the target path + - devices which do not have "driver"-link, just do not have a + driver; copying the driver value in a child device context, is a + bug in the application + + o attributes + - the files in the device directory or files below a subdirectories + of the same device directory + - accessing attributes reached by a symlink pointing to another device, + like the "device"-link, is a bug in the application + + Everything else is just a kernel driver-core implementation detail, + that should not be assumed to be stable across kernel releases. + +- Properties of parent devices never belong into a child device. + Always look at the parent devices themselves for determining device + context properties. If the device 'eth0' or 'sda' does not have a + "driver"-link, then this device does not have a driver. Its value is empty. + Never copy any property of the parent-device into a child-device. Parent + device-properties may change dynamically without any notice to the + child device. + +- Hierarchy in a single device-tree + There is only one valid place in sysfs where hierarchy can be examined + and this is below: /sys/devices. + It is planned, that all device directories will end up in the tree + below this directory. + +- Classification by subsystem + There are currently three places for classification of devices: + /sys/block, /sys/class and /sys/bus. It is planned that these will + not contain any device-directories themselves, but only flat lists of + symlinks pointing to the unified /sys/devices tree. + All three places have completely different rules on how to access + device information. It is planned to merge all three + classification-directories into one place at /sys/subsystem, + following the layout of the bus-directories. All buses and + classes, including the converted block-subsystem, will show up + there. + The devices belonging to a subsystem will create a symlink in the + "devices" directory at /sys/subsystem/<name>/devices. + + If /sys/subsystem exists, /sys/bus, /sys/class and /sys/block can be + ignored. If it does not exist, you have always to scan all three + places, as the kernel is free to move a subsystem from one place to + the other, as long as the devices are still reachable by the same + subsystem name. + + Assuming /sys/class/<subsystem> and /sys/bus/<subsystem>, or + /sys/block and /sys/class/block are not interchangeable, is a bug in + the application. + +- Block + The converted block-subsystem at /sys/class/block, or + /sys/subsystem/block will contain the links for disks and partitions + at the same level, never in a hierarchy. Assuming the block-subsytem to + contain only disks and not partition-devices in the same flat list is + a bug in the application. + +- "device"-link and <subsystem>:<kernel name>-links + Never depend on the "device"-link. The "device"-link is a workaround + for the old layout, where class-devices are not created in + /sys/devices/ like the bus-devices. If the link-resolving of a + device-directory does not end in /sys/devices/, you can use the + "device"-link to find the parent devices in /sys/devices/. That is the + single valid use of the "device"-link, it must never appear in any + path as an element. Assuming the existence of the "device"-link for + a device in /sys/devices/ is a bug in the application. + Accessing /sys/class/net/eth0/device is a bug in the application. + + Never depend on the class-specific links back to the /sys/class + directory. These links are also a workaround for the design mistake + that class-devices are not created in /sys/devices. If a device + directory does not contain directories for child devices, these links + may be used to find the child devices in /sys/class. That is the single + valid use of these links, they must never appear in any path as an + element. Assuming the existence of these links for devices which are + real child device directories in the /sys/devices tree, is a bug in + the application. + + It is planned to remove all these links when when all class-device + directories live in /sys/devices. + +- Position of devices along device chain can change. + Never depend on a specific parent device position in the devpath, + or the chain of parent devices. The kernel is free to insert devices into + the chain. You must always request the parent device you are looking for + by its subsystem value. You need to walk up the chain until you find + the device that matches the expected subsystem. Depending on a specific + position of a parent device, or exposing relative paths, using "../" to + access the chain of parents, is a bug in the application. +
Signature · 1 line
1.5.2.2
PATCH 2/61 debugfs: add rename for debugfs files
From: Jan Kara <[email protected]>
Implement debugfs_rename() to allow renaming files/directories in debugfs.
--- fs/debugfs/inode.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/debugfs.h | 9 ++++++ 2 files changed, 72 insertions(+), 0 deletions(-)
fs/debugfs/inode.c +63 -0
@@ -368,6 +368,69 @@ void debugfs_remove(struct dentry *dentry) }EXPORT_SYMBOL_GPL (debugfs_remove); +/** +* debugfs_rename - rename a file/directory in the debugfs filesystem +* @old_dir: a pointer to the parent dentry for the renamed object. This +* should be a directory dentry. +* @old_dentry: dentry of an object to be renamed. +* @new_dir: a pointer to the parent dentry where the object should be +* moved. This should be a directory dentry. +* @new_name: a pointer to a string containing the target name. +* +* This function renames a file/directory in debugfs. The target must not +* exist for rename to succeed. +* +* This function will return a pointer to old_dentry (which is updated to +* reflect renaming) if it succeeds. If an error occurs, %NULL will be +* returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. +*/ +struct dentry *debugfs_rename (struct dentry *old_dir,struct dentry *old_dentry, +struct dentry *new_dir,const char *new_name) +{ +int error; +struct dentry *dentry =NULL , *trap; +const char *old_name; + + trap =lock_rename (new_dir, old_dir); +/* Source or destination directories don't exist? */ +if (!old_dir->d_inode || !new_dir->d_inode) + goto exit; +/* Source does not exist, cyclic rename, or mountpoint? */ +if (!old_dentry->d_inode || old_dentry == trap || +d_mountpoint (old_dentry)) + goto exit; + dentry =lookup_one_len (new_name, new_dir,strlen (new_name)); +/* Lookup failed, cyclic rename or target exists? */ +if (IS_ERR (dentry) || dentry == trap || dentry->d_inode) + goto exit; + + old_name =fsnotify_oldname_init (old_dentry->d_name.name); + + error =simple_rename (old_dir->d_inode, old_dentry, new_dir->d_inode, + dentry); +if (error) { +fsnotify_oldname_free (old_name); + goto exit; + } +d_move (old_dentry, dentry); +fsnotify_move (old_dir->d_inode, new_dir->d_inode, old_name, + old_dentry->d_name.name,S_ISDIR (old_dentry->d_inode->i_mode), +NULL , old_dentry->d_inode); +fsnotify_oldname_free (old_name); +unlock_rename (new_dir, old_dir); +dput (dentry); +return old_dentry; +exit: +if (dentry && !IS_ERR (dentry)) +dput (dentry); +unlock_rename (new_dir, old_dir); +return NULL ; +} +EXPORT_SYMBOL_GPL (debugfs_rename); + static decl_subsys(debug, NULL, NULL);static int __init debugfs_init (void )
include/linux/debugfs.h +9 -0
@@ -38,6 +38,9 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,void debugfs_remove (struct dentry *dentry); +struct dentry *debugfs_rename (struct dentry *old_dir,struct dentry *old_dentry, +struct dentry *new_dir,const char *new_name); +struct dentry *debugfs_create_u8 (const char *name,mode_t mode,struct dentry *parent,u8 *value); struct dentry *debugfs_create_u16(const char *name, mode_t mode,
@@ -85,6 +88,12 @@ static inline struct dentry *debugfs_create_symlink(const char *name,static inline void debugfs_remove (struct dentry *dentry) { } +static inline struct dentry *debugfs_rename (struct dentry *old_dir,struct dentry *old_dentry, +struct dentry *new_dir,char *new_name) +{ +return ERR_PTR (-ENODEV ); +} +static inline struct dentry *debugfs_create_u8 (const char *name,mode_t mode,struct dentry *parent,u8 *value)
Signature · 1 line
1.5.2.2
PATCH 3/61 DMI-based module autoloading
From: Lennart Poettering <[email protected]>
The patch below adds DMI/SMBIOS based module autoloading to the Linux kernel. The idea is to load laptop drivers automatically (and other drivers which cannot be autoloaded otherwise), based on the DMI system identification information of the BIOS.
Right now most distros manually try to load all available laptop drivers on bootup in the hope that at least one of them loads successfully. This patch does away with all that, and uses udev to automatically load matching drivers on the right machines.
Basically the patch just exports the DMI information that has been parsed by the kernel anyway to userspace via a sysfs device /sys/class/dmi/id and makes sure that proper modalias attributes are available. Besides adding the "modalias" attribute it also adds attributes for a few other DMI fields which might be useful for writing udev rules.
This patch is not an attempt to export the entire DMI/SMBIOS data to userspace. We already have "dmidecode" which parses the complete DMI info from userspace. The purpose of this patch is machine model identification and good udev integration.
To take advantage of DMI based module autoloading, a driver should export one or more MODULE_ALIAS fields similar to these:
MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*"); MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*"); MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
These lines are specific to my msi-laptop.c driver. They are basically just a concatenation of a few carefully selected DMI fields with all potentially bad characters stripped.
Besides laptop drivers, modules like "hdaps", the i2c modules and the hwmon modules are good candidates for "dmi:" MODULE_ALIAS lines.
Besides merely exporting the DMI data via sysfs the patch adds support for a few more DMI fields. Especially the CHASSIS fields are very useful to identify different laptop modules. The patch also adds working MODULE_ALIAS lines to my msi-laptop.c driver.
I'd like to thank Kay Sievers for helping me to clean up this patch for posting it on lkml.
Patch is against Linus' current GIT HEAD. Should probably apply to older kernels as well without modification.
--- drivers/firmware/Kconfig | 9 ++ drivers/firmware/Makefile | 1 + drivers/firmware/dmi-id.c | 222 +++++++++++++++++++++++++++++++++++++++++++ drivers/firmware/dmi_scan.c | 73 +++++++++++++- drivers/misc/msi-laptop.c | 44 ++++++++- include/linux/dmi.h | 8 ++ 6 files changed, 348 insertions(+), 9 deletions(-) create mode 100644 drivers/firmware/dmi-id.c
drivers/firmware/Kconfig +9 -0
@@ -84,4 +84,13 @@ config DCDBAS Say Y or M here to enable the driver for use by Dell systems management software such as Dell OpenManage. +config DMIID + bool "Export DMI identification via sysfs to userspace" + depends on DMI + default y + help + Say Y here if you want to query SMBIOS/DMI system identification + information from userspace through /sys/class/dmi/id/ or if you want + DMI-based module auto-loading. + endmenu
drivers/firmware/Makefile +1 -0
@@ -7,3 +7,4 @@ obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_PCDP) += pcdp.o obj-$(CONFIG_DELL_RBU) += dell_rbu.o obj-$(CONFIG_DCDBAS) += dcdbas.o +obj-$(CONFIG_DMIID) += dmi-id.o
drivers/firmware/dmi-id.c new file +222 -0
222 lines not on this page · raw message
drivers/firmware/dmi_scan.c +67 -6
119 lines not on this page · raw message
drivers/misc/msi-laptop.c +41 -3
75 lines not on this page · raw message
include/linux/dmi.h +8 -0
@@ -12,9 +12,17 @@ enum dmi_field {DMI_PRODUCT_NAME ,DMI_PRODUCT_VERSION ,DMI_PRODUCT_SERIAL , +DMI_PRODUCT_UUID ,DMI_BOARD_VENDOR ,DMI_BOARD_NAME ,DMI_BOARD_VERSION , +DMI_BOARD_SERIAL , +DMI_BOARD_ASSET_TAG , +DMI_CHASSIS_VENDOR , +DMI_CHASSIS_TYPE , +DMI_CHASSIS_VERSION , +DMI_CHASSIS_SERIAL , +DMI_CHASSIS_ASSET_TAG , DMI_STRING_MAX, };
Signature · 1 line
1.5.2.2
PATCH 4/61 Driver core: add missing kset uevent
From: Kay Sievers <[email protected]>
We get uevents for a bus/class going away, but not one registering. Add the missing uevent in kset_register(), which will send an event for a new bus/class. Suppress all unwanted uevents for bus subdirectories like /bus/*/devices/, /bus/*/drivers/.
Now we get for module usbcore:
add /module/usbcore (module) add /bus/usb (bus) add /class/usb_host (class) add /bus/usb/drivers/hub (drivers) add /bus/usb/drivers/usb (drivers) remove /bus/usb/drivers/usb (drivers) remove /bus/usb/drivers/hub (drivers) remove /class/usb_host (class) remove /bus/usb (bus) remove /module/usbcore (module)
instead of:
add /module/usbcore (module) add /bus/usb/drivers/hub (drivers) add /bus/usb/drivers/usb (drivers) remove /bus/usb/drivers/usb (drivers) remove /bus/usb/drivers/hub (drivers) remove /class/usb_host (class) remove /bus/usb/drivers (bus) remove /bus/usb/devices (bus) remove /bus/usb (bus) remove /module/usbcore (module)
--- drivers/base/bus.c | 16 ++++++++++++++-- lib/kobject.c | 9 ++++++++- 2 files changed, 22 insertions(+), 3 deletions(-)
drivers/base/bus.c +14 -2
@@ -138,12 +138,24 @@ void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) } } -static struct kobj_type ktype_bus = { +static struct kobj_type bus_ktype = { .sysfs_ops = &bus_sysfs_ops, +}; + +static int bus_uevent_filter (struct kset *kset,struct kobject *kobj) +{ +struct kobj_type *ktype =get_ktype (kobj); + +if (ktype == &bus_ktype) +return 1 ; +return 0 ; +} +static struct kset_uevent_ops bus_uevent_ops = { + .filter = bus_uevent_filter, }; -static decl_subsys(bus, &ktype_bus, NULL); +static decl_subsys(bus, &bus_ktype, &bus_uevent_ops);#ifdef CONFIG_HOTPLUG
lib/kobject.c +8 -1
@@ -597,10 +597,17 @@ int kset_add(struct kset * k)int kset_register (struct kset * k) { +int err; +if (!k)return -EINVAL ; +kset_init (k); -return kset_add (k); + err =kset_add (k); +if (err) +return err; +kobject_uevent (&k->kobj,KOBJ_ADD ); +return 0 ; }
Signature · 1 line
1.5.2.2
PATCH 5/61 sysdev: use mutex instead of semaphore
From: Matthias Kaehlcke <[email protected]>
The sysdev code use a semaphore as mutex. Use the mutex API instead of the (binary) semaphore.
--- drivers/base/sys.c | 24 ++++++++++++------------ 1 files changed, 12 insertions(+), 12 deletions(-)
drivers/base/sys.c +12 -12
@@ -21,7 +21,7 @@#include <linux/string.h> #include <linux/pm.h> #include <linux/device.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include "base.h"
@@ -155,7 +155,7 @@ EXPORT_SYMBOL_GPL(sysdev_class_unregister);static LIST_HEAD (sysdev_drivers); -static DECLARE_MUTEX (sysdev_drivers_lock); +static DEFINE_MUTEX (sysdev_drivers_lock);/** * sysdev_driver_register - Register auxillary driver
@@ -172,7 +172,7 @@ static DECLARE_MUTEX(sysdev_drivers_lock);int sysdev_driver_register (struct sysdev_class * cls,struct sysdev_driver * drv) { -down (&sysdev_drivers_lock); +mutex_lock (&sysdev_drivers_lock);if (cls &&kset_get (&cls->kset)) {list_add_tail (&drv->entry, &cls->drivers);
@@ -184,7 +184,7 @@ int sysdev_driver_register(struct sysdev_class * cls, } }else list_add_tail (&drv->entry, &sysdev_drivers); -up (&sysdev_drivers_lock); +mutex_unlock (&sysdev_drivers_lock);return 0 ; }
@@ -197,7 +197,7 @@ int sysdev_driver_register(struct sysdev_class * cls,void sysdev_driver_unregister (struct sysdev_class * cls,struct sysdev_driver * drv) { -down (&sysdev_drivers_lock); +mutex_lock (&sysdev_drivers_lock);list_del_init (&drv->entry);if (cls) {if (drv->remove) {
@@ -207,7 +207,7 @@ void sysdev_driver_unregister(struct sysdev_class * cls, }kset_put (&cls->kset); } -up (&sysdev_drivers_lock); +mutex_unlock (&sysdev_drivers_lock); }EXPORT_SYMBOL_GPL (sysdev_driver_register);
@@ -246,7 +246,7 @@ int sysdev_register(struct sys_device * sysdev)if (!error) {struct sysdev_driver * drv; -down (&sysdev_drivers_lock); +mutex_lock (&sysdev_drivers_lock);/* Generic notification is implicit, because it's that * code that should have called us. */
@@ -262,7 +262,7 @@ int sysdev_register(struct sys_device * sysdev)if (drv->add) drv->add (sysdev); } -up (&sysdev_drivers_lock); +mutex_unlock (&sysdev_drivers_lock); }return error; }
@@ -271,7 +271,7 @@ void sysdev_unregister(struct sys_device * sysdev) {struct sysdev_driver * drv; -down (&sysdev_drivers_lock); +mutex_lock (&sysdev_drivers_lock);list_for_each_entry (drv, &sysdev_drivers, entry) {if (drv->remove) drv->remove (sysdev);
@@ -281,7 +281,7 @@ void sysdev_unregister(struct sys_device * sysdev)if (drv->remove) drv->remove (sysdev); } -up (&sysdev_drivers_lock); +mutex_unlock (&sysdev_drivers_lock);kobject_unregister (&sysdev->kobj); }
@@ -308,7 +308,7 @@ void sysdev_shutdown(void)pr_debug ("Shutting Down System Devices\n" ); -down (&sysdev_drivers_lock); +mutex_lock (&sysdev_drivers_lock);list_for_each_entry_reverse (cls, &system_subsys.list, kset.kobj.entry) {struct sys_device * sysdev;
@@ -337,7 +337,7 @@ void sysdev_shutdown(void) cls->shutdown (sysdev); } } -up (&sysdev_drivers_lock); +mutex_unlock (&sysdev_drivers_lock); }static void __sysdev_resume (struct sys_device *dev)
Signature · 1 line
1.5.2.2
PATCH 6/61 Power Management: use mutexes instead of semaphores
From: Matthias Kaehlcke <[email protected]>
The Power Management code uses semaphores as mutexes. Use the mutex API instead of the (binary) semaphores.
--- drivers/base/power/main.c | 14 ++++++++------ drivers/base/power/power.h | 4 ++-- drivers/base/power/resume.c | 12 ++++++------ drivers/base/power/runtime.c | 12 ++++++------ drivers/base/power/suspend.c | 14 +++++++------- 5 files changed, 29 insertions(+), 27 deletions(-)
drivers/base/power/main.c +8 -6
@@ -20,14 +20,16 @@*/ #include <linux/device.h> +#include <linux/mutex.h> +#include "power.h" LIST_HEAD (dpm_active);LIST_HEAD (dpm_off);LIST_HEAD (dpm_off_irq); -DECLARE_MUTEX (dpm_sem); -DECLARE_MUTEX (dpm_list_sem); +DEFINE_MUTEX (dpm_mtx); +DEFINE_MUTEX (dpm_list_mtx);int (*platform_enable_wakeup)(struct device *dev,int is_on);
@@ -59,12 +61,12 @@ int device_pm_add(struct device * dev)pr_debug ("PM: Adding info for %s:%s\n" , dev->bus ? dev->bus->name :"No Bus" ,kobject_name (&dev->kobj)); -down (&dpm_list_sem); +mutex_lock (&dpm_list_mtx);list_add_tail (&dev->power.entry, &dpm_active);device_pm_set_parent (dev, dev->parent);if ((error =dpm_sysfs_add (dev)))list_del (&dev->power.entry); -up (&dpm_list_sem); +mutex_unlock (&dpm_list_mtx);return error; }
@@ -73,11 +75,11 @@ void device_pm_remove(struct device * dev)pr_debug ("PM: Removing info for %s:%s\n" , dev->bus ? dev->bus->name :"No Bus" ,kobject_name (&dev->kobj)); -down (&dpm_list_sem); +mutex_lock (&dpm_list_mtx);dpm_sysfs_remove (dev);put_device (dev->power.pm_parent);list_del_init (&dev->power.entry); -up (&dpm_list_sem); +mutex_unlock (&dpm_list_mtx); }
drivers/base/power/power.h +2 -2
@@ -14,12 +14,12 @@ extern void device_shutdown(void);/* * Used to synchronize global power management operations. */ -extern struct semaphore dpm_sem; +extern struct mutex dpm_mtx;/* * Used to serialize changes to the dpm_* lists. */ -extern struct semaphore dpm_list_sem; +extern struct mutex dpm_list_mtx;/* * The PM lists.
drivers/base/power/resume.c +6 -6
@@ -80,7 +80,7 @@ static int resume_device_early(struct device * dev)*/ void dpm_resume (void ) { -down (&dpm_list_sem); +mutex_lock (&dpm_list_mtx);while (!list_empty (&dpm_off)) {struct list_head * entry = dpm_off.next;struct device * dev =to_device (entry);
@@ -88,13 +88,13 @@ void dpm_resume(void)get_device (dev);list_move_tail (entry, &dpm_active); -up (&dpm_list_sem); +mutex_unlock (&dpm_list_mtx);if (!dev->power.prev_state.event)resume_device (dev); -down (&dpm_list_sem); +mutex_lock (&dpm_list_mtx);put_device (dev); } -up (&dpm_list_sem); +mutex_unlock (&dpm_list_mtx); }
@@ -108,9 +108,9 @@ void dpm_resume(void)void device_resume (void ) {might_sleep (); -down (&dpm_sem); +mutex_lock (&dpm_mtx);dpm_resume (); -up (&dpm_sem); +mutex_unlock (&dpm_mtx); }EXPORT_SYMBOL_GPL (device_resume);
drivers/base/power/runtime.c +6 -6
@@ -32,9 +32,9 @@ static void runtime_resume(struct device * dev)void dpm_runtime_resume (struct device * dev) { -down (&dpm_sem); +mutex_lock (&dpm_mtx);runtime_resume (dev); -up (&dpm_sem); +mutex_unlock (&dpm_mtx); }EXPORT_SYMBOL (dpm_runtime_resume);
@@ -49,7 +49,7 @@ int dpm_runtime_suspend(struct device * dev, pm_message_t state) {int error =0 ; -down (&dpm_sem); +mutex_lock (&dpm_mtx);if (dev->power.power_state.event == state.event) goto Done;
@@ -59,7 +59,7 @@ int dpm_runtime_suspend(struct device * dev, pm_message_t state)if (!(error =suspend_device (dev, state))) dev->power.power_state = state; Done: -up (&dpm_sem); +mutex_unlock (&dpm_mtx);return error; }EXPORT_SYMBOL (dpm_runtime_suspend);
@@ -78,8 +78,8 @@ EXPORT_SYMBOL(dpm_runtime_suspend);*/ void dpm_set_power_state (struct device * dev,pm_message_t state) { -down (&dpm_sem); +mutex_lock (&dpm_mtx); dev->power.power_state = state; -up (&dpm_sem); +mutex_unlock (&dpm_mtx); }#endif /* 0 */
drivers/base/power/suspend.c +7 -7
@@ -108,7 +108,7 @@ int suspend_device(struct device * dev, pm_message_t state)/* * This is called with interrupts off, only a single CPU -* running. We can't do down() on a semaphore (and we don't +* running. We can't acquire a mutex or semaphore (and we don't * need the protection) */ static int suspend_device_late (struct device *dev,pm_message_t state)
@@ -153,18 +153,18 @@ int device_suspend(pm_message_t state)int error =0 ;might_sleep (); -down (&dpm_sem); -down (&dpm_list_sem); +mutex_lock (&dpm_mtx); +mutex_lock (&dpm_list_mtx);while (!list_empty (&dpm_active) && error ==0 ) {struct list_head * entry = dpm_active.prev;struct device * dev =to_device (entry);get_device (dev); -up (&dpm_list_sem); +mutex_unlock (&dpm_list_mtx); error =suspend_device (dev, state); -down (&dpm_list_sem); +mutex_lock (&dpm_list_mtx);/* Check if the device got removed */ if (!list_empty (&dev->power.entry)) {
@@ -179,11 +179,11 @@ int device_suspend(pm_message_t state) error == -EAGAIN ? " (please convert to suspend_late)" : "");put_device (dev); } -up (&dpm_list_sem); +mutex_unlock (&dpm_list_mtx);if (error)dpm_resume (); -up (&dpm_sem); +mutex_unlock (&dpm_mtx);return error; }
Signature · 1 line
1.5.2.2
PATCH 7/61 PM: Remove pm_parent from struct dev_pm_info
From: Rafael J. Wysocki <[email protected]>
The pm_parent member of struct dev_pm_info (defined in include/linux/pm.h) is only used to check if the device's parent is in the right state while the device is being suspended or resumed. However, this can be done just as well with the help of the parent pointer in struct device, so pm_parent can be removed along with some code that handles it.
--- drivers/base/power/main.c | 30 ++++-------------------------- drivers/base/power/resume.c | 7 +++---- drivers/base/power/suspend.c | 7 +++---- include/linux/pm.h | 3 --- 4 files changed, 10 insertions(+), 37 deletions(-)
drivers/base/power/main.c +4 -26
@@ -33,28 +33,7 @@ DEFINE_MUTEX(dpm_list_mtx);int (*platform_enable_wakeup)(struct device *dev,int is_on); - -/** -* device_pm_set_parent - Specify power dependency. -* @dev: Device who needs power. -* @parent: Device that supplies power. -* -* This function is used to manually describe a power-dependency -* relationship. It may be used to specify a transversal relationship -* (where the power supplier is not the physical (or electrical) -* ancestor of a specific device. -* The effect of this is that the supplier will not be powered down -* before the power dependent. -*/ - -void device_pm_set_parent (struct device * dev,struct device * parent) -{ -put_device (dev->power.pm_parent); - dev->power.pm_parent =get_device (parent); -} -EXPORT_SYMBOL_GPL (device_pm_set_parent); - -int device_pm_add (struct device * dev) +int device_pm_add (struct device *dev) {int error;
@@ -63,21 +42,20 @@ int device_pm_add(struct device * dev) kobject_name(&dev->kobj));mutex_lock (&dpm_list_mtx);list_add_tail (&dev->power.entry, &dpm_active); -device_pm_set_parent (dev, dev->parent); -if ((error =dpm_sysfs_add (dev))) + error =dpm_sysfs_add (dev); +if (error)list_del (&dev->power.entry);mutex_unlock (&dpm_list_mtx);return error; } -void device_pm_remove (struct device * dev) +void device_pm_remove (struct device *dev) {pr_debug ("PM: Removing info for %s:%s\n" , dev->bus ? dev->bus->name :"No Bus" ,kobject_name (&dev->kobj));mutex_lock (&dpm_list_mtx);dpm_sysfs_remove (dev); -put_device (dev->power.pm_parent);list_del_init (&dev->power.entry);mutex_unlock (&dpm_list_mtx); }
drivers/base/power/resume.c +3 -4
@@ -29,12 +29,11 @@ int resume_device(struct device * dev)down (&dev->sem); -if (dev->power.pm_parent - && dev->power.pm_parent->power.power_state.event) { +if (dev->parent && dev->parent->power.power_state.event) {dev_err (dev,"PM: resume from %d, parent %s still %d\n" , dev->power.power_state.event, - dev->power.pm_parent->bus_id, - dev->power.pm_parent->power.power_state.event); + dev->parent->bus_id, + dev->parent->power.power_state.event); }if (dev->bus && dev->bus->resume) {
drivers/base/power/suspend.c +3 -4
@@ -55,13 +55,12 @@ int suspend_device(struct device * dev, pm_message_t state)dev_dbg (dev,"PM: suspend %d-->%d\n" , dev->power.power_state.event, state.event); } -if (dev->power.pm_parent - && dev->power.pm_parent->power.power_state.event) { +if (dev->parent && dev->parent->power.power_state.event) {dev_err (dev,"PM: suspend %d->%d, parent %s already %d\n" , dev->power.power_state.event, state.event, - dev->power.pm_parent->bus_id, - dev->power.pm_parent->power.power_state.event); + dev->parent->bus_id, + dev->parent->power.power_state.event); } dev->power.prev_state = dev->power.power_state;
include/linux/pm.h +0 -3
@@ -269,13 +269,10 @@ struct dev_pm_info { unsigned should_wakeup:1;pm_message_t prev_state;void * saved_state; -struct device * pm_parent;struct list_head entry;#endif }; -extern void device_pm_set_parent (struct device * dev,struct device * parent); -extern int device_power_down (pm_message_t state);extern void device_power_up (void );extern void device_resume (void );
Signature · 1 line
1.5.2.2
PATCH 8/61 PM: Remove saved_state from struct dev_pm_info
From: Rafael J. Wysocki <[email protected]>
The saved_state member of struct dev_pm_info, defined in include/linux/pm.h, is not used anywhere, so it can be removed.
--- include/linux/pm.h | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
include/linux/pm.h +0 -1
@@ -268,7 +268,6 @@ struct dev_pm_info {#ifdef CONFIG_PM unsigned should_wakeup:1;pm_message_t prev_state; -void * saved_state;struct list_head entry;#endif };
Signature · 1 line
1.5.2.2
PATCH 9/61 PM: Simplify suspend_device
From: Rafael J. Wysocki <[email protected]>
Reduce code duplication in drivers/base/suspend.c by introducing a separate function for printing diagnostic messages.
--- drivers/base/power/suspend.c | 49 +++++++++++++++-------------------------- 1 files changed, 18 insertions(+), 31 deletions(-)
drivers/base/power/suspend.c +18 -31
@@ -40,6 +40,14 @@ static inline char *suspend_verb(u32 event) } +static void +suspend_device_dbg (struct device *dev,pm_message_t state,char *info) +{ +dev_dbg (dev,"%s%s%s\n" , info,suspend_verb (state.event), + ((state.event ==PM_EVENT_SUSPEND ) &&device_may_wakeup (dev)) ? +", may wakeup" :"" ); +} +/** * suspend_device - Save state of one device. * @dev: Device.
@@ -66,37 +74,21 @@ int suspend_device(struct device * dev, pm_message_t state) dev->power.prev_state = dev->power.power_state;if (dev->class && dev->class->suspend && !dev->power.power_state.event) { -dev_dbg (dev,"class %s%s\n" , -suspend_verb (state.event), - ((state.event ==PM_EVENT_SUSPEND ) - &&device_may_wakeup (dev)) - ?", may wakeup" - :"" - ); +suspend_device_dbg (dev, state,"class " ); error = dev->class->suspend (dev, state);suspend_report_result (dev->class->suspend, error); } -if (!error && dev->type && dev->type->suspend && !dev->power.power_state.event) { -dev_dbg (dev,"%s%s\n" , -suspend_verb (state.event), - ((state.event ==PM_EVENT_SUSPEND ) - &&device_may_wakeup (dev)) - ?", may wakeup" - :"" - ); +if (!error && dev->type && dev->type->suspend + && !dev->power.power_state.event) { +suspend_device_dbg (dev, state,"type " ); error = dev->type->suspend (dev, state);suspend_report_result (dev->type->suspend, error); } -if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) { -dev_dbg (dev,"%s%s\n" , -suspend_verb (state.event), - ((state.event ==PM_EVENT_SUSPEND ) - &&device_may_wakeup (dev)) - ?", may wakeup" - :"" - ); +if (!error && dev->bus && dev->bus->suspend + && !dev->power.power_state.event) { +suspend_device_dbg (dev, state,"" ); error = dev->bus->suspend (dev, state);suspend_report_result (dev->bus->suspend, error); }
@@ -114,14 +106,9 @@ static int suspend_device_late(struct device *dev, pm_message_t state) {int error =0 ; -if (dev->bus && dev->bus->suspend_late && !dev->power.power_state.event) { -dev_dbg (dev,"LATE %s%s\n" , -suspend_verb (state.event), - ((state.event ==PM_EVENT_SUSPEND ) - &&device_may_wakeup (dev)) - ?", may wakeup" - :"" - ); +if (dev->bus && dev->bus->suspend_late + && !dev->power.power_state.event) { +suspend_device_dbg (dev, state,"LATE " ); error = dev->bus->suspend_late (dev, state);suspend_report_result (dev->bus->suspend_late, error); }
Signature · 1 line
1.5.2.2
PATCH 10/61 Driver core: include linux/mutex.h from attribute_container.c
From: Michael S. Tsirkin <[email protected]>
attribute_container.c uses DEFINE_MUTEX, so while linux/mutex.h seems to be pulled in indirectly by one of the headers it includes, the right thing is to include linux/mutex.h directly.
--- drivers/base/attribute_container.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/base/attribute_container.c +1 -0
@@ -18,6 +18,7 @@#include <linux/slab.h> #include <linux/list.h> #include <linux/module.h> +#include <linux/mutex.h> #include "base.h"
Signature · 1 line
1.5.2.2
PATCH 11/61 driver core: properly get driver in device_release_driver
From: Stefan Richter <[email protected]>
--- drivers/base/dd.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-)
drivers/base/dd.c +1 -2
@@ -296,9 +296,8 @@ static void __device_release_driver(struct device * dev) {struct device_driver * drv; - drv = dev->driver; + drv =get_driver (dev->driver);if (drv) { -get_driver (drv);driver_sysfs_remove (dev);sysfs_remove_link (&dev->kobj,"driver" );klist_remove (&dev->knode_driver);
Signature · 1 line
1.5.2.2
PATCH 12/61 driver core: fix kernel doc of device_release_driver
From: Stefan Richter <[email protected]>
--- drivers/base/dd.c | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-)
drivers/base/dd.c +9 -9
@@ -281,17 +281,10 @@ int driver_attach(struct device_driver * drv)return bus_for_each_dev (drv->bus,NULL , drv, __driver_attach); } -/** -* device_release_driver - manually detach device from driver. -* @dev: device. -* -* Manually detach device from driver. -* +/* * __device_release_driver() must be called with @dev->sem held. -* When called for a USB interface, @dev->parent->sem must be held -* as well. +* When called for a USB interface, @dev->parent->sem must be held as well. */ -static void __device_release_driver (struct device * dev) {struct device_driver * drv;
@@ -317,6 +310,13 @@ static void __device_release_driver(struct device * dev) } } +/** +* device_release_driver - manually detach device from driver. +* @dev: device. +* +* Manually detach device from driver. +* When called for a USB interface, @dev->parent->sem must be held. +*/ void device_release_driver (struct device * dev) {/*
Signature · 1 line
1.5.2.2
PATCH 13/61 Driver core: fix devres_release_all() return value
From: Adrian Bunk <[email protected]>
Every file should include the headers containing the prototypes for it's global functions.
Since the GNU C compiler is now able to detect that the function prototype of devres_release_all() in the header and the actual function disagree regarding the return value, this patch also fixes this bug.
--- drivers/base/base.h | 2 +- drivers/base/devres.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-)
drivers/base/base.h +1 -1
@@ -44,6 +44,6 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)extern char *make_class_name (const char *name,struct kobject *kobj); -extern void devres_release_all (struct device *dev); +extern int devres_release_all (struct device *dev);extern struct kset devices_subsys;
drivers/base/devres.c +2 -0
@@ -10,6 +10,8 @@#include <linux/device.h> #include <linux/module.h> +#include "base.h" +struct devres_node {struct list_head entry;dr_release_t release;
Signature · 1 line
1.5.2.2
PATCH 14/61 PM: Remove prev_state from struct dev_pm_info
From: Rafael J. Wysocki <[email protected]>
The prev_state member of struct dev_pm_info (defined in include/linux/pm.h) is only used during a resume to check if the device's state before the suspend was 'off', in which case the device is not resumed. However, in such cases the decision whether or not to resume the device should be made on the driver level and the resume callbacks from the device's bus and class should be executed anyway (the may be needed for some things other than just powering on the device).
--- drivers/base/power/resume.c | 3 +-- drivers/base/power/suspend.c | 2 -- drivers/usb/core/hub.c | 5 ----- include/linux/pm.h | 1 - 4 files changed, 1 insertions(+), 10 deletions(-)
drivers/base/power/resume.c +1 -2
@@ -88,8 +88,7 @@ void dpm_resume(void)list_move_tail (entry, &dpm_active);mutex_unlock (&dpm_list_mtx); -if (!dev->power.prev_state.event) -resume_device (dev); +resume_device (dev);mutex_lock (&dpm_list_mtx);put_device (dev); }
drivers/base/power/suspend.c +0 -2
@@ -71,8 +71,6 @@ int suspend_device(struct device * dev, pm_message_t state) dev->parent->power.power_state.event); } - dev->power.prev_state = dev->power.power_state; -if (dev->class && dev->class->suspend && !dev->power.power_state.event) {suspend_device_dbg (dev, state,"class " ); error = dev->class->suspend (dev, state);
drivers/usb/core/hub.c +0 -5
@@ -1109,11 +1109,6 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)dev_warn (&rhdev->dev,"root hub lost power or was reset\n" ); -/* Make sure no potential wakeup events get lost, -* by forcing the root hub to be resumed. -*/ - rhdev->dev.power.prev_state.event =PM_EVENT_ON ; -spin_lock_irqsave (&device_state_lock, flags); hub =hdev_to_hub (rhdev);for (port1 =1 ; port1 <= rhdev->maxchild; ++port1) {
include/linux/pm.h +0 -1
@@ -267,7 +267,6 @@ struct dev_pm_info { unsigned can_wakeup:1;#ifdef CONFIG_PM unsigned should_wakeup:1; -pm_message_t prev_state;struct list_head entry;#endif };
Signature · 1 line
1.5.2.2
PATCH 15/61 PM: Remove power_state.event checks from suspend core code
From: Rafael J. Wysocki <[email protected]>
The suspend routines should be called for every device during a system sleep transition, regardless of the device's state, so that drivers can regard these method calls as notifications that the system is about to go to sleep, rather than as directives to put their devices into the 'off' state.
This is documented in Documentation/power/devices.txt and is already done in the core resume code, so it seems reasonable to make the core suspend code behave accordingly.
--- drivers/base/power/suspend.c | 11 ++++------- 1 files changed, 4 insertions(+), 7 deletions(-)
drivers/base/power/suspend.c +4 -7
@@ -71,21 +71,19 @@ int suspend_device(struct device * dev, pm_message_t state) dev->parent->power.power_state.event); } -if (dev->class && dev->class->suspend && !dev->power.power_state.event) { +if (dev->class && dev->class->suspend) {suspend_device_dbg (dev, state,"class " ); error = dev->class->suspend (dev, state);suspend_report_result (dev->class->suspend, error); } -if (!error && dev->type && dev->type->suspend - && !dev->power.power_state.event) { +if (!error && dev->type && dev->type->suspend) {suspend_device_dbg (dev, state,"type " ); error = dev->type->suspend (dev, state);suspend_report_result (dev->type->suspend, error); } -if (!error && dev->bus && dev->bus->suspend - && !dev->power.power_state.event) { +if (!error && dev->bus && dev->bus->suspend) {suspend_device_dbg (dev, state,"" ); error = dev->bus->suspend (dev, state);suspend_report_result (dev->bus->suspend, error);
@@ -104,8 +102,7 @@ static int suspend_device_late(struct device *dev, pm_message_t state) {int error =0 ; -if (dev->bus && dev->bus->suspend_late - && !dev->power.power_state.event) { +if (dev->bus && dev->bus->suspend_late) {suspend_device_dbg (dev, state,"LATE " ); error = dev->bus->suspend_late (dev, state);suspend_report_result (dev->bus->suspend_late, error);
Signature · 1 line
1.5.2.2
PATCH 16/61 PM: Do not check parent state in suspend and resume core code
From: Rafael J. Wysocki <[email protected]>
The checks if the device's parent is in the right state done in drivers/base/power/suspend.c and drivers/base/power/resume.c serve no particular purpose, since if the parent is in a wrong power state, the device's suspend or resume callbacks are supposed to return an error anyway. Moreover, they are also useless from the sanity checking point of view, because they rely on the code being checked to set dev->parent->power.power_state.event appropriately, which need not happen if that code is buggy. For these reasons they can be removed.
--- drivers/base/power/resume.c | 7 ------- drivers/base/power/suspend.c | 7 ------- 2 files changed, 0 insertions(+), 14 deletions(-)
drivers/base/power/resume.c +0 -7
@@ -29,13 +29,6 @@ int resume_device(struct device * dev)down (&dev->sem); -if (dev->parent && dev->parent->power.power_state.event) { -dev_err (dev,"PM: resume from %d, parent %s still %d\n" , - dev->power.power_state.event, - dev->parent->bus_id, - dev->parent->power.power_state.event); - } -if (dev->bus && dev->bus->resume) {dev_dbg (dev,"resuming\n" ); error = dev->bus->resume (dev);
drivers/base/power/suspend.c +0 -7
@@ -63,13 +63,6 @@ int suspend_device(struct device * dev, pm_message_t state)dev_dbg (dev,"PM: suspend %d-->%d\n" , dev->power.power_state.event, state.event); } -if (dev->parent && dev->parent->power.power_state.event) { -dev_err (dev, -"PM: suspend %d->%d, parent %s already %d\n" , - dev->power.power_state.event, state.event, - dev->parent->bus_id, - dev->parent->power.power_state.event); - }if (dev->class && dev->class->suspend) {suspend_device_dbg (dev, state,"class " );
Signature · 1 line
1.5.2.2
PATCH 17/61 PM: do not use saved_state from struct dev_pm_info on ARM
From: Rafael J. Wysocki <[email protected]>
The saved_state member of 'struct dev_pm_info' that's going to be removed is used in arch/arm/common/locomo.c, arch/arm/common/sa1111.c and arch/arm/mach-sa1100/neponset.c. Change the code in there to use local variables for saving the state of devices during suspend.
--- arch/arm/common/locomo.c | 11 ++++++++--- arch/arm/common/sa1111.c | 13 ++++++++----- arch/arm/mach-sa1100/neponset.c | 15 ++++----------- 3 files changed, 20 insertions(+), 19 deletions(-)
arch/arm/common/locomo.c +8 -3
@@ -60,6 +60,9 @@ struct locomo {unsigned int irq;spinlock_t lock;void __iomem *base; +#ifdef CONFIG_PM +void *saved_state; +#endif };struct locomo_dev_info {
@@ -565,7 +568,7 @@ static int locomo_suspend(struct platform_device *dev, pm_message_t state)if (!save)return -ENOMEM ; - dev->dev.power.saved_state = (void *) save; + lchip->saved_state = save;spin_lock_irqsave (&lchip->lock, flags);
@@ -605,8 +608,8 @@ static int locomo_resume(struct platform_device *dev)struct locomo_save_data *save;unsigned long r;unsigned long flags; - - save = (struct locomo_save_data *) dev->dev.power.saved_state; + + save = lchip->saved_state;if (!save)return 0 ;
@@ -628,6 +631,8 @@ static int locomo_resume(struct platform_device *dev)locomo_writel (0x1 , lchip->base +LOCOMO_KEYBOARD +LOCOMO_KCMD );spin_unlock_irqrestore (&lchip->lock, flags); + + lchip->saved_state =NULL ;kfree (save);return 0 ;
arch/arm/common/sa1111.c +8 -5
@@ -51,6 +51,9 @@ struct sa1111 {int irq;spinlock_t lock;void __iomem *base; +#ifdef CONFIG_PM +void *saved_state; +#endif };/*
@@ -822,7 +825,7 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state) save =kmalloc (sizeof (struct sa1111_save_data ),GFP_KERNEL );if (!save)return -ENOMEM ; - dev->dev.power.saved_state = save; + sachip->saved_state = save;spin_lock_irqsave (&sachip->lock, flags);
@@ -878,7 +881,7 @@ static int sa1111_resume(struct platform_device *dev)unsigned long flags, id;void __iomem *base; - save = (struct sa1111_save_data *)dev->dev.power.saved_state; + save = sachip->saved_state;if (!save)return 0 ;
@@ -923,7 +926,7 @@ static int sa1111_resume(struct platform_device *dev)spin_unlock_irqrestore (&sachip->lock, flags); - dev->dev.power.saved_state =NULL ; + sachip->saved_state =NULL ;kfree (save);return 0 ;
@@ -958,8 +961,8 @@ static int sa1111_remove(struct platform_device *pdev)platform_set_drvdata (pdev,NULL );#ifdef CONFIG_PM -kfree (pdev->dev.power.saved_state); - pdev->dev.power.saved_state =NULL ; +kfree (sachip->saved_state); + sachip->saved_state =NULL ;#endif }
arch/arm/mach-sa1100/neponset.c +4 -11
@@ -185,28 +185,21 @@ static int __devinit neponset_probe(struct platform_device *dev)/* * LDM power management. */ +static unsigned int neponset_saved_state; +static int neponset_suspend (struct platform_device *dev,pm_message_t state) {/* * Save state. */ -if (!dev->dev.power.saved_state) - dev->dev.power.saved_state =kmalloc (sizeof (unsigned int ),GFP_KERNEL ); -if (!dev->dev.power.saved_state) -return -ENOMEM ; - - *(unsigned int *)dev->dev.power.saved_state =NCR_0 ; + neponset_saved_state =NCR_0 ;return 0 ; }static int neponset_resume (struct platform_device *dev) { -if (dev->dev.power.saved_state) { -NCR_0 = *(unsigned int *)dev->dev.power.saved_state; -kfree (dev->dev.power.saved_state); - dev->dev.power.saved_state =NULL ; - } +NCR_0 = neponset_saved_state;return 0 ; }
Signature · 1 line
1.5.2.2
PATCH 18/61 Driver core: coding style cleanup
From: Cornelia Huck <[email protected]>
This converts code of the form
if ((error = some_func())) goto fixup; to error = some_func(); if (error) goto fixup;
--- drivers/base/bus.c | 6 ++++-- drivers/base/core.c | 9 ++++++--- 2 files changed, 10 insertions(+), 5 deletions(-)
drivers/base/bus.c +4 -2
@@ -622,7 +622,8 @@ int bus_add_driver(struct device_driver *drv)if (error) goto out_put_bus; drv->kobj.kset = &bus->drivers; -if ((error =kobject_register (&drv->kobj))) + error =kobject_register (&drv->kobj); +if (error) goto out_put_bus;if (drv->bus->drivers_autoprobe) {
@@ -772,7 +773,8 @@ static int bus_add_attrs(struct bus_type * bus)if (bus->bus_attrs) {for (i =0 ;attr_name (bus->bus_attrs[i]); i++) { -if ((error =bus_create_file (bus,&bus->bus_attrs[i]))) + error =bus_create_file (bus,&bus->bus_attrs[i]); +if (error) goto Err; } }
drivers/base/core.c +6 -3
@@ -733,11 +733,14 @@ int device_add(struct device *dev) } } -if ((error =device_add_attrs (dev))) + error =device_add_attrs (dev); +if (error) goto AttrsError; -if ((error =device_pm_add (dev))) + error =device_pm_add (dev); +if (error) goto PMError; -if ((error =bus_add_device (dev))) + error =bus_add_device (dev); +if (error) goto BusError;kobject_uevent (&dev->kobj,KOBJ_ADD );bus_attach_device (dev);
Signature · 1 line
1.5.2.2
PATCH 19/61 idr: fix obscure bug in allocation path
From: Tejun Heo <[email protected]>
In sub_alloc(), when bitmap search fails, it goes up one level to continue search. This is done by updating the id cursor and searching the upper level again. If the cursor was at the end of the upper level, we need to go further than that.
This wasn't implemented and when that happens the part of the cursor which indexes into the upper level wraps and sub_alloc() ends up searching the wrong bitmap. It allocates id which doesn't match the actual slot.
This patch fixes this by restarting from the top if the search needs to go higher than one level.
--- lib/idr.c | 16 ++++++++++++++-- 1 files changed, 14 insertions(+), 2 deletions(-)
lib/idr.c +14 -2
@@ -100,10 +100,11 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)int n, m, sh;struct idr_layer *p, *new;struct idr_layer *pa[MAX_LEVEL ]; -int l, id; +int l, id, oid;long bm; id = *starting_id; + restart: p = idp->top; l = idp->layers; pa[l--] =NULL ;
@@ -117,12 +118,23 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)if (m ==IDR_SIZE ) {/* no space available go back to previous layer. */ l++; + oid = id; id = (id | ((1 << (IDR_BITS * l)) -1 )) +1 ; + +/* if already at the top layer, we need to grow */ if (!(p = pa[l])) { *starting_id = id;return -2 ; } -continue ; + +/* If we need to go up one layer, continue the +* loop; otherwise, restart from the top. +*/ + sh =IDR_BITS * (l +1 ); +if (oid >> sh == id >> sh) +continue ; +else + goto restart; }if (m != n) { sh =IDR_BITS *l;
Signature · 1 line
1.5.2.2
PATCH 20/61 idr: separate out idr_mark_full()
From: Tejun Heo <[email protected]>
Separate out idr_mark_full() from sub_alloc() and make marking the allocated slot full the responsibility of idr_get_new_above_int().
Allocation part of idr_get_new_above_int() is renamed to idr_get_empty_slot(). New idr_get_new_above_int() allocates a slot using the function, install the user pointer and marks it full using idr_mark_full().
This change doesn't introduce any behavior change. This will be used by ida.
--- lib/idr.c | 71 +++++++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 46 insertions(+), 25 deletions(-)
lib/idr.c +46 -25
@@ -70,6 +70,26 @@ static void free_layer(struct idr *idp, struct idr_layer *p)spin_unlock_irqrestore (&idp->lock, flags); } +static void idr_mark_full (struct idr_layer **pa,int id) +{ +struct idr_layer *p = pa[0 ]; +int l =0 ; + +__set_bit (id &IDR_MASK , &p->bitmap); +/* +* If this layer is full mark the bit in the layer above to +* show that this part of the radix tree is full. This may +* complete the layer above and require walking up the radix +* tree. +*/ +while (p->bitmap ==IDR_FULL ) { +if (!(p = pa[++l])) +break ; + id = id >>IDR_BITS ; +__set_bit ((id &IDR_MASK ), &p->bitmap); + } +} +/** * idr_pre_get - reserver resources for idr allocation * @idp: idr handle
@@ -95,11 +115,10 @@ int idr_pre_get(struct idr *idp, gfp_t gfp_mask) }EXPORT_SYMBOL (idr_pre_get); -static int sub_alloc (struct idr *idp,void *ptr,int *starting_id) +static int sub_alloc (struct idr *idp,int *starting_id,struct idr_layer **pa) {int n, m, sh;struct idr_layer *p, *new; -struct idr_layer *pa[MAX_LEVEL ];int l, id, oid;long bm;
@@ -156,30 +175,13 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id) pa[l--] = p; p = p->ary[m]; } -/* -* We have reached the leaf node, plant the -* users pointer and return the raw id. -*/ - p->ary[m] = (struct idr_layer *)ptr; -__set_bit (m, &p->bitmap); - p->count++; -/* -* If this layer is full mark the bit in the layer above -* to show that this part of the radix tree is full. -* This may complete the layer above and require walking -* up the radix tree. -*/ - n = id; -while (p->bitmap ==IDR_FULL ) { -if (!(p = pa[++l])) -break ; - n = n >>IDR_BITS ; -__set_bit ((n &IDR_MASK ), &p->bitmap); - } -return (id); + + pa[l] = p; +return id; } -static int idr_get_new_above_int (struct idr *idp,void *ptr,int starting_id) +static int idr_get_empty_slot (struct idr *idp,int starting_id, +struct idr_layer **pa) {struct idr_layer *p, *new;int layers, v, id;
@@ -225,12 +227,31 @@ build_up: } idp->top = p; idp->layers = layers; - v =sub_alloc (idp, ptr, &id); + v =sub_alloc (idp, &id, pa);if (v ==-2 ) goto build_up;return (v); } +static int idr_get_new_above_int (struct idr *idp,void *ptr,int starting_id) +{ +struct idr_layer *pa[MAX_LEVEL ]; +int id; + + id =idr_get_empty_slot (idp, starting_id, pa); +if (id >=0 ) { +/* +* Successfully found an empty slot. Install the user +* pointer and mark the slot full. +*/ + pa[0 ]->ary[id &IDR_MASK ] = (struct idr_layer *)ptr; + pa[0 ]->count++; +idr_mark_full (pa, id); + } + +return id; +} +/** * idr_get_new_above - allocate new idr entry above or equal to a start id * @idp: idr handle
Signature · 1 line
1.5.2.2
PATCH 21/61 ida: implement idr based id allocator
From: Tejun Heo <[email protected]>
Implement idr based id allocator. ida is used the same way idr is used but lacks id -> ptr translation and thus consumes much less memory. struct ida_bitmap is attached as leaf nodes to idr tree which is managed by the idr code. Each ida_bitmap is 128bytes long and contains slightly less than a thousand slots.
ida is more aggressive with releasing extra resources acquired using ida_pre_get(). After every successful id allocation, ida frees one reserved idr_layer if possible. Reserved ida_bitmap is not freed automatically but only one ida_bitmap is reserved and it's almost always used right away. Under most circumstances, ida won't hold on to memory for too long which isn't actively used.
--- include/linux/idr.h | 29 ++++++ lib/idr.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+), 0 deletions(-)
include/linux/idr.h +29 -0
@@ -83,4 +83,33 @@ void idr_remove(struct idr *idp, int id);void idr_destroy (struct idr *idp);void idr_init (struct idr *idp); + +/* +* IDA - IDR based id allocator, use when translation from id to +* pointer isn't necessary. +*/ +#define IDA_CHUNK_SIZE 128/* 128 bytes per chunk */ +#define IDA_BITMAP_LONGS (128 / sizeof(long) - 1) +#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8) + +struct ida_bitmap { +long nr_busy; +unsigned long bitmap[IDA_BITMAP_LONGS ]; +}; + +struct ida { +struct idr idr; +struct ida_bitmap *free_bitmap; +}; + +#define IDA_INIT (name) { .idr = IDR_INIT(name), .free_bitmap = NULL, } +#define DEFINE_IDA (name) struct ida name = IDA_INIT(name) + +int ida_pre_get (struct ida *ida,gfp_t gfp_mask); +int ida_get_new_above (struct ida *ida,int starting_id,int *p_id); +int ida_get_new (struct ida *ida,int *p_id); +void ida_remove (struct ida *ida,int id); +void ida_destroy (struct ida *ida); +void ida_init (struct ida *ida); +#endif /* __IDR_H__ */
lib/idr.c +245 -0
248 lines not on this page · raw message
Signature · 1 line
1.5.2.2
PATCH 22/61 sysfs: move release_sysfs_dirent() to dir.c
From: Tejun Heo <[email protected]>
There is no reason this function should be inlined and soon to follow sysfs object reference simplification will make it heavier. Move it to dir.c.
--- fs/sysfs/dir.c | 12 ++++++++++++ fs/sysfs/sysfs.h | 13 +------------ 2 files changed, 13 insertions(+), 12 deletions(-)
fs/sysfs/dir.c +12 -0
@@ -15,6 +15,18 @@DECLARE_RWSEM (sysfs_rename_sem);spinlock_t sysfs_lock =SPIN_LOCK_UNLOCKED ; +void release_sysfs_dirent (struct sysfs_dirent * sd) +{ +if (sd->s_type &SYSFS_KOBJ_LINK ) { +struct sysfs_symlink * sl = sd->s_element; +kfree (sl->link_name); +kobject_put (sl->target_kobj); +kfree (sl); + } +kfree (sd->s_iattr); +kmem_cache_free (sysfs_dir_cachep, sd); +} +static void sysfs_d_iput (struct dentry * dentry,struct inode * inode) {struct sysfs_dirent * sd = dentry->d_fsdata;
fs/sysfs/sysfs.h +1 -12
@@ -18,6 +18,7 @@ extern void sysfs_delete_inode(struct inode *inode);extern struct inode *sysfs_new_inode (mode_t mode,struct sysfs_dirent *);extern int sysfs_create (struct dentry *,int mode,int (*init)(struct inode *)); +extern void release_sysfs_dirent (struct sysfs_dirent * sd);extern int sysfs_dirent_exist (struct sysfs_dirent *,const unsigned char *);extern int sysfs_make_dirent (struct sysfs_dirent *,struct dentry *,void *,umode_t ,int );
@@ -99,18 +100,6 @@ static inline struct kobject *sysfs_get_kobject(struct dentry *dentry)return kobj; } -static inline void release_sysfs_dirent (struct sysfs_dirent * sd) -{ -if (sd->s_type &SYSFS_KOBJ_LINK ) { -struct sysfs_symlink * sl = sd->s_element; -kfree (sl->link_name); -kobject_put (sl->target_kobj); -kfree (sl); - } -kfree (sd->s_iattr); -kmem_cache_free (sysfs_dir_cachep, sd); -} -static inline struct sysfs_dirent *sysfs_get (struct sysfs_dirent * sd) {if (sd) {
Signature · 1 line
1.5.2.2
PATCH 23/61 sysfs: allocate inode number using ida
From: Tejun Heo <[email protected]>
sysfs used simple incrementing allocator which is not guaranteed to be unique. This patch makes sysfs use ida to give each sd a unique and packed inode number.
--- fs/sysfs/dir.c | 45 ++++++++++++++++++++++++++++++++++++--------- 1 files changed, 36 insertions(+), 9 deletions(-)
fs/sysfs/dir.c +36 -9
@@ -9,12 +9,42 @@#include <linux/module.h> #include <linux/kobject.h> #include <linux/namei.h> +#include <linux/idr.h> #include <asm/semaphore.h> #include "sysfs.h" DECLARE_RWSEM (sysfs_rename_sem);spinlock_t sysfs_lock =SPIN_LOCK_UNLOCKED ; +static spinlock_t sysfs_ino_lock =SPIN_LOCK_UNLOCKED ; +static DEFINE_IDA (sysfs_ino_ida); + +int sysfs_alloc_ino (ino_t *pino) +{ +int ino, rc; + + retry: +spin_lock (&sysfs_ino_lock); + rc =ida_get_new_above (&sysfs_ino_ida,2 , &ino); +spin_unlock (&sysfs_ino_lock); + +if (rc == -EAGAIN ) { +if (ida_pre_get (&sysfs_ino_ida,GFP_KERNEL )) + goto retry; + rc = -ENOMEM ; + } + + *pino = ino; +return rc; +} + +static void sysfs_free_ino (ino_t ino) +{ +spin_lock (&sysfs_ino_lock); +ida_remove (&sysfs_ino_ida, ino); +spin_unlock (&sysfs_ino_lock); +} +void release_sysfs_dirent (struct sysfs_dirent * sd) {if (sd->s_type &SYSFS_KOBJ_LINK ) {
@@ -24,6 +54,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)kfree (sl); }kfree (sd->s_iattr); +sysfs_free_ino (sd->s_ino);kmem_cache_free (sysfs_dir_cachep, sd); }
@@ -54,14 +85,6 @@ static struct dentry_operations sysfs_dentry_ops = { .d_iput = sysfs_d_iput, }; -static unsigned int sysfs_inode_counter; -ino_t sysfs_get_inum (void ) -{ -if (unlikely (sysfs_inode_counter <3 )) - sysfs_inode_counter =3 ; -return sysfs_inode_counter++; -} -/* * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent */
@@ -73,7 +96,11 @@ static struct sysfs_dirent * __sysfs_new_dirent(void * element)if (!sd)return NULL ; - sd->s_ino =sysfs_get_inum (); +if (sysfs_alloc_ino (&sd->s_ino)) { +kmem_cache_free (sysfs_dir_cachep, sd); +return NULL ; + } +atomic_set (&sd->s_count,1 );atomic_set (&sd->s_event,1 );INIT_LIST_HEAD (&sd->s_children);
Signature · 1 line
1.5.2.2
PATCH 24/61 sysfs: make sysfs_put() ignore NULL sd
From: Tejun Heo <[email protected]>
Make sysfs_put() ignore NULL sd instead of oopsing.
--- fs/sysfs/sysfs.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
fs/sysfs/sysfs.h +1 -1
@@ -111,7 +111,7 @@ static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)static inline void sysfs_put (struct sysfs_dirent * sd) { -if (atomic_dec_and_test (&sd->s_count)) +if (sd &&atomic_dec_and_test (&sd->s_count))release_sysfs_dirent (sd); }
Signature · 1 line
1.5.2.2
PATCH 25/61 sysfs: fix error handling in binattr write()
From: Tejun Heo <[email protected]>
Error handling in fs/sysfs/bin.c:write() was wrong because size_t count is used to receive return value from flush_write() which is negative on failure.
This patch updates write() such that int variable is used instead. read() is updated the same way for consistency.
--- fs/sysfs/bin.c | 23 +++++++++-------------- 1 files changed, 9 insertions(+), 14 deletions(-)
fs/sysfs/bin.c +9 -14
@@ -33,16 +33,13 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) }static ssize_t -read (struct file * file,char __user * userbuf,size_t count,loff_t * off) +read (struct file *file,char __user *userbuf,size_t bytes,loff_t *off) {char *buffer = file->private_data;struct dentry *dentry = file->f_path.dentry;int size = dentry->d_inode->i_size;loff_t offs = *off; -int ret; - -if (count >PAGE_SIZE ) - count =PAGE_SIZE ; +int count =min_t (size_t, bytes,PAGE_SIZE );if (size) {if (offs > size)
@@ -51,15 +48,14 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off) count = size - offs; } - ret =fill_read (dentry, buffer, offs, count); -if (ret <0 ) -return ret; - count = ret; + count =fill_read (dentry, buffer, offs, count); +if (count <0 ) +return count;if (copy_to_user (userbuf, buffer, count))return -EFAULT ; -pr_debug ("offs = %lld, *off = %lld, count = %zd\n" , offs, *off, count); +pr_debug ("offs = %lld, *off = %lld, count = %d\n" , offs, *off, count); *off = offs + count;
@@ -78,16 +74,15 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)return attr->write (kobj, buffer, offset, count); } -static ssize_t write (struct file * file,const char __user * userbuf, -size_t count,loff_t * off) +static ssize_t write (struct file *file,const char __user *userbuf, +size_t bytes,loff_t *off) {char *buffer = file->private_data;struct dentry *dentry = file->f_path.dentry;int size = dentry->d_inode->i_size;loff_t offs = *off; +int count =min_t (size_t, bytes,PAGE_SIZE ); -if (count >PAGE_SIZE ) - count =PAGE_SIZE ;if (size) {if (offs > size)return 0 ;
Signature · 1 line
1.5.2.2
PATCH 26/61 sysfs: flatten cleanup paths in sysfs_add_link() and create_dir()
From: Tejun Heo <[email protected]>
Flatten cleanup paths in sysfs_add_link() and create_dir() to improve readability and ease further changes to these functions. This is in preparation of object reference simplification.
--- fs/sysfs/dir.c | 73 ++++++++++++++++++++++++++++++--------------------- fs/sysfs/symlink.c | 27 ++++++++++-------- 2 files changed, 58 insertions(+), 42 deletions(-)
fs/sysfs/dir.c +43 -30
@@ -207,40 +207,53 @@ static int init_symlink(struct inode * inode)return 0 ; } -static int create_dir (struct kobject * k,struct dentry * p, -const char * n,struct dentry ** d) +static int create_dir (struct kobject *kobj,struct dentry *parent, +const char *name,struct dentry **p_dentry) {int error;umode_t mode =S_IFDIR |S_IRWXU |S_IRUGO |S_IXUGO ; +struct dentry *dentry; +struct sysfs_dirent *sd; -mutex_lock (&p->d_inode->i_mutex); - *d =lookup_one_len (n, p,strlen (n)); -if (!IS_ERR (*d)) { -if (sysfs_dirent_exist (p->d_fsdata, n)) - error = -EEXIST ; -else - error =sysfs_make_dirent (p->d_fsdata, *d, k, mode, -SYSFS_DIR ); -if (!error) { - error =sysfs_create (*d, mode, init_dir); -if (!error) { -inc_nlink (p->d_inode); - (*d)->d_op = &sysfs_dentry_ops; -d_rehash (*d); - } - } -if (error && (error != -EEXIST )) { -struct sysfs_dirent *sd = (*d)->d_fsdata; -if (sd) { -list_del_init (&sd->s_sibling); -sysfs_put (sd); - } -d_drop (*d); - } -dput (*d); - }else - error =PTR_ERR (*d); -mutex_unlock (&p->d_inode->i_mutex); +mutex_lock (&parent->d_inode->i_mutex); + + dentry =lookup_one_len (name, parent,strlen (name)); +if (IS_ERR (dentry)) { + error =PTR_ERR (dentry); + goto out_unlock; + } + + error = -EEXIST ; +if (sysfs_dirent_exist (parent->d_fsdata, name)) + goto out_dput; + + error =sysfs_make_dirent (parent->d_fsdata, dentry, kobj, mode, +SYSFS_DIR ); +if (error) + goto out_drop; + + error =sysfs_create (dentry, mode, init_dir); +if (error) + goto out_sput; + +inc_nlink (parent->d_inode); + dentry->d_op = &sysfs_dentry_ops; +d_rehash (dentry); + + *p_dentry = dentry; + error =0 ; + goto out_dput; + + out_sput: + sd = dentry->d_fsdata; +list_del_init (&sd->s_sibling); +sysfs_put (sd); + out_drop: +d_drop (dentry); + out_dput: +dput (dentry); + out_unlock: +mutex_unlock (&parent->d_inode->i_mutex);return error; }
fs/sysfs/symlink.c +15 -12
@@ -49,30 +49,33 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj {struct sysfs_dirent * parent_sd = parent->d_fsdata;struct sysfs_symlink * sl; -int error =0 ; +int error; error = -ENOMEM ; - sl =kmalloc (sizeof (*sl),GFP_KERNEL ); + sl =kzalloc (sizeof (*sl),GFP_KERNEL );if (!sl) - goto exit1; + goto err_out; sl->link_name =kmalloc (strlen (name) +1 ,GFP_KERNEL );if (!sl->link_name) - goto exit2; + goto err_out;strcpy (sl->link_name, name); sl->target_kobj =kobject_get (target); error =sysfs_make_dirent (parent_sd,NULL , sl,S_IFLNK |S_IRWXUGO ,SYSFS_KOBJ_LINK ); -if (!error) -return 0 ; - -kobject_put (target); -kfree (sl->link_name); -exit2: -kfree (sl); -exit1: +if (error) + goto err_out; + +return 0 ; + + err_out: +if (sl) { +kobject_put (sl->target_kobj); +kfree (sl->link_name); +kfree (sl); + }return error; }
Signature · 1 line
1.5.2.2
PATCH 27/61 sysfs: flatten and fix sysfs_rename_dir() error handling
From: Tejun Heo <[email protected]>
Error handling in sysfs_rename_dir() was broken.
* When lookup_one_len() fails, 0 is returned.
* If parent inode check fails, returns with inode mutex and rename rwsem held.
This patch fixes the above bugs and flattens error handling such that it's more readable and easier to modify.
--- fs/sysfs/dir.c | 73 +++++++++++++++++++++++++++++++------------------------ 1 files changed, 41 insertions(+), 32 deletions(-)
fs/sysfs/dir.c +41 -32
@@ -452,8 +452,9 @@ void sysfs_remove_dir(struct kobject * kobj)int sysfs_rename_dir (struct kobject * kobj,struct dentry *new_parent,const char *new_name) { -int error =0 ; +int error;struct dentry * new_dentry; +struct sysfs_dirent *sd, *parent_sd;if (!new_parent)return -EFAULT ;
@@ -462,40 +463,48 @@ int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,mutex_lock (&new_parent->d_inode->i_mutex); new_dentry =lookup_one_len (new_name, new_parent,strlen (new_name)); -if (!IS_ERR (new_dentry)) { -/* By allowing two different directories with the -* same d_parent we allow this routine to move -* between different shadows of the same directory -*/ -if (kobj->dentry->d_parent->d_inode != new_parent->d_inode) -return -EINVAL ; -else if (new_dentry->d_parent->d_inode != new_parent->d_inode) - error = -EINVAL ; -else if (new_dentry == kobj->dentry) - error = -EINVAL ; -else if (!new_dentry->d_inode) { - error =kobject_set_name (kobj,"%s" , new_name); -if (!error) { -struct sysfs_dirent *sd, *parent_sd; - -d_add (new_dentry,NULL ); -d_move (kobj->dentry, new_dentry); - - sd = kobj->dentry->d_fsdata; - parent_sd = new_parent->d_fsdata; - -list_del_init (&sd->s_sibling); -list_add (&sd->s_sibling, &parent_sd->s_children); - } -else -d_drop (new_dentry); - }else - error = -EEXIST ; -dput (new_dentry); +if (IS_ERR (new_dentry)) { + error =PTR_ERR (new_dentry); + goto out_unlock; } + +/* By allowing two different directories with the same +* d_parent we allow this routine to move between different +* shadows of the same directory +*/ + error = -EINVAL ; +if (kobj->dentry->d_parent->d_inode != new_parent->d_inode || + new_dentry->d_parent->d_inode != new_parent->d_inode || + new_dentry == kobj->dentry) + goto out_dput; + + error = -EEXIST ; +if (new_dentry->d_inode) + goto out_dput; + + error =kobject_set_name (kobj,"%s" , new_name); +if (error) + goto out_drop; + +d_add (new_dentry,NULL ); +d_move (kobj->dentry, new_dentry); + + sd = kobj->dentry->d_fsdata; + parent_sd = new_parent->d_fsdata; + +list_del_init (&sd->s_sibling); +list_add (&sd->s_sibling, &parent_sd->s_children); + + error =0 ; + goto out_unlock; + + out_drop: +d_drop (new_dentry); + out_dput: +dput (new_dentry); + out_unlock:mutex_unlock (&new_parent->d_inode->i_mutex);up_write (&sysfs_rename_sem); -return error; }
Signature · 1 line
1.5.2.2
PATCH 28/61 sysfs: consolidate sysfs_dirent creation functions
From: Tejun Heo <[email protected]>
Currently there are four functions to create sysfs_dirent - __sysfs_new_dirent(), sysfs_new_dirent(), __sysfs_make_dirent() and sysfs_make_dirent(). Other than sysfs_make_dirent(), no function has two users if calls to implement other functions are excluded.
This patch consolidates sysfs_dirent creation functions into the following two.
* sysfs_new_dirent() : allocate and initialize
* sysfs_attach_dirent() : attach to sysfs_dirent hierarchy and/or associate with dentry
This simplifies interface and gives callers more flexibility. This is in preparation of object reference simplification.
--- fs/sysfs/dir.c | 82 ++++++++++++++++------------------------------------ fs/sysfs/file.c | 21 ++++++++++--- fs/sysfs/symlink.c | 7 ++-- fs/sysfs/sysfs.h | 7 +++- 4 files changed, 50 insertions(+), 67 deletions(-)
fs/sysfs/dir.c +25 -57
@@ -85,10 +85,7 @@ static struct dentry_operations sysfs_dentry_ops = { .d_iput = sysfs_d_iput, }; -/* -* Allocates a new sysfs_dirent and links it to the parent sysfs_dirent -*/ -static struct sysfs_dirent *__sysfs_new_dirent (void * element) +struct sysfs_dirent *sysfs_new_dirent (void *element,umode_t mode,int type) {struct sysfs_dirent * sd;
@@ -105,25 +102,25 @@ static struct sysfs_dirent * __sysfs_new_dirent(void * element)atomic_set (&sd->s_event,1 );INIT_LIST_HEAD (&sd->s_children);INIT_LIST_HEAD (&sd->s_sibling); + sd->s_element = element; + sd->s_mode = mode; + sd->s_type = type;return sd; } -static void __sysfs_list_dirent (struct sysfs_dirent *parent_sd, -struct sysfs_dirent *sd) +void sysfs_attach_dirent (struct sysfs_dirent *sd, +struct sysfs_dirent *parent_sd,struct dentry *dentry) { -if (sd) -list_add (&sd->s_sibling, &parent_sd->s_children); -} +if (dentry) { + sd->s_dentry = dentry; + dentry->d_fsdata =sysfs_get (sd); + dentry->d_op = &sysfs_dentry_ops; + } -static struct sysfs_dirent *sysfs_new_dirent (struct sysfs_dirent *parent_sd, -void * element) -{ -struct sysfs_dirent *sd; - sd =__sysfs_new_dirent (element); -__sysfs_list_dirent (parent_sd, sd); -return sd; +if (parent_sd) +list_add (&sd->s_sibling, &parent_sd->s_children); }/*
@@ -151,39 +148,6 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,return 0 ; } - -static struct sysfs_dirent * -__sysfs_make_dirent (struct dentry *dentry,void *element,mode_t mode,int type) -{ -struct sysfs_dirent * sd; - - sd =__sysfs_new_dirent (element); -if (!sd) - goto out; - - sd->s_mode = mode; - sd->s_type = type; - sd->s_dentry = dentry; -if (dentry) { - dentry->d_fsdata =sysfs_get (sd); - dentry->d_op = &sysfs_dentry_ops; - } - -out: -return sd; -} - -int sysfs_make_dirent (struct sysfs_dirent * parent_sd,struct dentry * dentry, -void * element,umode_t mode,int type) -{ -struct sysfs_dirent *sd; - - sd =__sysfs_make_dirent (dentry, element, mode, type); -__sysfs_list_dirent (parent_sd, sd); - -return sd ?0 : -ENOMEM ; -} -static int init_dir (struct inode * inode) { inode->i_op = &sysfs_dir_inode_operations;
@@ -227,10 +191,11 @@ static int create_dir(struct kobject *kobj, struct dentry *parent,if (sysfs_dirent_exist (parent->d_fsdata, name)) goto out_dput; - error =sysfs_make_dirent (parent->d_fsdata, dentry, kobj, mode, -SYSFS_DIR ); -if (error) + error = -ENOMEM ; + sd =sysfs_new_dirent (kobj, mode,SYSFS_DIR ); +if (!sd) goto out_drop; +sysfs_attach_dirent (sd, parent->d_fsdata, dentry); error =sysfs_create (dentry, mode, init_dir);if (error)
@@ -245,7 +210,6 @@ static int create_dir(struct kobject *kobj, struct dentry *parent, goto out_dput; out_sput: - sd = dentry->d_fsdata;list_del_init (&sd->s_sibling);sysfs_put (sd); out_drop:
@@ -557,13 +521,16 @@ static int sysfs_dir_open(struct inode *inode, struct file *file) {struct dentry * dentry = file->f_path.dentry;struct sysfs_dirent * parent_sd = dentry->d_fsdata; +struct sysfs_dirent * sd;mutex_lock (&dentry->d_inode->i_mutex); - file->private_data =sysfs_new_dirent (parent_sd,NULL ); + sd =sysfs_new_dirent (NULL ,0 ,0 ); +if (sd) +sysfs_attach_dirent (sd, parent_sd,NULL );mutex_unlock (&dentry->d_inode->i_mutex); -return file->private_data ?0 : -ENOMEM ; - + file->private_data = sd; +return sd ?0 : -ENOMEM ; }static int sysfs_dir_close (struct inode *inode,struct file *file)
@@ -736,9 +703,10 @@ struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)if (!shadow) goto nomem; - sd =__sysfs_make_dirent (shadow, kobj, inode->i_mode,SYSFS_DIR ); + sd =sysfs_new_dirent (kobj, inode->i_mode,SYSFS_DIR );if (!sd) goto nomem; +sysfs_attach_dirent (sd,NULL , shadow);d_instantiate (shadow,igrab (inode));inc_nlink (inode);
fs/sysfs/file.c +16 -5
@@ -444,14 +444,25 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) {struct sysfs_dirent * parent_sd = dir->d_fsdata;umode_t mode = (attr->mode &S_IALLUGO ) |S_IFREG ; -int error = -EEXIST ; +struct sysfs_dirent *sd; +int error =0 ;mutex_lock (&dir->d_inode->i_mutex); -if (!sysfs_dirent_exist (parent_sd, attr->name)) - error =sysfs_make_dirent (parent_sd,NULL , (void *)attr, - mode, type); -mutex_unlock (&dir->d_inode->i_mutex); +if (sysfs_dirent_exist (parent_sd, attr->name)) { + error = -EEXIST ; + goto out_unlock; + } + + sd =sysfs_new_dirent ((void *)attr, mode, type); +if (!sd) { + error = -ENOMEM ; + goto out_unlock; + } +sysfs_attach_dirent (sd, parent_sd,NULL ); + + out_unlock: +mutex_unlock (&dir->d_inode->i_mutex);return error; }
fs/sysfs/symlink.c +4 -3
@@ -49,6 +49,7 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj {struct sysfs_dirent * parent_sd = parent->d_fsdata;struct sysfs_symlink * sl; +struct sysfs_dirent * sd;int error; error = -ENOMEM ;
@@ -63,10 +64,10 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobjstrcpy (sl->link_name, name); sl->target_kobj =kobject_get (target); - error =sysfs_make_dirent (parent_sd,NULL , sl,S_IFLNK |S_IRWXUGO , -SYSFS_KOBJ_LINK ); -if (error) + sd =sysfs_new_dirent (sl,S_IFLNK |S_IRWXUGO ,SYSFS_KOBJ_LINK ); +if (!sd) goto err_out; +sysfs_attach_dirent (sd, parent_sd,NULL );return 0 ;
fs/sysfs/sysfs.h +5 -2
@@ -20,8 +20,11 @@ extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));extern void release_sysfs_dirent (struct sysfs_dirent * sd);extern int sysfs_dirent_exist (struct sysfs_dirent *,const unsigned char *); -extern int sysfs_make_dirent (struct sysfs_dirent *,struct dentry *,void *, -umode_t ,int ); +extern struct sysfs_dirent *sysfs_new_dirent (void *element,umode_t mode, +int type); +extern void sysfs_attach_dirent (struct sysfs_dirent *sd, +struct sysfs_dirent *parent_sd, +struct dentry *dentry);extern int sysfs_add_file (struct dentry *,const struct attribute *,int );extern int sysfs_hash_and_remove (struct dentry * dir,const char * name);
Signature · 1 line
1.5.2.2
PATCH 29/61 sysfs: add sysfs_dirent->s_parent
From: Tejun Heo <[email protected]>
Add sysfs_dirent->s_parent. With this patch, each sd points to and holds a reference to its parent. This allows walking sysfs tree without referencing sd->s_dentry which can go away anytime if the user doesn't control when it's deleted.
sd->s_parent is initialized and parent is referenced in sysfs_attach_dirent(). Reference to parent is released when the sd is released, so as long as reference to a sd is held, s_parent can be followed.
dentry walk in sysfs_readdir() is convereted to s_parent walk.
This will be used to reimplement symlink such that it uses only sysfs_dirent tree.
--- fs/sysfs/dir.c | 30 +++++++++++++++++++++++------- fs/sysfs/mount.c | 1 + fs/sysfs/sysfs.h | 1 + 3 files changed, 25 insertions(+), 7 deletions(-)
fs/sysfs/dir.c +23 -7
@@ -47,6 +47,11 @@ static void sysfs_free_ino(ino_t ino)void release_sysfs_dirent (struct sysfs_dirent * sd) { +struct sysfs_dirent *parent_sd; + + repeat: + parent_sd = sd->s_parent; +if (sd->s_type &SYSFS_KOBJ_LINK ) {struct sysfs_symlink * sl = sd->s_element;kfree (sl->link_name);
@@ -56,6 +61,10 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)kfree (sd->s_iattr);sysfs_free_ino (sd->s_ino);kmem_cache_free (sysfs_dir_cachep, sd); + + sd = parent_sd; +if (sd &&atomic_dec_and_test (&sd->s_count)) + goto repeat; }static void sysfs_d_iput (struct dentry * dentry,struct inode * inode)
@@ -119,8 +128,10 @@ void sysfs_attach_dirent(struct sysfs_dirent *sd, dentry->d_op = &sysfs_dentry_ops; } -if (parent_sd) +if (parent_sd) { + sd->s_parent =sysfs_get (parent_sd);list_add (&sd->s_sibling, &parent_sd->s_children); + } }/*
@@ -571,7 +582,10 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) i++;/* fallthrough */ case 1 : - ino =parent_ino (dentry); +if (parent_sd->s_parent) + ino = parent_sd->s_parent->s_ino; +else + ino = parent_sd->s_ino;if (filldir (dirent,".." ,2 , i, ino,DT_DIR ) <0 )break ; filp->f_pos++;
@@ -688,13 +702,13 @@ int sysfs_make_shadowed_dir(struct kobject *kobj,struct dentry *sysfs_create_shadow_dir (struct kobject *kobj) { +struct dentry *dir = kobj->dentry; +struct inode *inode = dir->d_inode; +struct dentry *parent = dir->d_parent; +struct sysfs_dirent *parent_sd = parent->d_fsdata; +struct dentry *shadow;struct sysfs_dirent *sd; -struct dentry *parent, *dir, *shadow; -struct inode *inode; - dir = kobj->dentry; - inode = dir->d_inode; - parent = dir->d_parent; shadow =ERR_PTR (-EINVAL );if (!sysfs_is_shadowed_inode (inode)) goto out;
@@ -706,6 +720,8 @@ struct dentry *sysfs_create_shadow_dir(struct kobject *kobj) sd =sysfs_new_dirent (kobj, inode->i_mode,SYSFS_DIR );if (!sd) goto nomem; +/* point to parent_sd but don't attach to it */ + sd->s_parent =sysfs_get (parent_sd);sysfs_attach_dirent (sd,NULL , shadow);d_instantiate (shadow,igrab (inode));
fs/sysfs/mount.c +1 -0
@@ -28,6 +28,7 @@ static const struct super_operations sysfs_ops = { };static struct sysfs_dirent sysfs_root = { + .s_count =ATOMIC_INIT (1 ), .s_sibling =LIST_HEAD_INIT (sysfs_root.s_sibling), .s_children =LIST_HEAD_INIT (sysfs_root.s_children), .s_element =NULL ,
fs/sysfs/sysfs.h +1 -0
@@ -1,5 +1,6 @@struct sysfs_dirent {atomic_t s_count; +struct sysfs_dirent * s_parent;struct list_head s_sibling;struct list_head s_children;void * s_element;
Signature · 1 line
1.5.2.2
PATCH 30/61 sysfs: add sysfs_dirent->s_name
From: Tejun Heo <[email protected]>
Add s_name to sysfs_dirent. This is to further reduce dependency to the associated dentry. Name is copied for directories and symlinks but not for attributes.
Where possible, name dereferences are converted to use sd->s_name. sysfs_symlink->link_name and sysfs_get_name() are unused now and removed.
This change allows symlink to be implemented using sysfs_dirent tree proper, which is the last remaining dentry-dependent sysfs walk.
--- fs/sysfs/dir.c | 67 ++++++++++++++++++++++++++++++++----------------- fs/sysfs/file.c | 2 +- fs/sysfs/inode.c | 33 +----------------------- fs/sysfs/symlink.c | 8 +----- fs/sysfs/sysfs.h | 7 ++--- include/linux/sysfs.h | 1 + 6 files changed, 51 insertions(+), 67 deletions(-)
fs/sysfs/dir.c +44 -23
@@ -54,10 +54,11 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)if (sd->s_type &SYSFS_KOBJ_LINK ) {struct sysfs_symlink * sl = sd->s_element; -kfree (sl->link_name);kobject_put (sl->target_kobj);kfree (sl); } +if (sd->s_type &SYSFS_COPY_NAME ) +kfree (sd->s_name);kfree (sd->s_iattr);sysfs_free_ino (sd->s_ino);kmem_cache_free (sysfs_dir_cachep, sd);
@@ -94,29 +95,41 @@ static struct dentry_operations sysfs_dentry_ops = { .d_iput = sysfs_d_iput, }; -struct sysfs_dirent *sysfs_new_dirent (void *element,umode_t mode,int type) +struct sysfs_dirent *sysfs_new_dirent (const char *name,void *element, +umode_t mode,int type) { -struct sysfs_dirent * sd; +char *dup_name =NULL ; +struct sysfs_dirent *sd =NULL ; + +if (type &SYSFS_COPY_NAME ) { + name = dup_name =kstrdup (name,GFP_KERNEL ); +if (!name) + goto err_out; + } sd =kmem_cache_zalloc (sysfs_dir_cachep,GFP_KERNEL );if (!sd) -return NULL ; + goto err_out; -if (sysfs_alloc_ino (&sd->s_ino)) { -kmem_cache_free (sysfs_dir_cachep, sd); -return NULL ; - } +if (sysfs_alloc_ino (&sd->s_ino)) + goto err_out;atomic_set (&sd->s_count,1 );atomic_set (&sd->s_event,1 );INIT_LIST_HEAD (&sd->s_children);INIT_LIST_HEAD (&sd->s_sibling); + sd->s_name = name; sd->s_element = element; sd->s_mode = mode; sd->s_type = type;return sd; + + err_out: +kfree (dup_name); +kmem_cache_free (sysfs_dir_cachep, sd); +return NULL ; } void sysfs_attach_dirent(struct sysfs_dirent *sd,
@@ -148,8 +161,7 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,list_for_each_entry (sd, &parent_sd->s_children, s_sibling) {if (sd->s_element) { -const unsigned char *existing =sysfs_get_name (sd); -if (strcmp (existing, new)) +if (strcmp (sd->s_name, new))continue ;else return -EEXIST ;
@@ -203,7 +215,7 @@ static int create_dir(struct kobject *kobj, struct dentry *parent, goto out_dput; error = -ENOMEM ; - sd =sysfs_new_dirent (kobj, mode,SYSFS_DIR ); + sd =sysfs_new_dirent (name, kobj, mode,SYSFS_DIR );if (!sd) goto out_drop;sysfs_attach_dirent (sd, parent->d_fsdata, dentry);
@@ -334,9 +346,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,list_for_each_entry (sd, &parent_sd->s_children, s_sibling) {if (sd->s_type &SYSFS_NOT_PINNED ) { -const unsigned char * name =sysfs_get_name (sd); - -if (strcmp (name, dentry->d_name.name)) +if (strcmp (sd->s_name, dentry->d_name.name))continue ;if (sd->s_type &SYSFS_KOBJ_LINK )
@@ -427,9 +437,11 @@ void sysfs_remove_dir(struct kobject * kobj)int sysfs_rename_dir (struct kobject * kobj,struct dentry *new_parent,const char *new_name) { +struct sysfs_dirent *sd = kobj->dentry->d_fsdata; +struct sysfs_dirent *parent_sd = new_parent->d_fsdata; +struct dentry *new_dentry; +char *dup_name;int error; -struct dentry * new_dentry; -struct sysfs_dirent *sd, *parent_sd;if (!new_parent)return -EFAULT ;
@@ -457,22 +469,31 @@ int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,if (new_dentry->d_inode) goto out_dput; +/* rename kobject and sysfs_dirent */ + error = -ENOMEM ; + new_name = dup_name =kstrdup (new_name,GFP_KERNEL ); +if (!new_name) + goto out_drop; + error =kobject_set_name (kobj,"%s" , new_name);if (error) - goto out_drop; + goto out_free; +kfree (sd->s_name); + sd->s_name = new_name; + +/* move under the new parent */ d_add (new_dentry,NULL );d_move (kobj->dentry, new_dentry); - sd = kobj->dentry->d_fsdata; - parent_sd = new_parent->d_fsdata; -list_del_init (&sd->s_sibling);list_add (&sd->s_sibling, &parent_sd->s_children); error =0 ; goto out_unlock; + out_free: +kfree (dup_name); out_drop:d_drop (new_dentry); out_dput:
@@ -535,7 +556,7 @@ static int sysfs_dir_open(struct inode *inode, struct file *file)struct sysfs_dirent * sd;mutex_lock (&dentry->d_inode->i_mutex); - sd =sysfs_new_dirent (NULL ,0 ,0 ); + sd =sysfs_new_dirent ("_DIR_" ,NULL ,0 ,0 );if (sd)sysfs_attach_dirent (sd, parent_sd,NULL );mutex_unlock (&dentry->d_inode->i_mutex);
@@ -605,7 +626,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)if (!next->s_element)continue ; - name =sysfs_get_name (next); + name = next->s_name; len =strlen (name); ino = next->s_ino;
@@ -717,7 +738,7 @@ struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)if (!shadow) goto nomem; - sd =sysfs_new_dirent (kobj, inode->i_mode,SYSFS_DIR ); + sd =sysfs_new_dirent ("_SHADOW_" , kobj, inode->i_mode,SYSFS_DIR );if (!sd) goto nomem;/* point to parent_sd but don't attach to it */
fs/sysfs/file.c +1 -1
@@ -454,7 +454,7 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) goto out_unlock; } - sd =sysfs_new_dirent ((void *)attr, mode, type); + sd =sysfs_new_dirent (attr->name, (void *)attr, mode, type);if (!sd) { error = -ENOMEM ; goto out_unlock;
fs/sysfs/inode.c +1 -32
@@ -191,37 +191,6 @@ int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))return error; } -/* -* Get the name for corresponding element represented by the given sysfs_dirent -*/ -const unsigned char *sysfs_get_name (struct sysfs_dirent *sd) -{ -struct attribute * attr; -struct bin_attribute * bin_attr; -struct sysfs_symlink * sl; - -BUG_ON (!sd || !sd->s_element); - -switch (sd->s_type) { -case SYSFS_DIR : -/* Always have a dentry so use that */ -return sd->s_dentry->d_name.name; - -case SYSFS_KOBJ_ATTR : - attr = sd->s_element; -return attr->name; - -case SYSFS_KOBJ_BIN_ATTR : - bin_attr = sd->s_element; -return bin_attr->attr.name; - -case SYSFS_KOBJ_LINK : - sl = sd->s_element; -return sl->link_name; - } -return NULL ; -} -static inline void orphan_all_buffers (struct inode *node) {struct sysfs_buffer_collection *set;
@@ -305,7 +274,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name)list_for_each_entry (sd, &parent_sd->s_children, s_sibling) {if (!sd->s_element)continue ; -if (!strcmp (sysfs_get_name (sd), name)) { +if (!strcmp (sd->s_name, name)) {list_del_init (&sd->s_sibling);sysfs_drop_dentry (sd, dir);sysfs_put (sd);
fs/sysfs/symlink.c +1 -7
@@ -57,14 +57,9 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobjif (!sl) goto err_out; - sl->link_name =kmalloc (strlen (name) +1 ,GFP_KERNEL ); -if (!sl->link_name) - goto err_out; - -strcpy (sl->link_name, name); sl->target_kobj =kobject_get (target); - sd =sysfs_new_dirent (sl,S_IFLNK |S_IRWXUGO ,SYSFS_KOBJ_LINK ); + sd =sysfs_new_dirent (name, sl,S_IFLNK |S_IRWXUGO ,SYSFS_KOBJ_LINK );if (!sd) goto err_out;sysfs_attach_dirent (sd, parent_sd,NULL );
@@ -74,7 +69,6 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj err_out:if (sl) {kobject_put (sl->target_kobj); -kfree (sl->link_name);kfree (sl); }return error;
fs/sysfs/sysfs.h +3 -4
@@ -3,6 +3,7 @@ struct sysfs_dirent {struct sysfs_dirent * s_parent;struct list_head s_sibling;struct list_head s_children; +const char * s_name;void * s_element;int s_type;umode_t s_mode;
@@ -21,8 +22,8 @@ extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));extern void release_sysfs_dirent (struct sysfs_dirent * sd);extern int sysfs_dirent_exist (struct sysfs_dirent *,const unsigned char *); -extern struct sysfs_dirent *sysfs_new_dirent (void *element,umode_t mode, -int type); +extern struct sysfs_dirent *sysfs_new_dirent (const char *name,void *element, +umode_t mode,int type);extern void sysfs_attach_dirent (struct sysfs_dirent *sd,struct sysfs_dirent *parent_sd,struct dentry *dentry);
@@ -34,7 +35,6 @@ extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * naextern int sysfs_create_subdir (struct kobject *,const char *,struct dentry **);extern void sysfs_remove_subdir (struct dentry *); -extern const unsigned char *sysfs_get_name (struct sysfs_dirent *sd);extern void sysfs_drop_dentry (struct sysfs_dirent *sd,struct dentry *parent);extern int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);
@@ -48,7 +48,6 @@ extern const struct inode_operations sysfs_dir_inode_operations;extern const struct inode_operations sysfs_symlink_inode_operations;struct sysfs_symlink { -char * link_name;struct kobject * target_kobj; };
include/linux/sysfs.h +1 -0
@@ -76,6 +76,7 @@ struct sysfs_ops {#define SYSFS_KOBJ_BIN_ATTR 0x0008#define SYSFS_KOBJ_LINK 0x0020#define SYSFS_NOT_PINNED (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK) +#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)#ifdef CONFIG_SYSFS
Signature · 1 line
1.5.2.2
PATCH 31/61 sysfs: make sysfs_dirent->s_element a union
From: Tejun Heo <[email protected]>
Make sd->s_element a union of sysfs_elem_{dir|symlink|attr|bin_attr} and rename it to s_elem. This is to achieve...
* some level of type checking : changing symlink to point to sysfs_dirent instead of kobject is much safer and less painful now.
* easier / standardized dereferencing
* allow sysfs_elem_* to contain more than one entry
Where possible, pointer is obtained by directly deferencing from sd instead of going through other entities. This reduces dependencies to dentry, inode and kobject. to_attr() and to_bin_attr() are unused now and removed.
This is in preparation of object reference simplification.
--- fs/sysfs/bin.c | 18 ++++++++++------ fs/sysfs/dir.c | 31 +++++++++++++--------------- fs/sysfs/file.c | 19 +++++++++-------- fs/sysfs/inode.c | 2 +- fs/sysfs/mount.c | 1 - fs/sysfs/symlink.c | 23 +++----------------- fs/sysfs/sysfs.h | 56 ++++++++++++++++++++++++++++----------------------- 7 files changed, 71 insertions(+), 79 deletions(-)
fs/sysfs/bin.c +11 -7
@@ -23,7 +23,8 @@static int fill_read (struct dentry *dentry,char *buffer,loff_t off,size_t count) { -struct bin_attribute * attr =to_bin_attr (dentry); +struct sysfs_dirent *attr_sd = dentry->d_fsdata; +struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;struct kobject * kobj =to_kobj (dentry->d_parent);if (!attr->read)
@@ -65,7 +66,8 @@ read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)static int flush_write (struct dentry *dentry,char *buffer,loff_t offset,size_t count) { -struct bin_attribute *attr =to_bin_attr (dentry); +struct sysfs_dirent *attr_sd = dentry->d_fsdata; +struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;struct kobject *kobj =to_kobj (dentry->d_parent);if (!attr->write)
@@ -101,9 +103,9 @@ static ssize_t write(struct file *file, const char __user *userbuf,static int mmap (struct file *file,struct vm_area_struct *vma) { -struct dentry *dentry = file->f_path.dentry; -struct bin_attribute *attr =to_bin_attr (dentry); -struct kobject *kobj =to_kobj (dentry->d_parent); +struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; +struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; +struct kobject *kobj =to_kobj (file->f_path.dentry->d_parent);if (!attr->mmap)return -EINVAL ;
@@ -114,7 +116,8 @@ static int mmap(struct file *file, struct vm_area_struct *vma)static int open (struct inode * inode,struct file * file) {struct kobject *kobj =sysfs_get_kobject (file->f_path.dentry->d_parent); -struct bin_attribute * attr =to_bin_attr (file->f_path.dentry); +struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; +struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;int error = -EINVAL ;if (!kobj || !attr)
@@ -150,7 +153,8 @@ static int open(struct inode * inode, struct file * file)static int release (struct inode * inode,struct file * file) {struct kobject * kobj =to_kobj (file->f_path.dentry->d_parent); -struct bin_attribute * attr =to_bin_attr (file->f_path.dentry); +struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; +struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;u8 * buffer = file->private_data;kobject_put (kobj);
fs/sysfs/dir.c +14 -17
@@ -52,11 +52,8 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) repeat: parent_sd = sd->s_parent; -if (sd->s_type &SYSFS_KOBJ_LINK ) { -struct sysfs_symlink * sl = sd->s_element; -kobject_put (sl->target_kobj); -kfree (sl); - } +if (sd->s_type &SYSFS_KOBJ_LINK ) +kobject_put (sd->s_elem.symlink.target_kobj);if (sd->s_type &SYSFS_COPY_NAME )kfree (sd->s_name);kfree (sd->s_iattr);
@@ -95,8 +92,7 @@ static struct dentry_operations sysfs_dentry_ops = { .d_iput = sysfs_d_iput, }; -struct sysfs_dirent *sysfs_new_dirent (const char *name,void *element, -umode_t mode,int type) +struct sysfs_dirent *sysfs_new_dirent (const char *name,umode_t mode,int type) {char *dup_name =NULL ;struct sysfs_dirent *sd =NULL ;
@@ -120,7 +116,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, void *element,INIT_LIST_HEAD (&sd->s_sibling); sd->s_name = name; - sd->s_element = element; sd->s_mode = mode; sd->s_type = type;
@@ -160,7 +155,7 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,struct sysfs_dirent * sd;list_for_each_entry (sd, &parent_sd->s_children, s_sibling) { -if (sd->s_element) { +if (sd->s_type) {if (strcmp (sd->s_name, new))continue ;else
@@ -215,9 +210,10 @@ static int create_dir(struct kobject *kobj, struct dentry *parent, goto out_dput; error = -ENOMEM ; - sd =sysfs_new_dirent (name, kobj, mode,SYSFS_DIR ); + sd =sysfs_new_dirent (name, mode,SYSFS_DIR );if (!sd) goto out_drop; + sd->s_elem.dir.kobj = kobj;sysfs_attach_dirent (sd, parent->d_fsdata, dentry); error =sysfs_create (dentry, mode, init_dir);
@@ -290,10 +286,10 @@ static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry)int error =0 ;if (sd->s_type &SYSFS_KOBJ_BIN_ATTR ) { - bin_attr = sd->s_element; + bin_attr = sd->s_elem.bin_attr.bin_attr; attr = &bin_attr->attr; }else { - attr = sd->s_element; + attr = sd->s_elem.attr.attr; init = init_file; }
@@ -404,7 +400,7 @@ static void __sysfs_remove_dir(struct dentry *dentry)mutex_lock (&dentry->d_inode->i_mutex); parent_sd = dentry->d_fsdata;list_for_each_entry_safe (sd, tmp, &parent_sd->s_children, s_sibling) { -if (!sd->s_element || !(sd->s_type &SYSFS_NOT_PINNED )) +if (!sd->s_type || !(sd->s_type &SYSFS_NOT_PINNED ))continue ;list_del_init (&sd->s_sibling);sysfs_drop_dentry (sd, dentry);
@@ -556,7 +552,7 @@ static int sysfs_dir_open(struct inode *inode, struct file *file)struct sysfs_dirent * sd;mutex_lock (&dentry->d_inode->i_mutex); - sd =sysfs_new_dirent ("_DIR_" ,NULL ,0 ,0 ); + sd =sysfs_new_dirent ("_DIR_" ,0 ,0 );if (sd)sysfs_attach_dirent (sd, parent_sd,NULL );mutex_unlock (&dentry->d_inode->i_mutex);
@@ -623,7 +619,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) next = list_entry(p, struct sysfs_dirent, s_sibling); -if (!next->s_element) +if (!next->s_type)continue ; name = next->s_name;
@@ -671,7 +667,7 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)struct sysfs_dirent *next; next = list_entry(p, struct sysfs_dirent, s_sibling); -if (next->s_element) +if (next->s_type) n--; p = p->next; }
@@ -738,9 +734,10 @@ struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)if (!shadow) goto nomem; - sd =sysfs_new_dirent ("_SHADOW_" , kobj, inode->i_mode,SYSFS_DIR ); + sd =sysfs_new_dirent ("_SHADOW_" , inode->i_mode,SYSFS_DIR );if (!sd) goto nomem; + sd->s_elem.dir.kobj = kobj;/* point to parent_sd but don't attach to it */ sd->s_parent =sysfs_get (parent_sd);sysfs_attach_dirent (sd,NULL , shadow);
fs/sysfs/file.c +10 -9
@@ -88,7 +88,6 @@ remove_from_collection(struct sysfs_buffer *buffer, struct inode *node)static int fill_read_buffer (struct dentry * dentry,struct sysfs_buffer * buffer) {struct sysfs_dirent * sd = dentry->d_fsdata; -struct attribute * attr =to_attr (dentry);struct kobject * kobj =to_kobj (dentry->d_parent);struct sysfs_ops * ops = buffer->ops;int ret =0 ;
@@ -100,7 +99,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * bufferreturn -ENOMEM ; buffer->event =atomic_read (&sd->s_event); - count = ops->show (kobj,attr,buffer->page); + count = ops->show (kobj, sd->s_elem.attr.attr, buffer->page);BUG_ON (count > (ssize_t )PAGE_SIZE );if (count >=0 ) { buffer->needs_read_fill =0 ;
@@ -199,11 +198,11 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_tstatic int flush_write_buffer (struct dentry * dentry,struct sysfs_buffer * buffer,size_t count) { -struct attribute * attr =to_attr (dentry); +struct sysfs_dirent *attr_sd = dentry->d_fsdata;struct kobject * kobj =to_kobj (dentry->d_parent);struct sysfs_ops * ops = buffer->ops; -return ops->store (kobj,attr,buffer->page,count); +return ops->store (kobj, attr_sd->s_elem.attr.attr, buffer->page, count); }
@@ -248,7 +247,8 @@ out:static int sysfs_open_file (struct inode *inode,struct file *file) {struct kobject *kobj =sysfs_get_kobject (file->f_path.dentry->d_parent); -struct attribute * attr =to_attr (file->f_path.dentry); +struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; +struct attribute *attr = attr_sd->s_elem.attr.attr;struct sysfs_buffer_collection *set;struct sysfs_buffer * buffer;struct sysfs_ops * ops =NULL ;
@@ -341,15 +341,15 @@ static int sysfs_open_file(struct inode *inode, struct file *file)static int sysfs_release (struct inode * inode,struct file * filp) {struct kobject * kobj =to_kobj (filp->f_path.dentry->d_parent); -struct attribute * attr =to_attr (filp->f_path.dentry); -struct module * owner = attr->owner; +struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; +struct attribute *attr = attr_sd->s_elem.attr.attr;struct sysfs_buffer * buffer = filp->private_data;if (buffer)remove_from_collection (buffer, inode);kobject_put (kobj);/* After this point, attr should not be accessed. */ -module_put (owner); +module_put (attr->owner);if (buffer) {if (buffer->page)
@@ -454,11 +454,12 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) goto out_unlock; } - sd =sysfs_new_dirent (attr->name, (void *)attr, mode, type); + sd =sysfs_new_dirent (attr->name, mode, type);if (!sd) { error = -ENOMEM ; goto out_unlock; } + sd->s_elem.attr.attr = (void *)attr;sysfs_attach_dirent (sd, parent_sd,NULL ); out_unlock:
fs/sysfs/inode.c +1 -1
@@ -272,7 +272,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name) parent_sd = dir->d_fsdata;mutex_lock_nested (&dir->d_inode->i_mutex,I_MUTEX_PARENT );list_for_each_entry (sd, &parent_sd->s_children, s_sibling) { -if (!sd->s_element) +if (!sd->s_type)continue ;if (!strcmp (sd->s_name, name)) {list_del_init (&sd->s_sibling);
fs/sysfs/mount.c +0 -1
@@ -31,7 +31,6 @@ static struct sysfs_dirent sysfs_root = { .s_count = ATOMIC_INIT(1), .s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling), .s_children = LIST_HEAD_INIT(sysfs_root.s_children), - .s_element = NULL, .s_type = SYSFS_ROOT, .s_iattr = NULL, .s_ino = 1,
fs/sysfs/symlink.c +4 -19
@@ -48,30 +48,15 @@ static void fill_object_path(struct kobject * kobj, char * buffer, int length)static int sysfs_add_link (struct dentry * parent,const char * name,struct kobject * target) {struct sysfs_dirent * parent_sd = parent->d_fsdata; -struct sysfs_symlink * sl;struct sysfs_dirent * sd; -int error; - error = -ENOMEM ; - sl =kzalloc (sizeof (*sl),GFP_KERNEL ); -if (!sl) - goto err_out; - - sl->target_kobj =kobject_get (target); - - sd =sysfs_new_dirent (name, sl,S_IFLNK |S_IRWXUGO ,SYSFS_KOBJ_LINK ); + sd =sysfs_new_dirent (name,S_IFLNK |S_IRWXUGO ,SYSFS_KOBJ_LINK );if (!sd) - goto err_out; -sysfs_attach_dirent (sd, parent_sd,NULL ); +return -ENOMEM ; + sd->s_elem.symlink.target_kobj =kobject_get (target); +sysfs_attach_dirent (sd, parent_sd,NULL );return 0 ; - - err_out: -if (sl) { -kobject_put (sl->target_kobj); -kfree (sl); - } -return error; }/**
fs/sysfs/sysfs.h +31 -25
89 lines not on this page · raw message
Signature · 1 line
1.5.2.2
PATCH 32/61 sysfs: implement kobj_sysfs_assoc_lock
From: Tejun Heo <[email protected]>
kobj->dentry can go away anytime unless the user controls when the associated sysfs node is deleted. This patch implements kobj_sysfs_assoc_lock which protects kobj->dentry. This will be used to maintain kobj based API when converting sysfs to use sysfs_dirent tree instead of dentry/kobject.
Note that this lock belongs to kobject/driver-model not sysfs. Once sysfs is converted to not use kobject in its interface, this can be removed from sysfs.
This is in preparation of object reference simplification.
--- fs/sysfs/dir.c | 8 +++++++- fs/sysfs/sysfs.h | 1 + 2 files changed, 8 insertions(+), 1 deletions(-)
fs/sysfs/dir.c +7 -1
@@ -15,6 +15,7 @@DECLARE_RWSEM (sysfs_rename_sem);spinlock_t sysfs_lock =SPIN_LOCK_UNLOCKED ; +spinlock_t kobj_sysfs_assoc_lock =SPIN_LOCK_UNLOCKED ;static spinlock_t sysfs_ino_lock =SPIN_LOCK_UNLOCKED ;static DEFINE_IDA (sysfs_ino_ida);
@@ -426,8 +427,13 @@ static void __sysfs_remove_dir(struct dentry *dentry)void sysfs_remove_dir (struct kobject * kobj) { -__sysfs_remove_dir (kobj->dentry); +struct dentry *d = kobj->dentry; + +spin_lock (&kobj_sysfs_assoc_lock); kobj->dentry =NULL ; +spin_unlock (&kobj_sysfs_assoc_lock); + +__sysfs_remove_dir (d); } int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
fs/sysfs/sysfs.h +1 -0
@@ -62,6 +62,7 @@ extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent);extern int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);extern spinlock_t sysfs_lock; +extern spinlock_t kobj_sysfs_assoc_lock;extern struct rw_semaphore sysfs_rename_sem;extern struct super_block * sysfs_sb;extern const struct file_operations sysfs_dir_operations;
Signature · 1 line
1.5.2.2
PATCH 33/61 sysfs: reimplement symlink using sysfs_dirent tree
From: Tejun Heo <[email protected]>
sysfs symlink is implemented by referencing dentry and kobject from sysfs_dirent - symlink entry references kobject, dentry is used to walk the tree. This complicates object lifetimes rules and is dangerous - for example, there is no way to tell to which module the target of a symlink belongs and referencing that kobject can make it linger after the module is gone.
This patch reimplements symlink using only sysfs_dirent tree. sd for a symlink points and holds reference to the target sysfs_dirent and all walking is done using sysfs_dirent tree. Simpler and safer.
Please read the following message for more info.
http://article.gmane.org/gmane.linux.kernel/510293
--- fs/sysfs/dir.c | 2 +- fs/sysfs/symlink.c | 88 +++++++++++++++++++++++++++------------------------ fs/sysfs/sysfs.h | 9 +++-- 3 files changed, 53 insertions(+), 46 deletions(-)
fs/sysfs/dir.c +1 -1
@@ -54,7 +54,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) parent_sd = sd->s_parent;if (sd->s_type &SYSFS_KOBJ_LINK ) -kobject_put (sd->s_elem.symlink.target_kobj); +sysfs_put (sd->s_elem.symlink.target_sd);if (sd->s_type &SYSFS_COPY_NAME )kfree (sd->s_name);kfree (sd->s_iattr);
fs/sysfs/symlink.c +47 -41
162 lines not on this page · raw message
fs/sysfs/sysfs.h +5 -4
@@ -3,7 +3,7 @@ struct sysfs_elem_dir { };struct sysfs_elem_symlink { -struct kobject * target_kobj; +struct sysfs_dirent * target_sd; };struct sysfs_elem_attr {
@@ -100,10 +100,11 @@ static inline struct kobject *sysfs_get_kobject(struct dentry *dentry)spin_lock (&dcache_lock);if (!d_unhashed (dentry)) {struct sysfs_dirent * sd = dentry->d_fsdata; +if (sd->s_type &SYSFS_KOBJ_LINK ) - kobj =kobject_get (sd->s_elem.symlink.target_kobj); -else - kobj =kobject_get (sd->s_elem.dir.kobj); + sd = sd->s_elem.symlink.target_sd; + + kobj =kobject_get (sd->s_elem.dir.kobj); }spin_unlock (&dcache_lock);
Signature · 1 line
1.5.2.2
PATCH 34/61 sysfs: implement bin_buffer
From: Tejun Heo <[email protected]>
Implement bin_buffer which contains a mutex and pointer to PAGE_SIZE buffer to properly synchronize accesses to per-openfile buffer and prepare for immediate-kobj-disconnect.
--- fs/sysfs/bin.c | 64 ++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 49 insertions(+), 15 deletions(-)
fs/sysfs/bin.c +49 -15
@@ -20,6 +20,11 @@#include "sysfs.h" +struct bin_buffer { +struct mutex mutex; +void *buffer; +}; +static int fill_read (struct dentry *dentry,char *buffer,loff_t off,size_t count) {
@@ -36,7 +41,7 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)static ssize_t read (struct file *file,char __user *userbuf,size_t bytes,loff_t *off) { -char *buffer = file->private_data; +struct bin_buffer *bb = file->private_data;struct dentry *dentry = file->f_path.dentry;int size = dentry->d_inode->i_size;loff_t offs = *off;
@@ -49,17 +54,23 @@ read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) count = size - offs; } - count =fill_read (dentry, buffer, offs, count); +mutex_lock (&bb->mutex); + + count =fill_read (dentry, bb->buffer, offs, count);if (count <0 ) -return count; + goto out_unlock; -if (copy_to_user (userbuf, buffer, count)) -return -EFAULT ; +if (copy_to_user (userbuf, bb->buffer, count)) { + count = -EFAULT ; + goto out_unlock; + }pr_debug ("offs = %lld, *off = %lld, count = %d\n" , offs, *off, count); *off = offs + count; + out_unlock: +mutex_unlock (&bb->mutex);return count; }
@@ -79,7 +90,7 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)static ssize_t write (struct file *file,const char __user *userbuf,size_t bytes,loff_t *off) { -char *buffer = file->private_data; +struct bin_buffer *bb = file->private_data;struct dentry *dentry = file->f_path.dentry;int size = dentry->d_inode->i_size;loff_t offs = *off;
@@ -92,25 +103,38 @@ static ssize_t write(struct file *file, const char __user *userbuf, count = size - offs; } -if (copy_from_user (buffer, userbuf, count)) -return -EFAULT ; +mutex_lock (&bb->mutex); + +if (copy_from_user (bb->buffer, userbuf, count)) { + count = -EFAULT ; + goto out_unlock; + } - count =flush_write (dentry, buffer, offs, count); + count =flush_write (dentry, bb->buffer, offs, count);if (count >0 ) *off = offs + count; + + out_unlock: +mutex_unlock (&bb->mutex);return count; }static int mmap (struct file *file,struct vm_area_struct *vma) { +struct bin_buffer *bb = file->private_data;struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;struct kobject *kobj =to_kobj (file->f_path.dentry->d_parent); +int rc;if (!attr->mmap)return -EINVAL ; -return attr->mmap (kobj, attr, vma); +mutex_lock (&bb->mutex); + rc = attr->mmap (kobj, attr, vma); +mutex_unlock (&bb->mutex); + +return rc; }static int open (struct inode * inode,struct file * file)
@@ -118,6 +142,7 @@ static int open(struct inode * inode, struct file * file)struct kobject *kobj =sysfs_get_kobject (file->f_path.dentry->d_parent);struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; +struct bin_buffer *bb =NULL ;int error = -EINVAL ;if (!kobj || !attr)
@@ -135,14 +160,22 @@ static int open(struct inode * inode, struct file * file) goto Error; error = -ENOMEM ; - file->private_data =kmalloc (PAGE_SIZE ,GFP_KERNEL ); -if (!file->private_data) + bb =kzalloc (sizeof (*bb),GFP_KERNEL ); +if (!bb) goto Error; + bb->buffer =kmalloc (PAGE_SIZE ,GFP_KERNEL ); +if (!bb->buffer) + goto Error; + +mutex_init (&bb->mutex); + file->private_data = bb; + error =0 ; - goto Done; + goto Done; Error: +kfree (bb);module_put (attr->attr.owner); Done:if (error)
@@ -155,11 +188,12 @@ static int release(struct inode * inode, struct file * file)struct kobject * kobj =to_kobj (file->f_path.dentry->d_parent);struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; -u8 * buffer = file->private_data; +struct bin_buffer *bb = file->private_data;kobject_put (kobj);module_put (attr->attr.owner); -kfree (buffer); +kfree (bb->buffer); +kfree (bb);return 0 ; }
Signature · 1 line
1.5.2.2
PATCH 35/61 sysfs: implement sysfs_dirent active reference and immediate disconnect
From: Tejun Heo <[email protected]>
sysfs: implement sysfs_dirent active reference and immediate disconnect
Opening a sysfs node references its associated kobject, so userland can arbitrarily prolong lifetime of a kobject which complicates lifetime rules in drivers. This patch implements active reference and makes the association between kobject and sysfs immediately breakable.
Now each sysfs_dirent has two reference counts - s_count and s_active. s_count is a regular reference count which guarantees that the containing sysfs_dirent is accessible. As long as s_count reference is held, all sysfs internal fields in sysfs_dirent are accessible including s_parent and s_name.
The newly added s_active is active reference count. This is acquired by invoking sysfs_get_active() and it's the caller's responsibility to ensure sysfs_dirent itself is accessible (should be holding s_count one way or the other). Dereferencing sysfs_dirent to access objects out of sysfs proper requires active reference. This includes access to the associated kobjects, attributes and ops.
The active references can be drained and denied by calling sysfs_deactivate(). All active sysfs_dirents must be deactivated after deletion but before the default reference is dropped. This enables immediate disconnect of sysfs nodes. Once a sysfs_dirent is deleted, it won't access any entity external to sysfs proper.
Because attr/bin_attr ops access both the node itself and its parent for kobject, they need to hold active references to both. sysfs_get/put_active_two() helpers are provided to help grabbing both references. Parent's is acquired first and released last.
Unlike other operations, mmapped area lingers on after mmap() is finished and the module implement implementing it and kobj need to stay referenced till all the mapped pages are gone. This is accomplished by holding one set of active references to the bin_attr and its parent if there have been any mmap during lifetime of an openfile. The references are dropped when the openfile is released.
This change makes sysfs lifetime rules independent from both kobject's and module's. It not only fixes several race conditions caused by sysfs not holding onto the proper module when referencing kobject, but also helps fixing and simplifying lifetime management in driver model and drivers by taking sysfs out of the equation.
Please read the following message for more info.
http://article.gmane.org/gmane.linux.kernel/510293
--- fs/sysfs/bin.c | 95 ++++++++++++++++++++++++++-------------- fs/sysfs/dir.c | 28 ++++++++++- fs/sysfs/file.c | 130 +++++++++++++++++++++++++++++++---------------------- fs/sysfs/inode.c | 8 +++- fs/sysfs/sysfs.h | 123 ++++++++++++++++++++++++++++++++++++++++++--------- 5 files changed, 271 insertions(+), 113 deletions(-)
fs/sysfs/bin.c +62 -33
@@ -23,6 +23,7 @@struct bin_buffer {struct mutex mutex;void *buffer; +int mmapped; }; static int
@@ -30,12 +31,20 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) {struct sysfs_dirent *attr_sd = dentry->d_fsdata;struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; -struct kobject * kobj =to_kobj (dentry->d_parent); +struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; +int rc; + +/* need attr_sd for attr, its parent for kobj */ +if (!sysfs_get_active_two (attr_sd)) +return -ENODEV ; -if (!attr->read) -return -EIO ; + rc = -EIO ; +if (attr->read) + rc = attr->read (kobj, buffer, off, count); -return attr->read (kobj, buffer, off, count); +sysfs_put_active_two (attr_sd); + +return rc; } static ssize_t
@@ -79,12 +88,20 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) {struct sysfs_dirent *attr_sd = dentry->d_fsdata;struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; -struct kobject *kobj =to_kobj (dentry->d_parent); +struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; +int rc; + +/* need attr_sd for attr, its parent for kobj */ +if (!sysfs_get_active_two (attr_sd)) +return -ENODEV ; -if (!attr->write) -return -EIO ; + rc = -EIO ; +if (attr->write) + rc = attr->write (kobj, buffer, offset, count); -return attr->write (kobj, buffer, offset, count); +sysfs_put_active_two (attr_sd); + +return rc; } static ssize_t write(struct file *file, const char __user *userbuf,
@@ -124,14 +141,24 @@ static int mmap(struct file *file, struct vm_area_struct *vma)struct bin_buffer *bb = file->private_data;struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr; -struct kobject *kobj =to_kobj (file->f_path.dentry->d_parent); +struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;int rc; -if (!attr->mmap) -return -EINVAL ; -mutex_lock (&bb->mutex); - rc = attr->mmap (kobj, attr, vma); + +/* need attr_sd for attr, its parent for kobj */ +if (!sysfs_get_active_two (attr_sd)) +return -ENODEV ; + + rc = -EINVAL ; +if (attr->mmap) + rc = attr->mmap (kobj, attr, vma); + +if (rc ==0 && !bb->mmapped) + bb->mmapped =1 ; +else +sysfs_put_active_two (attr_sd); +mutex_unlock (&bb->mutex);return rc;
@@ -139,58 +166,60 @@ static int mmap(struct file *file, struct vm_area_struct *vma)static int open (struct inode * inode,struct file * file) { -struct kobject *kobj =sysfs_get_kobject (file->f_path.dentry->d_parent);struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;struct bin_buffer *bb =NULL ; -int error = -EINVAL ; +int error; -if (!kobj || !attr) - goto Done; +/* need attr_sd for attr */ +if (!sysfs_get_active (attr_sd)) +return -ENODEV ; -/* Grab the module reference for this attribute if we have one */ +/* Grab the module reference for this attribute */ error = -ENODEV ; -if (!try_module_get (attr->attr.owner)) - goto Done; +if (!try_module_get (attr->attr.owner)) + goto err_sput; error = -EACCES ;if ((file->f_mode &FMODE_WRITE ) && !(attr->write || attr->mmap)) - goto Error; + goto err_mput;if ((file->f_mode &FMODE_READ ) && !(attr->read || attr->mmap)) - goto Error; + goto err_mput; error = -ENOMEM ; bb =kzalloc (sizeof (*bb),GFP_KERNEL );if (!bb) - goto Error; + goto err_mput; bb->buffer =kmalloc (PAGE_SIZE ,GFP_KERNEL );if (!bb->buffer) - goto Error; + goto err_mput;mutex_init (&bb->mutex); file->private_data = bb; - error =0 ; - goto Done; +/* open succeeded, put active reference and pin attr_sd */ +sysfs_put_active (attr_sd); +sysfs_get (attr_sd); +return 0 ; - Error: -kfree (bb); + err_mput:module_put (attr->attr.owner); - Done: -if (error) -kobject_put (kobj); + err_sput: +sysfs_put_active (attr_sd); +kfree (bb);return error; }static int release (struct inode * inode,struct file * file) { -struct kobject * kobj =to_kobj (file->f_path.dentry->d_parent);struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;struct bin_buffer *bb = file->private_data; -kobject_put (kobj); +if (bb->mmapped) +sysfs_put_active_two (attr_sd); +sysfs_put (attr_sd);module_put (attr->attr.owner);kfree (bb->buffer);kfree (bb);
fs/sysfs/dir.c +25 -3
@@ -53,6 +53,19 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) repeat: parent_sd = sd->s_parent; +/* If @sd is being released after deletion, s_active is write +* locked. If @sd is cursor for directory walk or being +* released prematurely, s_active has no reader or writer. +* +* sysfs_deactivate() lies to lockdep that s_active is +* unlocked immediately. Lie one more time to cover the +* previous lie. +*/ +if (!down_write_trylock (&sd->s_active)) +rwsem_acquire (&sd->s_active.dep_map, +SYSFS_S_ACTIVE_DEACTIVATE ,0 , _RET_IP_); +up_write (&sd->s_active); +if (sd->s_type &SYSFS_KOBJ_LINK )sysfs_put (sd->s_elem.symlink.target_sd);if (sd->s_type &SYSFS_COPY_NAME )
@@ -113,6 +126,7 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)atomic_set (&sd->s_count,1 );atomic_set (&sd->s_event,1 ); +init_rwsem (&sd->s_active);INIT_LIST_HEAD (&sd->s_children);INIT_LIST_HEAD (&sd->s_sibling);
@@ -371,7 +385,6 @@ static void remove_dir(struct dentry * d)d_delete (d); sd = d->d_fsdata;list_del_init (&sd->s_sibling); -sysfs_put (sd);if (d->d_inode)simple_rmdir (parent->d_inode,d);
@@ -380,6 +393,9 @@ static void remove_dir(struct dentry * d)mutex_unlock (&parent->d_inode->i_mutex);dput (parent); + +sysfs_deactivate (sd); +sysfs_put (sd); }void sysfs_remove_subdir (struct dentry * d)
@@ -390,6 +406,7 @@ void sysfs_remove_subdir(struct dentry * d)static void __sysfs_remove_dir (struct dentry *dentry) { +LIST_HEAD (removed);struct sysfs_dirent * parent_sd;struct sysfs_dirent * sd, * tmp;
@@ -403,12 +420,17 @@ static void __sysfs_remove_dir(struct dentry *dentry)list_for_each_entry_safe (sd, tmp, &parent_sd->s_children, s_sibling) {if (!sd->s_type || !(sd->s_type &SYSFS_NOT_PINNED ))continue ; -list_del_init (&sd->s_sibling); +list_move (&sd->s_sibling, &removed);sysfs_drop_dentry (sd, dentry); -sysfs_put (sd); }mutex_unlock (&dentry->d_inode->i_mutex); +list_for_each_entry_safe (sd, tmp, &removed, s_sibling) { +list_del_init (&sd->s_sibling); +sysfs_deactivate (sd); +sysfs_put (sd); + } +remove_dir (dentry);/** * Drop reference from dget() on entrance.
fs/sysfs/file.c +76 -54
222 lines not on this page · raw message
fs/sysfs/inode.c +6 -2
@@ -277,12 +277,16 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name)if (!strcmp (sd->s_name, name)) {list_del_init (&sd->s_sibling);sysfs_drop_dentry (sd, dir); -sysfs_put (sd); found =1 ;break ; } }mutex_unlock (&dir->d_inode->i_mutex); -return found ?0 : -ENOENT ; +if (!found) +return -ENOENT ; + +sysfs_deactivate (sd); +sysfs_put (sd); +return 0 ; }
fs/sysfs/sysfs.h +102 -21
159 lines not on this page · raw message
Signature · 1 line
1.5.2.2
PATCH 36/61 sysfs: kill attribute file orphaning
From: Tejun Heo <[email protected]>
Now that sysfs_dirent can be disconnected from kobject on deletion, there is no need to orphan each attribute files. All [bin_]attribute nodes are automatically orphaned when the parent node is deleted. Kill attribute file orphaning.
--- fs/sysfs/file.c | 65 ++++++++++------------------------------------------- fs/sysfs/inode.c | 25 -------------------- fs/sysfs/mount.c | 8 ------ fs/sysfs/sysfs.h | 16 ------------- 4 files changed, 13 insertions(+), 101 deletions(-)
fs/sysfs/file.c +13 -52
@@ -50,29 +50,15 @@ static struct sysfs_ops subsys_sysfs_ops = { .store = subsys_attr_store, }; -/** -* add_to_collection - add buffer to a collection -* @buffer: buffer to be added -* @node: inode of set to add to -*/ - -static inline void -add_to_collection (struct sysfs_buffer *buffer,struct inode *node) -{ -struct sysfs_buffer_collection *set = node->i_private; - -mutex_lock (&node->i_mutex); -list_add (&buffer->associates, &set->associates); -mutex_unlock (&node->i_mutex); -} - -static inline void -remove_from_collection (struct sysfs_buffer *buffer,struct inode *node) -{ -mutex_lock (&node->i_mutex); -list_del (&buffer->associates); -mutex_unlock (&node->i_mutex); -} +struct sysfs_buffer { +size_t count; +loff_t pos; +char * page; +struct sysfs_ops * ops; +struct semaphore sem; +int needs_read_fill; +int event; +};/** * fill_read_buffer - allocate and fill buffer from object.
@@ -144,10 +130,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)down (&buffer->sem);if (buffer->needs_read_fill) { -if (buffer->orphaned) - retval = -ENODEV ; -else - retval =fill_read_buffer (file->f_path.dentry,buffer); + retval =fill_read_buffer (file->f_path.dentry,buffer);if (retval) goto out; }
@@ -246,16 +229,11 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_tssize_t len;down (&buffer->sem); -if (buffer->orphaned) { - len = -ENODEV ; - goto out; - } len =fill_write_buffer (buffer, buf, count);if (len >0 ) len =flush_write_buffer (file->f_path.dentry, buffer, len);if (len >0 ) *ppos += len; -out:up (&buffer->sem);return len; }
@@ -265,7 +243,6 @@ static int sysfs_open_file(struct inode *inode, struct file *file)struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;struct attribute *attr = attr_sd->s_elem.attr.attr;struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj; -struct sysfs_buffer_collection *set;struct sysfs_buffer * buffer;struct sysfs_ops * ops =NULL ;int error;
@@ -289,26 +266,14 @@ static int sysfs_open_file(struct inode *inode, struct file *file)else ops = &subsys_sysfs_ops; + error = -EACCES ; +/* No sysfs operations, either from having no subsystem, * or the subsystem have no operations. */ - error = -EACCES ;if (!ops) goto err_mput; -/* make sure we have a collection to add our buffers to */ -mutex_lock (&inode->i_mutex); -if (!(set = inode->i_private)) { - error = -ENOMEM ; -if (!(set = inode->i_private =kmalloc (sizeof (struct sysfs_buffer_collection ),GFP_KERNEL ))) - goto err_mput; -else -INIT_LIST_HEAD (&set->associates); - } -mutex_unlock (&inode->i_mutex); - - error = -EACCES ; -/* File needs write support. * The inode's perms must say it's ok, * and we must have a store method.
@@ -335,11 +300,9 @@ static int sysfs_open_file(struct inode *inode, struct file *file)if (!buffer) goto err_mput; -INIT_LIST_HEAD (&buffer->associates);init_MUTEX (&buffer->sem); buffer->needs_read_fill =1 ; buffer->ops = ops; -add_to_collection (buffer, inode); file->private_data = buffer;/* open succeeded, put active references and pin attr_sd */
@@ -358,10 +321,8 @@ static int sysfs_release(struct inode * inode, struct file * filp) {struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;struct attribute *attr = attr_sd->s_elem.attr.attr; -struct sysfs_buffer * buffer = filp->private_data; +struct sysfs_buffer *buffer = filp->private_data; -if (buffer) -remove_from_collection (buffer, inode);sysfs_put (attr_sd);/* After this point, attr should not be accessed. */ module_put (attr->owner);
fs/sysfs/inode.c +0 -25
@@ -191,24 +191,6 @@ int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))return error; } -static inline void orphan_all_buffers (struct inode *node) -{ -struct sysfs_buffer_collection *set; -struct sysfs_buffer *buf; - -mutex_lock_nested (&node->i_mutex,I_MUTEX_CHILD ); - set = node->i_private; -if (set) { -list_for_each_entry (buf, &set->associates, associates) { -down (&buf->sem); - buf->orphaned =1 ; -up (&buf->sem); - } - } -mutex_unlock (&node->i_mutex); -} - -/* * Unhashes the dentry corresponding to given sysfs_dirent * Called with parent inode's i_mutex held.
@@ -216,7 +198,6 @@ static inline void orphan_all_buffers(struct inode *node)void sysfs_drop_dentry (struct sysfs_dirent * sd,struct dentry * parent) {struct dentry *dentry =NULL ; -struct inode *inode;/* We're not holding a reference to ->s_dentry dentry but the * field will stay valid as long as sysfs_lock is held.
@@ -236,17 +217,11 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)spin_lock (&dcache_lock);spin_lock (&dentry->d_lock);if (!d_unhashed (dentry) && dentry->d_inode) { - inode = dentry->d_inode; -spin_lock (&inode->i_lock); -__iget (inode); -spin_unlock (&inode->i_lock);dget_locked (dentry);__d_drop (dentry);spin_unlock (&dentry->d_lock);spin_unlock (&dcache_lock);simple_unlink (parent->d_inode, dentry); -orphan_all_buffers (inode); -iput (inode); }else {spin_unlock (&dentry->d_lock);spin_unlock (&dcache_lock);
fs/sysfs/mount.c +0 -8
@@ -19,12 +19,9 @@ struct vfsmount *sysfs_mount;struct super_block * sysfs_sb =NULL ;struct kmem_cache *sysfs_dir_cachep; -static void sysfs_clear_inode (struct inode *inode); -static const struct super_operations sysfs_ops = { .statfs = simple_statfs, .drop_inode = sysfs_delete_inode, - .clear_inode = sysfs_clear_inode, };static struct sysfs_dirent sysfs_root = {
@@ -36,11 +33,6 @@ static struct sysfs_dirent sysfs_root = { .s_ino = 1, }; -static void sysfs_clear_inode (struct inode *inode) -{ -kfree (inode->i_private); -} -static int sysfs_fill_super (struct super_block *sb,void *data,int silent) {struct inode *inode;
fs/sysfs/sysfs.h +0 -16
@@ -88,22 +88,6 @@ extern const struct file_operations bin_fops;extern const struct inode_operations sysfs_dir_inode_operations;extern const struct inode_operations sysfs_symlink_inode_operations; -struct sysfs_buffer { -struct list_head associates; -size_t count; -loff_t pos; -char * page; -struct sysfs_ops * ops; -struct semaphore sem; -int orphaned; -int needs_read_fill; -int event; -}; - -struct sysfs_buffer_collection { -struct list_head associates; -}; -static inline struct sysfs_dirent *sysfs_get (struct sysfs_dirent * sd) {if (sd) {
Signature · 1 line
1.5.2.2
PATCH 37/61 sysfs: separate out sysfs_attach_dentry()
From: Tejun Heo <[email protected]>
Consolidate sd <-> dentry association into sysfs_attach_dentry() and call it after dentry and inode are properly set up. This is in preparation of sysfs_drop_dentry() updates.
--- fs/sysfs/dir.c | 59 +++++++++++++++++++++++------------------------------ fs/sysfs/inode.c | 4 +- fs/sysfs/sysfs.h | 3 +- 3 files changed, 30 insertions(+), 36 deletions(-)
fs/sysfs/dir.c +26 -33
@@ -142,14 +142,24 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)return NULL ; } +static void sysfs_attach_dentry (struct sysfs_dirent *sd,struct dentry *dentry) +{ + dentry->d_op = &sysfs_dentry_ops; + dentry->d_fsdata =sysfs_get (sd); + +/* protect sd->s_dentry against sysfs_d_iput */ +spin_lock (&sysfs_lock); + sd->s_dentry = dentry; +spin_unlock (&sysfs_lock); + +d_rehash (dentry); +} +void sysfs_attach_dirent (struct sysfs_dirent *sd,struct sysfs_dirent *parent_sd,struct dentry *dentry) { -if (dentry) { - sd->s_dentry = dentry; - dentry->d_fsdata =sysfs_get (sd); - dentry->d_op = &sysfs_dentry_ops; - } +if (dentry) +sysfs_attach_dentry (sd, dentry);if (parent_sd) { sd->s_parent =sysfs_get (parent_sd);
@@ -229,15 +239,13 @@ static int create_dir(struct kobject *kobj, struct dentry *parent,if (!sd) goto out_drop; sd->s_elem.dir.kobj = kobj; -sysfs_attach_dirent (sd, parent->d_fsdata, dentry); - error =sysfs_create (dentry, mode, init_dir); + error =sysfs_create (sd, dentry, mode, init_dir);if (error) goto out_sput;inc_nlink (parent->d_inode); - dentry->d_op = &sysfs_dentry_ops; -d_rehash (dentry); +sysfs_attach_dirent (sd, parent->d_fsdata, dentry); *p_dentry = dentry; error =0 ;
@@ -308,42 +316,28 @@ static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry) init = init_file; } - dentry->d_fsdata =sysfs_get (sd); -/* protect sd->s_dentry against sysfs_d_iput */ -spin_lock (&sysfs_lock); - sd->s_dentry = dentry; -spin_unlock (&sysfs_lock); - error =sysfs_create (dentry, (attr->mode &S_IALLUGO ) |S_IFREG , init); -if (error) { -sysfs_put (sd); + error =sysfs_create (sd, dentry, + (attr->mode &S_IALLUGO ) |S_IFREG , init); +if (error)return error; - }if (bin_attr) { dentry->d_inode->i_size = bin_attr->size; dentry->d_inode->i_fop = &bin_fops; } - dentry->d_op = &sysfs_dentry_ops; -d_rehash (dentry); + +sysfs_attach_dentry (sd, dentry);return 0 ; }static int sysfs_attach_link (struct sysfs_dirent * sd,struct dentry * dentry) { -int err =0 ; +int err; - dentry->d_fsdata =sysfs_get (sd); -/* protect sd->s_dentry against sysfs_d_iput */ -spin_lock (&sysfs_lock); - sd->s_dentry = dentry; -spin_unlock (&sysfs_lock); - err =sysfs_create (dentry,S_IFLNK |S_IRWXUGO , init_symlink); -if (!err) { - dentry->d_op = &sysfs_dentry_ops; -d_rehash (dentry); - }else -sysfs_put (sd); + err =sysfs_create (sd, dentry,S_IFLNK |S_IRWXUGO , init_symlink); +if (!err) +sysfs_attach_dentry (sd, dentry);return err; }
@@ -773,7 +767,6 @@ struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)d_instantiate (shadow,igrab (inode));inc_nlink (inode);inc_nlink (parent->d_inode); - shadow->d_op = &sysfs_dentry_ops;dget (shadow);/* Extra count - pin the dentry in core */
fs/sysfs/inode.c +2 -2
@@ -156,13 +156,13 @@ struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd)return inode; } -int sysfs_create (struct dentry * dentry,int mode,int (*init)(struct inode *)) +int sysfs_create (struct sysfs_dirent *sd,struct dentry *dentry,int mode, +int (*init)(struct inode *)) {int error =0 ;struct inode * inode =NULL ;if (dentry) {if (!dentry->d_inode) { -struct sysfs_dirent * sd = dentry->d_fsdata;if ((inode =sysfs_new_inode (mode, sd))) {if (dentry->d_parent && dentry->d_parent->d_inode) {struct inode *p_inode = dentry->d_parent->d_inode;
fs/sysfs/sysfs.h +2 -1
@@ -58,7 +58,8 @@ extern struct kmem_cache *sysfs_dir_cachep;extern void sysfs_delete_inode (struct inode *inode);extern struct inode *sysfs_new_inode (mode_t mode,struct sysfs_dirent *); -extern int sysfs_create (struct dentry *,int mode,int (*init)(struct inode *)); +extern int sysfs_create (struct sysfs_dirent *sd,struct dentry *dentry, +int mode,int (*init)(struct inode *));extern void release_sysfs_dirent (struct sysfs_dirent * sd);extern int sysfs_dirent_exist (struct sysfs_dirent *,const unsigned char *);
Signature · 1 line
1.5.2.2
PATCH 38/61 sysfs: reimplement sysfs_drop_dentry()
From: Tejun Heo <[email protected]>
This patch reimplements sysfs_drop_dentry() such that remove_dir() can use it to drop dentry instead of using a separate mechanism. With this change, making directories reclaimable is much easier.
This patch used to contain fixes for two race conditions around sd->s_dentry but that part has been separated out and included into mainline early as commit 6aa054aadfea613a437ad0b15d38eca2b963fc0a and dd14cbc994709a1c5a64ed3621f583c49a27e521.
--- fs/sysfs/dir.c | 18 +++-------- fs/sysfs/inode.c | 82 ++++++++++++++++++++++++++++++++++++++++-------------- fs/sysfs/sysfs.h | 2 +- 3 files changed, 67 insertions(+), 35 deletions(-)
fs/sysfs/dir.c +5 -13
@@ -372,22 +372,19 @@ const struct inode_operations sysfs_dir_inode_operations = {static void remove_dir (struct dentry * d) { -struct dentry * parent =dget (d->d_parent); -struct sysfs_dirent * sd; +struct dentry *parent = d->d_parent; +struct sysfs_dirent *sd = d->d_fsdata;mutex_lock (&parent->d_inode->i_mutex); -d_delete (d); - sd = d->d_fsdata; +list_del_init (&sd->s_sibling); -if (d->d_inode) -simple_rmdir (parent->d_inode,d);pr_debug (" o %s removing done (%d)\n" ,d->d_name.name,atomic_read (&d->d_count));mutex_unlock (&parent->d_inode->i_mutex); -dput (parent); +sysfs_drop_dentry (sd);sysfs_deactivate (sd);sysfs_put (sd); }
@@ -404,7 +401,6 @@ static void __sysfs_remove_dir(struct dentry *dentry)struct sysfs_dirent * parent_sd;struct sysfs_dirent * sd, * tmp; -dget (dentry);if (!dentry)return ;
@@ -415,21 +411,17 @@ static void __sysfs_remove_dir(struct dentry *dentry)if (!sd->s_type || !(sd->s_type &SYSFS_NOT_PINNED ))continue ;list_move (&sd->s_sibling, &removed); -sysfs_drop_dentry (sd, dentry); }mutex_unlock (&dentry->d_inode->i_mutex);list_for_each_entry_safe (sd, tmp, &removed, s_sibling) {list_del_init (&sd->s_sibling); +sysfs_drop_dentry (sd);sysfs_deactivate (sd);sysfs_put (sd); }remove_dir (dentry); -/** -* Drop reference from dget() on entrance. -*/ -dput (dentry); }/**
fs/sysfs/inode.c +61 -21
118 lines not on this page · raw message
fs/sysfs/sysfs.h +1 -1
@@ -76,7 +76,7 @@ extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * naextern int sysfs_create_subdir (struct kobject *,const char *,struct dentry **);extern void sysfs_remove_subdir (struct dentry *); -extern void sysfs_drop_dentry (struct sysfs_dirent *sd,struct dentry *parent); +extern void sysfs_drop_dentry (struct sysfs_dirent *sd);extern int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);extern spinlock_t sysfs_lock;
Signature · 1 line
1.5.2.2
PATCH 39/61 sysfs: kill unnecessary attribute->owner
From: Tejun Heo <[email protected]>
sysfs is now completely out of driver/module lifetime game. After deletion, a sysfs node doesn't access anything outside sysfs proper, so there's no reason to hold onto the attribute owners. Note that often the wrong modules were accounted for as owners leading to accessing removed modules.
This patch kills now unnecessary attribute->owner. Note that with this change, userland holding a sysfs node does not prevent the backing module from being unloaded.
For more info regarding lifetime rule cleanup, please read the following message.
http://article.gmane.org/gmane.linux.kernel/510293
(tweaked by Greg to not delete the field just yet, to make it easier to merge things properly.)
--- arch/ppc/syslib/mv64x60.c | 1 - arch/s390/kernel/ipl.c | 2 -- drivers/base/bus.c | 2 -- drivers/base/class.c | 2 -- drivers/base/core.c | 4 ---- drivers/base/firmware_class.c | 2 +- drivers/block/pktcdvd.c | 3 +-- drivers/char/ipmi/ipmi_msghandler.c | 10 ---------- drivers/cpufreq/cpufreq_stats.c | 3 +-- drivers/cpufreq/cpufreq_userspace.c | 2 +- drivers/cpufreq/freq_table.c | 1 - drivers/firmware/dcdbas.h | 3 +-- drivers/firmware/dell_rbu.c | 6 +++--- drivers/firmware/edd.c | 2 +- drivers/firmware/efivars.c | 6 +++--- drivers/i2c/chips/eeprom.c | 1 - drivers/i2c/chips/max6875.c | 1 - drivers/infiniband/core/sysfs.c | 1 - drivers/input/mouse/psmouse.h | 1 - drivers/macintosh/windfarm_core.c | 2 -- drivers/misc/asus-laptop.c | 3 +-- drivers/net/ibmveth.c | 2 +- drivers/parisc/pdc_stable.c | 4 ++-- drivers/pci/hotplug/acpiphp_ibm.c | 1 - drivers/pci/pci-sysfs.c | 4 ---- drivers/pci/probe.c | 2 -- drivers/pcmcia/socket_sysfs.c | 2 +- drivers/rapidio/rio-sysfs.c | 1 - drivers/rtc/rtc-ds1553.c | 1 - drivers/rtc/rtc-ds1742.c | 1 - drivers/s390/cio/chp.c | 2 -- drivers/s390/net/qeth_sys.c | 2 +- drivers/scsi/arcmsr/arcmsr_attr.c | 3 --- drivers/scsi/libsas/sas_expander.c | 1 - drivers/scsi/lpfc/lpfc_attr.c | 2 -- drivers/scsi/qla2xxx/qla_attr.c | 6 ------ drivers/spi/at25.c | 1 - drivers/video/aty/radeon_base.c | 2 -- drivers/video/backlight/backlight.c | 2 +- drivers/video/backlight/lcd.c | 2 +- drivers/w1/slaves/w1_ds2433.c | 1 - drivers/w1/slaves/w1_therm.c | 1 - drivers/w1/w1.c | 2 -- drivers/zorro/zorro-sysfs.c | 1 - fs/ecryptfs/main.c | 2 -- fs/ocfs2/cluster/masklog.c | 1 - fs/partitions/check.c | 1 - fs/sysfs/bin.c | 19 +++++-------------- fs/sysfs/file.c | 21 +++++---------------- include/linux/sysdev.h | 3 +-- include/linux/sysfs.h | 12 ++++++++---- kernel/module.c | 9 +++------ kernel/params.c | 1 - net/bridge/br_sysfs_br.c | 3 +-- net/bridge/br_sysfs_if.c | 3 +-- 55 files changed, 44 insertions(+), 135 deletions(-)
arch/ppc/syslib/mv64x60.c +0 -1
@@ -2415,7 +2415,6 @@ static struct bin_attribute mv64xxx_hs_reg_attr = { /* Hotswap register */ .attr = { .name = "hs_reg", .mode = S_IRUGO | S_IWUSR, - .owner = THIS_MODULE, }, .size = VAL_LEN_MAX, .read = mv64xxx_hs_reg_read,
arch/s390/kernel/ipl.c +0 -2
@@ -312,7 +312,6 @@ static struct bin_attribute ipl_parameter_attr = { .attr = { .name = "binary_parameter", .mode = S_IRUGO, - .owner = THIS_MODULE, }, .size = PAGE_SIZE, .read = &ipl_parameter_read,
@@ -336,7 +335,6 @@ static struct bin_attribute ipl_scp_data_attr = { .attr = { .name = "scp_data", .mode = S_IRUGO, - .owner = THIS_MODULE, }, .size = PAGE_SIZE, .read = &ipl_scp_data_read,
drivers/base/bus.c +0 -2
@@ -574,7 +574,6 @@ static int add_probe_files(struct bus_type *bus) bus->drivers_probe_attr.attr.name ="drivers_probe" ; bus->drivers_probe_attr.attr.mode =S_IWUSR ; - bus->drivers_probe_attr.attr.owner = bus->owner; bus->drivers_probe_attr.store = store_drivers_probe; retval =bus_create_file (bus, &bus->drivers_probe_attr);if (retval)
@@ -582,7 +581,6 @@ static int add_probe_files(struct bus_type *bus) bus->drivers_autoprobe_attr.attr.name ="drivers_autoprobe" ; bus->drivers_autoprobe_attr.attr.mode =S_IWUSR |S_IRUGO ; - bus->drivers_autoprobe_attr.attr.owner = bus->owner; bus->drivers_autoprobe_attr.show = show_drivers_autoprobe; bus->drivers_autoprobe_attr.store = store_drivers_autoprobe; retval =bus_create_file (bus, &bus->drivers_autoprobe_attr);
drivers/base/class.c +0 -2
@@ -605,7 +605,6 @@ int class_device_add(struct class_device *class_dev) goto out3; class_dev->uevent_attr.attr.name ="uevent" ; class_dev->uevent_attr.attr.mode =S_IWUSR ; - class_dev->uevent_attr.attr.owner = parent_class->owner; class_dev->uevent_attr.store = store_uevent; error =class_device_create_file (class_dev, &class_dev->uevent_attr);if (error)
@@ -620,7 +619,6 @@ int class_device_add(struct class_device *class_dev) } attr->attr.name ="dev" ; attr->attr.mode =S_IRUGO ; - attr->attr.owner = parent_class->owner; attr->show = show_dev; error =class_device_create_file (class_dev, attr);if (error) {
drivers/base/core.c +0 -4
@@ -683,8 +683,6 @@ int device_add(struct device *dev) dev->uevent_attr.attr.name ="uevent" ; dev->uevent_attr.attr.mode =S_IRUGO |S_IWUSR ; -if (dev->driver) - dev->uevent_attr.attr.owner = dev->driver->owner; dev->uevent_attr.store = store_uevent; dev->uevent_attr.show = show_uevent; error =device_create_file (dev, &dev->uevent_attr);
@@ -700,8 +698,6 @@ int device_add(struct device *dev) } attr->attr.name ="dev" ; attr->attr.mode =S_IRUGO ; -if (dev->driver) - attr->attr.owner = dev->driver->owner; attr->show = show_dev; error =device_create_file (dev, attr);if (error) {
drivers/base/firmware_class.c +1 -1
@@ -271,7 +271,7 @@ out: }static struct bin_attribute firmware_attr_data_tmpl = { - .attr = {.name ="data" , .mode =0644 , .owner =THIS_MODULE }, + .attr = {.name ="data" , .mode =0644 }, .size =0 , .read = firmware_data_read, .write = firmware_data_write,
drivers/block/pktcdvd.c +1 -2
@@ -146,8 +146,7 @@ static void pkt_kobj_release(struct kobject *kobj)**********************************************************/ #define DEF_ATTR (_obj,_name,_mode) \ - static struct attribute _obj = { \ - .name = _name, .owner = THIS_MODULE, .mode = _mode } + static struct attribute _obj = { .name = _name, .mode = _mode }/********************************************************** /sys/class/pktcdvd/pktcdvd[0-7]/
drivers/char/ipmi/ipmi_msghandler.c +0 -10
@@ -2171,52 +2171,42 @@ static int create_files(struct bmc_device *bmc)int err; bmc->device_id_attr.attr.name ="device_id" ; - bmc->device_id_attr.attr.owner =THIS_MODULE ; bmc->device_id_attr.attr.mode =S_IRUGO ; bmc->device_id_attr.show = device_id_show; bmc->provides_dev_sdrs_attr.attr.name ="provides_device_sdrs" ; - bmc->provides_dev_sdrs_attr.attr.owner =THIS_MODULE ; bmc->provides_dev_sdrs_attr.attr.mode =S_IRUGO ; bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show; bmc->revision_attr.attr.name ="revision" ; - bmc->revision_attr.attr.owner =THIS_MODULE ; bmc->revision_attr.attr.mode =S_IRUGO ; bmc->revision_attr.show = revision_show; bmc->firmware_rev_attr.attr.name ="firmware_revision" ; - bmc->firmware_rev_attr.attr.owner =THIS_MODULE ; bmc->firmware_rev_attr.attr.mode =S_IRUGO ; bmc->firmware_rev_attr.show = firmware_rev_show; bmc->version_attr.attr.name ="ipmi_version" ; - bmc->version_attr.attr.owner =THIS_MODULE ; bmc->version_attr.attr.mode =S_IRUGO ; bmc->version_attr.show = ipmi_version_show; bmc->add_dev_support_attr.attr.name ="additional_device_support" ; - bmc->add_dev_support_attr.attr.owner =THIS_MODULE ; bmc->add_dev_support_attr.attr.mode =S_IRUGO ; bmc->add_dev_support_attr.show = add_dev_support_show; bmc->manufacturer_id_attr.attr.name ="manufacturer_id" ; - bmc->manufacturer_id_attr.attr.owner =THIS_MODULE ; bmc->manufacturer_id_attr.attr.mode =S_IRUGO ; bmc->manufacturer_id_attr.show = manufacturer_id_show; bmc->product_id_attr.attr.name ="product_id" ; - bmc->product_id_attr.attr.owner =THIS_MODULE ; bmc->product_id_attr.attr.mode =S_IRUGO ; bmc->product_id_attr.show = product_id_show; bmc->guid_attr.attr.name ="guid" ; - bmc->guid_attr.attr.owner =THIS_MODULE ; bmc->guid_attr.attr.mode =S_IRUGO ; bmc->guid_attr.show = guid_show; bmc->aux_firmware_rev_attr.attr.name ="aux_firmware_revision" ; - bmc->aux_firmware_rev_attr.attr.owner =THIS_MODULE ; bmc->aux_firmware_rev_attr.attr.mode =S_IRUGO ; bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
drivers/cpufreq/cpufreq_stats.c +1 -2
@@ -25,8 +25,7 @@ static spinlock_t cpufreq_stats_lock;#define CPUFREQ_STATDEVICE_ATTR (_name,_mode,_show) \ static struct freq_attr _attr_##_name = {\ - .attr = {.name = __stringify(_name), .owner = THIS_MODULE, \ - .mode = _mode, }, \ + .attr = {.name = __stringify(_name), .mode = _mode, }, \ .show = _show,\ };
drivers/cpufreq/cpufreq_userspace.c +1 -1
@@ -120,7 +120,7 @@ store_speed (struct cpufreq_policy *policy, const char *buf, size_t count)static struct freq_attr freq_attr_scaling_setspeed = { - .attr = { .name ="scaling_setspeed" , .mode =0644 , .owner =THIS_MODULE }, + .attr = { .name ="scaling_setspeed" , .mode =0644 }, .show = show_speed, .store = store_speed, };
drivers/cpufreq/freq_table.c +0 -1
@@ -199,7 +199,6 @@ static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { .attr = { .name ="scaling_available_frequencies" , .mode =0444 , - .owner=THIS_MODULE }, .show = show_available_freqs, };
drivers/firmware/dcdbas.h +1 -2
@@ -67,8 +67,7 @@#define DCDBAS_BIN_ATTR_RW (_name) \ struct bin_attribute bin_attr_##_name = { \ .attr = { .name = __stringify(_name), \ - .mode = 0600, \ - .owner = THIS_MODULE }, \ + .mode = 0600 }, \ .read = _name##_read, \ .write = _name##_write, \ }
drivers/firmware/dell_rbu.c +3 -3
@@ -687,18 +687,18 @@ static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer, }static struct bin_attribute rbu_data_attr = { - .attr = {.name ="data" ,.owner =THIS_MODULE ,.mode =0444 }, + .attr = {.name ="data" , .mode =0444 }, .read = read_rbu_data, };static struct bin_attribute rbu_image_type_attr = { - .attr = {.name ="image_type" ,.owner =THIS_MODULE ,.mode =0644 }, + .attr = {.name ="image_type" , .mode =0644 }, .read = read_rbu_image_type, .write = write_rbu_image_type, };static struct bin_attribute rbu_packet_size_attr = { - .attr = {.name ="packet_size" ,.owner =THIS_MODULE ,.mode =0644 }, + .attr = {.name ="packet_size" , .mode =0644 }, .read = read_rbu_packet_size, .write = write_rbu_packet_size, };
drivers/firmware/edd.c +1 -1
@@ -74,7 +74,7 @@ static struct edd_device *edd_devices[EDD_MBR_SIG_MAX];#define EDD_DEVICE_ATTR (_name,_mode,_show,_test) \ struct edd_attribute edd_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .test = _test, \ };
drivers/firmware/efivars.c +3 -3
@@ -131,21 +131,21 @@ struct efivar_attribute {#define EFI_ATTR (_name, _mode, _show, _store) \ struct subsys_attribute efi_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \ + .attr = {.name = __stringify(_name), .mode = _mode}, \ .show = _show, \ .store = _store, \ };#define EFIVAR_ATTR (_name, _mode, _show, _store) \ struct efivar_attribute efivar_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \ + .attr = {.name = __stringify(_name), .mode = _mode}, \ .show = _show, \ .store = _store, \ };#define VAR_SUBSYS_ATTR (_name, _mode, _show, _store) \ struct subsys_attribute var_subsys_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \ + .attr = {.name = __stringify(_name), .mode = _mode}, \ .show = _show, \ .store = _store, \ };
drivers/i2c/chips/eeprom.c +0 -1
@@ -143,7 +143,6 @@ static struct bin_attribute eeprom_attr = { .attr = { .name = "eeprom", .mode = S_IRUGO, - .owner = THIS_MODULE, }, .size = EEPROM_SIZE, .read = eeprom_read,
drivers/i2c/chips/max6875.c +0 -1
@@ -152,7 +152,6 @@ static struct bin_attribute user_eeprom_attr = { .attr = { .name = "eeprom", .mode = S_IRUGO, - .owner = THIS_MODULE, }, .size = USER_EEPROM_SIZE, .read = max6875_read,
drivers/infiniband/core/sysfs.c +0 -1
@@ -479,7 +479,6 @@ alloc_group_attrs(ssize_t (*show)(struct ib_port *, element->attr.attr.name = element->name; element->attr.attr.mode =S_IRUGO ; - element->attr.attr.owner =THIS_MODULE ; element->attr.show = show; element->index = i;
drivers/input/mouse/psmouse.h +0 -1
@@ -119,7 +119,6 @@ static struct psmouse_attribute psmouse_attr_##_name = { \ .attr = { \ .name = __stringify(_name), \ .mode = _mode, \ - .owner = THIS_MODULE, \ }, \ .show = psmouse_attr_show_helper, \ .store = psmouse_attr_set_helper, \
drivers/macintosh/windfarm_core.c +0 -2
@@ -212,7 +212,6 @@ int wf_register_control(struct wf_control *new_ct)list_add (&new_ct->link, &wf_controls); new_ct->attr.attr.name = new_ct->name; - new_ct->attr.attr.owner =THIS_MODULE ; new_ct->attr.attr.mode =0644 ; new_ct->attr.show = wf_show_control; new_ct->attr.store = wf_store_control;
@@ -325,7 +324,6 @@ int wf_register_sensor(struct wf_sensor *new_sr)list_add (&new_sr->link, &wf_sensors); new_sr->attr.attr.name = new_sr->name; - new_sr->attr.attr.owner =THIS_MODULE ; new_sr->attr.attr.mode =0444 ; new_sr->attr.show = wf_show_sensor; new_sr->attr.store =NULL ;
drivers/misc/asus-laptop.c +1 -2
@@ -737,8 +737,7 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) struct device_attribute dev_attr_##_name = { \ .attr = { \ .name =__stringify (_name), \ - .mode =0 , \ - .owner =THIS_MODULE }, \ + .mode =0 }, \ .show =NULL , \ .store =NULL , \ }
drivers/net/ibmveth.c +1 -1
@@ -1337,7 +1337,7 @@ const char * buf, size_t count)#define ATTR (_name, _mode) \ struct attribute veth_##_name##_attr = { \ - .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE \ + .name = __stringify(_name), .mode = _mode, \ }; static ATTR(active, 0644);
drivers/parisc/pdc_stable.c +2 -2
@@ -121,14 +121,14 @@ struct pdcspath_entry pdcspath_entry_##_name = { \#define PDCS_ATTR (_name, _mode, _show, _store) \ struct subsys_attribute pdcs_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \ + .attr = {.name = __stringify(_name), .mode = _mode}, \ .show = _show, \ .store = _store, \ };#define PATHS_ATTR (_name, _mode, _show, _store) \ struct pdcspath_attribute paths_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \ + .attr = {.name = __stringify(_name), .mode = _mode}, \ .show = _show, \ .store = _store, \ };
drivers/pci/hotplug/acpiphp_ibm.c +0 -1
@@ -117,7 +117,6 @@ static struct notification ibm_note;static struct bin_attribute ibm_apci_table_attr = { .attr = { .name ="apci_table" , - .owner =THIS_MODULE , .mode =S_IRUGO , }, .read = ibm_read_apci_table,
drivers/pci/pci-sysfs.c +0 -4
@@ -499,7 +499,6 @@ static int pci_create_resource_files(struct pci_dev *pdev)sprintf (res_attr_name,"resource%d" , i); res_attr->attr.name = res_attr_name; res_attr->attr.mode =S_IRUSR |S_IWUSR ; - res_attr->attr.owner =THIS_MODULE ; res_attr->size =pci_resource_len (pdev, i); res_attr->mmap = pci_mmap_resource; res_attr->private = &pdev->resource[i];
@@ -582,7 +581,6 @@ static struct bin_attribute pci_config_attr = { .attr = { .name = "config", .mode = S_IRUGO | S_IWUSR, - .owner = THIS_MODULE, }, .size = 256, .read = pci_read_config,
@@ -593,7 +591,6 @@ static struct bin_attribute pcie_config_attr = { .attr = { .name = "config", .mode = S_IRUGO | S_IWUSR, - .owner = THIS_MODULE, }, .size = 4096, .read = pci_read_config,
@@ -628,7 +625,6 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) rom_attr->size =pci_resource_len (pdev,PCI_ROM_RESOURCE ); rom_attr->attr.name ="rom" ; rom_attr->attr.mode =S_IRUSR ; - rom_attr->attr.owner =THIS_MODULE ; rom_attr->read = pci_read_rom; rom_attr->write = pci_write_rom; retval =sysfs_create_bin_file (&pdev->dev.kobj, rom_attr);
drivers/pci/probe.c +0 -2
@@ -39,7 +39,6 @@ static void pci_create_legacy_files(struct pci_bus *b) b->legacy_io->attr.name ="legacy_io" ; b->legacy_io->size =0xffff ; b->legacy_io->attr.mode =S_IRUSR |S_IWUSR ; - b->legacy_io->attr.owner =THIS_MODULE ; b->legacy_io->read = pci_read_legacy_io; b->legacy_io->write = pci_write_legacy_io;class_device_create_bin_file (&b->class_dev, b->legacy_io);
@@ -49,7 +48,6 @@ static void pci_create_legacy_files(struct pci_bus *b) b->legacy_mem->attr.name ="legacy_mem" ; b->legacy_mem->size =1024 *1024 ; b->legacy_mem->attr.mode =S_IRUSR |S_IWUSR ; - b->legacy_mem->attr.owner =THIS_MODULE ; b->legacy_mem->mmap = pci_mmap_legacy_mem;class_device_create_bin_file (&b->class_dev, b->legacy_mem); }
drivers/pcmcia/socket_sysfs.c +1 -1
@@ -366,7 +366,7 @@ static struct device_attribute *pccard_socket_attributes[] = { };static struct bin_attribute pccard_cis_attr = { - .attr = { .name ="cis" , .mode =S_IRUGO |S_IWUSR , .owner =THIS_MODULE }, + .attr = { .name ="cis" , .mode =S_IRUGO |S_IWUSR }, .size =0x200 , .read = pccard_show_cis, .write = pccard_store_cis,
drivers/rapidio/rio-sysfs.c +0 -1
@@ -197,7 +197,6 @@ static struct bin_attribute rio_config_attr = { .attr = { .name = "config", .mode =S_IRUGO |S_IWUSR , - .owner =THIS_MODULE , }, .size = 0x200000, .read = rio_read_config,
drivers/rtc/rtc-ds1553.c +0 -1
@@ -290,7 +290,6 @@ static struct bin_attribute ds1553_nvram_attr = { .attr = { .name = "nvram", .mode = S_IRUGO | S_IWUGO, - .owner = THIS_MODULE, }, .size = RTC_OFFSET, .read = ds1553_nvram_read,
drivers/rtc/rtc-ds1742.c +0 -1
@@ -159,7 +159,6 @@ static struct bin_attribute ds1742_nvram_attr = { .attr = { .name = "nvram", .mode = S_IRUGO | S_IWUGO, - .owner = THIS_MODULE, }, .read = ds1742_nvram_read, .write = ds1742_nvram_write,
drivers/s390/cio/chp.c +0 -2
@@ -165,7 +165,6 @@ static struct bin_attribute chp_measurement_chars_attr = { .attr = { .name = "measurement_chars", .mode = S_IRUSR, - .owner = THIS_MODULE, }, .size = sizeof(struct cmg_chars), .read = chp_measurement_chars_read,
@@ -217,7 +216,6 @@ static struct bin_attribute chp_measurement_attr = { .attr = { .name = "measurement", .mode = S_IRUSR, - .owner = THIS_MODULE, }, .size = sizeof(struct cmg_entry), .read = chp_measurement_read,
drivers/s390/net/qeth_sys.c +1 -1
@@ -991,7 +991,7 @@ static struct attribute_group qeth_osn_device_attr_group = {#define QETH_DEVICE_ATTR (_id,_name,_mode,_show,_store) \ struct device_attribute dev_attr_##_id = { \ - .attr = {.name=__stringify(_name), .mode=_mode, .owner=THIS_MODULE },\ + .attr = {.name=__stringify(_name), .mode=_mode, },\ .show = _show, \ .store = _store, \ };
drivers/scsi/arcmsr/arcmsr_attr.c +0 -3
@@ -188,7 +188,6 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = { .attr = { .name = "mu_read", .mode = S_IRUSR , - .owner = THIS_MODULE, }, .size = 1032, .read = arcmsr_sysfs_iop_message_read,
@@ -198,7 +197,6 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = { .attr = { .name = "mu_write", .mode = S_IWUSR, - .owner = THIS_MODULE, }, .size = 1032, .write = arcmsr_sysfs_iop_message_write,
@@ -208,7 +206,6 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = { .attr = { .name = "mu_clear", .mode = S_IWUSR, - .owner = THIS_MODULE, }, .size = 1, .write = arcmsr_sysfs_iop_message_clear,
drivers/scsi/libsas/sas_expander.c +0 -1
@@ -1368,7 +1368,6 @@ static void sas_ex_smp_hook(struct domain_device *dev)memset (bin_attr,0 ,sizeof (*bin_attr)); bin_attr->attr.name =SMP_BIN_ATTR_NAME ; - bin_attr->attr.owner =THIS_MODULE ; bin_attr->attr.mode =0600 ; bin_attr->size =0 ;
drivers/scsi/lpfc/lpfc_attr.c +0 -2
@@ -1200,7 +1200,6 @@ static struct bin_attribute sysfs_ctlreg_attr = { .attr = { .name = "ctlreg", .mode = S_IRUSR | S_IWUSR, - .owner = THIS_MODULE, }, .size = 256, .read = sysfs_ctlreg_read,
@@ -1422,7 +1421,6 @@ static struct bin_attribute sysfs_mbox_attr = { .attr = { .name = "mbox", .mode = S_IRUSR | S_IWUSR, - .owner = THIS_MODULE, }, .size = MAILBOX_CMD_SIZE, .read = sysfs_mbox_read,
drivers/scsi/qla2xxx/qla_attr.c +0 -6
@@ -73,7 +73,6 @@ static struct bin_attribute sysfs_fw_dump_attr = { .attr = { .name = "fw_dump", .mode = S_IRUSR | S_IWUSR, - .owner = THIS_MODULE, }, .size = 0, .read = qla2x00_sysfs_read_fw_dump,
@@ -149,7 +148,6 @@ static struct bin_attribute sysfs_nvram_attr = { .attr = { .name = "nvram", .mode = S_IRUSR | S_IWUSR, - .owner = THIS_MODULE, }, .size = 512, .read = qla2x00_sysfs_read_nvram,
@@ -198,7 +196,6 @@ static struct bin_attribute sysfs_optrom_attr = { .attr = { .name = "optrom", .mode = S_IRUSR | S_IWUSR, - .owner = THIS_MODULE, }, .size = OPTROM_SIZE_24XX, .read = qla2x00_sysfs_read_optrom,
@@ -279,7 +276,6 @@ static struct bin_attribute sysfs_optrom_ctl_attr = { .attr = { .name = "optrom_ctl", .mode = S_IWUSR, - .owner = THIS_MODULE, }, .size = 0, .write = qla2x00_sysfs_write_optrom_ctl,
@@ -327,7 +323,6 @@ static struct bin_attribute sysfs_vpd_attr = { .attr = { .name = "vpd", .mode = S_IRUSR | S_IWUSR, - .owner = THIS_MODULE, }, .size = 0, .read = qla2x00_sysfs_read_vpd,
@@ -375,7 +370,6 @@ static struct bin_attribute sysfs_sfp_attr = { .attr = { .name = "sfp", .mode = S_IRUSR | S_IWUSR, - .owner = THIS_MODULE, }, .size = SFP_DEV_SIZE * 2, .read = qla2x00_sysfs_read_sfp,
drivers/spi/at25.c +0 -1
@@ -314,7 +314,6 @@ static int at25_probe(struct spi_device *spi)*/ at25->bin.attr.name ="eeprom" ; at25->bin.attr.mode =S_IRUSR ; - at25->bin.attr.owner =THIS_MODULE ; at25->bin.read = at25_bin_read; at25->bin.size = at25->chip.byte_len;
drivers/video/aty/radeon_base.c +0 -2
@@ -2126,7 +2126,6 @@ static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, sistatic struct bin_attribute edid1_attr = { .attr = { .name ="edid1" , - .owner =THIS_MODULE , .mode =0444 , }, .size =EDID_LENGTH ,
@@ -2136,7 +2135,6 @@ static struct bin_attribute edid1_attr = {static struct bin_attribute edid2_attr = { .attr = { .name ="edid2" , - .owner =THIS_MODULE , .mode =0444 , }, .size =EDID_LENGTH ,
drivers/video/backlight/backlight.c +1 -1
@@ -172,7 +172,7 @@ static struct class backlight_class = {#define DECLARE_ATTR (_name,_mode,_show,_store) \ { \ - .attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }
drivers/video/backlight/lcd.c +1 -1
@@ -157,7 +157,7 @@ static struct class lcd_class = {#define DECLARE_ATTR (_name,_mode,_show,_store) \ { \ - .attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }
drivers/w1/slaves/w1_ds2433.c +0 -1
@@ -252,7 +252,6 @@ static struct bin_attribute w1_f23_bin_attr = { .attr = { .name = "eeprom", .mode = S_IRUGO | S_IWUSR, - .owner = THIS_MODULE, }, .size = W1_EEPROM_SIZE, .read = w1_f23_read_bin,
drivers/w1/slaves/w1_therm.c +0 -1
@@ -48,7 +48,6 @@ static struct bin_attribute w1_therm_bin_attr = { .attr = { .name = "w1_slave", .mode = S_IRUGO, - .owner = THIS_MODULE, }, .size = W1_SLAVE_DATA_SIZE, .read = w1_therm_read_bin,
drivers/w1/w1.c +0 -2
@@ -128,7 +128,6 @@ static struct bin_attribute w1_slave_attr_bin_id = { .attr = { .name = "id", .mode = S_IRUGO, - .owner = THIS_MODULE, }, .size = 8, .read = w1_slave_read_id,
@@ -167,7 +166,6 @@ static struct bin_attribute w1_default_attr = { .attr = { .name = "rw", .mode = S_IRUGO | S_IWUSR, - .owner = THIS_MODULE, }, .size = PAGE_SIZE, .read = w1_default_read,
drivers/zorro/zorro-sysfs.c +0 -1
@@ -78,7 +78,6 @@ static struct bin_attribute zorro_config_attr = { .attr = { .name = "config", .mode = S_IRUGO | S_IWUSR, - .owner =THIS_MODULE }, .size = sizeof(struct ConfigDev), .read = zorro_read_config,
fs/ecryptfs/main.c +0 -2
@@ -840,8 +840,6 @@ static int __init ecryptfs_init(void) goto out; }kobj_set_kset_s (&ecryptfs_subsys, fs_subsys); - sysfs_attr_version.attr.owner =THIS_MODULE ; - sysfs_attr_version_str.attr.owner =THIS_MODULE ; rc =do_sysfs_registration ();if (rc) {printk (KERN_ERR "sysfs registration failed\n" );
fs/ocfs2/cluster/masklog.c +0 -1
@@ -74,7 +74,6 @@ struct mlog_attribute {#define define_mask (_name) { \ .attr = { \ .name = #_name, \ - .owner = THIS_MODULE, \ .mode = S_IRUGO | S_IWUSR, \ }, \ .mask = ML_##_name, \
fs/partitions/check.c +0 -1
@@ -397,7 +397,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,static struct attribute addpartattr = { .name ="whole_disk" , .mode =S_IRUSR |S_IRGRP |S_IROTH , - .owner =THIS_MODULE , };sysfs_create_file (&p->kobj, &addpartattr);
fs/sysfs/bin.c +5 -14
@@ -175,25 +175,20 @@ static int open(struct inode * inode, struct file * file)if (!sysfs_get_active (attr_sd))return -ENODEV ; -/* Grab the module reference for this attribute */ - error = -ENODEV ; -if (!try_module_get (attr->attr.owner)) - goto err_sput; - error = -EACCES ;if ((file->f_mode &FMODE_WRITE ) && !(attr->write || attr->mmap)) - goto err_mput; + goto err_out;if ((file->f_mode &FMODE_READ ) && !(attr->read || attr->mmap)) - goto err_mput; + goto err_out; error = -ENOMEM ; bb =kzalloc (sizeof (*bb),GFP_KERNEL );if (!bb) - goto err_mput; + goto err_out; bb->buffer =kmalloc (PAGE_SIZE ,GFP_KERNEL );if (!bb->buffer) - goto err_mput; + goto err_out;mutex_init (&bb->mutex); file->private_data = bb;
@@ -203,9 +198,7 @@ static int open(struct inode * inode, struct file * file)sysfs_get (attr_sd);return 0 ; - err_mput: -module_put (attr->attr.owner); - err_sput: + err_out:sysfs_put_active (attr_sd);kfree (bb);return error;
@@ -214,13 +207,11 @@ static int open(struct inode * inode, struct file * file)static int release (struct inode * inode,struct file * file) {struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; -struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;struct bin_buffer *bb = file->private_data;if (bb->mmapped)sysfs_put_active_two (attr_sd);sysfs_put (attr_sd); -module_put (attr->attr.owner);kfree (bb->buffer);kfree (bb);return 0 ;
fs/sysfs/file.c +5 -16
@@ -241,7 +241,6 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_tstatic int sysfs_open_file (struct inode *inode,struct file *file) {struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; -struct attribute *attr = attr_sd->s_elem.attr.attr;struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;struct sysfs_buffer * buffer;struct sysfs_ops * ops =NULL ;
@@ -251,11 +250,6 @@ static int sysfs_open_file(struct inode *inode, struct file *file)if (!sysfs_get_active_two (attr_sd))return -ENODEV ; -/* Grab the module reference for this attribute */ - error = -ENODEV ; -if (!try_module_get (attr->owner)) - goto err_sput; -/* if the kobject has no ktype, then we assume that it is a subsystem * itself, and use ops for it. */
@@ -272,7 +266,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file)* or the subsystem have no operations. */ if (!ops) - goto err_mput; + goto err_out;/* File needs write support. * The inode's perms must say it's ok,
@@ -280,7 +274,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file)*/ if (file->f_mode &FMODE_WRITE ) {if (!(inode->i_mode &S_IWUGO ) || !ops->store) - goto err_mput; + goto err_out; }/* File needs read support.
@@ -289,7 +283,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file)*/ if (file->f_mode &FMODE_READ ) {if (!(inode->i_mode &S_IRUGO ) || !ops->show) - goto err_mput; + goto err_out; }/* No error? Great, allocate a buffer for the file, and store it
@@ -298,7 +292,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) error = -ENOMEM ; buffer =kzalloc (sizeof (struct sysfs_buffer ),GFP_KERNEL );if (!buffer) - goto err_mput; + goto err_out;init_MUTEX (&buffer->sem); buffer->needs_read_fill =1 ;
@@ -310,9 +304,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file)sysfs_get (attr_sd);return 0 ; - err_mput: -module_put (attr->owner); - err_sput: + err_out:sysfs_put_active_two (attr_sd);return error; }
@@ -320,12 +312,9 @@ static int sysfs_open_file(struct inode *inode, struct file *file)static int sysfs_release (struct inode * inode,struct file * filp) {struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; -struct attribute *attr = attr_sd->s_elem.attr.attr;struct sysfs_buffer *buffer = filp->private_data;sysfs_put (attr_sd); -/* After this point, attr should not be accessed. */ -module_put (attr->owner);if (buffer) {if (buffer->page)
include/linux/sysdev.h +1 -2
@@ -101,8 +101,7 @@ struct sysdev_attribute {#define _SYSDEV_ATTR (_name,_mode,_show,_store) \ { \ - .attr = { .name = __stringify(_name), .mode = _mode, \ - .owner = THIS_MODULE }, \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }
include/linux/sysfs.h +8 -4
@@ -20,9 +20,13 @@ struct module;struct nameidata ;struct dentry ; +/* FIXME +* The *owner field is no longer used, but leave around +* until the tree gets cleaned up fully. +*/ struct attribute {const char * name; -struct module * owner; +struct module * owner;mode_t mode; };
@@ -39,14 +43,14 @@ struct attribute_group {*/ #define __ATTR (_name,_mode,_show,_store) { \ - .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }#define __ATTR_RO (_name) { \ - .attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \ - .show = _name##_show, \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = _name##_show, \ }#define __ATTR_NULL { .attr = { .name = NULL } }
kernel/module.c +3 -6
@@ -488,8 +488,7 @@ static void free_modinfo_##field(struct module *mod) \ mod->field =NULL ; \ } \ static struct module_attribute modinfo_##field = { \ - .attr = { .name = __stringify(field), .mode = 0444, \ - .owner = THIS_MODULE }, \ + .attr = { .name = __stringify(field), .mode = 0444 }, \ .show = show_modinfo_##field, \ .setup = setup_modinfo_##field, \ .test = modinfo_##field##_exists, \
@@ -793,7 +792,7 @@ static ssize_t show_refcnt(struct module_attribute *mattr, }static struct module_attribute refcnt = { - .attr = { .name ="refcnt" , .mode =0444 , .owner =THIS_MODULE }, + .attr = { .name ="refcnt" , .mode =0444 }, .show = show_refcnt, };
@@ -851,7 +850,7 @@ static ssize_t show_initstate(struct module_attribute *mattr, }static struct module_attribute initstate = { - .attr = { .name ="initstate" , .mode =0444 , .owner =THIS_MODULE }, + .attr = { .name ="initstate" , .mode =0444 }, .show = show_initstate, };
@@ -1032,7 +1031,6 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect, sattr->mattr.show = module_sect_show; sattr->mattr.store =NULL ; sattr->mattr.attr.name = sattr->name; - sattr->mattr.attr.owner = mod; sattr->mattr.attr.mode =S_IRUGO ; *(gattr++) = &(sattr++)->mattr.attr; }
@@ -1090,7 +1088,6 @@ int module_add_modinfo_attrs(struct module *mod)if (!attr->test || (attr->test && attr->test (mod))) {memcpy (temp_attr, attr,sizeof (*temp_attr)); - temp_attr->attr.owner = mod; error =sysfs_create_file (&mod->mkobj.kobj,&temp_attr->attr); ++temp_attr; }
kernel/params.c +0 -1
@@ -491,7 +491,6 @@ param_sysfs_setup(struct module_kobject *mk, pattr->mattr.show = param_attr_show; pattr->mattr.store = param_attr_store; pattr->mattr.attr.name = (char *)&kp->name[name_skip]; - pattr->mattr.attr.owner = mk->mod; pattr->mattr.attr.mode = kp->perm; *(gattr++) = &(pattr++)->mattr.attr; }
net/bridge/br_sysfs_br.c +1 -2
@@ -383,8 +383,7 @@ static ssize_t brforward_read(struct kobject *kobj, char *buf,static struct bin_attribute bridge_forward = { .attr = { .name =SYSFS_BRIDGE_FDB , - .mode =S_IRUGO , - .owner =THIS_MODULE , }, + .mode =S_IRUGO , }, .read = brforward_read, };
net/bridge/br_sysfs_if.c +1 -2
@@ -29,8 +29,7 @@ struct brport_attribute {#define BRPORT_ATTR (_name,_mode,_show,_store) \ struct brport_attribute brport_attr_##_name = { \ .attr = {.name = __stringify(_name), \ - .mode = _mode, \ - .owner = THIS_MODULE, }, \ + .mode = _mode }, \ .show = _show, \ .store = _store, \ };
Signature · 1 line
1.5.2.2
PATCH 40/61 driver-core: make devt_attr and uevent_attr static
From: Tejun Heo <[email protected]>
devt_attr and uevent_attr are either allocated dynamically with or embedded in device and class_device as they needed their owner field set to the module implementing the driver. Now that sysfs implements immediate disconnect and owner field removed from struct attribute, there is no reason to do this. Remove these attributes from [class_]device and use static attribute structures instead.
--- drivers/base/class.c | 44 ++++++++++++++++---------------------------- drivers/base/core.c | 45 +++++++++++++++------------------------------ include/linux/device.h | 5 ----- 3 files changed, 31 insertions(+), 63 deletions(-)
drivers/base/class.c +16 -28
@@ -312,9 +312,6 @@ static void class_dev_release(struct kobject * kobj)pr_debug ("device class '%s': release.\n" , cd->class_id); -kfree (cd->devt_attr); - cd->devt_attr =NULL ; -if (cd->release) cd->release (cd);else if (cls->release)
@@ -547,6 +544,9 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf)return print_dev_t (buf, class_dev->devt); } +static struct class_device_attribute class_devt_attr = +__ATTR (dev,S_IRUGO , show_dev,NULL ); +static ssize_t store_uevent (struct class_device *class_dev,const char *buf,size_t count) {
@@ -554,6 +554,9 @@ static ssize_t store_uevent(struct class_device *class_dev,return count; } +static struct class_device_attribute class_uevent_attr = +__ATTR (uevent,S_IWUSR ,NULL , store_uevent); +void class_device_initialize (struct class_device *class_dev) {kobj_set_kset_s (class_dev, class_obj_subsys);
@@ -603,30 +606,15 @@ int class_device_add(struct class_device *class_dev) &parent_class->subsys.kobj, "subsystem");if (error) goto out3; - class_dev->uevent_attr.attr.name ="uevent" ; - class_dev->uevent_attr.attr.mode =S_IWUSR ; - class_dev->uevent_attr.store = store_uevent; - error =class_device_create_file (class_dev, &class_dev->uevent_attr); + + error =class_device_create_file (class_dev, &class_uevent_attr);if (error) goto out3;if (MAJOR (class_dev->devt)) { -struct class_device_attribute *attr; - attr =kzalloc (sizeof (*attr),GFP_KERNEL ); -if (!attr) { - error = -ENOMEM ; - goto out4; - } - attr->attr.name ="dev" ; - attr->attr.mode =S_IRUGO ; - attr->show = show_dev; - error =class_device_create_file (class_dev, attr); -if (error) { -kfree (attr); + error =class_device_create_file (class_dev, &class_devt_attr); +if (error) goto out4; - } - - class_dev->devt_attr = attr; } error =class_device_add_attrs (class_dev);
@@ -669,10 +657,10 @@ int class_device_add(struct class_device *class_dev) out6:class_device_remove_attrs (class_dev); out5: -if (class_dev->devt_attr) -class_device_remove_file (class_dev, class_dev->devt_attr); +if (MAJOR (class_dev->devt)) +class_device_remove_file (class_dev, &class_devt_attr); out4: -class_device_remove_file (class_dev, &class_dev->uevent_attr); +class_device_remove_file (class_dev, &class_uevent_attr); out3:kobject_del (&class_dev->kobj); out2:
@@ -772,9 +760,9 @@ void class_device_del(struct class_device *class_dev)sysfs_remove_link (&class_dev->kobj,"device" ); }sysfs_remove_link (&class_dev->kobj,"subsystem" ); -class_device_remove_file (class_dev, &class_dev->uevent_attr); -if (class_dev->devt_attr) -class_device_remove_file (class_dev, class_dev->devt_attr); +class_device_remove_file (class_dev, &class_uevent_attr); +if (MAJOR (class_dev->devt)) +class_device_remove_file (class_dev, &class_devt_attr);class_device_remove_attrs (class_dev);class_device_remove_groups (class_dev);
drivers/base/core.c +15 -30
92 lines not on this page · raw message
include/linux/device.h +0 -5
@@ -238,7 +238,6 @@ extern int __must_check class_device_create_file(struct class_device *,* @devt: for internal use by the driver core only. * @node: for internal use by the driver core only. * @kobj: for internal use by the driver core only. -* @devt_attr: for internal use by the driver core only. * @groups: optional additional groups to be created * @dev: if set, a symlink to the struct device is created in the sysfs * directory for this struct class device.
@@ -263,8 +262,6 @@ struct class_device {struct kobject kobj;struct class * class;/* required */ dev_t devt;/* dev_t, creates the sysfs "dev" */ -struct class_device_attribute *devt_attr; -struct class_device_attribute uevent_attr;struct device * dev;/* not necessary, but nice to have */ void * class_data;/* class-specific data */ struct class_device *parent;/* parent of this child device, if there is one */
@@ -419,8 +416,6 @@ struct device {struct device_type *type; unsigned is_registered:1; unsigned uevent_suppress:1; -struct device_attribute uevent_attr; -struct device_attribute *devt_attr;struct semaphore sem;/* semaphore to synchronize calls to * its driver.
Signature · 1 line
1.5.2.2
PATCH 41/61 sysfs: make sysfs_alloc_ino() static
From: Tejun Heo <[email protected]>
sysfs_alloc_ino() isn't used out side of fs/sysfs/dir.c. Make it static.
--- fs/sysfs/dir.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
fs/sysfs/dir.c +1 -1
@@ -20,7 +20,7 @@ spinlock_t kobj_sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;static spinlock_t sysfs_ino_lock =SPIN_LOCK_UNLOCKED ;static DEFINE_IDA (sysfs_ino_ida); -int sysfs_alloc_ino (ino_t *pino) +static int sysfs_alloc_ino (ino_t *pino) {int ino, rc;
Signature · 1 line
1.5.2.2
PATCH 42/61 sysfs: fix parent refcounting during rename and move
From: Tejun Heo <[email protected]>
Parent reference wasn't properly transferred during rename and move. Fix it.
--- fs/sysfs/dir.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
fs/sysfs/dir.c +6 -0
@@ -497,6 +497,9 @@ int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,d_move (kobj->dentry, new_dentry);list_del_init (&sd->s_sibling); +sysfs_get (parent_sd); +sysfs_put (sd->s_parent); + sd->s_parent = parent_sd;list_add (&sd->s_sibling, &parent_sd->s_children); error =0 ;
@@ -550,6 +553,9 @@ again:/* Remove from old parent's list and insert into new parent's list. */ list_del_init (&sd->s_sibling); +sysfs_get (new_parent_sd); +sysfs_put (sd->s_parent); + sd->s_parent = new_parent_sd;list_add (&sd->s_sibling, &new_parent_sd->s_children); out:
Signature · 1 line
1.5.2.2
PATCH 43/61 sysfs: reorganize sysfs_new_indoe() and sysfs_create()
From: Tejun Heo <[email protected]>
Reorganize/clean up sysfs_new_inode() and sysfs_create().
* sysfs_init_inode() is separated out from sysfs_new_inode() and is responsible for basic initialization.
* sysfs_instantiate() replaces the last step of sysfs_create() and is responsible for dentry instantitaion.
* type-specific initialization is moved out to the callers.
* mode is specified only once when creating a sysfs_dirent.
* spurious list_del_init(&sd->s_sibling) dropped from create_dir()
This change is to
* prepare for inode allocation fix.
* separate alloc and init code for synchronization update.
* make dentry/inode initialization more flexible for later changes.
This patch doesn't introduce visible behavior change.
--- fs/sysfs/dir.c | 130 ++++++++++++++++++++---------------------------------- fs/sysfs/inode.c | 108 ++++++++++++++++++++++++--------------------- fs/sysfs/mount.c | 18 ++++--- fs/sysfs/sysfs.h | 6 +- 4 files changed, 118 insertions(+), 144 deletions(-)
fs/sysfs/dir.c +48 -82
@@ -191,39 +191,18 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,return 0 ; } -static int init_dir (struct inode * inode) -{ - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; - -/* directory inodes start off with i_nlink == 2 (for "." entry) */ -inc_nlink (inode); -return 0 ; -} - -static int init_file (struct inode * inode) -{ - inode->i_size =PAGE_SIZE ; - inode->i_fop = &sysfs_file_operations; -return 0 ; -} - -static int init_symlink (struct inode * inode) -{ - inode->i_op = &sysfs_symlink_inode_operations; -return 0 ; -} -static int create_dir (struct kobject *kobj,struct dentry *parent,const char *name,struct dentry **p_dentry) {int error;umode_t mode =S_IFDIR |S_IRWXU |S_IRUGO |S_IXUGO ;struct dentry *dentry; +struct inode *inode;struct sysfs_dirent *sd;mutex_lock (&parent->d_inode->i_mutex); +/* allocate */ dentry =lookup_one_len (name, parent,strlen (name));if (IS_ERR (dentry)) { error =PTR_ERR (dentry);
@@ -231,7 +210,7 @@ static int create_dir(struct kobject *kobj, struct dentry *parent, } error = -EEXIST ; -if (sysfs_dirent_exist (parent->d_fsdata, name)) +if (dentry->d_inode) goto out_dput; error = -ENOMEM ;
@@ -240,19 +219,31 @@ static int create_dir(struct kobject *kobj, struct dentry *parent, goto out_drop; sd->s_elem.dir.kobj = kobj; - error =sysfs_create (sd, dentry, mode, init_dir); -if (error) + inode =sysfs_new_inode (sd); +if (!inode) goto out_sput; + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; +/* directory inodes start off with i_nlink == 2 (for "." entry) */ +inc_nlink (inode); + +/* link in */ + error = -EEXIST ; +if (sysfs_dirent_exist (parent->d_fsdata, name)) + goto out_iput; + +sysfs_instantiate (dentry, inode);inc_nlink (parent->d_inode);sysfs_attach_dirent (sd, parent->d_fsdata, dentry); *p_dentry = dentry; error =0 ; - goto out_dput; + goto out_unlock;/* pin directory dentry in core */ + out_iput: +iput (inode); out_sput: -list_del_init (&sd->s_sibling);sysfs_put (sd); out_drop:d_drop (dentry);
@@ -298,71 +289,46 @@ int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)return error; } -/* attaches attribute's sysfs_dirent to the dentry corresponding to the -* attribute file -*/ -static int sysfs_attach_attr (struct sysfs_dirent * sd,struct dentry * dentry) -{ -struct attribute * attr =NULL ; -struct bin_attribute * bin_attr =NULL ; -int (* init) (struct inode *) =NULL ; -int error =0 ; - -if (sd->s_type &SYSFS_KOBJ_BIN_ATTR ) { - bin_attr = sd->s_elem.bin_attr.bin_attr; - attr = &bin_attr->attr; - }else { - attr = sd->s_elem.attr.attr; - init = init_file; - } - - error =sysfs_create (sd, dentry, - (attr->mode &S_IALLUGO ) |S_IFREG , init); -if (error) -return error; - -if (bin_attr) { - dentry->d_inode->i_size = bin_attr->size; - dentry->d_inode->i_fop = &bin_fops; - } - -sysfs_attach_dentry (sd, dentry); - -return 0 ; -} - -static int sysfs_attach_link (struct sysfs_dirent * sd,struct dentry * dentry) -{ -int err; - - err =sysfs_create (sd, dentry,S_IFLNK |S_IRWXUGO , init_symlink); -if (!err) -sysfs_attach_dentry (sd, dentry); - -return err; -} -static struct dentry *sysfs_lookup (struct inode *dir,struct dentry *dentry,struct nameidata *nd) {struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;struct sysfs_dirent * sd; -int err =0 ; +struct inode *inode; +int found =0 ;list_for_each_entry (sd, &parent_sd->s_children, s_sibling) { -if (sd->s_type &SYSFS_NOT_PINNED ) { -if (strcmp (sd->s_name, dentry->d_name.name)) -continue ; - -if (sd->s_type &SYSFS_KOBJ_LINK ) - err =sysfs_attach_link (sd, dentry); -else - err =sysfs_attach_attr (sd, dentry); +if ((sd->s_type &SYSFS_NOT_PINNED ) && + !strcmp (sd->s_name, dentry->d_name.name)) { + found =1 ;break ; } } -return ERR_PTR (err); +/* no such entry */ +if (!found) +return NULL ; + +/* attach dentry and inode */ + inode =sysfs_new_inode (sd); +if (!inode) +return ERR_PTR (-ENOMEM ); + +/* initialize inode according to type */ +if (sd->s_type &SYSFS_KOBJ_ATTR ) { + inode->i_size =PAGE_SIZE ; + inode->i_fop = &sysfs_file_operations; + }else if (sd->s_type &SYSFS_KOBJ_BIN_ATTR ) { +struct bin_attribute *bin_attr = sd->s_elem.bin_attr.bin_attr; + inode->i_size = bin_attr->size; + inode->i_fop = &bin_fops; + }else if (sd->s_type &SYSFS_KOBJ_LINK ) + inode->i_op = &sysfs_symlink_inode_operations; + +sysfs_instantiate (dentry, inode); +sysfs_attach_dentry (sd, dentry); + +return NULL ; }const struct inode_operations sysfs_dir_inode_operations = {
fs/sysfs/inode.c +57 -51
119 lines not on this page · raw message
fs/sysfs/mount.c +10 -8
@@ -29,6 +29,7 @@ static struct sysfs_dirent sysfs_root = { .s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling), .s_children = LIST_HEAD_INIT(sysfs_root.s_children), .s_type = SYSFS_ROOT, + .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, .s_iattr = NULL, .s_ino = 1, };
@@ -45,18 +46,19 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran =1 ; sysfs_sb = sb; - inode =sysfs_new_inode (S_IFDIR |S_IRWXU |S_IRUGO |S_IXUGO , - &sysfs_root); -if (inode) { - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; -/* directory inodes start off with i_nlink == 2 (for "." entry) */ -inc_nlink (inode); - }else { + inode =new_inode (sysfs_sb); +if (!inode) {pr_debug ("sysfs: could not get root inode\n" );return -ENOMEM ; } +sysfs_init_inode (&sysfs_root, inode); + + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; +/* directory inodes start off with i_nlink == 2 (for "." entry) */ +inc_nlink (inode); + root =d_alloc_root (inode);if (!root) {pr_debug ("%s: could not get root dentry!\n" ,__FUNCTION__);
fs/sysfs/sysfs.h +3 -3
@@ -57,9 +57,9 @@ extern struct vfsmount * sysfs_mount;extern struct kmem_cache *sysfs_dir_cachep;extern void sysfs_delete_inode (struct inode *inode); -extern struct inode *sysfs_new_inode (mode_t mode,struct sysfs_dirent *); -extern int sysfs_create (struct sysfs_dirent *sd,struct dentry *dentry, -int mode,int (*init)(struct inode *)); +extern void sysfs_init_inode (struct sysfs_dirent *sd,struct inode *inode); +extern struct inode *sysfs_new_inode (struct sysfs_dirent *sd); +extern void sysfs_instantiate (struct dentry *dentry,struct inode *inode);extern void release_sysfs_dirent (struct sysfs_dirent * sd);extern int sysfs_dirent_exist (struct sysfs_dirent *,const unsigned char *);
Signature · 1 line
1.5.2.2
PATCH 44/61 sysfs: use iget_locked() instead of new_inode()
From: Tejun Heo <[email protected]>
After dentry is reclaimed, sysfs always used to allocate new dentry and inode if the file is accessed again. This causes problem with operations which only pin the inode. For example, if inotify watch is added to a sysfs file and the dentry for the file is reclaimed, the next update event creates new dentry and new inode making the inotify watch miss all the events from there on.
This patch fixes it by using iget_locked() instead of new_inode(). sysfs_new_inode() is renamed to sysfs_get_inode() and inode is initialized iff the inode is newly allocated. sysfs_instantiate() is responsible for unlocking new inodes.
--- fs/sysfs/dir.c | 37 +++++++++++++++++++++---------------- fs/sysfs/inode.c | 24 +++++++++++++++--------- fs/sysfs/sysfs.h | 2 +- 3 files changed, 37 insertions(+), 26 deletions(-)
fs/sysfs/dir.c +21 -16
@@ -219,14 +219,16 @@ static int create_dir(struct kobject *kobj, struct dentry *parent, goto out_drop; sd->s_elem.dir.kobj = kobj; - inode =sysfs_new_inode (sd); + inode =sysfs_get_inode (sd);if (!inode) goto out_sput; - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; -/* directory inodes start off with i_nlink == 2 (for "." entry) */ -inc_nlink (inode); +if (inode->i_state &I_NEW ) { + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; +/* directory inodes start off with i_nlink == 2 (for ".") */ +inc_nlink (inode); + }/* link in */ error = -EEXIST ;
@@ -310,20 +312,23 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,return NULL ;/* attach dentry and inode */ - inode =sysfs_new_inode (sd); + inode =sysfs_get_inode (sd);if (!inode)return ERR_PTR (-ENOMEM ); -/* initialize inode according to type */ -if (sd->s_type &SYSFS_KOBJ_ATTR ) { - inode->i_size =PAGE_SIZE ; - inode->i_fop = &sysfs_file_operations; - }else if (sd->s_type &SYSFS_KOBJ_BIN_ATTR ) { -struct bin_attribute *bin_attr = sd->s_elem.bin_attr.bin_attr; - inode->i_size = bin_attr->size; - inode->i_fop = &bin_fops; - }else if (sd->s_type &SYSFS_KOBJ_LINK ) - inode->i_op = &sysfs_symlink_inode_operations; +if (inode->i_state &I_NEW ) { +/* initialize inode according to type */ +if (sd->s_type &SYSFS_KOBJ_ATTR ) { + inode->i_size =PAGE_SIZE ; + inode->i_fop = &sysfs_file_operations; + }else if (sd->s_type &SYSFS_KOBJ_BIN_ATTR ) { +struct bin_attribute *bin_attr = + sd->s_elem.bin_attr.bin_attr; + inode->i_size = bin_attr->size; + inode->i_fop = &bin_fops; + }else if (sd->s_type &SYSFS_KOBJ_LINK ) + inode->i_op = &sysfs_symlink_inode_operations; + }sysfs_instantiate (dentry, inode);sysfs_attach_dentry (sd, dentry);
fs/sysfs/inode.c +15 -9
@@ -153,10 +153,12 @@ void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) }/** -* sysfs_new_inode - allocate new inode for sysfs_dirent +* sysfs_get_inode - get inode for sysfs_dirent * @sd: sysfs_dirent to allocate inode for * -* Allocate inode for @sd and initialize basics. +* Get inode for @sd. If such inode doesn't exist, a new inode +* is allocated and basics are initialized. New inode is +* returned locked. * * LOCKING: * Kernel thread context (may sleep).
@@ -164,12 +166,12 @@ void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)* RETURNS: * Pointer to allocated inode on success, NULL on failure. */ -struct inode *sysfs_new_inode (struct sysfs_dirent *sd) +struct inode *sysfs_get_inode (struct sysfs_dirent *sd) {struct inode *inode; - inode =new_inode (sysfs_sb); -if (inode) + inode =iget_locked (sysfs_sb, sd->s_ino); +if (inode && (inode->i_state &I_NEW ))sysfs_init_inode (sd, inode);return inode;
@@ -180,7 +182,7 @@ struct inode * sysfs_new_inode(struct sysfs_dirent *sd)* @dentry: dentry to be instantiated * @inode: inode associated with @sd * -* Instantiate @dentry with @inode. +* Unlock @inode if locked and instantiate @dentry with @inode. * * LOCKING: * None.
@@ -189,9 +191,13 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode) {BUG_ON (!dentry || dentry->d_inode); -if (dentry->d_parent && dentry->d_parent->d_inode) { -struct inode *p_inode = dentry->d_parent->d_inode; - p_inode->i_mtime = p_inode->i_ctime =CURRENT_TIME ; +if (inode->i_state &I_NEW ) { +unlock_new_inode (inode); + +if (dentry->d_parent && dentry->d_parent->d_inode) { +struct inode *p_inode = dentry->d_parent->d_inode; + p_inode->i_mtime = p_inode->i_ctime =CURRENT_TIME ; + } }d_instantiate (dentry, inode);
fs/sysfs/sysfs.h +1 -1
@@ -58,7 +58,7 @@ extern struct kmem_cache *sysfs_dir_cachep;extern void sysfs_delete_inode (struct inode *inode);extern void sysfs_init_inode (struct sysfs_dirent *sd,struct inode *inode); -extern struct inode *sysfs_new_inode (struct sysfs_dirent *sd); +extern struct inode *sysfs_get_inode (struct sysfs_dirent *sd);extern void sysfs_instantiate (struct dentry *dentry,struct inode *inode);extern void release_sysfs_dirent (struct sysfs_dirent * sd);
Signature · 1 line
1.5.2.2
PATCH 45/61 sysfs: fix root sysfs_dirent -> root dentry association
From: Tejun Heo <[email protected]>
The root sysfs_dirent didn't point to the root dentry fix it.
--- fs/sysfs/mount.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
fs/sysfs/mount.c +1 -0
@@ -65,6 +65,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)iput (inode);return -ENOMEM ; } + sysfs_root.s_dentry = root; root->d_fsdata = &sysfs_root; sb->s_root = root;return 0 ;
Signature · 1 line
1.5.2.2
PATCH 46/61 sysfs: move s_active functions to fs/sysfs/dir.c
From: Tejun Heo <[email protected]>
These functions are about to receive more complexity and doesn't really need to be inlined in the first place. Move them from fs/sysfs/sysfs.h to fs/sysfs/dir.c.
--- fs/sysfs/dir.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/sysfs/sysfs.h | 94 +++-------------------------------------------------- 2 files changed, 94 insertions(+), 88 deletions(-)
fs/sysfs/dir.c +88 -0
@@ -20,6 +20,94 @@ spinlock_t kobj_sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;static spinlock_t sysfs_ino_lock =SPIN_LOCK_UNLOCKED ;static DEFINE_IDA (sysfs_ino_ida); +/** +* sysfs_get_active - get an active reference to sysfs_dirent +* @sd: sysfs_dirent to get an active reference to +* +* Get an active reference of @sd. This function is noop if @sd +* is NULL. +* +* RETURNS: +* Pointer to @sd on success, NULL on failure. +*/ +struct sysfs_dirent *sysfs_get_active (struct sysfs_dirent *sd) +{ +if (sd) { +if (unlikely (!down_read_trylock (&sd->s_active))) + sd =NULL ; + } +return sd; +} + +/** +* sysfs_put_active - put an active reference to sysfs_dirent +* @sd: sysfs_dirent to put an active reference to +* +* Put an active reference to @sd. This function is noop if @sd +* is NULL. +*/ +void sysfs_put_active (struct sysfs_dirent *sd) +{ +if (sd) +up_read (&sd->s_active); +} + +/** +* sysfs_get_active_two - get active references to sysfs_dirent and parent +* @sd: sysfs_dirent of interest +* +* Get active reference to @sd and its parent. Parent's active +* reference is grabbed first. This function is noop if @sd is +* NULL. +* +* RETURNS: +* Pointer to @sd on success, NULL on failure. +*/ +struct sysfs_dirent *sysfs_get_active_two (struct sysfs_dirent *sd) +{ +if (sd) { +if (sd->s_parent &&unlikely (!sysfs_get_active (sd->s_parent))) +return NULL ; +if (unlikely (!sysfs_get_active (sd))) { +sysfs_put_active (sd->s_parent); +return NULL ; + } + } +return sd; +} + +/** +* sysfs_put_active_two - put active references to sysfs_dirent and parent +* @sd: sysfs_dirent of interest +* +* Put active references to @sd and its parent. This function is +* noop if @sd is NULL. +*/ +void sysfs_put_active_two (struct sysfs_dirent *sd) +{ +if (sd) { +sysfs_put_active (sd); +sysfs_put_active (sd->s_parent); + } +} + +/** +* sysfs_deactivate - deactivate sysfs_dirent +* @sd: sysfs_dirent to deactivate +* +* Deny new active references and drain existing ones. s_active +* will be unlocked when the sysfs_dirent is released. +*/ +void sysfs_deactivate (struct sysfs_dirent *sd) +{ +down_write_nested (&sd->s_active,SYSFS_S_ACTIVE_DEACTIVATE ); + +/* s_active will be unlocked by the thread doing the final put +* on @sd. Lie to lockdep. +*/ +rwsem_release (&sd->s_active.dep_map,1 , _RET_IP_); +} +static int sysfs_alloc_ino (ino_t *pino) {int ino, rc;
fs/sysfs/sysfs.h +6 -88
106 lines not on this page · raw message
Signature · 1 line
1.5.2.2
PATCH 47/61 sysfs: slim down sysfs_dirent->s_active
From: Tejun Heo <[email protected]>
Make sysfs_dirent->s_active an atomic_t instead of rwsem. This reduces the size of sysfs_dirent from 136 to 104 on 64bit and from 76 to 60 on 32bit with lock debugging turned off. With lock debugging turned on the reduction is much larger.
s_active starts at zero and each active reference increments s_active. Putting a reference decrements s_active. Deactivation subtracts SD_DEACTIVATED_BIAS which is currently INT_MIN and assumed to be small enough to make s_active negative. If s_active is negative, sysfs_get() no longer grants new references. Deactivation succeeds immediately if there is no active user; otherwise, it waits using a completion for the last put.
Due to the removal of lockdep tricks, this change makes things less trickier in release_sysfs_dirent(). As all the complexity is contained in three s_active functions, I think it's more readable this way.
--- fs/sysfs/dir.c | 74 +++++++++++++++++++++++++++++++++++------------------- fs/sysfs/sysfs.h | 13 +-------- 2 files changed, 50 insertions(+), 37 deletions(-)
fs/sysfs/dir.c +48 -26
@@ -10,6 +10,7 @@#include <linux/kobject.h> #include <linux/namei.h> #include <linux/idr.h> +#include <linux/completion.h> #include <asm/semaphore.h> #include "sysfs.h"
@@ -32,11 +33,24 @@ static DEFINE_IDA(sysfs_ino_ida);*/ struct sysfs_dirent *sysfs_get_active (struct sysfs_dirent *sd) { -if (sd) { -if (unlikely (!down_read_trylock (&sd->s_active))) - sd =NULL ; +if (unlikely (!sd)) +return NULL ; + +while (1 ) { +int v, t; + + v =atomic_read (&sd->s_active); +if (unlikely (v <0 )) +return NULL ; + + t =atomic_cmpxchg (&sd->s_active, v, v +1 ); +if (likely (t == v)) +return sd; +if (t <0 ) +return NULL ; + +cpu_relax (); } -return sd; }/**
@@ -48,8 +62,21 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)*/ void sysfs_put_active (struct sysfs_dirent *sd) { -if (sd) -up_read (&sd->s_active); +struct completion *cmpl; +int v; + +if (unlikely (!sd)) +return ; + + v =atomic_dec_return (&sd->s_active); +if (likely (v !=SD_DEACTIVATED_BIAS )) +return ; + +/* atomic_dec_return() is a mb(), we'll always see the updated +* sd->s_sibling.next. +*/ + cmpl = (void *)sd->s_sibling.next; +complete (cmpl); }/**
@@ -95,17 +122,25 @@ void sysfs_put_active_two(struct sysfs_dirent *sd)* sysfs_deactivate - deactivate sysfs_dirent * @sd: sysfs_dirent to deactivate * -* Deny new active references and drain existing ones. s_active -* will be unlocked when the sysfs_dirent is released. +* Deny new active references and drain existing ones. */ void sysfs_deactivate (struct sysfs_dirent *sd) { -down_write_nested (&sd->s_active,SYSFS_S_ACTIVE_DEACTIVATE ); +DECLARE_COMPLETION_ONSTACK (wait); +int v; + +BUG_ON (!list_empty (&sd->s_sibling)); + sd->s_sibling.next = (void *)&wait; -/* s_active will be unlocked by the thread doing the final put -* on @sd. Lie to lockdep. +/* atomic_add_return() is a mb(), put_active() will always see +* the updated sd->s_sibling.next. */ -rwsem_release (&sd->s_active.dep_map,1 , _RET_IP_); + v =atomic_add_return (SD_DEACTIVATED_BIAS , &sd->s_active); + +if (v !=SD_DEACTIVATED_BIAS ) +wait_for_completion (&wait); + +INIT_LIST_HEAD (&sd->s_sibling); }static int sysfs_alloc_ino (ino_t *pino)
@@ -141,19 +176,6 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) repeat: parent_sd = sd->s_parent; -/* If @sd is being released after deletion, s_active is write -* locked. If @sd is cursor for directory walk or being -* released prematurely, s_active has no reader or writer. -* -* sysfs_deactivate() lies to lockdep that s_active is -* unlocked immediately. Lie one more time to cover the -* previous lie. -*/ -if (!down_write_trylock (&sd->s_active)) -rwsem_acquire (&sd->s_active.dep_map, -SYSFS_S_ACTIVE_DEACTIVATE ,0 , _RET_IP_); -up_write (&sd->s_active); -if (sd->s_type &SYSFS_KOBJ_LINK )sysfs_put (sd->s_elem.symlink.target_sd);if (sd->s_type &SYSFS_COPY_NAME )
@@ -213,8 +235,8 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) goto err_out;atomic_set (&sd->s_count,1 ); +atomic_set (&sd->s_active,0 );atomic_set (&sd->s_event,1 ); -init_rwsem (&sd->s_active);INIT_LIST_HEAD (&sd->s_children);INIT_LIST_HEAD (&sd->s_sibling);
fs/sysfs/sysfs.h +2 -11
@@ -21,7 +21,7 @@ struct sysfs_elem_bin_attr {*/ struct sysfs_dirent {atomic_t s_count; -struct rw_semaphore s_active; +atomic_t s_active;struct sysfs_dirent * s_parent;struct list_head s_sibling;struct list_head s_children;
@@ -42,16 +42,7 @@ struct sysfs_dirent {atomic_t s_event; }; -/* -* A sysfs file which deletes another file when written to need to -* write lock the s_active of the victim while its s_active is read -* locked for the write operation. Tell lockdep that this is okay. -*/ -enum sysfs_s_active_class -{ -SYSFS_S_ACTIVE_NORMAL ,/* file r/w access, etc - default */ -SYSFS_S_ACTIVE_DEACTIVATE ,/* file deactivation */ -}; +#define SD_DEACTIVATED_BIAS INT_MINextern struct vfsmount * sysfs_mount;extern struct kmem_cache *sysfs_dir_cachep;
Signature · 1 line
1.5.2.2
PATCH 48/61 sysfs: use singly-linked list for sysfs_dirent tree
From: Tejun Heo <[email protected]>
Make sysfs_dirent use singly linked list for its tree structure. sysfs_link_sibling() and sysfs_unlink_sibling() functions are added to handle simpler cases. It adds some complexity and cpu cycle overhead but reduced memory footprint is worthwhile on big machines.
This change reduces the sizeof sysfs_dirent from 104 to 88 on 64bit and from 60 to 52 on 32bit.
--- fs/sysfs/dir.c | 146 +++++++++++++++++++++++++++++++++++++---------------- fs/sysfs/inode.c | 12 +++-- fs/sysfs/mount.c | 3 - fs/sysfs/sysfs.h | 4 +- 4 files changed, 111 insertions(+), 54 deletions(-)
fs/sysfs/dir.c +102 -44
@@ -22,6 +22,48 @@ static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;static DEFINE_IDA (sysfs_ino_ida);/** +* sysfs_link_sibling - link sysfs_dirent into sibling list +* @sd: sysfs_dirent of interest +* +* Link @sd into its sibling list which starts from +* sd->s_parent->s_children. +* +* Locking: +* mutex_lock(sd->s_parent->dentry->d_inode->i_mutex) +*/ +static void sysfs_link_sibling (struct sysfs_dirent *sd) +{ +struct sysfs_dirent *parent_sd = sd->s_parent; + +BUG_ON (sd->s_sibling); + sd->s_sibling = parent_sd->s_children; + parent_sd->s_children = sd; +} + +/** +* sysfs_unlink_sibling - unlink sysfs_dirent from sibling list +* @sd: sysfs_dirent of interest +* +* Unlink @sd from its sibling list which starts from +* sd->s_parent->s_children. +* +* Locking: +* mutex_lock(sd->s_parent->dentry->d_inode->i_mutex) +*/ +static void sysfs_unlink_sibling (struct sysfs_dirent *sd) +{ +struct sysfs_dirent **pos; + +for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) { +if (*pos == sd) { + *pos = sd->s_sibling; + sd->s_sibling =NULL ; +break ; + } + } +} + +/** * sysfs_get_active - get an active reference to sysfs_dirent * @sd: sysfs_dirent to get an active reference to *
@@ -73,9 +115,9 @@ void sysfs_put_active(struct sysfs_dirent *sd)return ;/* atomic_dec_return() is a mb(), we'll always see the updated -* sd->s_sibling.next. +* sd->s_sibling. */ - cmpl = (void *)sd->s_sibling.next; + cmpl = (void *)sd->s_sibling;complete (cmpl); }
@@ -129,18 +171,18 @@ void sysfs_deactivate(struct sysfs_dirent *sd)DECLARE_COMPLETION_ONSTACK (wait);int v; -BUG_ON (!list_empty (&sd->s_sibling)); - sd->s_sibling.next = (void *)&wait; +BUG_ON (sd->s_sibling); + sd->s_sibling = (void *)&wait;/* atomic_add_return() is a mb(), put_active() will always see -* the updated sd->s_sibling.next. +* the updated sd->s_sibling. */ v =atomic_add_return (SD_DEACTIVATED_BIAS , &sd->s_active);if (v !=SD_DEACTIVATED_BIAS )wait_for_completion (&wait); -INIT_LIST_HEAD (&sd->s_sibling); + sd->s_sibling =NULL ; }static int sysfs_alloc_ino (ino_t *pino)
@@ -237,8 +279,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)atomic_set (&sd->s_count,1 );atomic_set (&sd->s_active,0 );atomic_set (&sd->s_event,1 ); -INIT_LIST_HEAD (&sd->s_children); -INIT_LIST_HEAD (&sd->s_sibling); sd->s_name = name; sd->s_mode = mode;
@@ -273,7 +313,7 @@ void sysfs_attach_dirent(struct sysfs_dirent *sd,if (parent_sd) { sd->s_parent =sysfs_get (parent_sd); -list_add (&sd->s_sibling, &parent_sd->s_children); +sysfs_link_sibling (sd); } }
@@ -289,7 +329,7 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd, {struct sysfs_dirent * sd; -list_for_each_entry (sd, &parent_sd->s_children, s_sibling) { +for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {if (sd->s_type) {if (strcmp (sd->s_name, new))continue ;
@@ -409,7 +449,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,struct inode *inode;int found =0 ; -list_for_each_entry (sd, &parent_sd->s_children, s_sibling) { +for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {if ((sd->s_type &SYSFS_NOT_PINNED ) && !strcmp (sd->s_name, dentry->d_name.name)) { found =1 ;
@@ -458,7 +498,7 @@ static void remove_dir(struct dentry * d)mutex_lock (&parent->d_inode->i_mutex); -list_del_init (&sd->s_sibling); +sysfs_unlink_sibling (sd);pr_debug (" o %s removing done (%d)\n" ,d->d_name.name,atomic_read (&d->d_count));
@@ -478,9 +518,9 @@ void sysfs_remove_subdir(struct dentry * d)static void __sysfs_remove_dir (struct dentry *dentry) { -LIST_HEAD (removed); -struct sysfs_dirent * parent_sd; -struct sysfs_dirent * sd, * tmp; +struct sysfs_dirent *removed =NULL ; +struct sysfs_dirent *parent_sd; +struct sysfs_dirent **pos;if (!dentry)return ;
@@ -488,15 +528,25 @@ static void __sysfs_remove_dir(struct dentry *dentry)pr_debug ("sysfs %s: removing dir\n" ,dentry->d_name.name);mutex_lock (&dentry->d_inode->i_mutex); parent_sd = dentry->d_fsdata; -list_for_each_entry_safe (sd, tmp, &parent_sd->s_children, s_sibling) { -if (!sd->s_type || !(sd->s_type &SYSFS_NOT_PINNED )) -continue ; -list_move (&sd->s_sibling, &removed); + pos = &parent_sd->s_children; +while (*pos) { +struct sysfs_dirent *sd = *pos; + +if (sd->s_type && (sd->s_type &SYSFS_NOT_PINNED )) { + *pos = sd->s_sibling; + sd->s_sibling = removed; + removed = sd; + }else + pos = &(*pos)->s_sibling; }mutex_unlock (&dentry->d_inode->i_mutex); -list_for_each_entry_safe (sd, tmp, &removed, s_sibling) { -list_del_init (&sd->s_sibling); +while (removed) { +struct sysfs_dirent *sd = removed; + + removed = sd->s_sibling; + sd->s_sibling =NULL ; +sysfs_drop_dentry (sd);sysfs_deactivate (sd);sysfs_put (sd);
@@ -577,11 +627,11 @@ int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,d_add (new_dentry,NULL );d_move (kobj->dentry, new_dentry); -list_del_init (&sd->s_sibling); +sysfs_unlink_sibling (sd);sysfs_get (parent_sd);sysfs_put (sd->s_parent); sd->s_parent = parent_sd; -list_add (&sd->s_sibling, &parent_sd->s_children); +sysfs_link_sibling (sd); error =0 ; goto out_unlock;
@@ -633,11 +683,11 @@ again:dput (new_dentry);/* Remove from old parent's list and insert into new parent's list. */ -list_del_init (&sd->s_sibling); +sysfs_unlink_sibling (sd);sysfs_get (new_parent_sd);sysfs_put (sd->s_parent); sd->s_parent = new_parent_sd; -list_add (&sd->s_sibling, &new_parent_sd->s_children); +sysfs_link_sibling (sd); out:mutex_unlock (&new_parent_dentry->d_inode->i_mutex);
@@ -668,7 +718,7 @@ static int sysfs_dir_close(struct inode *inode, struct file *file)struct sysfs_dirent * cursor = file->private_data;mutex_lock (&dentry->d_inode->i_mutex); -list_del_init (&cursor->s_sibling); +sysfs_unlink_sibling (cursor);mutex_unlock (&dentry->d_inode->i_mutex);release_sysfs_dirent (cursor);
@@ -687,7 +737,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)struct dentry *dentry = filp->f_path.dentry;struct sysfs_dirent * parent_sd = dentry->d_fsdata;struct sysfs_dirent *cursor = filp->private_data; -struct list_head *p, *q = &cursor->s_sibling; +struct sysfs_dirent **pos;ino_t ino;int i = filp->f_pos;
@@ -710,16 +760,21 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) i++;/* fallthrough */ default : + pos = &parent_sd->s_children; +while (*pos != cursor) + pos = &(*pos)->s_sibling; + +/* unlink cursor */ + *pos = cursor->s_sibling; +if (filp->f_pos ==2 ) -list_move (q, &parent_sd->s_children); + pos = &parent_sd->s_children; -for (p=q->next; p!= &parent_sd->s_children; p=p->next) { -struct sysfs_dirent *next; +for ( ; *pos; pos = &(*pos)->s_sibling) { +struct sysfs_dirent *next = *pos;const char * name;int len; - next = list_entry(p, struct sysfs_dirent, - s_sibling);if (!next->s_type)continue ;
@@ -729,12 +784,14 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)if (filldir (dirent, name, len, filp->f_pos, ino,dt_type (next)) <0 ) -return 0 ; +break ; -list_move (q, p); - p = q; filp->f_pos++; } + +/* put cursor back in */ + cursor->s_sibling = *pos; + *pos = cursor; }return 0 ; }
@@ -759,20 +816,21 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)if (file->f_pos >=2 ) {struct sysfs_dirent *sd = dentry->d_fsdata;struct sysfs_dirent *cursor = file->private_data; -struct list_head *p; +struct sysfs_dirent **pos;loff_t n = file->f_pos -2 ; -list_del (&cursor->s_sibling); - p = sd->s_children.next; -while (n && p != &sd->s_children) { -struct sysfs_dirent *next; - next = list_entry(p, struct sysfs_dirent, - s_sibling); +sysfs_unlink_sibling (cursor); + + pos = &sd->s_children; +while (n && *pos) { +struct sysfs_dirent *next = *pos;if (next->s_type) n--; - p = p->next; + pos = &(*pos)->s_sibling; } -list_add_tail (&cursor->s_sibling, p); + + cursor->s_sibling = *pos; + *pos = cursor; } }mutex_unlock (&dentry->d_inode->i_mutex);
fs/sysfs/inode.c +7 -5
@@ -284,8 +284,8 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)int sysfs_hash_and_remove (struct dentry * dir,const char * name) { -struct sysfs_dirent * sd; -struct sysfs_dirent * parent_sd; +struct sysfs_dirent **pos, *sd; +struct sysfs_dirent *parent_sd = dir->d_fsdata;int found =0 ;if (!dir)
@@ -295,13 +295,15 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name)/* no inode means this hasn't been made visible yet */ return -ENOENT ; - parent_sd = dir->d_fsdata;mutex_lock_nested (&dir->d_inode->i_mutex,I_MUTEX_PARENT ); -list_for_each_entry (sd, &parent_sd->s_children, s_sibling) { +for (pos = &parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) { + sd = *pos; +if (!sd->s_type)continue ;if (!strcmp (sd->s_name, name)) { -list_del_init (&sd->s_sibling); + *pos = sd->s_sibling; + sd->s_sibling =NULL ; found =1 ;break ; }
fs/sysfs/mount.c +0 -3
@@ -26,11 +26,8 @@ static const struct super_operations sysfs_ops = {static struct sysfs_dirent sysfs_root = { .s_count =ATOMIC_INIT (1 ), - .s_sibling =LIST_HEAD_INIT (sysfs_root.s_sibling), - .s_children =LIST_HEAD_INIT (sysfs_root.s_children), .s_type =SYSFS_ROOT , .s_mode =S_IFDIR |S_IRWXU |S_IRUGO |S_IXUGO , - .s_iattr =NULL , .s_ino =1 , };
fs/sysfs/sysfs.h +2 -2
@@ -23,8 +23,8 @@ struct sysfs_dirent {atomic_t s_count;atomic_t s_active;struct sysfs_dirent * s_parent; -struct list_head s_sibling; -struct list_head s_children; +struct sysfs_dirent * s_sibling; +struct sysfs_dirent * s_children;const char * s_name;union {
Signature · 1 line
1.5.2.2
PATCH 49/61 sysfs: Fix oops in sysfs_drop_dentry on x86_64
From: Rafael J. Wysocki <[email protected]>
Fix oops on x86_64 caused by the dereference of dir in sysfs_drop_dentry() made before checking if dir is not NULL (cf. http://marc.info/?l=linux-kernel&m=118151626704924&w=2).
--- fs/sysfs/inode.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
fs/sysfs/inode.c +2 -1
@@ -285,7 +285,7 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)int sysfs_hash_and_remove (struct dentry * dir,const char * name) {struct sysfs_dirent **pos, *sd; -struct sysfs_dirent *parent_sd = dir->d_fsdata; +struct sysfs_dirent *parent_sd;int found =0 ;if (!dir)
@@ -295,6 +295,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name)/* no inode means this hasn't been made visible yet */ return -ENOENT ; + parent_sd = dir->d_fsdata;mutex_lock_nested (&dir->d_inode->i_mutex,I_MUTEX_PARENT );for (pos = &parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) { sd = *pos;
Signature · 1 line
1.5.2.2
PATCH 50/61 sysfs: make sysfs_drop_dentry() access inodes using ilookup()
From: Tejun Heo <[email protected]>
sysfs_drop_dentry() used to go through sd->s_dentry and sd->s_parent->s_dentry to access the inodes. This is incorrect because inode can be cached without dentry.
This patch makes sysfs_drop_dentry() access inodes using ilookup() on sd->s_ino. This is both correct and simpler.
--- fs/sysfs/inode.c | 63 ++++++++++++++++++++++++------------------------------ 1 files changed, 28 insertions(+), 35 deletions(-)
fs/sysfs/inode.c +28 -35
@@ -219,9 +219,9 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode)*/ void sysfs_drop_dentry (struct sysfs_dirent *sd) { -struct dentry *dentry =NULL , *parent =NULL ; -struct inode *dir; +struct dentry *dentry =NULL ;struct timespec curtime; +struct inode *inode;/* We're not holding a reference to ->s_dentry dentry but the * field will stay valid as long as sysfs_lock is held.
@@ -229,19 +229,9 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)spin_lock (&sysfs_lock);spin_lock (&dcache_lock); +/* drop dentry if it's there and dput() didn't kill it yet */ if (sd->s_dentry && sd->s_dentry->d_inode) { -/* get dentry if it's there and dput() didn't kill it yet */ dentry =dget_locked (sd->s_dentry); - parent = dentry->d_parent; - }else if (sd->s_parent->s_dentry->d_inode) { -/* We need to update the parent even if dentry for the -* victim itself doesn't exist. -*/ - parent =dget_locked (sd->s_parent->s_dentry); - } - -/* drop */ -if (dentry) {spin_lock (&dentry->d_lock);__d_drop (dentry);spin_unlock (&dentry->d_lock);
@@ -250,36 +240,39 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)spin_unlock (&dcache_lock);spin_unlock (&sysfs_lock); -/* nothing to do if the parent isn't in dcache */ -if (!parent) -return ; +dput (dentry); +/* XXX: unpin if directory, this will go away soon */ +if (sd->s_type &SYSFS_DIR ) +dput (dentry);/* adjust nlink and update timestamp */ - dir = parent->d_inode; -mutex_lock (&dir->i_mutex); - curtime =CURRENT_TIME ; - dir->i_ctime = dir->i_mtime = curtime; + inode =ilookup (sysfs_sb, sd->s_ino); +if (inode) { +mutex_lock (&inode->i_mutex); -if (dentry) { - dentry->d_inode->i_ctime = curtime; -drop_nlink (dentry->d_inode); -if (sd->s_type &SYSFS_DIR ) { -drop_nlink (dentry->d_inode); -drop_nlink (dir); -/* XXX: unpin if directory, this will go away soon */ -dput (dentry); - } + inode->i_ctime = curtime; +drop_nlink (inode); +if (sd->s_type &SYSFS_DIR ) +drop_nlink (inode); + +mutex_unlock (&inode->i_mutex); +iput (inode); } -mutex_unlock (&dir->i_mutex); +/* adjust nlink and udpate timestamp of the parent */ + inode =ilookup (sysfs_sb, sd->s_parent->s_ino); +if (inode) { +mutex_lock (&inode->i_mutex); -/* bye bye */ -if (dentry) -dput (dentry); -else -dput (parent); + inode->i_ctime = inode->i_mtime = curtime; +if (sd->s_type &SYSFS_DIR ) +drop_nlink (inode); + +mutex_unlock (&inode->i_mutex); +iput (inode); + } }int sysfs_hash_and_remove (struct dentry * dir,const char * name)
Signature · 1 line
1.5.2.2
PATCH 51/61 sysfs: rename sysfs_dirent->s_type to s_flags and make room for flags
From: Tejun Heo <[email protected]>
Rename sysfs_dirent->s_type to s_flags, pack type into lower eight bits and reserve the rest for flags. sysfs_type() can used to access the type. All existing sd->s_type accesses are converted to use sysfs_type(). While at it, type test is changed to equality test instead of bit-and test where appropriate.
--- fs/sysfs/dir.c | 33 ++++++++++++++++++++------------- fs/sysfs/inode.c | 8 ++++---- fs/sysfs/mount.c | 2 +- fs/sysfs/sysfs.h | 7 ++++++- include/linux/sysfs.h | 3 +++ 5 files changed, 34 insertions(+), 19 deletions(-)
fs/sysfs/dir.c +20 -13
@@ -218,9 +218,9 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) repeat: parent_sd = sd->s_parent; -if (sd->s_type &SYSFS_KOBJ_LINK ) +if (sysfs_type (sd) ==SYSFS_KOBJ_LINK )sysfs_put (sd->s_elem.symlink.target_sd); -if (sd->s_type &SYSFS_COPY_NAME ) +if (sysfs_type (sd) &SYSFS_COPY_NAME )kfree (sd->s_name);kfree (sd->s_iattr);sysfs_free_ino (sd->s_ino);
@@ -282,7 +282,7 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) sd->s_name = name; sd->s_mode = mode; - sd->s_type = type; + sd->s_flags = type;return sd;
@@ -330,7 +330,7 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,struct sysfs_dirent * sd;for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { -if (sd->s_type) { +if (sysfs_type (sd)) {if (strcmp (sd->s_name, new))continue ;else
@@ -446,11 +446,12 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, {struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;struct sysfs_dirent * sd; +struct bin_attribute *bin_attr;struct inode *inode;int found =0 ;for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { -if ((sd->s_type &SYSFS_NOT_PINNED ) && +if ((sysfs_type (sd) &SYSFS_NOT_PINNED ) && !strcmp (sd->s_name, dentry->d_name.name)) { found =1 ;break ;
@@ -468,16 +469,22 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,if (inode->i_state &I_NEW ) {/* initialize inode according to type */ -if (sd->s_type &SYSFS_KOBJ_ATTR ) { +switch (sysfs_type (sd)) { +case SYSFS_KOBJ_ATTR : inode->i_size =PAGE_SIZE ; inode->i_fop = &sysfs_file_operations; - }else if (sd->s_type &SYSFS_KOBJ_BIN_ATTR ) { -struct bin_attribute *bin_attr = - sd->s_elem.bin_attr.bin_attr; +break ; +case SYSFS_KOBJ_BIN_ATTR : + bin_attr = sd->s_elem.bin_attr.bin_attr; inode->i_size = bin_attr->size; inode->i_fop = &bin_fops; - }else if (sd->s_type &SYSFS_KOBJ_LINK ) +break ; +case SYSFS_KOBJ_LINK : inode->i_op = &sysfs_symlink_inode_operations; +break ; +default : +BUG (); + } }sysfs_instantiate (dentry, inode);
@@ -532,7 +539,7 @@ static void __sysfs_remove_dir(struct dentry *dentry)while (*pos) {struct sysfs_dirent *sd = *pos; -if (sd->s_type && (sd->s_type &SYSFS_NOT_PINNED )) { +if (sysfs_type (sd) && (sysfs_type (sd) &SYSFS_NOT_PINNED )) { *pos = sd->s_sibling; sd->s_sibling = removed; removed = sd;
@@ -775,7 +782,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)const char * name;int len; -if (!next->s_type) +if (!sysfs_type (next))continue ; name = next->s_name;
@@ -824,7 +831,7 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) pos = &sd->s_children;while (n && *pos) {struct sysfs_dirent *next = *pos; -if (next->s_type) +if (sysfs_type (next)) n--; pos = &(*pos)->s_sibling; }
fs/sysfs/inode.c +4 -4
@@ -242,7 +242,7 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)dput (dentry);/* XXX: unpin if directory, this will go away soon */ -if (sd->s_type &SYSFS_DIR ) +if (sysfs_type (sd) ==SYSFS_DIR )dput (dentry);/* adjust nlink and update timestamp */
@@ -254,7 +254,7 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd) inode->i_ctime = curtime;drop_nlink (inode); -if (sd->s_type &SYSFS_DIR ) +if (sysfs_type (sd) ==SYSFS_DIR )drop_nlink (inode);mutex_unlock (&inode->i_mutex);
@@ -267,7 +267,7 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)mutex_lock (&inode->i_mutex); inode->i_ctime = inode->i_mtime = curtime; -if (sd->s_type &SYSFS_DIR ) +if (sysfs_type (sd) ==SYSFS_DIR )drop_nlink (inode);mutex_unlock (&inode->i_mutex);
@@ -293,7 +293,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name)for (pos = &parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) { sd = *pos; -if (!sd->s_type) +if (!sysfs_type (sd))continue ;if (!strcmp (sd->s_name, name)) { *pos = sd->s_sibling;
fs/sysfs/mount.c +1 -1
@@ -26,7 +26,7 @@ static const struct super_operations sysfs_ops = {static struct sysfs_dirent sysfs_root = { .s_count =ATOMIC_INIT (1 ), - .s_type =SYSFS_ROOT , + .s_flags =SYSFS_ROOT , .s_mode =S_IFDIR |S_IRWXU |S_IRUGO |S_IXUGO , .s_ino =1 , };
fs/sysfs/sysfs.h +6 -1
@@ -34,7 +34,7 @@ struct sysfs_dirent {struct sysfs_elem_bin_attr bin_attr; } s_elem; -int s_type; +unsigned int s_flags;umode_t s_mode;ino_t s_ino;struct dentry * s_dentry;
@@ -86,6 +86,11 @@ extern const struct file_operations bin_fops;extern const struct inode_operations sysfs_dir_inode_operations;extern const struct inode_operations sysfs_symlink_inode_operations; +static inline unsigned int sysfs_type (struct sysfs_dirent *sd) +{ +return sd->s_flags &SYSFS_TYPE_MASK ; +} +static inline struct sysfs_dirent *sysfs_get (struct sysfs_dirent * sd) {if (sd) {
include/linux/sysfs.h +3 -0
@@ -74,6 +74,7 @@ struct sysfs_ops {ssize_t (*store)(struct kobject *,struct attribute *,const char *,size_t ); }; +#define SYSFS_TYPE_MASK 0x00ff#define SYSFS_ROOT 0x0001#define SYSFS_DIR 0x0002#define SYSFS_KOBJ_ATTR 0x0004
@@ -82,6 +83,8 @@ struct sysfs_ops {#define SYSFS_NOT_PINNED (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK)#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) +#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK +#ifdef CONFIG_SYSFS extern int sysfs_schedule_callback(struct kobject *kobj,
Signature · 1 line
1.5.2.2
PATCH 52/61 sysfs: implement SYSFS_FLAG_REMOVED flag
From: Tejun Heo <[email protected]>
Implement SYSFS_FLAG_REMOVED flag which currently is used only to improve sanity check in sysfs_deactivate(). The flag will be used to make directory entries reclamiable.
--- fs/sysfs/dir.c | 4 +++- fs/sysfs/inode.c | 1 + include/linux/sysfs.h | 1 + 3 files changed, 5 insertions(+), 1 deletions(-)
fs/sysfs/dir.c +3 -1
@@ -171,7 +171,7 @@ void sysfs_deactivate(struct sysfs_dirent *sd)DECLARE_COMPLETION_ONSTACK (wait);int v; -BUG_ON (sd->s_sibling); +BUG_ON (sd->s_sibling || !(sd->s_flags &SYSFS_FLAG_REMOVED )); sd->s_sibling = (void *)&wait;/* atomic_add_return() is a mb(), put_active() will always see
@@ -506,6 +506,7 @@ static void remove_dir(struct dentry * d)mutex_lock (&parent->d_inode->i_mutex);sysfs_unlink_sibling (sd); + sd->s_flags |=SYSFS_FLAG_REMOVED ;pr_debug (" o %s removing done (%d)\n" ,d->d_name.name,atomic_read (&d->d_count));
@@ -540,6 +541,7 @@ static void __sysfs_remove_dir(struct dentry *dentry)struct sysfs_dirent *sd = *pos;if (sysfs_type (sd) && (sysfs_type (sd) &SYSFS_NOT_PINNED )) { + sd->s_flags |=SYSFS_FLAG_REMOVED ; *pos = sd->s_sibling; sd->s_sibling = removed; removed = sd;
fs/sysfs/inode.c +1 -0
@@ -296,6 +296,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name)if (!sysfs_type (sd))continue ;if (!strcmp (sd->s_name, name)) { + sd->s_flags |=SYSFS_FLAG_REMOVED ; *pos = sd->s_sibling; sd->s_sibling =NULL ; found =1 ;
include/linux/sysfs.h +1 -0
@@ -84,6 +84,7 @@ struct sysfs_ops {#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK +#define SYSFS_FLAG_REMOVED 0x0100#ifdef CONFIG_SYSFS
Signature · 1 line
1.5.2.2
PATCH 53/61 sysfs: implement sysfs_find_dirent() and sysfs_get_dirent()
From: Tejun Heo <[email protected]>
Implement sysfs_find_dirent() and sysfs_get_dirent(). sysfs_dirent_exist() is replaced by sysfs_find_dirent(). These will be used to make directory entries reclamiable.
--- fs/sysfs/dir.c | 61 +++++++++++++++++++++++++++++++++++++-------------- fs/sysfs/file.c | 2 +- fs/sysfs/symlink.c | 2 +- fs/sysfs/sysfs.h | 5 +++- 4 files changed, 50 insertions(+), 20 deletions(-)
fs/sysfs/dir.c +44 -17
@@ -317,28 +317,55 @@ void sysfs_attach_dirent(struct sysfs_dirent *sd, } } -/* +/** +* sysfs_find_dirent - find sysfs_dirent with the given name +* @parent_sd: sysfs_dirent to search under +* @name: name to look for * -* Return -EEXIST if there is already a sysfs element with the same name for -* the same parent. +* Look for sysfs_dirent with name @name under @parent_sd. * -* called with parent inode's i_mutex held +* LOCKING: +* mutex_lock(parent->i_mutex) +* +* RETURNS: +* Pointer to sysfs_dirent if found, NULL if not. */ -int sysfs_dirent_exist (struct sysfs_dirent *parent_sd, -const unsigned char *new) +struct sysfs_dirent *sysfs_find_dirent (struct sysfs_dirent *parent_sd, +const unsigned char *name) { -struct sysfs_dirent * sd; +struct sysfs_dirent *sd; -for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { -if (sysfs_type (sd)) { -if (strcmp (sd->s_name, new)) -continue ; -else -return -EEXIST ; - } - } +for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) +if (sysfs_type (sd) && !strcmp (sd->s_name, name)) +return sd; +return NULL ; +} -return 0 ; +/** +* sysfs_get_dirent - find and get sysfs_dirent with the given name +* @parent_sd: sysfs_dirent to search under +* @name: name to look for +* +* Look for sysfs_dirent with name @name under @parent_sd and get +* it if found. +* +* LOCKING: +* Kernel thread context (may sleep) +* +* RETURNS: +* Pointer to sysfs_dirent if found, NULL if not. +*/ +struct sysfs_dirent *sysfs_get_dirent (struct sysfs_dirent *parent_sd, +const unsigned char *name) +{ +struct sysfs_dirent *sd; + +mutex_lock (&parent_sd->s_dentry->d_inode->i_mutex); + sd =sysfs_find_dirent (parent_sd, name); +sysfs_get (sd); +mutex_unlock (&parent_sd->s_dentry->d_inode->i_mutex); + +return sd; } static int create_dir(struct kobject *kobj, struct dentry *parent,
@@ -382,7 +409,7 @@ static int create_dir(struct kobject *kobj, struct dentry *parent,/* link in */ error = -EEXIST ; -if (sysfs_dirent_exist (parent->d_fsdata, name)) +if (sysfs_find_dirent (parent->d_fsdata, name)) goto out_iput;sysfs_instantiate (dentry, inode);
fs/sysfs/file.c +1 -1
@@ -421,7 +421,7 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)mutex_lock (&dir->d_inode->i_mutex); -if (sysfs_dirent_exist (parent_sd, attr->name)) { +if (sysfs_find_dirent (parent_sd, attr->name)) { error = -EEXIST ; goto out_unlock; }
fs/sysfs/symlink.c +1 -1
@@ -95,7 +95,7 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const charreturn -ENOENT ;mutex_lock (&dentry->d_inode->i_mutex); -if (!sysfs_dirent_exist (dentry->d_fsdata, name)) +if (!sysfs_find_dirent (dentry->d_fsdata, name)) error =sysfs_add_link (parent_sd, name, target_sd);mutex_unlock (&dentry->d_inode->i_mutex);
fs/sysfs/sysfs.h +4 -1
@@ -59,7 +59,10 @@ extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);extern void sysfs_instantiate (struct dentry *dentry,struct inode *inode);extern void release_sysfs_dirent (struct sysfs_dirent * sd); -extern int sysfs_dirent_exist (struct sysfs_dirent *,const unsigned char *); +extern struct sysfs_dirent *sysfs_find_dirent (struct sysfs_dirent *parent_sd, +const unsigned char *name); +extern struct sysfs_dirent *sysfs_get_dirent (struct sysfs_dirent *parent_sd, +const unsigned char *name);extern struct sysfs_dirent *sysfs_new_dirent (const char *name,umode_t mode,int type); extern void sysfs_attach_dirent(struct sysfs_dirent *sd,
Signature · 1 line
1.5.2.2
PATCH 54/61 sysfs: make kobj point to sysfs_dirent instead of dentry
From: Tejun Heo <[email protected]>
As kobj sysfs dentries and inodes are gonna be made reclaimable, dentry can't be used as naming token for sysfs file/directory, replace kobj->dentry with kobj->sd. The only external interface change is shadow directory handling. All other changes are contained in kobj and sysfs.
--- fs/sysfs/bin.c | 6 +- fs/sysfs/dir.c | 119 +++++++++++++++++++++++------------------------ fs/sysfs/file.c | 47 +++++++++--------- fs/sysfs/group.c | 55 +++++++++++----------- fs/sysfs/inode.c | 11 ++-- fs/sysfs/symlink.c | 22 ++++----- fs/sysfs/sysfs.h | 10 ++-- include/linux/kobject.h | 9 ++-- include/linux/sysfs.h | 19 ++++--- lib/kobject.c | 10 ++-- 10 files changed, 156 insertions(+), 152 deletions(-)
fs/sysfs/bin.c +3 -3
@@ -234,9 +234,9 @@ const struct file_operations bin_fops = {int sysfs_create_bin_file (struct kobject * kobj,struct bin_attribute * attr) { -BUG_ON (!kobj || !kobj->dentry || !attr); +BUG_ON (!kobj || !kobj->sd || !attr); -return sysfs_add_file (kobj->dentry, &attr->attr,SYSFS_KOBJ_BIN_ATTR ); +return sysfs_add_file (kobj->sd, &attr->attr,SYSFS_KOBJ_BIN_ATTR ); }
@@ -248,7 +248,7 @@ int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)void sysfs_remove_bin_file (struct kobject * kobj,struct bin_attribute * attr) { -if (sysfs_hash_and_remove (kobj->dentry, attr->attr.name) <0 ) { +if (sysfs_hash_and_remove (kobj->sd, attr->attr.name) <0 ) {printk (KERN_ERR "%s: " "bad dentry or inode or no such file: \"%s\"\n" , __FUNCTION__, attr->attr.name);
fs/sysfs/dir.c +59 -60
294 lines not on this page · raw message
fs/sysfs/file.c +24 -23
112 lines not on this page · raw message
fs/sysfs/group.c +27 -28
97 lines not on this page · raw message
fs/sysfs/inode.c +6 -5
@@ -275,22 +275,23 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd) } } -int sysfs_hash_and_remove (struct dentry * dir,const char * name) +int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name) { +struct dentry *dir;struct sysfs_dirent **pos, *sd; -struct sysfs_dirent *parent_sd;int found =0 ; -if (!dir) +if (!dir_sd)return -ENOENT ; + dir = dir_sd->s_dentry; +if (dir->d_inode ==NULL )/* no inode means this hasn't been made visible yet */ return -ENOENT ; - parent_sd = dir->d_fsdata;mutex_lock_nested (&dir->d_inode->i_mutex,I_MUTEX_PARENT ); -for (pos = &parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) { +for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { sd = *pos;if (!sysfs_type (sd))
fs/sysfs/symlink.c +10 -12
@@ -66,7 +66,6 @@ static int sysfs_add_link(struct sysfs_dirent * parent_sd, const char * name,*/ int sysfs_create_link (struct kobject * kobj,struct kobject * target,const char * name) { -struct dentry *dentry =NULL ;struct sysfs_dirent *parent_sd =NULL ;struct sysfs_dirent *target_sd =NULL ;int error = -EEXIST ;
@@ -75,29 +74,28 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const charif (!kobj) {if (sysfs_mount && sysfs_mount->mnt_sb) - dentry = sysfs_mount->mnt_sb->s_root; + parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; }else - dentry = kobj->dentry; + parent_sd = kobj->sd; -if (!dentry) +if (!parent_sd)return -EFAULT ; - parent_sd = dentry->d_fsdata; -/* target->dentry can go away beneath us but is protected with +/* target->sd can go away beneath us but is protected with * kobj_sysfs_assoc_lock. Fetch target_sd from it. */ spin_lock (&kobj_sysfs_assoc_lock); -if (target->dentry) - target_sd =sysfs_get (target->dentry->d_fsdata); +if (target->sd) + target_sd =sysfs_get (target->sd);spin_unlock (&kobj_sysfs_assoc_lock);if (!target_sd)return -ENOENT ; -mutex_lock (&dentry->d_inode->i_mutex); -if (!sysfs_find_dirent (dentry->d_fsdata, name)) +mutex_lock (&parent_sd->s_dentry->d_inode->i_mutex); +if (!sysfs_find_dirent (parent_sd, name)) error =sysfs_add_link (parent_sd, name, target_sd); -mutex_unlock (&dentry->d_inode->i_mutex); +mutex_unlock (&parent_sd->s_dentry->d_inode->i_mutex);if (error)sysfs_put (target_sd);
@@ -114,7 +112,7 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const charvoid sysfs_remove_link (struct kobject * kobj,const char * name) { -sysfs_hash_and_remove (kobj->dentry,name); +sysfs_hash_and_remove (kobj->sd, name); } static int sysfs_get_target_path(struct sysfs_dirent * parent_sd,
fs/sysfs/sysfs.h +6 -4
@@ -69,12 +69,14 @@ extern void sysfs_attach_dirent(struct sysfs_dirent *sd,struct sysfs_dirent *parent_sd, struct dentry *dentry); -extern int sysfs_add_file (struct dentry *,const struct attribute *,int ); -extern int sysfs_hash_and_remove (struct dentry * dir,const char * name); +extern int sysfs_add_file (struct sysfs_dirent *dir_sd, +const struct attribute *attr,int type); +extern int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name);extern struct sysfs_dirent *sysfs_find (struct sysfs_dirent *dir,const char * name); -extern int sysfs_create_subdir (struct kobject *,const char *,struct dentry **); -extern void sysfs_remove_subdir (struct dentry *); +extern int sysfs_create_subdir (struct kobject *kobj,const char *name, +struct sysfs_dirent **p_sd); +extern void sysfs_remove_subdir (struct sysfs_dirent *sd);extern void sysfs_drop_dentry (struct sysfs_dirent *sd);extern int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);
include/linux/kobject.h +5 -4
@@ -55,7 +55,7 @@ struct kobject {struct kobject * parent;struct kset * kset;struct kobj_type * ktype; -struct dentry * dentry; +struct sysfs_dirent * sd;wait_queue_head_t poll; };
@@ -71,13 +71,14 @@ extern void kobject_init(struct kobject *);extern void kobject_cleanup (struct kobject *);extern int __must_check kobject_add (struct kobject *); -extern int __must_check kobject_shadow_add (struct kobject *,struct dentry *); +extern int __must_check kobject_shadow_add (struct kobject *kobj, +struct sysfs_dirent *shadow_parent);extern void kobject_del (struct kobject *);extern int __must_check kobject_rename (struct kobject *,const char *new_name);extern int __must_check kobject_shadow_rename (struct kobject *kobj, -struct dentry *new_parent, -const char *new_name); +struct sysfs_dirent *new_parent, +const char *new_name);extern int __must_check kobject_move (struct kobject *,struct kobject *);extern int __must_check kobject_register (struct kobject *);
include/linux/sysfs.h +11 -8
@@ -19,6 +19,7 @@ struct kobject;struct module ;struct nameidata ;struct dentry ; +struct sysfs_dirent ;/* FIXME * The *owner field is no longer used, but leave around
@@ -92,13 +93,14 @@ extern int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), void *data, struct module *owner);extern int __must_check -sysfs_create_dir (struct kobject *,struct dentry *); +sysfs_create_dir (struct kobject *kobj,struct sysfs_dirent *shadow_parent_sd);extern void sysfs_remove_dir (struct kobject *);extern int __must_check -sysfs_rename_dir (struct kobject *,struct dentry *,const char *new_name); +sysfs_rename_dir (struct kobject *kobj,struct sysfs_dirent *new_parent_sd, +const char *new_name);extern int __must_check sysfs_move_dir (struct kobject *,struct kobject *);
@@ -138,8 +140,8 @@ void sysfs_notify(struct kobject * k, char *dir, char *attr);extern int sysfs_make_shadowed_dir (struct kobject *kobj,void * (*follow_link)(struct dentry *,struct nameidata *)); -extern struct dentry *sysfs_create_shadow_dir (struct kobject *kobj); -extern void sysfs_remove_shadow_dir (struct dentry *dir); +extern struct sysfs_dirent *sysfs_create_shadow_dir (struct kobject *kobj); +extern void sysfs_remove_shadow_dir (struct sysfs_dirent *shadow_sd);extern int __must_check sysfs_init (void );
@@ -151,7 +153,8 @@ static inline int sysfs_schedule_callback(struct kobject *kobj,return -ENOSYS ; } -static inline int sysfs_create_dir (struct kobject * k,struct dentry *shadow) +static inline int sysfs_create_dir (struct kobject *kobj, +struct sysfs_dirent *shadow_parent_sd) {return 0 ; }
@@ -161,9 +164,9 @@ static inline void sysfs_remove_dir(struct kobject * k) ; } -static inline int sysfs_rename_dir (struct kobject * k, -struct dentry *new_parent, -const char *new_name) +static inline int sysfs_rename_dir (struct kobject *kobj, +struct sysfs_dirent *new_parent_sd, +const char *new_name) {return 0 ; }
lib/kobject.c +5 -5
@@ -44,7 +44,7 @@ static int populate_dir(struct kobject * kobj)return error; } -static int create_dir (struct kobject * kobj,struct dentry *shadow_parent) +static int create_dir (struct kobject *kobj,struct sysfs_dirent *shadow_parent) {int error =0 ;if (kobject_name (kobj)) {
@@ -162,7 +162,7 @@ static void unlink(struct kobject * kobj)* @shadow_parent: sysfs directory to add to. */ -int kobject_shadow_add (struct kobject * kobj,struct dentry *shadow_parent) +int kobject_shadow_add (struct kobject *kobj,struct sysfs_dirent *shadow_parent) {int error =0 ;struct kobject * parent;
@@ -338,7 +338,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)/* Note : if we want to send the new name alone, not the full path, * we could probably use kobject_name(kobj); */ - error =sysfs_rename_dir (kobj, kobj->parent->dentry, new_name); + error =sysfs_rename_dir (kobj, kobj->parent->sd, new_name);/* This function is mostly/only used for network interface. * Some hotplug package track interfaces by their name and
@@ -361,8 +361,8 @@ out:* @new_name: object's new name */ -int kobject_shadow_rename (struct kobject * kobj,struct dentry *new_parent, -const char *new_name) +int kobject_shadow_rename (struct kobject *kobj, +struct sysfs_dirent *new_parent,const char *new_name) {int error =0 ;
Signature · 1 line
1.5.2.2
PATCH 55/61 sysfs: consolidate sysfs spinlocks
From: Tejun Heo <[email protected]>
Replace sysfs_lock and kobj_sysfs_assoc_lock with sysfs_assoc_lock. sysfs_lock was originally to be used to protect sysfs_dirent tree but mutex seems better choice, so there is no reason to keep sysfs_lock separate. Merge the two spinlocks into one.
--- fs/sysfs/dir.c | 19 +++++++++---------- fs/sysfs/inode.c | 16 ++++++++-------- fs/sysfs/symlink.c | 6 +++--- fs/sysfs/sysfs.h | 3 +-- 4 files changed, 21 insertions(+), 23 deletions(-)
fs/sysfs/dir.c +9 -10
@@ -15,8 +15,7 @@#include "sysfs.h" DECLARE_RWSEM (sysfs_rename_sem); -spinlock_t sysfs_lock =SPIN_LOCK_UNLOCKED ; -spinlock_t kobj_sysfs_assoc_lock =SPIN_LOCK_UNLOCKED ; +spinlock_t sysfs_assoc_lock =SPIN_LOCK_UNLOCKED ;static spinlock_t sysfs_ino_lock =SPIN_LOCK_UNLOCKED ;static DEFINE_IDA (sysfs_ino_ida);
@@ -236,10 +235,10 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)struct sysfs_dirent * sd = dentry->d_fsdata;if (sd) { -/* sd->s_dentry is protected with sysfs_lock. This -* allows sysfs_drop_dentry() to dereference it. +/* sd->s_dentry is protected with sysfs_assoc_lock. +* This allows sysfs_drop_dentry() to dereference it. */ -spin_lock (&sysfs_lock); +spin_lock (&sysfs_assoc_lock);/* The dentry might have been deleted or another * lookup could have happened updating sd->s_dentry to
@@ -248,7 +247,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)*/ if (sd->s_dentry == dentry) sd->s_dentry =NULL ; -spin_unlock (&sysfs_lock); +spin_unlock (&sysfs_assoc_lock);sysfs_put (sd); }iput (inode);
@@ -298,9 +297,9 @@ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) dentry->d_fsdata =sysfs_get (sd);/* protect sd->s_dentry against sysfs_d_iput */ -spin_lock (&sysfs_lock); +spin_lock (&sysfs_assoc_lock); sd->s_dentry = dentry; -spin_unlock (&sysfs_lock); +spin_unlock (&sysfs_assoc_lock);d_rehash (dentry); }
@@ -603,9 +602,9 @@ void sysfs_remove_dir(struct kobject * kobj) {struct sysfs_dirent *sd = kobj->sd; -spin_lock (&kobj_sysfs_assoc_lock); +spin_lock (&sysfs_assoc_lock); kobj->sd =NULL ; -spin_unlock (&kobj_sysfs_assoc_lock); +spin_unlock (&sysfs_assoc_lock);__sysfs_remove_dir (sd); }
fs/sysfs/inode.c +8 -8
@@ -211,11 +211,11 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode)* parent on entry to this function such that it can't be looked * up anymore. * -* @sd->s_dentry which is protected with sysfs_lock points to the -* currently associated dentry but we're not holding a reference -* to it and racing with dput(). Grab dcache_lock and verify -* dentry before dropping it. If @sd->s_dentry is NULL or dput() -* beats us, no need to bother. +* @sd->s_dentry which is protected with sysfs_assoc_lock points +* to the currently associated dentry but we're not holding a +* reference to it and racing with dput(). Grab dcache_lock and +* verify dentry before dropping it. If @sd->s_dentry is NULL or +* dput() beats us, no need to bother. */ void sysfs_drop_dentry (struct sysfs_dirent *sd) {
@@ -224,9 +224,9 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)struct inode *inode;/* We're not holding a reference to ->s_dentry dentry but the -* field will stay valid as long as sysfs_lock is held. +* field will stay valid as long as sysfs_assoc_lock is held. */ -spin_lock (&sysfs_lock); +spin_lock (&sysfs_assoc_lock);spin_lock (&dcache_lock);/* drop dentry if it's there and dput() didn't kill it yet */
@@ -238,7 +238,7 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd) }spin_unlock (&dcache_lock); -spin_unlock (&sysfs_lock); +spin_unlock (&sysfs_assoc_lock);dput (dentry);/* XXX: unpin if directory, this will go away soon */
fs/sysfs/symlink.c +3 -3
@@ -82,12 +82,12 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const charreturn -EFAULT ;/* target->sd can go away beneath us but is protected with -* kobj_sysfs_assoc_lock. Fetch target_sd from it. +* sysfs_assoc_lock. Fetch target_sd from it. */ -spin_lock (&kobj_sysfs_assoc_lock); +spin_lock (&sysfs_assoc_lock);if (target->sd) target_sd =sysfs_get (target->sd); -spin_unlock (&kobj_sysfs_assoc_lock); +spin_unlock (&sysfs_assoc_lock);if (!target_sd)return -ENOENT ;
fs/sysfs/sysfs.h +1 -2
@@ -81,8 +81,7 @@ extern void sysfs_remove_subdir(struct sysfs_dirent *sd);extern void sysfs_drop_dentry (struct sysfs_dirent *sd);extern int sysfs_setattr (struct dentry *dentry,struct iattr *iattr); -extern spinlock_t sysfs_lock; -extern spinlock_t kobj_sysfs_assoc_lock; +extern spinlock_t sysfs_assoc_lock;extern struct rw_semaphore sysfs_rename_sem;extern struct super_block * sysfs_sb;extern const struct file_operations sysfs_dir_operations;
Signature · 1 line
1.5.2.2
PATCH 56/61 sysfs: use sysfs_mutex to protect the sysfs_dirent tree
From: Tejun Heo <[email protected]>
As kobj sysfs dentries and inodes are gonna be made reclaimable, i_mutex can't be used to protect sysfs_dirent tree. Use sysfs_mutex globally instead. As the whole tree is protected with sysfs_mutex, there is no reason to keep sysfs_rename_sem. Drop it.
While at it, add docbook comments to functions which require sysfs_mutex locking.
--- fs/sysfs/dir.c | 101 ++++++++++++++++++++++++++++++++++++--------------- fs/sysfs/file.c | 31 ++++++++-------- fs/sysfs/inode.c | 11 ++---- fs/sysfs/symlink.c | 51 +++++++++++++------------- fs/sysfs/sysfs.h | 2 +- 5 files changed, 116 insertions(+), 80 deletions(-)
fs/sysfs/dir.c +71 -30
@@ -14,7 +14,7 @@#include <asm/semaphore.h> #include "sysfs.h" -DECLARE_RWSEM (sysfs_rename_sem); +DEFINE_MUTEX (sysfs_mutex);spinlock_t sysfs_assoc_lock =SPIN_LOCK_UNLOCKED ;static spinlock_t sysfs_ino_lock =SPIN_LOCK_UNLOCKED ;
@@ -28,7 +28,7 @@ static DEFINE_IDA(sysfs_ino_ida);* sd->s_parent->s_children. * * Locking: -* mutex_lock(sd->s_parent->dentry->d_inode->i_mutex) +* mutex_lock(sysfs_mutex) */ static void sysfs_link_sibling (struct sysfs_dirent *sd) {
@@ -47,7 +47,7 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd)* sd->s_parent->s_children. * * Locking: -* mutex_lock(sd->s_parent->dentry->d_inode->i_mutex) +* mutex_lock(sysfs_mutex) */ static void sysfs_unlink_sibling (struct sysfs_dirent *sd) {
@@ -215,6 +215,9 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)struct sysfs_dirent *parent_sd; repeat: +/* Moving/renaming is always done while holding reference. +* sd->s_parent won't change beneath us. +*/ parent_sd = sd->s_parent;if (sysfs_type (sd) ==SYSFS_KOBJ_LINK )
@@ -291,6 +294,17 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)return NULL ; } +/** +* sysfs_attach_dentry - associate sysfs_dirent with dentry +* @sd: target sysfs_dirent +* @dentry: dentry to associate +* +* Associate @sd with @dentry. This is protected by +* sysfs_assoc_lock to avoid race with sysfs_d_iput(). +* +* LOCKING: +* mutex_lock(sysfs_mutex) +*/ static void sysfs_attach_dentry (struct sysfs_dirent *sd,struct dentry *dentry) { dentry->d_op = &sysfs_dentry_ops;
@@ -304,6 +318,17 @@ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)d_rehash (dentry); } +/** +* sysfs_attach_dirent - attach sysfs_dirent to its parent and dentry +* @sd: sysfs_dirent to attach +* @parent_sd: parent to attach to (optional) +* @dentry: dentry to be associated to @sd (optional) +* +* Attach @sd to @parent_sd and/or @dentry. Both are optional. +* +* LOCKING: +* mutex_lock(sysfs_mutex) +*/ void sysfs_attach_dirent (struct sysfs_dirent *sd,struct sysfs_dirent *parent_sd,struct dentry *dentry) {
@@ -324,7 +349,7 @@ void sysfs_attach_dirent(struct sysfs_dirent *sd,* Look for sysfs_dirent with name @name under @parent_sd. * * LOCKING: -* mutex_lock(parent->i_mutex) +* mutex_lock(sysfs_mutex) * * RETURNS: * Pointer to sysfs_dirent if found, NULL if not.
@@ -349,7 +374,7 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,* it if found. * * LOCKING: -* Kernel thread context (may sleep) +* Kernel thread context (may sleep). Grabs sysfs_mutex. * * RETURNS: * Pointer to sysfs_dirent if found, NULL if not.
@@ -359,10 +384,10 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, {struct sysfs_dirent *sd; -mutex_lock (&parent_sd->s_dentry->d_inode->i_mutex); +mutex_lock (&sysfs_mutex); sd =sysfs_find_dirent (parent_sd, name);sysfs_get (sd); -mutex_unlock (&parent_sd->s_dentry->d_inode->i_mutex); +mutex_unlock (&sysfs_mutex);return sd; }
@@ -408,14 +433,20 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, }/* link in */ +mutex_lock (&sysfs_mutex); + error = -EEXIST ; -if (sysfs_find_dirent (parent_sd, name)) +if (sysfs_find_dirent (parent_sd, name)) { +mutex_unlock (&sysfs_mutex); goto out_iput; + }sysfs_instantiate (dentry, inode);inc_nlink (parent->d_inode);sysfs_attach_dirent (sd, parent_sd, dentry); +mutex_unlock (&sysfs_mutex); + *p_sd = sd; error =0 ; goto out_unlock;/* pin directory dentry in core */
@@ -493,6 +524,8 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,if (!inode)return ERR_PTR (-ENOMEM ); +mutex_lock (&sysfs_mutex); +if (inode->i_state &I_NEW ) {/* initialize inode according to type */ switch (sysfs_type (sd)) {
@@ -516,6 +549,8 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,sysfs_instantiate (dentry, inode);sysfs_attach_dentry (sd, dentry); +mutex_unlock (&sysfs_mutex); +return NULL ; }
@@ -526,17 +561,13 @@ const struct inode_operations sysfs_dir_inode_operations = {static void remove_dir (struct sysfs_dirent *sd) { -struct dentry *parent = sd->s_parent->s_dentry; - -mutex_lock (&parent->d_inode->i_mutex); - +mutex_lock (&sysfs_mutex);sysfs_unlink_sibling (sd); sd->s_flags |=SYSFS_FLAG_REMOVED ; +mutex_unlock (&sysfs_mutex);pr_debug (" o %s removing done\n" , sd->s_name); -mutex_unlock (&parent->d_inode->i_mutex); -sysfs_drop_dentry (sd);sysfs_deactivate (sd);sysfs_put (sd);
@@ -552,15 +583,12 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) {struct sysfs_dirent *removed =NULL ;struct sysfs_dirent **pos; -struct dentry *dir;if (!dir_sd)return ; - dir = dir_sd->s_dentry; -pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); -mutex_lock (&dir->d_inode->i_mutex); +mutex_lock (&sysfs_mutex); pos = &dir_sd->s_children;while (*pos) {struct sysfs_dirent *sd = *pos;
@@ -573,7 +601,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) }else pos = &(*pos)->s_sibling; } -mutex_unlock (&dir->d_inode->i_mutex); +mutex_unlock (&sysfs_mutex);while (removed) {struct sysfs_dirent *sd = removed;
@@ -621,7 +649,6 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,if (!new_parent_sd)return -EFAULT ; -down_write (&sysfs_rename_sem);mutex_lock (&new_parent->d_inode->i_mutex); new_dentry =lookup_one_len (new_name, new_parent,strlen (new_name));
@@ -661,12 +688,16 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,d_add (new_dentry,NULL );d_move (sd->s_dentry, new_dentry); +mutex_lock (&sysfs_mutex); +sysfs_unlink_sibling (sd);sysfs_get (new_parent_sd);sysfs_put (sd->s_parent); sd->s_parent = new_parent_sd;sysfs_link_sibling (sd); +mutex_unlock (&sysfs_mutex); + error =0 ; goto out_unlock;
@@ -678,7 +709,6 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,dput (new_dentry); out_unlock:mutex_unlock (&new_parent->d_inode->i_mutex); -up_write (&sysfs_rename_sem);return error; }
@@ -717,12 +747,15 @@ again:dput (new_dentry);/* Remove from old parent's list and insert into new parent's list. */ +mutex_lock (&sysfs_mutex); +sysfs_unlink_sibling (sd);sysfs_get (new_parent_sd);sysfs_put (sd->s_parent); sd->s_parent = new_parent_sd;sysfs_link_sibling (sd); +mutex_unlock (&sysfs_mutex); out:mutex_unlock (&new_parent_dentry->d_inode->i_mutex);mutex_unlock (&old_parent_dentry->d_inode->i_mutex);
@@ -736,11 +769,12 @@ static int sysfs_dir_open(struct inode *inode, struct file *file)struct sysfs_dirent * parent_sd = dentry->d_fsdata;struct sysfs_dirent * sd; -mutex_lock (&dentry->d_inode->i_mutex); sd =sysfs_new_dirent ("_DIR_" ,0 ,0 ); -if (sd) +if (sd) { +mutex_lock (&sysfs_mutex);sysfs_attach_dirent (sd, parent_sd,NULL ); -mutex_unlock (&dentry->d_inode->i_mutex); +mutex_unlock (&sysfs_mutex); + } file->private_data = sd;return sd ?0 : -ENOMEM ;
@@ -748,12 +782,11 @@ static int sysfs_dir_open(struct inode *inode, struct file *file)static int sysfs_dir_close (struct inode *inode,struct file *file) { -struct dentry * dentry = file->f_path.dentry;struct sysfs_dirent * cursor = file->private_data; -mutex_lock (&dentry->d_inode->i_mutex); +mutex_lock (&sysfs_mutex);sysfs_unlink_sibling (cursor); -mutex_unlock (&dentry->d_inode->i_mutex); +mutex_unlock (&sysfs_mutex);release_sysfs_dirent (cursor);
@@ -794,6 +827,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) i++;/* fallthrough */ default : +mutex_lock (&sysfs_mutex); + pos = &parent_sd->s_children;while (*pos != cursor) pos = &(*pos)->s_sibling;
@@ -826,6 +861,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)/* put cursor back in */ cursor->s_sibling = *pos; *pos = cursor; + +mutex_unlock (&sysfs_mutex); }return 0 ; }
@@ -834,7 +871,6 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) {struct dentry * dentry = file->f_path.dentry; -mutex_lock (&dentry->d_inode->i_mutex);switch (origin) {case 1 : offset += file->f_pos;
@@ -842,10 +878,11 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)if (offset >=0 )break ;default : -mutex_unlock (&file->f_path.dentry->d_inode->i_mutex);return -EINVAL ; }if (offset != file->f_pos) { +mutex_lock (&sysfs_mutex); + file->f_pos = offset;if (file->f_pos >=2 ) {struct sysfs_dirent *sd = dentry->d_fsdata;
@@ -866,8 +903,10 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) cursor->s_sibling = *pos; *pos = cursor; } + +mutex_unlock (&sysfs_mutex); } -mutex_unlock (&dentry->d_inode->i_mutex); +return offset; }
@@ -933,7 +972,9 @@ struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) sd->s_elem.dir.kobj = kobj;/* point to parent_sd but don't attach to it */ sd->s_parent =sysfs_get (parent_sd); +mutex_lock (&sysfs_mutex);sysfs_attach_dirent (sd,NULL , shadow); +mutex_unlock (&sysfs_mutex);d_instantiate (shadow,igrab (inode));inc_nlink (inode);
fs/sysfs/file.c +15 -16
@@ -415,29 +415,28 @@ const struct file_operations sysfs_file_operations = {int sysfs_add_file (struct sysfs_dirent *dir_sd,const struct attribute *attr,int type) { -struct dentry *dir = dir_sd->s_dentry;umode_t mode = (attr->mode &S_IALLUGO ) |S_IFREG ;struct sysfs_dirent *sd; -int error =0 ; -mutex_lock (&dir->d_inode->i_mutex); + sd =sysfs_new_dirent (attr->name, mode, type); +if (!sd) +return -ENOMEM ; + sd->s_elem.attr.attr = (void *)attr; -if (sysfs_find_dirent (dir_sd, attr->name)) { - error = -EEXIST ; - goto out_unlock; - } +mutex_lock (&sysfs_mutex); - sd =sysfs_new_dirent (attr->name, mode, type); -if (!sd) { - error = -ENOMEM ; - goto out_unlock; +if (!sysfs_find_dirent (dir_sd, attr->name)) { +sysfs_attach_dirent (sd, dir_sd,NULL ); + sd =NULL ; } - sd->s_elem.attr.attr = (void *)attr; -sysfs_attach_dirent (sd, dir_sd,NULL ); - out_unlock: -mutex_unlock (&dir->d_inode->i_mutex); -return error; +mutex_unlock (&sysfs_mutex); + +if (sd) { +sysfs_put (sd); +return -EEXIST ; + } +return 0 ; }
fs/sysfs/inode.c +3 -8
@@ -277,20 +277,14 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)int sysfs_hash_and_remove (struct sysfs_dirent *dir_sd,const char *name) { -struct dentry *dir;struct sysfs_dirent **pos, *sd;int found =0 ;if (!dir_sd)return -ENOENT ; - dir = dir_sd->s_dentry; +mutex_lock (&sysfs_mutex); -if (dir->d_inode ==NULL ) -/* no inode means this hasn't been made visible yet */ -return -ENOENT ; - -mutex_lock_nested (&dir->d_inode->i_mutex,I_MUTEX_PARENT );for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { sd = *pos;
@@ -304,7 +298,8 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)break ; } } -mutex_unlock (&dir->d_inode->i_mutex); + +mutex_unlock (&sysfs_mutex);if (!found)return -ENOENT ;
fs/sysfs/symlink.c +26 -25
87 lines not on this page · raw message
fs/sysfs/sysfs.h +1 -1
@@ -82,7 +82,7 @@ extern void sysfs_drop_dentry(struct sysfs_dirent *sd);extern int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);extern spinlock_t sysfs_assoc_lock; -extern struct rw_semaphore sysfs_rename_sem; +extern struct mutex sysfs_mutex;extern struct super_block * sysfs_sb;extern const struct file_operations sysfs_dir_operations;extern const struct file_operations sysfs_file_operations;
Signature · 1 line
1.5.2.2
PATCH 57/61 sysfs: restructure add/remove paths and fix inode update
From: Tejun Heo <[email protected]>
The original add/remove code had the following problems.
* parent's timestamps are updated on dentry instantiation. this is incorrect with reclaimable files.
* updating parent's timestamps isn't synchronized.
* parent nlink update assumes the inode is accessible which won't be true once directory dentries are made reclaimable.
This patch restructures add/remove paths to resolve the above problems. Add/removal are done in the following steps.
1. sysfs_addrm_start() : acquire locks including sysfs_mutex and other resources.
2-a. sysfs_add_one() : add new sd. linking the new sd into the
children list is caller's responsibility.
2-b. sysfs_remove_one() : remove a sd. unlinking the sd from the
children list is caller's responsibility.
3. sysfs_addrm_finish() : release all resources and clean up.
Steps 2-a and/or 2-b can be repeated multiple times.
Parent's inode is looked up during sysfs_addrm_start(). If available (always at the moment), it's pinned and nlink is updated as sd's are added and removed. Timestamps are updated during finish if any sd has been added or removed. If parent's inode is not available during start, sysfs_mutex ensures that parent inode is not created till add/remove is complete.
All the complexity is contained inside the helper functions. Especially, dentry/inode handling is properly hidden from the rest of sysfs which now mostly operate on sysfs_dirents. As an added bonus, codes which use these helpers to add and remove sysfs_dirents are now more structured and simpler.
--- fs/sysfs/dir.c | 250 ++++++++++++++++++++++++++++++++++++++------------- fs/sysfs/file.c | 17 ++-- fs/sysfs/inode.c | 46 ++-------- fs/sysfs/symlink.c | 20 +++-- fs/sysfs/sysfs.h | 20 ++++- 5 files changed, 229 insertions(+), 124 deletions(-)
fs/sysfs/dir.c +186 -64
@@ -30,7 +30,7 @@ static DEFINE_IDA(sysfs_ino_ida);* Locking: * mutex_lock(sysfs_mutex) */ -static void sysfs_link_sibling (struct sysfs_dirent *sd) +void sysfs_link_sibling (struct sysfs_dirent *sd) {struct sysfs_dirent *parent_sd = sd->s_parent;
@@ -49,7 +49,7 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd)* Locking: * mutex_lock(sysfs_mutex) */ -static void sysfs_unlink_sibling (struct sysfs_dirent *sd) +void sysfs_unlink_sibling (struct sysfs_dirent *sd) {struct sysfs_dirent **pos;
@@ -165,7 +165,7 @@ void sysfs_put_active_two(struct sysfs_dirent *sd)* * Deny new active references and drain existing ones. */ -void sysfs_deactivate (struct sysfs_dirent *sd) +static void sysfs_deactivate (struct sysfs_dirent *sd) {DECLARE_COMPLETION_ONSTACK (wait);int v;
@@ -318,27 +318,164 @@ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)d_rehash (dentry); } +static int sysfs_ilookup_test (struct inode *inode,void *arg) +{ +struct sysfs_dirent *sd = arg; +return inode->i_ino == sd->s_ino; +} +/** -* sysfs_attach_dirent - attach sysfs_dirent to its parent and dentry -* @sd: sysfs_dirent to attach -* @parent_sd: parent to attach to (optional) -* @dentry: dentry to be associated to @sd (optional) +* sysfs_addrm_start - prepare for sysfs_dirent add/remove +* @acxt: pointer to sysfs_addrm_cxt to be used +* @parent_sd: parent sysfs_dirent * -* Attach @sd to @parent_sd and/or @dentry. Both are optional. +* This function is called when the caller is about to add or +* remove sysfs_dirent under @parent_sd. This function acquires +* sysfs_mutex, grabs inode for @parent_sd if available and lock +* i_mutex of it. @acxt is used to keep and pass context to +* other addrm functions. * * LOCKING: -* mutex_lock(sysfs_mutex) +* Kernel thread context (may sleep). sysfs_mutex is locked on +* return. i_mutex of parent inode is locked on return if +* available. */ -void sysfs_attach_dirent (struct sysfs_dirent *sd, -struct sysfs_dirent *parent_sd,struct dentry *dentry) +void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt, +struct sysfs_dirent *parent_sd) { -if (dentry) -sysfs_attach_dentry (sd, dentry); +struct inode *inode; -if (parent_sd) { - sd->s_parent =sysfs_get (parent_sd); -sysfs_link_sibling (sd); +memset (acxt,0 ,sizeof (*acxt)); + acxt->parent_sd = parent_sd; + +/* Lookup parent inode. inode initialization and I_NEW +* clearing are protected by sysfs_mutex. By grabbing it and +* looking up with _nowait variant, inode state can be +* determined reliably. +*/ +mutex_lock (&sysfs_mutex); + + inode =ilookup5_nowait (sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test, + parent_sd); + +if (inode && !(inode->i_state &I_NEW )) { +/* parent inode available */ + acxt->parent_inode = inode; + +/* sysfs_mutex is below i_mutex in lock hierarchy. +* First, trylock i_mutex. If fails, unlock +* sysfs_mutex and lock them in order. +*/ +if (!mutex_trylock (&inode->i_mutex)) { +mutex_unlock (&sysfs_mutex); +mutex_lock (&inode->i_mutex); +mutex_lock (&sysfs_mutex); + } + }else +iput (inode); +} + +/** +* sysfs_add_one - add sysfs_dirent to parent +* @acxt: addrm context to use +* @sd: sysfs_dirent to be added +* +* Get @acxt->parent_sd and set sd->s_parent to it and increment +* nlink of parent inode if @sd is a directory. @sd is NOT +* linked into the children list of the parent. The caller +* should invoke sysfs_link_sibling() after this function +* completes if @sd needs to be on the children list. +* +* This function should be called between calls to +* sysfs_addrm_start() and sysfs_addrm_finish() and should be +* passed the same @acxt as passed to sysfs_addrm_start(). +* +* LOCKING: +* Determined by sysfs_addrm_start(). +*/ +void sysfs_add_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) +{ + sd->s_parent =sysfs_get (acxt->parent_sd); + +if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) +inc_nlink (acxt->parent_inode); + + acxt->cnt++; +} + +/** +* sysfs_remove_one - remove sysfs_dirent from parent +* @acxt: addrm context to use +* @sd: sysfs_dirent to be added +* +* Mark @sd removed and drop nlink of parent inode if @sd is a +* directory. @sd is NOT unlinked from the children list of the +* parent. The caller is repsonsible for removing @sd from the +* children list before calling this function. +* +* This function should be called between calls to +* sysfs_addrm_start() and sysfs_addrm_finish() and should be +* passed the same @acxt as passed to sysfs_addrm_start(). +* +* LOCKING: +* Determined by sysfs_addrm_start(). +*/ +void sysfs_remove_one (struct sysfs_addrm_cxt *acxt,struct sysfs_dirent *sd) +{ +BUG_ON (sd->s_sibling || (sd->s_flags &SYSFS_FLAG_REMOVED )); + + sd->s_flags |=SYSFS_FLAG_REMOVED ; + sd->s_sibling = acxt->removed; + acxt->removed = sd; + +if (sysfs_type (sd) ==SYSFS_DIR && acxt->parent_inode) +drop_nlink (acxt->parent_inode); + + acxt->cnt++; +} + +/** +* sysfs_addrm_finish - finish up sysfs_dirent add/remove +* @acxt: addrm context to finish up +* +* Finish up sysfs_dirent add/remove. Resources acquired by +* sysfs_addrm_start() are released and removed sysfs_dirents are +* cleaned up. Timestamps on the parent inode are updated. +* +* LOCKING: +* All mutexes acquired by sysfs_addrm_start() are released. +* +* RETURNS: +* Number of added/removed sysfs_dirents since sysfs_addrm_start(). +*/ +int sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt) +{ +/* release resources acquired by sysfs_addrm_start() */ +mutex_unlock (&sysfs_mutex); +if (acxt->parent_inode) { +struct inode *inode = acxt->parent_inode; + +/* if added/removed, update timestamps on the parent */ +if (acxt->cnt) + inode->i_ctime = inode->i_mtime =CURRENT_TIME ; + +mutex_unlock (&inode->i_mutex); +iput (inode); + } + +/* kill removed sysfs_dirents */ +while (acxt->removed) { +struct sysfs_dirent *sd = acxt->removed; + + acxt->removed = sd->s_sibling; + sd->s_sibling =NULL ; + +sysfs_drop_dentry (sd); +sysfs_deactivate (sd); +sysfs_put (sd); } + +return acxt->cnt; }/**
@@ -396,19 +533,20 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, const char *name, struct sysfs_dirent **p_sd) { struct dentry *parent = parent_sd->s_dentry; +struct sysfs_addrm_cxt acxt;int error;umode_t mode =S_IFDIR |S_IRWXU |S_IRUGO |S_IXUGO ;struct dentry *dentry;struct inode *inode;struct sysfs_dirent *sd; -mutex_lock (&parent->d_inode->i_mutex); +sysfs_addrm_start (&acxt, parent_sd);/* allocate */ dentry =lookup_one_len (name, parent,strlen (name));if (IS_ERR (dentry)) { error =PTR_ERR (dentry); - goto out_unlock; + goto out_finish; } error = -EEXIST ;
@@ -433,23 +571,18 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, }/* link in */ -mutex_lock (&sysfs_mutex); - error = -EEXIST ; -if (sysfs_find_dirent (parent_sd, name)) { -mutex_unlock (&sysfs_mutex); +if (sysfs_find_dirent (parent_sd, name)) goto out_iput; - } +sysfs_add_one (&acxt, sd); +sysfs_link_sibling (sd);sysfs_instantiate (dentry, inode); -inc_nlink (parent->d_inode); -sysfs_attach_dirent (sd, parent_sd, dentry); - -mutex_unlock (&sysfs_mutex); +sysfs_attach_dentry (sd, dentry); *p_sd = sd; error =0 ; - goto out_unlock;/* pin directory dentry in core */ + goto out_finish;/* pin directory dentry in core */ out_iput:iput (inode);
@@ -459,8 +592,8 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,d_drop (dentry); out_dput:dput (dentry); - out_unlock: -mutex_unlock (&parent->d_inode->i_mutex); + out_finish: +sysfs_addrm_finish (&acxt);return error; }
@@ -561,16 +694,12 @@ const struct inode_operations sysfs_dir_inode_operations = {static void remove_dir (struct sysfs_dirent *sd) { -mutex_lock (&sysfs_mutex); -sysfs_unlink_sibling (sd); - sd->s_flags |=SYSFS_FLAG_REMOVED ; -mutex_unlock (&sysfs_mutex); +struct sysfs_addrm_cxt acxt; -pr_debug (" o %s removing done\n" , sd->s_name); - -sysfs_drop_dentry (sd); -sysfs_deactivate (sd); -sysfs_put (sd); +sysfs_addrm_start (&acxt, sd->s_parent); +sysfs_unlink_sibling (sd); +sysfs_remove_one (&acxt, sd); +sysfs_addrm_finish (&acxt); }void sysfs_remove_subdir (struct sysfs_dirent *sd)
@@ -581,38 +710,26 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd)static void __sysfs_remove_dir (struct sysfs_dirent *dir_sd) { -struct sysfs_dirent *removed =NULL ; +struct sysfs_addrm_cxt acxt;struct sysfs_dirent **pos;if (!dir_sd)return ;pr_debug ("sysfs %s: removing dir\n" , dir_sd->s_name); -mutex_lock (&sysfs_mutex); +sysfs_addrm_start (&acxt, dir_sd); pos = &dir_sd->s_children;while (*pos) {struct sysfs_dirent *sd = *pos;if (sysfs_type (sd) && (sysfs_type (sd) &SYSFS_NOT_PINNED )) { - sd->s_flags |=SYSFS_FLAG_REMOVED ; *pos = sd->s_sibling; - sd->s_sibling = removed; - removed = sd; + sd->s_sibling =NULL ; +sysfs_remove_one (&acxt, sd); }else pos = &(*pos)->s_sibling; } -mutex_unlock (&sysfs_mutex); - -while (removed) { -struct sysfs_dirent *sd = removed; - - removed = sd->s_sibling; - sd->s_sibling =NULL ; - -sysfs_drop_dentry (sd); -sysfs_deactivate (sd); -sysfs_put (sd); - } +sysfs_addrm_finish (&acxt);remove_dir (dir_sd); }
@@ -772,7 +889,8 @@ static int sysfs_dir_open(struct inode *inode, struct file *file) sd =sysfs_new_dirent ("_DIR_" ,0 ,0 );if (sd) {mutex_lock (&sysfs_mutex); -sysfs_attach_dirent (sd, parent_sd,NULL ); + sd->s_parent =sysfs_get (parent_sd); +sysfs_link_sibling (sd);mutex_unlock (&sysfs_mutex); }
@@ -957,6 +1075,7 @@ struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)struct sysfs_dirent *parent_sd = parent->d_fsdata;struct dentry *shadow;struct sysfs_dirent *sd; +struct sysfs_addrm_cxt acxt; sd =ERR_PTR (-EINVAL );if (!sysfs_is_shadowed_inode (inode))
@@ -970,15 +1089,18 @@ struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)if (!sd) goto nomem; sd->s_elem.dir.kobj = kobj; -/* point to parent_sd but don't attach to it */ - sd->s_parent =sysfs_get (parent_sd); -mutex_lock (&sysfs_mutex); -sysfs_attach_dirent (sd,NULL , shadow); -mutex_unlock (&sysfs_mutex); +sysfs_addrm_start (&acxt, parent_sd); + +/* add but don't link into children list */ +sysfs_add_one (&acxt, sd); + +/* attach and instantiate dentry */ +sysfs_attach_dentry (sd, shadow);d_instantiate (shadow,igrab (inode)); -inc_nlink (inode); -inc_nlink (parent->d_inode); +inc_nlink (inode);/* tj: synchronization? */ + +sysfs_addrm_finish (&acxt);dget (shadow);/* Extra count - pin the dentry in core */
fs/sysfs/file.c +8 -9
@@ -416,6 +416,7 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type) {umode_t mode = (attr->mode &S_IALLUGO ) |S_IFREG ; +struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd; sd =sysfs_new_dirent (attr->name, mode, type);
@@ -423,20 +424,18 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,return -ENOMEM ; sd->s_elem.attr.attr = (void *)attr; -mutex_lock (&sysfs_mutex); +sysfs_addrm_start (&acxt, dir_sd);if (!sysfs_find_dirent (dir_sd, attr->name)) { -sysfs_attach_dirent (sd, dir_sd,NULL ); - sd =NULL ; +sysfs_add_one (&acxt, sd); +sysfs_link_sibling (sd); } -mutex_unlock (&sysfs_mutex); +if (sysfs_addrm_finish (&acxt)) +return 0 ; -if (sd) { -sysfs_put (sd); -return -EEXIST ; - } -return 0 ; +sysfs_put (sd); +return -EEXIST ; }
fs/sysfs/inode.c +8 -38
95 lines not on this page · raw message
fs/sysfs/symlink.c +11 -9
@@ -55,6 +55,7 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const charstruct sysfs_dirent *parent_sd =NULL ;struct sysfs_dirent *target_sd =NULL ;struct sysfs_dirent *sd =NULL ; +struct sysfs_addrm_cxt acxt;int error;BUG_ON (!name);
@@ -87,17 +88,18 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char goto out_put; sd->s_elem.symlink.target_sd = target_sd; -mutex_lock (&sysfs_mutex); - error = -EEXIST ; -if (sysfs_find_dirent (parent_sd, name)) - goto out_unlock; -sysfs_attach_dirent (sd, parent_sd,NULL ); -mutex_unlock (&sysfs_mutex); +sysfs_addrm_start (&acxt, parent_sd); -return 0 ; +if (!sysfs_find_dirent (parent_sd, name)) { +sysfs_add_one (&acxt, sd); +sysfs_link_sibling (sd); + } - out_unlock: -mutex_unlock (&sysfs_mutex); +if (sysfs_addrm_finish (&acxt)) +return 0 ; + + error = -EEXIST ; +/* fall through */ out_put:sysfs_put (target_sd);sysfs_put (sd);
fs/sysfs/sysfs.h +16 -4
@@ -44,14 +44,29 @@ struct sysfs_dirent {#define SD_DEACTIVATED_BIAS INT_MIN +struct sysfs_addrm_cxt { +struct sysfs_dirent *parent_sd; +struct inode *parent_inode; +struct sysfs_dirent *removed; +int cnt; +}; +extern struct vfsmount * sysfs_mount;extern struct kmem_cache *sysfs_dir_cachep; +extern void sysfs_link_sibling (struct sysfs_dirent *sd); +extern void sysfs_unlink_sibling (struct sysfs_dirent *sd);extern struct sysfs_dirent *sysfs_get_active (struct sysfs_dirent *sd);extern void sysfs_put_active (struct sysfs_dirent *sd);extern struct sysfs_dirent *sysfs_get_active_two (struct sysfs_dirent *sd);extern void sysfs_put_active_two (struct sysfs_dirent *sd); -extern void sysfs_deactivate (struct sysfs_dirent *sd); +extern void sysfs_addrm_start (struct sysfs_addrm_cxt *acxt, +struct sysfs_dirent *parent_sd); +extern void sysfs_add_one (struct sysfs_addrm_cxt *acxt, +struct sysfs_dirent *sd); +extern void sysfs_remove_one (struct sysfs_addrm_cxt *acxt, +struct sysfs_dirent *sd); +extern int sysfs_addrm_finish (struct sysfs_addrm_cxt *acxt);extern void sysfs_delete_inode (struct inode *inode);extern void sysfs_init_inode (struct sysfs_dirent *sd,struct inode *inode);
@@ -65,9 +80,6 @@ extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, const unsigned char *name);extern struct sysfs_dirent *sysfs_new_dirent (const char *name,umode_t mode,int type); -extern void sysfs_attach_dirent (struct sysfs_dirent *sd, -struct sysfs_dirent *parent_sd, -struct dentry *dentry);extern int sysfs_add_file (struct sysfs_dirent *dir_sd,const struct attribute *attr,int type);
Signature · 1 line
1.5.2.2
PATCH 58/61 sysfs: move sysfs_drop_dentry() to dir.c and make it static
From: Tejun Heo <[email protected]>
After add/remove path restructuring, the only user of sysfs_drop_dentry() is sysfs_addrm_finish(). Move sysfs_drop_dentry() to dir.c and make it static.
--- fs/sysfs/dir.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/sysfs/inode.c | 56 ------------------------------------------------------ fs/sysfs/sysfs.h | 1 - 3 files changed, 56 insertions(+), 57 deletions(-)
fs/sysfs/dir.c +56 -0
@@ -435,6 +435,62 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) }/** +* sysfs_drop_dentry - drop dentry for the specified sysfs_dirent +* @sd: target sysfs_dirent +* +* Drop dentry for @sd. @sd must have been unlinked from its +* parent on entry to this function such that it can't be looked +* up anymore. +* +* @sd->s_dentry which is protected with sysfs_assoc_lock points +* to the currently associated dentry but we're not holding a +* reference to it and racing with dput(). Grab dcache_lock and +* verify dentry before dropping it. If @sd->s_dentry is NULL or +* dput() beats us, no need to bother. +*/ +static void sysfs_drop_dentry (struct sysfs_dirent *sd) +{ +struct dentry *dentry =NULL ; +struct inode *inode; + +/* We're not holding a reference to ->s_dentry dentry but the +* field will stay valid as long as sysfs_assoc_lock is held. +*/ +spin_lock (&sysfs_assoc_lock); +spin_lock (&dcache_lock); + +/* drop dentry if it's there and dput() didn't kill it yet */ +if (sd->s_dentry && sd->s_dentry->d_inode) { + dentry =dget_locked (sd->s_dentry); +spin_lock (&dentry->d_lock); +__d_drop (dentry); +spin_unlock (&dentry->d_lock); + } + +spin_unlock (&dcache_lock); +spin_unlock (&sysfs_assoc_lock); + +dput (dentry); +/* XXX: unpin if directory, this will go away soon */ +if (sysfs_type (sd) ==SYSFS_DIR ) +dput (dentry); + +/* adjust nlink and update timestamp */ + inode =ilookup (sysfs_sb, sd->s_ino); +if (inode) { +mutex_lock (&inode->i_mutex); + + inode->i_ctime =CURRENT_TIME ; +drop_nlink (inode); +if (sysfs_type (sd) ==SYSFS_DIR ) +drop_nlink (inode); + +mutex_unlock (&inode->i_mutex); +iput (inode); + } +} + +/** * sysfs_addrm_finish - finish up sysfs_dirent add/remove * @acxt: addrm context to finish up *
fs/sysfs/inode.c +0 -56
62 lines not on this page · raw message
fs/sysfs/sysfs.h +0 -1
@@ -90,7 +90,6 @@ extern int sysfs_create_subdir(struct kobject *kobj, const char *name, struct sysfs_dirent **p_sd);extern void sysfs_remove_subdir (struct sysfs_dirent *sd); -extern void sysfs_drop_dentry (struct sysfs_dirent *sd);extern int sysfs_setattr (struct dentry *dentry,struct iattr *iattr);extern spinlock_t sysfs_assoc_lock;
Signature · 1 line
1.5.2.2
PATCH 59/61 sysfs: implement sysfs_get_dentry()
From: Tejun Heo <[email protected]>
Some sysfs operations require dentry and inode. sysfs_get_dentry() looks up and gets dentry for the specified sysfs_dirent. It finds the first ancestor with dentry attached and starts looking up dentries from there.
Looking up from the nearest ancestor is necessary to support shadowed directories because we can't reliably lookup dentry for one of the shadows. Dentries for each shadow will be pinned in memory such that they can serve as the starting point for dentry lookup.
--- fs/sysfs/dir.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/sysfs/sysfs.h | 1 + 2 files changed, 99 insertions(+), 0 deletions(-)
fs/sysfs/dir.c +98 -0
@@ -63,6 +63,104 @@ void sysfs_unlink_sibling(struct sysfs_dirent *sd) }/** +* sysfs_get_dentry - get dentry for the given sysfs_dirent +* @sd: sysfs_dirent of interest +* +* Get dentry for @sd. Dentry is looked up if currently not +* present. This function climbs sysfs_dirent tree till it +* reaches a sysfs_dirent with valid dentry attached and descends +* down from there looking up dentry for each step. +* +* LOCKING: +* Kernel thread context (may sleep) +* +* RETURNS: +* Pointer to found dentry on success, ERR_PTR() value on error. +*/ +struct dentry *sysfs_get_dentry (struct sysfs_dirent *sd) +{ +struct sysfs_dirent *cur; +struct dentry *parent_dentry, *dentry; +int i, depth; + +/* Find the first parent which has valid s_dentry and get the +* dentry. +*/ +mutex_lock (&sysfs_mutex); + restart0: +spin_lock (&sysfs_assoc_lock); + restart1: +spin_lock (&dcache_lock); + + dentry =NULL ; + depth =0 ; + cur = sd; +while (!cur->s_dentry || !cur->s_dentry->d_inode) { +if (cur->s_flags &SYSFS_FLAG_REMOVED ) { + dentry =ERR_PTR (-ENOENT ); + depth =0 ; +break ; + } + cur = cur->s_parent; + depth++; + } +if (!IS_ERR (dentry)) + dentry =dget_locked (cur->s_dentry); + +spin_unlock (&dcache_lock); +spin_unlock (&sysfs_assoc_lock); + +/* from the found dentry, look up depth times */ +while (depth--) { +/* find and get depth'th ancestor */ +for (cur = sd, i =0 ; cur && i < depth; i++) + cur = cur->s_parent; + +/* This can happen if tree structure was modified due +* to move/rename. Restart. +*/ +if (i != depth) { +dput (dentry); + goto restart0; + } + +sysfs_get (cur); + +mutex_unlock (&sysfs_mutex); + +/* look it up */ + parent_dentry = dentry; + dentry =lookup_one_len_kern (cur->s_name, parent_dentry, +strlen (cur->s_name)); +dput (parent_dentry); + +if (IS_ERR (dentry)) { +sysfs_put (cur); +return dentry; + } + +mutex_lock (&sysfs_mutex); +spin_lock (&sysfs_assoc_lock); + +/* This, again, can happen if tree structure has +* changed and we looked up the wrong thing. Restart. +*/ +if (cur->s_dentry != dentry) { +dput (dentry); +sysfs_put (cur); + goto restart1; + } + +spin_unlock (&sysfs_assoc_lock); + +sysfs_put (cur); + } + +mutex_unlock (&sysfs_mutex); +return dentry; +} + +/** * sysfs_get_active - get an active reference to sysfs_dirent * @sd: sysfs_dirent to get an active reference to *
fs/sysfs/sysfs.h +1 -0
@@ -54,6 +54,7 @@ struct sysfs_addrm_cxt {extern struct vfsmount * sysfs_mount;extern struct kmem_cache *sysfs_dir_cachep; +extern struct dentry *sysfs_get_dentry (struct sysfs_dirent *sd);extern void sysfs_link_sibling (struct sysfs_dirent *sd);extern void sysfs_unlink_sibling (struct sysfs_dirent *sd);extern struct sysfs_dirent *sysfs_get_active (struct sysfs_dirent *sd);
Signature · 1 line
1.5.2.2
PATCH 60/61 sysfs: make directory dentries and inodes reclaimable
From: Tejun Heo <[email protected]>
This patch makes dentries and inodes for sysfs directories reclaimable.
* sysfs_notify() is modified to walk sysfs_dirent tree instead of dentry tree.
* sysfs_update_file() and sysfs_chmod_file() use sysfs_get_dentry() to grab the victim dentry.
* sysfs_rename_dir() and sysfs_move_dir() grab all dentries using sysfs_get_dentry() on startup.
* Dentries for all shadowed directories are pinned in memory to serve as lookup start point.
--- fs/sysfs/dir.c | 231 +++++++++++++++++++++++++++---------------------- fs/sysfs/file.c | 134 +++++++++++++---------------- fs/sysfs/mount.c | 2 +- fs/sysfs/sysfs.h | 1 + include/linux/sysfs.h | 1 - 5 files changed, 187 insertions(+), 182 deletions(-)
fs/sysfs/dir.c +126 -105
@@ -568,10 +568,10 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd)spin_unlock (&dcache_lock);spin_unlock (&sysfs_assoc_lock); -dput (dentry); -/* XXX: unpin if directory, this will go away soon */ -if (sysfs_type (sd) ==SYSFS_DIR ) +/* dentries for shadowed inodes are pinned, unpin */ +if (dentry &&sysfs_is_shadowed_inode (dentry->d_inode))dput (dentry); +dput (dentry);/* adjust nlink and update timestamp */ inode =ilookup (sysfs_sb, sd->s_ino);
@@ -686,69 +686,29 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,static int create_dir (struct kobject *kobj,struct sysfs_dirent *parent_sd,const char *name,struct sysfs_dirent **p_sd) { -struct dentry *parent = parent_sd->s_dentry; -struct sysfs_addrm_cxt acxt; -int error;umode_t mode =S_IFDIR |S_IRWXU |S_IRUGO |S_IXUGO ; -struct dentry *dentry; -struct inode *inode; +struct sysfs_addrm_cxt acxt;struct sysfs_dirent *sd; -sysfs_addrm_start (&acxt, parent_sd); -/* allocate */ - dentry =lookup_one_len (name, parent,strlen (name)); -if (IS_ERR (dentry)) { - error =PTR_ERR (dentry); - goto out_finish; - } - - error = -EEXIST ; -if (dentry->d_inode) - goto out_dput; - - error = -ENOMEM ; sd =sysfs_new_dirent (name, mode,SYSFS_DIR );if (!sd) - goto out_drop; +return -ENOMEM ; sd->s_elem.dir.kobj = kobj; - inode =sysfs_get_inode (sd); -if (!inode) - goto out_sput; - -if (inode->i_state &I_NEW ) { - inode->i_op = &sysfs_dir_inode_operations; - inode->i_fop = &sysfs_dir_operations; -/* directory inodes start off with i_nlink == 2 (for ".") */ -inc_nlink (inode); - } -/* link in */ - error = -EEXIST ; -if (sysfs_find_dirent (parent_sd, name)) - goto out_iput; - -sysfs_add_one (&acxt, sd); -sysfs_link_sibling (sd); -sysfs_instantiate (dentry, inode); -sysfs_attach_dentry (sd, dentry); - - *p_sd = sd; - error =0 ; - goto out_finish;/* pin directory dentry in core */ +sysfs_addrm_start (&acxt, parent_sd); +if (!sysfs_find_dirent (parent_sd, name)) { +sysfs_add_one (&acxt, sd); +sysfs_link_sibling (sd); + } +if (sysfs_addrm_finish (&acxt)) { + *p_sd = sd; +return 0 ; + } - out_iput: -iput (inode); - out_sput:sysfs_put (sd); - out_drop: -d_drop (dentry); - out_dput: -dput (dentry); - out_finish: -sysfs_addrm_finish (&acxt); -return error; +return -EEXIST ; } int sysfs_create_subdir(struct kobject *kobj, const char *name,
@@ -785,6 +745,17 @@ int sysfs_create_dir(struct kobject *kobj,return error; } +static int sysfs_count_nlink (struct sysfs_dirent *sd) +{ +struct sysfs_dirent *child; +int nr =0 ; + +for (child = sd->s_children; child; child = child->s_sibling) +if (sysfs_type (child) ==SYSFS_DIR ) + nr++; +return nr +2 ; +} +static struct dentry *sysfs_lookup (struct inode *dir,struct dentry *dentry,struct nameidata *nd) {
@@ -795,7 +766,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,int found =0 ;for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { -if ((sysfs_type (sd) &SYSFS_NOT_PINNED ) && +if (sysfs_type (sd) && !strcmp (sd->s_name, dentry->d_name.name)) { found =1 ;break ;
@@ -816,6 +787,11 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,if (inode->i_state &I_NEW ) {/* initialize inode according to type */ switch (sysfs_type (sd)) { +case SYSFS_DIR : + inode->i_op = &sysfs_dir_inode_operations; + inode->i_fop = &sysfs_dir_operations; + inode->i_nlink =sysfs_count_nlink (sd); +break ;case SYSFS_KOBJ_ATTR : inode->i_size =PAGE_SIZE ; inode->i_fop = &sysfs_file_operations;
@@ -876,7 +852,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)while (*pos) {struct sysfs_dirent *sd = *pos; -if (sysfs_type (sd) && (sysfs_type (sd) &SYSFS_NOT_PINNED )) { +if (sysfs_type (sd) &&sysfs_type (sd) !=SYSFS_DIR ) { *pos = sd->s_sibling; sd->s_sibling =NULL ;sysfs_remove_one (&acxt, sd);
@@ -912,14 +888,25 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, const char *new_name) {struct sysfs_dirent *sd = kobj->sd; -struct dentry *new_parent = new_parent_sd->s_dentry; -struct dentry *new_dentry; -char *dup_name; +struct dentry *new_parent =NULL ; +struct dentry *old_dentry =NULL , *new_dentry =NULL ; +const char *dup_name =NULL ;int error; -if (!new_parent_sd) -return -EFAULT ; +/* get dentries */ + old_dentry =sysfs_get_dentry (sd); +if (IS_ERR (old_dentry)) { + error =PTR_ERR (old_dentry); + goto out_dput; + } + + new_parent =sysfs_get_dentry (new_parent_sd); +if (IS_ERR (new_parent)) { + error =PTR_ERR (new_parent); + goto out_dput; + } +/* lock new_parent and get dentry for new name */ mutex_lock (&new_parent->d_inode->i_mutex); new_dentry =lookup_one_len (new_name, new_parent,strlen (new_name));
@@ -933,14 +920,14 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,* shadows of the same directory */ error = -EINVAL ; -if (sd->s_parent->s_dentry->d_inode != new_parent->d_inode || +if (old_dentry->d_parent->d_inode != new_parent->d_inode || new_dentry->d_parent->d_inode != new_parent->d_inode || - new_dentry == sd->s_dentry) - goto out_dput; + old_dentry == new_dentry) + goto out_unlock; error = -EEXIST ;if (new_dentry->d_inode) - goto out_dput; + goto out_unlock;/* rename kobject and sysfs_dirent */ error = -ENOMEM ;
@@ -950,9 +937,9 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, error =kobject_set_name (kobj,"%s" , new_name);if (error) - goto out_free; + goto out_drop; -kfree (sd->s_name); + dup_name = sd->s_name; sd->s_name = new_name;/* move under the new parent */
@@ -972,45 +959,58 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, error =0 ; goto out_unlock; - out_free: -kfree (dup_name); out_drop:d_drop (new_dentry); - out_dput: -dput (new_dentry); out_unlock:mutex_unlock (&new_parent->d_inode->i_mutex); + out_dput: +kfree (dup_name); +dput (new_parent); +dput (old_dentry); +dput (new_dentry);return error; } -int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent) +int sysfs_move_dir (struct kobject *kobj,struct kobject *new_parent_kobj) { -struct dentry *old_parent_dentry, *new_parent_dentry, *new_dentry; -struct sysfs_dirent *new_parent_sd, *sd; +struct sysfs_dirent *sd = kobj->sd; +struct sysfs_dirent *new_parent_sd; +struct dentry *old_parent, *new_parent =NULL ; +struct dentry *old_dentry =NULL , *new_dentry =NULL ;int error; - old_parent_dentry = kobj->parent ? - kobj->parent->sd->s_dentry : sysfs_mount->mnt_sb->s_root; - new_parent_dentry = new_parent ? - new_parent->sd->s_dentry : sysfs_mount->mnt_sb->s_root; +BUG_ON (!sd->s_parent); + new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; + +/* get dentries */ + old_dentry =sysfs_get_dentry (sd); +if (IS_ERR (old_dentry)) { + error =PTR_ERR (old_dentry); + goto out_dput; + } + old_parent = sd->s_parent->s_dentry; + + new_parent =sysfs_get_dentry (new_parent_sd); +if (IS_ERR (new_parent)) { + error =PTR_ERR (new_parent); + goto out_dput; + } -if (old_parent_dentry->d_inode == new_parent_dentry->d_inode) -return 0 ;/* nothing to move */ +if (old_parent->d_inode == new_parent->d_inode) { + error =0 ; + goto out_dput;/* nothing to move */ + } again: -mutex_lock (&old_parent_dentry->d_inode->i_mutex); -if (!mutex_trylock (&new_parent_dentry->d_inode->i_mutex)) { -mutex_unlock (&old_parent_dentry->d_inode->i_mutex); +mutex_lock (&old_parent->d_inode->i_mutex); +if (!mutex_trylock (&new_parent->d_inode->i_mutex)) { +mutex_unlock (&old_parent->d_inode->i_mutex); goto again; } - new_parent_sd = new_parent_dentry->d_fsdata; - sd = kobj->sd; - - new_dentry =lookup_one_len (kobj->name, new_parent_dentry, -strlen (kobj->name)); + new_dentry =lookup_one_len (kobj->name, new_parent,strlen (kobj->name));if (IS_ERR (new_dentry)) { error =PTR_ERR (new_dentry); - goto out; + goto out_unlock; }else error =0 ;d_add (new_dentry,NULL );
@@ -1027,10 +1027,14 @@ again:sysfs_link_sibling (sd);mutex_unlock (&sysfs_mutex); -out: -mutex_unlock (&new_parent_dentry->d_inode->i_mutex); -mutex_unlock (&old_parent_dentry->d_inode->i_mutex); + out_unlock: +mutex_unlock (&new_parent->d_inode->i_mutex); +mutex_unlock (&old_parent->d_inode->i_mutex); + out_dput: +dput (new_parent); +dput (old_dentry); +dput (new_dentry);return error; }
@@ -1191,12 +1195,20 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)int sysfs_make_shadowed_dir (struct kobject *kobj,void * (*follow_link)(struct dentry *,struct nameidata *)) { +struct dentry *dentry;struct inode *inode;struct inode_operations *i_op; - inode = kobj->sd->s_dentry->d_inode; -if (inode->i_op != &sysfs_dir_inode_operations) +/* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */ + dentry =sysfs_get_dentry (kobj->sd); +if (IS_ERR (dentry)) +return PTR_ERR (dentry); + + inode = dentry->d_inode; +if (inode->i_op != &sysfs_dir_inode_operations) { +dput (dentry);return -EINVAL ; + } i_op =kmalloc (sizeof (*i_op),GFP_KERNEL );if (!i_op)
@@ -1223,17 +1235,23 @@ int sysfs_make_shadowed_dir(struct kobject *kobj,struct sysfs_dirent *sysfs_create_shadow_dir (struct kobject *kobj) { -struct dentry *dir = kobj->sd->s_dentry; -struct inode *inode = dir->d_inode; -struct dentry *parent = dir->d_parent; -struct sysfs_dirent *parent_sd = parent->d_fsdata; -struct dentry *shadow; +struct sysfs_dirent *parent_sd = kobj->sd->s_parent; +struct dentry *dir, *parent, *shadow; +struct inode *inode;struct sysfs_dirent *sd;struct sysfs_addrm_cxt acxt; + dir =sysfs_get_dentry (kobj->sd); +if (IS_ERR (dir)) { + sd = (void *)dir; + goto out; + } + parent = dir->d_parent; + + inode = dir->d_inode; sd =ERR_PTR (-EINVAL );if (!sysfs_is_shadowed_inode (inode)) - goto out; + goto out_dput; shadow =d_alloc (parent, &dir->d_name);if (!shadow)
@@ -1258,12 +1276,15 @@ struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)dget (shadow);/* Extra count - pin the dentry in core */ -out: -return sd; -nomem: + goto out_dput; + + nomem:dput (shadow); sd =ERR_PTR (-ENOMEM ); - goto out; + out_dput: +dput (dir); + out: +return sd; }/**
fs/sysfs/file.c +59 -75
162 lines not on this page · raw message
fs/sysfs/mount.c +1 -1
@@ -24,7 +24,7 @@ static const struct super_operations sysfs_ops = { .drop_inode = sysfs_delete_inode, }; -static struct sysfs_dirent sysfs_root = { +struct sysfs_dirent sysfs_root = { .s_count =ATOMIC_INIT (1 ), .s_flags =SYSFS_ROOT , .s_mode =S_IFDIR |S_IRWXU |S_IRUGO |S_IXUGO ,
fs/sysfs/sysfs.h +1 -0
@@ -52,6 +52,7 @@ struct sysfs_addrm_cxt { };extern struct vfsmount * sysfs_mount; +extern struct sysfs_dirent sysfs_root;extern struct kmem_cache *sysfs_dir_cachep;extern struct dentry *sysfs_get_dentry (struct sysfs_dirent *sd);
include/linux/sysfs.h +0 -1
@@ -81,7 +81,6 @@ struct sysfs_ops {#define SYSFS_KOBJ_ATTR 0x0004#define SYSFS_KOBJ_BIN_ATTR 0x0008#define SYSFS_KOBJ_LINK 0x0020 -#define SYSFS_NOT_PINNED (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK)#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK
Signature · 1 line
1.5.2.2
PATCH 61/61 sysfs: add parameter "struct bin_attribute *" in .read/.write methods for sysfs binary attributes
From: Zhang Rui <[email protected]>
Well, first of all, I don't want to change so many files either.
What I do:
Adding a new parameter "struct bin_attribute *" in the .read/.write methods for the sysfs binary attributes.
In fact, only the four lines change in fs/sysfs/bin.c and include/linux/sysfs.h do the real work.
But I have to update all the files that use binary attributes to make them compatible with the new .read and .write methods. I'm not sure if I missed any. :(
Why I do this:
For a sysfs attribute, we can get a pointer pointing to the struct attribute in the .show/.store method,
while we can't do this for the binary attributes.
I don't know why this is different, but this does make it not so handy to use the binary attributes as the regular ones. So I think this patch is reasonable. :)
Who benefits from it:
The patch that exposes ACPI tables in sysfs requires such an improvement.
All the table binary attributes share the same .read method. Parameter "struct bin_attribute *" is used to get the table signature and instance number which are used to distinguish different ACPI table binary attributes.
Without this parameter, we need to offer different .read methods for different ACPI table binary attributes.
This is impossible as there are various ACPI tables on different platforms, and we don't know what they are until they are loaded.
--- .../firmware_sample_firmware_class.c | 2 + drivers/base/firmware_class.c | 4 +- drivers/firmware/dcdbas.c | 10 ++-- drivers/firmware/dell_rbu.c | 25 ++++++---- drivers/i2c/chips/eeprom.c | 3 +- drivers/i2c/chips/max6875.c | 5 +- drivers/pci/hotplug/acpiphp_ibm.c | 6 ++- drivers/pci/pci-sysfs.c | 18 +++++-- drivers/pcmcia/socket_sysfs.c | 8 ++- drivers/rapidio/rio-sysfs.c | 6 ++- drivers/rtc/rtc-ds1553.c | 10 ++-- drivers/rtc/rtc-ds1742.c | 10 ++-- drivers/s390/cio/chp.c | 10 ++-- drivers/scsi/arcmsr/arcmsr_attr.c | 15 ++++-- drivers/scsi/ipr.c | 18 +++++-- drivers/scsi/libsas/sas_expander.c | 16 ++++-- drivers/scsi/lpfc/lpfc_attr.c | 12 +++-- drivers/scsi/qla2xxx/qla_attr.c | 50 ++++++++++++-------- drivers/spi/at25.c | 6 ++- drivers/video/aty/radeon_base.c | 8 ++- drivers/w1/slaves/w1_ds2433.c | 10 ++-- drivers/w1/slaves/w1_therm.c | 7 ++- drivers/w1/w1.c | 12 ++++- drivers/zorro/zorro-sysfs.c | 5 +- fs/sysfs/bin.c | 4 +- include/linux/sysfs.h | 6 ++- net/bridge/br_sysfs_br.c | 5 +- 27 files changed, 185 insertions(+), 106 deletions(-)
Documentation/firmware_class/firmware_sample_firmware_class.c +2 -0
@@ -78,6 +78,7 @@ static CLASS_DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);static ssize_t firmware_data_read (struct kobject *kobj, +struct bin_attribute *bin_attr,char *buffer,loff_t offset,size_t count) {struct class_device *class_dev =to_class_dev (kobj);
@@ -88,6 +89,7 @@ static ssize_t firmware_data_read(struct kobject *kobj,return count; }static ssize_t firmware_data_write (struct kobject *kobj, +struct bin_attribute *bin_attr,char *buffer,loff_t offset,size_t count) {struct class_device *class_dev =to_class_dev (kobj);
drivers/base/firmware_class.c +2 -2
@@ -175,7 +175,7 @@ static ssize_t firmware_loading_store(struct device *dev, static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);static ssize_t -firmware_data_read (struct kobject *kobj, +firmware_data_read (struct kobject *kobj,struct bin_attribute *bin_attr,char *buffer,loff_t offset,size_t count) {struct device *dev =to_dev (kobj);
@@ -240,7 +240,7 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)* the driver as a firmware image. **/ static ssize_t -firmware_data_write (struct kobject *kobj, +firmware_data_write (struct kobject *kobj,struct bin_attribute *bin_attr,char *buffer,loff_t offset,size_t count) {struct device *dev =to_dev (kobj);
drivers/firmware/dcdbas.c +6 -4
@@ -149,8 +149,9 @@ static ssize_t smi_data_buf_size_store(struct device *dev,return count; } -static ssize_t smi_data_read (struct kobject *kobj,char *buf,loff_t pos, -size_t count) +static ssize_t smi_data_read (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t pos,size_t count) {size_t max_read;ssize_t ret;
@@ -170,8 +171,9 @@ out:return ret; } -static ssize_t smi_data_write (struct kobject *kobj,char *buf,loff_t pos, -size_t count) +static ssize_t smi_data_write (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t pos,size_t count) {ssize_t ret;
drivers/firmware/dell_rbu.c +15 -10
@@ -543,8 +543,9 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)return ret_count; } -static ssize_t read_rbu_data (struct kobject *kobj,char *buffer, -loff_t pos,size_t count) +static ssize_t read_rbu_data (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buffer,loff_t pos,size_t count) {ssize_t ret_count =0 ;
@@ -591,8 +592,9 @@ static void callbackfn_rbu(const struct firmware *fw, void *context)spin_unlock (&rbu_data.lock); } -static ssize_t read_rbu_image_type (struct kobject *kobj,char *buffer, -loff_t pos,size_t count) +static ssize_t read_rbu_image_type (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buffer,loff_t pos,size_t count) {int size =0 ;if (!pos)
@@ -600,8 +602,9 @@ static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer,return size; } -static ssize_t write_rbu_image_type (struct kobject *kobj,char *buffer, -loff_t pos,size_t count) +static ssize_t write_rbu_image_type (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buffer,loff_t pos,size_t count) {int rc = count;int req_firm_rc =0 ;
@@ -660,8 +663,9 @@ static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer,return rc; } -static ssize_t read_rbu_packet_size (struct kobject *kobj,char *buffer, -loff_t pos,size_t count) +static ssize_t read_rbu_packet_size (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buffer,loff_t pos,size_t count) {int size =0 ;if (!pos) {
@@ -672,8 +676,9 @@ static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer,return size; } -static ssize_t write_rbu_packet_size (struct kobject *kobj,char *buffer, -loff_t pos,size_t count) +static ssize_t write_rbu_packet_size (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buffer,loff_t pos,size_t count) {unsigned long temp;spin_lock (&rbu_data.lock);
drivers/i2c/chips/eeprom.c +2 -1
@@ -110,7 +110,8 @@ exit:mutex_unlock (&data->update_lock); } -static ssize_t eeprom_read (struct kobject *kobj,char *buf,loff_t off,size_t count) +static ssize_t eeprom_read (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));struct eeprom_data *data =i2c_get_clientdata (client);
drivers/i2c/chips/max6875.c +3 -2
@@ -125,8 +125,9 @@ exit_up:mutex_unlock (&data->update_lock); } -static ssize_t max6875_read (struct kobject *kobj,char *buf,loff_t off, -size_t count) +static ssize_t max6875_read (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct i2c_client *client =kobj_to_i2c_client (kobj);struct max6875_data *data =i2c_get_clientdata (client);
drivers/pci/hotplug/acpiphp_ibm.c +4 -2
@@ -106,7 +106,8 @@ static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status);static void ibm_handle_events (acpi_handle handle,u32 event,void *context);static int ibm_get_table_from_acpi (char **bufp);static ssize_t ibm_read_apci_table (struct kobject *kobj, -char *buffer,loff_t pos,size_t size); +struct bin_attribute *bin_attr, +char *buffer,loff_t pos,size_t size);static acpi_status __init ibm_find_acpi_device (acpi_handle handle,u32 lvl,void *context,void **rv);static int __init ibm_acpiphp_init (void );
@@ -357,7 +358,8 @@ read_table_done:* our solution is to only allow reading the table in all at once **/ static ssize_t ibm_read_apci_table (struct kobject *kobj, -char *buffer,loff_t pos,size_t size) +struct bin_attribute *bin_attr, +char *buffer,loff_t pos,size_t size) {int bytes_read = -EINVAL ;char *table =NULL ;
drivers/pci/pci-sysfs.c +12 -6
@@ -213,7 +213,8 @@ struct device_attribute pci_dev_attrs[] = { };static ssize_t -pci_read_config (struct kobject *kobj,char *buf,loff_t off,size_t count) +pci_read_config (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));unsigned int size =64 ;
@@ -285,7 +286,8 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) }static ssize_t -pci_write_config (struct kobject *kobj,char *buf,loff_t off,size_t count) +pci_write_config (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));unsigned int size = count;
@@ -352,7 +354,8 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)* callback routine (pci_legacy_read). */ ssize_t -pci_read_legacy_io (struct kobject *kobj,char *buf,loff_t off,size_t count) +pci_read_legacy_io (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct pci_bus *bus = to_pci_bus(container_of(kobj, struct class_device,
@@ -376,7 +379,8 @@ pci_read_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)* callback routine (pci_legacy_write). */ ssize_t -pci_write_legacy_io (struct kobject *kobj,char *buf,loff_t off,size_t count) +pci_write_legacy_io (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct pci_bus *bus = to_pci_bus(container_of(kobj, struct class_device,
@@ -528,7 +532,8 @@ static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }* writing anything except 0 enables it */ static ssize_t -pci_write_rom (struct kobject *kobj,char *buf,loff_t off,size_t count) +pci_write_rom (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
@@ -551,7 +556,8 @@ pci_write_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)* device corresponding to @kobj. */ static ssize_t -pci_read_rom (struct kobject *kobj,char *buf,loff_t off,size_t count) +pci_read_rom (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));void __iomem *rom;
drivers/pcmcia/socket_sysfs.c +6 -2
@@ -283,7 +283,9 @@ static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t offreturn (ret); } -static ssize_t pccard_show_cis (struct kobject *kobj,char *buf,loff_t off,size_t count) +static ssize_t pccard_show_cis (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {unsigned int size =0x200 ;
@@ -311,7 +313,9 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, sizereturn (count); } -static ssize_t pccard_store_cis (struct kobject *kobj,char *buf,loff_t off,size_t count) +static ssize_t pccard_store_cis (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));cisdump_t *cis;
drivers/rapidio/rio-sysfs.c +4 -2
@@ -67,7 +67,8 @@ struct device_attribute rio_dev_attrs[] = { };static ssize_t -rio_read_config (struct kobject *kobj,char *buf,loff_t off,size_t count) +rio_read_config (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct rio_dev *dev = to_rio_dev(container_of(kobj, struct device, kobj));
@@ -137,7 +138,8 @@ rio_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) }static ssize_t -rio_write_config (struct kobject *kobj,char *buf,loff_t off,size_t count) +rio_write_config (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct rio_dev *dev = to_rio_dev(container_of(kobj, struct device, kobj));
drivers/rtc/rtc-ds1553.c +6 -4
@@ -258,8 +258,9 @@ static const struct rtc_class_ops ds1553_rtc_ops = { .ioctl = ds1553_rtc_ioctl, }; -static ssize_t ds1553_nvram_read (struct kobject *kobj,char *buf, -loff_t pos,size_t size) +static ssize_t ds1553_nvram_read (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t pos,size_t size) {struct platform_device *pdev = to_platform_device(container_of(kobj, struct device, kobj));
@@ -272,8 +273,9 @@ static ssize_t ds1553_nvram_read(struct kobject *kobj, char *buf,return count; } -static ssize_t ds1553_nvram_write (struct kobject *kobj,char *buf, -loff_t pos,size_t size) +static ssize_t ds1553_nvram_write (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t pos,size_t size) {struct platform_device *pdev = to_platform_device(container_of(kobj, struct device, kobj));
drivers/rtc/rtc-ds1742.c +6 -4
@@ -127,8 +127,9 @@ static const struct rtc_class_ops ds1742_rtc_ops = { .set_time = ds1742_rtc_set_time, }; -static ssize_t ds1742_nvram_read (struct kobject *kobj,char *buf, -loff_t pos,size_t size) +static ssize_t ds1742_nvram_read (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t pos,size_t size) {struct platform_device *pdev = to_platform_device(container_of(kobj, struct device, kobj));
@@ -141,8 +142,9 @@ static ssize_t ds1742_nvram_read(struct kobject *kobj, char *buf,return count; } -static ssize_t ds1742_nvram_write (struct kobject *kobj,char *buf, -loff_t pos,size_t size) +static ssize_t ds1742_nvram_write (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t pos,size_t size) {struct platform_device *pdev = to_platform_device(container_of(kobj, struct device, kobj));
drivers/s390/cio/chp.c +6 -4
@@ -141,8 +141,9 @@ static int s390_vary_chpid(struct chp_id chpid, int on)/* * Channel measurement related functions */ -static ssize_t chp_measurement_chars_read (struct kobject *kobj,char *buf, -loff_t off,size_t count) +static ssize_t chp_measurement_chars_read (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct channel_path *chp;unsigned int size;
@@ -192,8 +193,9 @@ static void chp_measurement_copy_block(struct cmg_entry *buf, }while (reference_buf.values[0 ] != buf->values[0 ]); } -static ssize_t chp_measurement_read (struct kobject *kobj,char *buf, -loff_t off,size_t count) +static ssize_t chp_measurement_read (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct channel_path *chp;struct channel_subsystem *css;
drivers/scsi/arcmsr/arcmsr_attr.c +9 -6
@@ -59,8 +59,9 @@struct class_device_attribute *arcmsr_host_attrs[];static ssize_t -arcmsr_sysfs_iop_message_read (struct kobject *kobj,char *buf,loff_t off, -size_t count) +arcmsr_sysfs_iop_message_read (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj);struct Scsi_Host *host =class_to_shost (cdev);
@@ -105,8 +106,9 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off, }static ssize_t -arcmsr_sysfs_iop_message_write (struct kobject *kobj,char *buf,loff_t off, -size_t count) +arcmsr_sysfs_iop_message_write (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj);struct Scsi_Host *host =class_to_shost (cdev);
@@ -152,8 +154,9 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off, }static ssize_t -arcmsr_sysfs_iop_message_clear (struct kobject *kobj,char *buf,loff_t off, -size_t count) +arcmsr_sysfs_iop_message_clear (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj);struct Scsi_Host *host =class_to_shost (cdev);
drivers/scsi/ipr.c +12 -6
@@ -2465,6 +2465,7 @@ restart:/** * ipr_read_trace - Dump the adapter trace * @kobj: kobject struct +* @bin_attr: bin_attribute struct * @buf: buffer * @off: offset * @count: buffer size
@@ -2472,8 +2473,9 @@ restart:* Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_read_trace (struct kobject *kobj,char *buf, -loff_t off,size_t count) +static ssize_t ipr_read_trace (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj);struct Scsi_Host *shost =class_to_shost (cdev);
@@ -3166,6 +3168,7 @@ static struct class_device_attribute *ipr_ioa_attrs[] = {/** * ipr_read_dump - Dump the adapter * @kobj: kobject struct +* @bin_attr: bin_attribute struct * @buf: buffer * @off: offset * @count: buffer size
@@ -3173,8 +3176,9 @@ static struct class_device_attribute *ipr_ioa_attrs[] = {* Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_read_dump (struct kobject *kobj,char *buf, -loff_t off,size_t count) +static ssize_t ipr_read_dump (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj);struct Scsi_Host *shost =class_to_shost (cdev);
@@ -3327,6 +3331,7 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg)/** * ipr_write_dump - Setup dump state of adapter * @kobj: kobject struct +* @bin_attr: bin_attribute struct * @buf: buffer * @off: offset * @count: buffer size
@@ -3334,8 +3339,9 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg)* Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_write_dump (struct kobject *kobj,char *buf, -loff_t off,size_t count) +static ssize_t ipr_write_dump (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj);struct Scsi_Host *shost =class_to_shost (cdev);
drivers/scsi/libsas/sas_expander.c +10 -6
@@ -38,8 +38,10 @@ static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr);#if 0 /* FIXME: smp needs to migrate into the sas class */ -static ssize_t smp_portal_read (struct kobject *,char *,loff_t ,size_t ); -static ssize_t smp_portal_write (struct kobject *,char *,loff_t ,size_t ); +static ssize_t smp_portal_read (struct kobject *,struct bin_attribute *, +char *,loff_t ,size_t ); +static ssize_t smp_portal_write (struct kobject *,struct bin_attribute *, +char *,loff_t ,size_t );#endif /* ---------- SMP task management ---------- */
@@ -1845,8 +1847,9 @@ out:#if 0 /* ---------- SMP portal ---------- */ -static ssize_t smp_portal_write (struct kobject *kobj,char *buf,loff_t offs, -size_t size) +static ssize_t smp_portal_write (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t offs,size_t size) {struct domain_device *dev =to_dom_device (kobj);struct expander_device *ex = &dev->ex_dev;
@@ -1872,8 +1875,9 @@ static ssize_t smp_portal_write(struct kobject *kobj, char *buf, loff_t offs,return size; } -static ssize_t smp_portal_read (struct kobject *kobj,char *buf,loff_t offs, -size_t size) +static ssize_t smp_portal_read (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t offs,size_t size) {struct domain_device *dev =to_dom_device (kobj);struct expander_device *ex = &dev->ex_dev;
drivers/scsi/lpfc/lpfc_attr.c +8 -4
@@ -1133,7 +1133,8 @@ struct class_device_attribute *lpfc_host_attrs[] = { };static ssize_t -sysfs_ctlreg_write (struct kobject *kobj,char *buf,loff_t off,size_t count) +sysfs_ctlreg_write (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {size_t buf_off; struct Scsi_Host *host = class_to_shost(container_of(kobj,
@@ -1165,7 +1166,8 @@ sysfs_ctlreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count) }static ssize_t -sysfs_ctlreg_read (struct kobject *kobj,char *buf,loff_t off,size_t count) +sysfs_ctlreg_read (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {size_t buf_off;uint32_t * tmp_ptr;
@@ -1221,7 +1223,8 @@ sysfs_mbox_idle (struct lpfc_hba * phba) }static ssize_t -sysfs_mbox_write (struct kobject *kobj,char *buf,loff_t off,size_t count) +sysfs_mbox_write (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct Scsi_Host * host = class_to_shost(container_of(kobj, struct class_device, kobj));
@@ -1273,7 +1276,8 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) }static ssize_t -sysfs_mbox_read (struct kobject *kobj,char *buf,loff_t off,size_t count) +sysfs_mbox_read (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct Scsi_Host *host = class_to_shost(container_of(kobj, struct class_device,
drivers/scsi/qla2xxx/qla_attr.c +30 -20
110 lines not on this page · raw message
drivers/spi/at25.c +4 -2
@@ -111,7 +111,8 @@ at25_ee_read( }static ssize_t -at25_bin_read (struct kobject *kobj,char *buf,loff_t off,size_t count) +at25_bin_read (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct device *dev;struct at25_data *at25;
@@ -236,7 +237,8 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count) }static ssize_t -at25_bin_write (struct kobject *kobj,char *buf,loff_t off,size_t count) +at25_bin_write (struct kobject *kobj,struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct device *dev;struct at25_data *at25;
drivers/video/aty/radeon_base.c +6 -2
@@ -2102,7 +2102,9 @@ static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u } -static ssize_t radeon_show_edid1 (struct kobject *kobj,char *buf,loff_t off,size_t count) +static ssize_t radeon_show_edid1 (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct device *dev = container_of(kobj, struct device, kobj);struct pci_dev *pdev =to_pci_dev (dev);
@@ -2113,7 +2115,9 @@ static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, si } -static ssize_t radeon_show_edid2 (struct kobject *kobj,char *buf,loff_t off,size_t count) +static ssize_t radeon_show_edid2 (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct device *dev = container_of(kobj, struct device, kobj);struct pci_dev *pdev =to_pci_dev (dev);
drivers/w1/slaves/w1_ds2433.c +6 -4
@@ -91,8 +91,9 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data, }#endif /* CONFIG_W1_SLAVE_DS2433_CRC */ -static ssize_t w1_f23_read_bin (struct kobject *kobj,char *buf,loff_t off, -size_t count) +static ssize_t w1_f23_read_bin (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct w1_slave *sl =kobj_to_w1_slave (kobj);#ifdef CONFIG_W1_SLAVE_DS2433_CRC
@@ -199,8 +200,9 @@ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)return 0 ; } -static ssize_t w1_f23_write_bin (struct kobject *kobj,char *buf,loff_t off, -size_t count) +static ssize_t w1_f23_write_bin (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct w1_slave *sl =kobj_to_w1_slave (kobj);int addr, len, idx;
drivers/w1/slaves/w1_therm.c +5 -2
@@ -42,7 +42,8 @@ static u8 bad_roms[][9] = { {} }; -static ssize_t w1_therm_read_bin (struct kobject *,char *,loff_t ,size_t ); +static ssize_t w1_therm_read_bin (struct kobject *,struct bin_attribute *, +char *,loff_t ,size_t );static struct bin_attribute w1_therm_bin_attr = { .attr = {
@@ -158,7 +159,9 @@ static int w1_therm_check_rom(u8 rom[9])return 0 ; } -static ssize_t w1_therm_read_bin (struct kobject *kobj,char *buf,loff_t off,size_t count) +static ssize_t w1_therm_read_bin (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct w1_slave *sl =kobj_to_w1_slave (kobj);struct w1_master *dev = sl->master;
drivers/w1/w1.c +9 -3
@@ -105,7 +105,9 @@ static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *areturn sprintf (buf,"%s\n" , sl->name); } -static ssize_t w1_slave_read_id (struct kobject *kobj,char *buf,loff_t off,size_t count) +static ssize_t w1_slave_read_id (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct w1_slave *sl =kobj_to_w1_slave (kobj);
@@ -135,7 +137,9 @@ static struct bin_attribute w1_slave_attr_bin_id = {/* Default family */ -static ssize_t w1_default_write (struct kobject *kobj,char *buf,loff_t off,size_t count) +static ssize_t w1_default_write (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct w1_slave *sl =kobj_to_w1_slave (kobj);
@@ -152,7 +156,9 @@ out_up:return count; } -static ssize_t w1_default_read (struct kobject *kobj,char *buf,loff_t off,size_t count) +static ssize_t w1_default_read (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct w1_slave *sl =kobj_to_w1_slave (kobj);
drivers/zorro/zorro-sysfs.c +3 -2
@@ -49,8 +49,9 @@ static ssize_t zorro_show_resource(struct device *dev, struct device_attribute * static DEVICE_ATTR(resource, S_IRUGO, zorro_show_resource, NULL); -static ssize_t zorro_read_config (struct kobject *kobj,char *buf,loff_t off, -size_t count) +static ssize_t zorro_read_config (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) { struct zorro_dev *z = to_zorro_dev(container_of(kobj, struct device, kobj));
fs/sysfs/bin.c +2 -2
@@ -40,7 +40,7 @@ fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) rc = -EIO ;if (attr->read) - rc = attr->read (kobj, buffer, off, count); + rc = attr->read (kobj, attr, buffer, off, count);sysfs_put_active_two (attr_sd);
@@ -97,7 +97,7 @@ flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) rc = -EIO ;if (attr->write) - rc = attr->write (kobj, buffer, offset, count); + rc = attr->write (kobj, attr, buffer, offset, count);sysfs_put_active_two (attr_sd);
include/linux/sysfs.h +4 -2
@@ -64,8 +64,10 @@ struct bin_attribute {struct attribute attr;size_t size;void *private; -ssize_t (*read)(struct kobject *,char *,loff_t ,size_t ); -ssize_t (*write)(struct kobject *,char *,loff_t ,size_t ); +ssize_t (*read)(struct kobject *,struct bin_attribute *, +char *,loff_t ,size_t ); +ssize_t (*write)(struct kobject *,struct bin_attribute *, +char *,loff_t ,size_t );int (*mmap)(struct kobject *,struct bin_attribute *attr,struct vm_area_struct *vma); };
net/bridge/br_sysfs_br.c +3 -2
@@ -360,8 +360,9 @@ static struct attribute_group bridge_group = {* * Returns the number of bytes read. */ -static ssize_t brforward_read (struct kobject *kobj,char *buf, -loff_t off,size_t count) +static ssize_t brforward_read (struct kobject *kobj, +struct bin_attribute *bin_attr, +char *buf,loff_t off,size_t count) {struct device *dev =to_dev (kobj);struct net_bridge *br =to_bridge (dev);
Signature · 1 line
1.5.2.2
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
In reply to Greg Kroah-HartmanIn article <[email protected]> (at Wed, 11 Jul 2007 16:31:43 -0700), Greg Kroah-Hartman <[email protected]> says:
Quoted 1 line
Make
sysfs_put()ignore NULL sd instead of oopsing.
I do not think this is a good idea; it is non-sense (and rather a bug) to call "put" with NULL argument in general.
--yoshfuji
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
Quoted 6 lines · On Thu, Jul 12, 2007 at 08:50:47AM +0900, YOSHIFUJI Hideaki / ?$B5HF#1QL@ wrote:
In article <[email protected]> (at Wed, 11 Jul 2007 16:31:43 -0700), Greg Kroah-Hartman <[email protected]> says:
Quoted 1 line
Make
sysfs_put()ignore NULL sd instead of oopsing.I do not think this is a good idea; it is non-sense (and rather a bug) to call "put" with NULL argument in general.
It's better than having to check it all the time in the caller :)
thanks,
greg k-h
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
In article <[email protected]> (at Wed, 11 Jul 2007 16:55:29 -0700), Greg KH <[email protected]> says:
Quoted 9 lines · On Thu, Jul 12, 2007 at 08:50:47AM +0900, YOSHIFUJI Hideaki / ?$B5HF#1QL@ wrote:
Quoted 6 lines
In article <[email protected]> (at Wed, 11 Jul 2007 16:31:43 -0700), Greg Kroah-Hartman <[email protected]> says:
Quoted 1 line
Make
sysfs_put()ignore NULL sd instead of oopsing.I do not think this is a good idea; it is non-sense (and rather a bug) to call "put" with NULL argument in general.
It's better than having to check it all the time in the caller :)
How many callers do we have that will get benefit from this change?
Well, the change will hide the bug. It seems all callers in fs/sysfs already assume that the argument is NOT NULL, and it is a bug to call sysfs_put() with NULL; the function should be used to "put" something you "have" (non-NULL). If it is called with NULL, I would say, we should BUG here to detect the logical bug.
--yoshfuji
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
Quoted 10 lines · YOSHIFUJI Hideaki / 吉藤英明
In article <[email protected]> (at Wed, 11 Jul 2007 16:55:29 -0700), Greg KH <[email protected]> says:
Quoted 7 lines · On Thu, Jul 12, 2007 at 08:50:47AM +0900, YOSHIFUJI Hideaki / ?$B5HF#1QL@ wrote:
Quoted 5 lines
In article <[email protected]> (at Wed, 11 Jul 2007 16:31:43 -0700), Greg Kroah-Hartman <[email protected]> says:
Quoted 1 line
Make
sysfs_put()ignore NULL sd instead of oopsing.I do not think this is a good idea; it is non-sense (and rather a bug) to call "put" with NULL argument in general.
It's better than having to check it all the time in the caller :)
Quoted 7 lines
How many callers do we have that will get benefit from this change?
Well, the change will hide the bug. It seems all callers in fs/sysfs already assume that the argument is NOT NULL, and it is a bug to call
sysfs_put()with NULL; the function should be used to "put" something you "have" (non-NULL). If it is called with NULL, I would say, we should BUG here to detect the logical bug.
Well, I'm okay either way. It's not like one way is undisputably better than the other but we're leaning toward accepting NULL argument in this type of functions. Think about kfree(NULL) and its usefulness. More importantly, the ecosystem around sysfs - that is, kobject, driver model
- generally accepts NULL argument for their get/put functions, so unless there's a compelling reason to convert them all, and I don't see any, sysfs_put() needs to follow the same rule.
Signature · 1 line
tejun
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
Hi,
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
Quoted 3 lines
Quoted 1 line
Make
sysfs_put()ignore NULL sd instead of oopsing.I do not think this is a good idea; it is non-sense (and rather a bug) to call "put" with NULL argument in general.
It's better than having to check it all the time in the caller :)
Quoted 7 lines
Quoted 7 lines
How many callers do we have that will get benefit from this change?
Well, the change will hide the bug. It seems all callers in fs/sysfs already assume that the argument is NOT NULL, and it is a bug to call
sysfs_put()with NULL; the function should be used to "put" something you "have" (non-NULL). If it is called with NULL, I would say, we should BUG here to detect the logical bug.
Yoshifuji is 100% correct, IMNSHO.
Please, this is _basic_ refcounting semantics. For those who disagree, kindly read Yoshifuji's above paragraph again.
Quoted 2 lines
Well, I'm okay either way. It's not like one way is undisputably better than the other
Yes, it is, of course. Allowing xxx_put(NULL) to succeed (without any warnings/oops) is *absolutely* nonsensical, and can *only* occur if the caller (or worse, the API itself) is buggy in the first place (i.e. does not use proper locking and/or refcounting).
I can't believe it should be so difficult to understand this. How can any caller (that first did a xxx_get() on that shared object) land up with that object getting NULL _from under it_ unless some logic is wrong somewhere? And instead of flagging this broken logic, the proposed change here would hide it.
Worse, if that object did become NULL between the _get() and _put() code, then we'll have an oops (which would be even more difficult to debug now) anyway.
Quoted 2 lines
but we're leaning toward accepting NULL argument in this type of functions. Think about kfree(NULL) and its usefulness.
Don't {mis}quote the kfree() mistake here, please.
Quoted 3 lines
More
importantly, the ecosystem around sysfs - that is, kobject, driver model
- generally accepts NULL argument for their get/put functions
This can only mean two things:
(1) Either, they simply do not _need_ the refcounting in the first place (which means -- better do away with get() and put() for them altogether)
(2) Or, all that code / APIs are so horribly misdesigned and/or buggy that you're now having to hide that by allowing NULL arguments in get() and put() functions (which means -- fix the bugs, please)
Quoted 3 lines
so unless
there's a compelling reason to convert them all, and I don't see any,sysfs_put()needs to follow the same rule.
Ok, what's the compelling reason to change sysfs_put() then? I don't see any, either.
Satyam
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
Hello,
Quoted 4 lines · Satyam Sharma
Yoshifuji is 100% correct, IMNSHO.
Please, this is _basic_ refcounting semantics. For those who disagree, kindly read Yoshifuji's above paragraph again.
I did but I don't really see anything so basic about refcounting semantics there.
Quoted 9 lines
Quoted 2 lines
Well, I'm okay either way. It's not like one way is undisputably better than the other
Yes, it is, of course. Allowing
xxx_put(NULL)to succeed (without any warnings/oops) is *absolutely* nonsensical, and can *only* occur if the caller (or worse, the API itself) is buggy in the first place (i.e. does not
use proper locking and/or refcounting).
Quoted 5 lines
I can't believe it should be so difficult to understand this. How can any caller (that first did a
xxx_get()on that shared object) land up with that object getting NULL_fromunderit_unless some logic is wrong somewhere? And instead of flagging this broken logic, the proposed change here would hide it.
NULL put is usually used to simplify error handling / cleanup codes.
Quoted 3 lines
Worse, if that object did become NULL between the
_get()and_put()code, then we'll have an oops (which would be even more difficult to debug now) anyway.
Yeah, if NULL was a mistake, we're gonna oops anyway.
Quoted 4 lines
Quoted 2 lines
but we're leaning toward accepting NULL argument in this type of functions. Think about kfree(NULL) and its usefulness.
Don't {mis}quote the
kfree()mistake here, please.
Like it or not, kfree(NULL) is used the same way.
Quoted 8 lines
Quoted 3 lines
More
importantly, the ecosystem around sysfs - that is, kobject, driver model
- generally accepts NULL argument for their get/put functionsThis can only mean two things:
(1) Either, they simply do not _need_ the refcounting in the first place (which means -- better do away with
get()andput()for them altogether)
I don't really see how you can jump there from allowing NULL argument. Your conclusion is really far from the origin.
Quoted 10 lines
(2) Or, all that code / APIs are so horribly misdesigned and/or buggy that you're now having to hide that by allowing NULL arguments in
get()andput()functions (which means -- fix the bugs, please)Quoted 3 lines
so unless
there's a compelling reason to convert them all, and I don't see any,sysfs_put()needs to follow the same rule.Ok, what's the compelling reason to change
sysfs_put()then? I don't see any, either.
Because mixed situation is undisputably worse than one way or the other && making sysfs_put() to conform to its surroundings is the shortest path to achieve uniformity. Gees, what's so important about allowing or not allowing NULL? You can get used to either way. If you feel allowing NULL argument to get/put functions are wrong. Just go ahead and submit separate patches to change that. I won't object to that although I won't feel too hot for that either.
Signature · 1 line
tejun
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
Hello, forgot one thing.
Quoted 5 lines · Tejun Heo
Quoted 5 lines
I can't believe it should be so difficult to understand this. How can any caller (that first did a
xxx_get()on that shared object) land up with that object getting NULL_fromunderit_unless some logic is wrong somewhere? And instead of flagging this broken logic, the proposed change here would hide it.
I agree with you about get(). Allowing NULL argument doesn't really help anything. It only increases the chance of getting things wrong. I'm all for not allowing NULL argument to get(). For put(), as I wrote before, I think allowing NULL has some advantages and I don't care either way as long as it's not confusing. The 'not confusing' part is way more important to me than advantages of either way.
Signature · 1 line
tejun
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
Hi,
Thanks for explaining the purpose behind the proposed change, but I'm still not convinced that allowing NULL argument in _put() is a good idea, however:
Quoted 7 lines · Tejun Heo
Quoted 2 lines · Satyam Sharma
Please, this is _basic_ refcounting semantics. For those who disagree, kindly read Yoshifuji's above paragraph again.
I did but I don't really see anything so basic about refcounting semantics there.
[...]
Quoted 7 lines
Quoted 2 lines
Ok, what's the compelling reason to change
sysfs_put()then? I don't see any, either.Because mixed situation is undisputably worse than one way or the other && making
sysfs_put()to conform to its surroundings is the shortest path to achieve uniformity. Gees, what's so important about allowing or not allowing NULL?
The whole _purpose_ of get()/put() functions (i.e. refcounting in general) is to ensure that the (shared) objects don't go away from under us while we're holding them. The proposed change _weakens_ the API itself by allowing a buggy driver (that somehow called into _put() codepath without a _get() before it) to not get flagged immediately (through an oops). This inevitably leads to some difficult-to-debug problems -- I have suffered debugging issues created by such weak/loose APIs myself.
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
but we're leaning toward accepting NULL argument in this type of functions. Think about kfree(NULL) and its usefulness.
Don't {mis}quote the
kfree()mistake here, please.Like it or not, kfree(NULL) is used the same way.
But we pay a heavy price for the "programmer convenience" (just avoiding some conditionals / multiple goto labels in error cleanup paths) that we get in return. I do believe the kernel would've been much less buggy, if only kfree(NULL) wasn't legal.
But even if you do want to allow NULL arguments to such functions, for certain situations, you could always write a little wrapper over the lower function that'll include the "if (not NULL)" kind of check.
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
More
importantly, the ecosystem around sysfs - that is, kobject, driver model
- generally accepts NULL argument for their get/put functionsThis can only mean two things:
Quoted 7 lines
Quoted 2 lines
(1) Either, they simply do not _need_ the refcounting in the first place (which means -- better do away with
get()andput()for them altogether)I don't really see how you can jump there from allowing NULL argument. Your conclusion is really far from the origin.
[...]
NULL put is usually used to simplify error handling / cleanup codes.
I'd be gladder if you could point me to code where this change really helps. I'd definitely like to send patches, why not.
Quoted 6 lines · Tejun Heo
Quoted 5 lines
Quoted 5 lines
I can't believe it should be so difficult to understand this. How can any caller (that first did a
xxx_get()on that shared object) land up with that object getting NULL_fromunderit_unless some logic is wrong somewhere? And instead of flagging this broken logic, the proposed change here would hide it.
Quoted 6 lines
I agree with you about
get(). Allowing NULL argument doesn't really help anything. It only increases the chance of getting things wrong. I'm all for not allowing NULL argument toget(). Forput(), as I wrote before, I think allowing NULL has some advantages and I don't care either way as long as it's not confusing. The 'not confusing' part is way more important to me than advantages of either way.
As I said, changing generic refcounting API functions (which is what xxx_put() is) to simplify open-coding of a conditional in the caller's error cleanup paths does not sound advantageous to me at all. On the contrary, it weakens the refcounting API, and I can only imagine the kernel getting buggier with such changes.
Satyam
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
Hello,
Quoted 5 lines · Satyam Sharma
Quoted 4 lines
Because mixed situation is undisputably worse than one way or the other && making
sysfs_put()to conform to its surroundings is the shortest path to achieve uniformity. Gees, what's so important about allowing or not allowing NULL?
Quoted 7 lines
The whole _purpose_ of get()/put() functions (i.e. refcounting in general) is to ensure that the (shared) objects don't go away from under us while we're holding them. The proposed change _weakens_ the API itself by allowing a buggy driver (that somehow called into
_put()codepath without a_get()before it) to not get flagged immediately (through an oops). This inevitably leads to some difficult-to-debug problems -- I have suffered debugging issues created by such weak/loose APIs myself.
Yeah, that's the advantage of not allowing NULL, well, or disadvantage of allowing. I get that. If I were to reimplement all these functions, I probably wouldn't allow NULL argument myself either. As much as I understand your POV, I just don't think it's as critical as maintaining uniformity. There are million and one ways to get refcounting wrong and allowing or not allowing NULL seems like a very small factor to me. On the other hand, if you make things confusing by allowing on some but not allowing on others, it's much more likely to trigger programmer error.
Quoted 11 lines
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
but we're leaning toward accepting NULL argument in this type of functions. Think about kfree(NULL) and its usefulness.
Don't {mis}quote the
kfree()mistake here, please.Like it or not, kfree(NULL) is used the same way.
But we pay a heavy price for the "programmer convenience" (just avoiding some conditionals / multiple goto labels in error cleanup paths) that we get in return. I do believe the kernel would've been much less buggy, if only kfree(NULL) wasn't legal.
I'm not sure whether it has contributed a lot to bugs, maybe. But still, on cases like this, I think staying with what people are used to is the best way. The advantages or disadvantages are really small compared to the confusion overhead.
Quoted 3 lines
But even if you do want to allow NULL arguments to such functions, for certain situations, you could always write a little wrapper over the lower function that'll include the "if (not NULL)" kind of check.
Yeap, sure.
Quoted 8 lines
Quoted 4 lines
I don't really see how you can jump there from allowing NULL argument. Your conclusion is really far from the origin.
[...]
NULL put is usually used to simplify error handling / cleanup codes.I'd be gladder if you could point me to code where this change really helps.
I'd definitely like to send patches, why not.
It's added by later patches. The patch itself is created because I was hit by the confusion. sysfs_get() allowed NULL argument but sysfs_put() didn't. Where's sense in that? I thought about converting sysfs_get() to not accepting NULL but then the whole kobject and friends would act differently.
For sysfs, changing behavior is okay. It's mostly self-contained subsystem and sysfs_get/put() aren't even exported to outside world, but kobject and driver model are different story. Changing such subtle behavior of such widely used interface is bound to create a lot of confusion.
Think about what would happen if NULL is suddenly disallowed on kfree().
Even if all the current in-kernel users are converted at once (I'm sure
we're gonna miss some tho), all the out of tree (including devel) codes and future codes will suffer and some of the bugs would be really hard to catch as kfree(NULL) is buried in error handling path which generally isn't triggered too often.
The same thing holds for kobject/driver model interface. The confusion which will be caused by such change outweighs any benefit which can come from it. So, I can't change kobject/driver model behavior. If I then come back to sysfs, the only option I have is to make sysfs follow the rule in its neighborhood.
It's almost similar in get() too, but I think we have better chance there because NULL get() is much more useless than NULL put() which means it's used less. Also, another plus is that get() errors are easy to catch. It usually lives in hot paths, but still I can't tell whether the cost of conversion would worth the gained benefit.
Quoted 7 lines
Quoted 6 lines
I agree with you about
get(). Allowing NULL argument doesn't really help anything. It only increases the chance of getting things wrong. I'm all for not allowing NULL argument toget(). Forput(), as I wrote before, I think allowing NULL has some advantages and I don't care either way as long as it's not confusing. The 'not confusing' part is way more important to me than advantages of either way.
Quoted 5 lines
As I said, changing generic refcounting API functions (which is what
xxx_put()is) to simplify open-coding of a conditional in the caller's error cleanup paths does not sound advantageous to me at all. On the contrary, it weakens the refcounting API, and I can only imagine the kernel getting buggier with such changes.
I hope my 'confusion' argument explained my logic a bit better. Again, if you wanna change it, I'm not necessarily against it but that should be a completely separate step && till that happens, making sysfs_put() to follow its surrounding world _is_ a good idea.
Thanks.
Signature · 1 line
tejun
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
Hi Tejun,
Quoted 11 lines · Tejun Heo
Hello,
Quoted 7 lines · Satyam Sharma
The whole _purpose_ of get()/put() functions (i.e. refcounting in general) is to ensure that the (shared) objects don't go away from under us while we're holding them. The proposed change _weakens_ the API itself by allowing a buggy driver (that somehow called into
_put()codepath without a_get()before it) to not get flagged immediately (through an oops). This inevitably leads to some difficult-to-debug problems -- I have suffered debugging issues created by such weak/loose APIs myself.
Quoted 3 lines
Yeah, that's the advantage of not allowing NULL, well, or disadvantage of allowing. I get that. If I were to reimplement all these functions, I probably wouldn't allow NULL argument myself either.
Good, at least we're on the same plane here :-)
Quoted 7 lines
As much as I
understand your POV, I just don't think it's as critical as maintaining uniformity.
[...] if you make things confusing by allowing on some but not allowing on others, it's much more likely to trigger programmer error. [...] The advantages or disadvantages are really small compared to the confusion overhead.
Well, I don't really buy the uniformity/confusion argument either:
fput() will oops on NULL file *put_super() will oops on NULL super_block * put_task_struct() will oops on NULL task_struct * mmput() will oops on NULL mm_struct * configfs_put() will oops on NULL configfs_dirent * kref_put() will oops on NULL kref * (and this one better do) dev_put() will oops on NULL net_device * put_driver() will oops on NULL device_driver *
and sysfs_put() also oopsed on NULL sysfs_dirent *, till you changed it not to, that is :-)
[ and there are other examples, of course ]
I think put()'s *must* oops on NULL arguments -- it's simply a matter of writing a good, strict, (I could add "tasteful" but that would make it subjective) API that will *prevent* mysterious bugs.
Of course, dput(), kobject_put() and put_device() are a few counter examples that allowing put-ing NULL objects, but it's not as if this _disease_ has become widespread enough throughout the kernel -- that is, till we _make_ it widespread by following the lead of *mistakes*.
[ Perhaps you don't really care for the examples I mentioned above because sysfs is "closer" in some sense to kobjects / devices and so because those allow put-ing NULL objects, you want to make sysfs "uniform" to them in that sense ... but that's a bad excuse. ]
Quoted 10 lines
Quoted 3 lines
I'd be gladder if you could point me to code where this change really helps.
I'd definitely like to send patches, why not.It's added by later patches. The patch itself is created because I was hit by the confusion.
sysfs_get()allowed NULL argument butsysfs_put()didn't. Where's sense in that? I thought about convertingsysfs_get()to not accepting NULL but then the whole kobject and friends would act differently.
Quoted 5 lines
For sysfs, changing behavior is okay. It's mostly self-contained subsystem and sysfs_get/put() aren't even exported to outside world, but kobject and driver model are different story. Changing such subtle behavior of such widely used interface is bound to create a lot of confusion.
Well, what I'm asking here is not to change the mistakes already made (it's probably too late for that), but to avoid *repeating* them.
Quoted 6 lines
Think about what would happen if NULL is suddenly disallowed on
kfree().
Even if all the current in-kernel users are converted at once (I'm sure
we're gonna miss some tho), all the out of tree (including devel) codes and future codes will suffer and some of the bugs would be really hard to catch as kfree(NULL) is buried in error handling path which generally isn't triggered too often.
kfree(NULL) is not exactly analogous. And obviously I don't intend changing that and then trying to change the 6,732,893 or so callsites that assume the same :-) But what if everybody starts taking this lead and starts {re}writing APIs accordingly throughout the kernel ... *shudder to think*
Anyway, we've wasted enough time and bandwidth discussing this (relatively trivial) matter, and I know nobody's mind is changed after the end of it all (at least mine won't), so I suggest let's stop. The proposed change is in Greg's tree already, and if he's fine with it, then there's not much to do about it, is there :-)
Satyam
Re: [PATCH 24/61] sysfs: make sysfs_put() ignore NULL sd
Hello,
Quoted 5 lines · Satyam Sharma
Anyway, we've wasted enough time and bandwidth discussing this (relatively trivial) matter, and I know nobody's mind is changed after the end of it all (at least mine won't), so I suggest let's stop. The proposed change is in Greg's tree already, and if he's fine with it, then there's not much to do about it, is there :-)
I have no problem regenerating the patchset without this allow-NULL patch but as I said, I see it as an improvement and we'll have to agree to disagree on that point. But, if you think NULL get/put() are bad, please go ahead and change things. As long as things stay consistent, I'm okay with, well, even slightly prefer not allowing NULL.
Thanks. :-)
Signature · 1 line
tejun
Re: [PATCH 01/61] Rules on how to use sysfs in userspace programs
In reply to Greg Kroah-HartmanQuoted 17 lines · Greg Kroah-Hartman
From: Kay Sievers <[email protected]>
Here's a document to help clear things up.
Signed-off-by Kay Sievers <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- Documentation/sysfs-rules.txt | 166 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 166 insertions(+), 0 deletions(-) create mode 100644 Documentation/sysfs-rules.txtDocumentation/sysfs-rules.txt new file +0
-0
Documentation/sysfs-rules.txt line 3
Quoted 3 lines
Documentation/sysfs-rules.txt new file +3
-0@@ -0,0 +1,166 @@ +Rules on how to access information in the Linux kernel sysfs + +The kernel exported sysfs exports internal kernel implementation-details
kernel-exported implementation details
Documentation/sysfs-rules.txt line 7
Quoted 4 lines
Documentation/sysfs-rules.txt new file +4
-0+and depends on internal kernel structures and layout. It is agreed upon +by the kernel developers that the Linux kernel does not provide a stable +internal API. As sysfs is a direct export of kernel internal +structures, the sysfs interface can not provide a stable interface eighter,
either
...
you might want to hold off on that patch for a few minutes. :-)
rday
Signature · 7 lines
======================================================================== Robert P. J. Day Linux Consulting, Training and Annoying Kernel Pedantry Waterloo, Ontario, CANADA http://fsdev.net/wiki/index.php?title=Main_Page ========================================================================
Re: [PATCH 01/61] Rules on how to use sysfs in userspace programs
Quoted 23 lines · Robert P. J. Day
Quoted 17 lines · Greg Kroah-Hartman
From: Kay Sievers <[email protected]>
Here's a document to help clear things up.
Signed-off-by Kay Sievers <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- Documentation/sysfs-rules.txt | 166 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 166 insertions(+), 0 deletions(-) create mode 100644 Documentation/sysfs-rules.txtDocumentation/sysfs-rules.txt new file +0
-0Documentation/sysfs-rules.txt line 3
Quoted 3 lines
Documentation/sysfs-rules.txt new file +3
-0@@ -0,0 +1,166 @@ +Rules on how to access information in the Linux kernel sysfs + +The kernel exported sysfs exports internal kernel implementation-detailskernel-exported implementation details
Quoted 8 lines
Documentation/sysfs-rules.txt line 7
Quoted 4 lines
Documentation/sysfs-rules.txt new file +4
-0+and depends on internal kernel structures and layout. It is agreed upon +by the kernel developers that the Linux kernel does not provide a stable +internal API. As sysfs is a direct export of kernel internal +structures, the sysfs interface can not provide a stable interface eighter,either
...you might want to hold off on that patch for a few minutes. :-)
Patches for grammer are always accepted :)
Care to make up one against Linus's tree after this goes in?
thanks,
greg k-h
Re: [PATCH 01/61] Rules on how to use sysfs in userspace programs
Quoted 1 line · Greg KH
Patches for grammer are always accepted :)
b renamed from a +1 -1
@@ -1 +1 @@ -Patches for grammer are always accepted :) +Patches for grammar are always accepted :)
Rene.
Re: [PATCH 01/61] Rules on how to use sysfs in userspace programs
In reply to Greg Kroah-HartmanQuoted 17 lines · Greg Kroah-Hartman
From: Kay Sievers <[email protected]>
Here's a document to help clear things up.
Signed-off-by Kay Sievers <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- Documentation/sysfs-rules.txt | 166 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 166 insertions(+), 0 deletions(-) create mode 100644 Documentation/sysfs-rules.txtDocumentation/sysfs-rules.txt new file +0
-0
Documentation/sysfs-rules.txt line 8
Quoted 8 lines
Documentation/sysfs-rules.txt new file +8
-0@@ -0,0 +1,166 @@ +Rules on how to access information in the Linux kernel sysfs + +The kernel exported sysfs exports internal kernel implementation-details +and depends on internal kernel structures and layout. It is agreed upon +by the kernel developers that the Linux kernel does not provide a stable +internal API. As sysfs is a direct export of kernel internal +structures, the sysfs interface can not provide a stable interface eighter, +it may always change along with internal kernel changes.
It is also agreed upon by the kernel developers that the Linux kernel does have a stable user<->kernel API... so we have a small problem here.
Maybe solution is to declare /sys unstable, but... perhaps /sys can stop mirroring internal structures? I do not think we should codify our failure to keep /sys stable here.
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH 01/61] Rules on how to use sysfs in userspace programs
Quoted 31 lines · Pavel Machek
Quoted 17 lines · Greg Kroah-Hartman
From: Kay Sievers <[email protected]>
Here's a document to help clear things up.
Signed-off-by Kay Sievers <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- Documentation/sysfs-rules.txt | 166 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 166 insertions(+), 0 deletions(-) create mode 100644 Documentation/sysfs-rules.txtDocumentation/sysfs-rules.txt new file +0
-0Documentation/sysfs-rules.txt line 8
Quoted 8 lines
Documentation/sysfs-rules.txt new file +8
-0@@ -0,0 +1,166 @@ +Rules on how to access information in the Linux kernel sysfs + +The kernel exported sysfs exports internal kernel implementation-details +and depends on internal kernel structures and layout. It is agreed upon +by the kernel developers that the Linux kernel does not provide a stable +internal API. As sysfs is a direct export of kernel internal +structures, the sysfs interface can not provide a stable interface eighter, +it may always change along with internal kernel changes.It is also agreed upon by the kernel developers that the Linux kernel does have a stable user<->kernel API... so we have a small problem here.
Quoted 3 lines
Maybe solution is to declare /sys unstable, but... perhaps /sys can stop mirroring internal structures? I do not think we should codify our failure to keep /sys stable here.
Sysfs never tried to be an ABI/API in the usual sense, parts of it are just a nicer looking "kernel dump". :)
You have to follow _very_ special rules to extract information here in a way that will not produce unexpected results between kernel releases, or even a second later on the same system.
In sysfs, all information is located in a tree, and the nodes in the tree can move around even at runtime, directories get dynamically renamed, or whole directories get reparented with all their contained information. Things you've seen in this second can be somewhere else just a second later. That's the expected behavior of sysfs and can certainly not be compared to the stability of syscalls, ioctl's, proc and similar.
We can't remove information from sysfs because it is needed and useful, but most of the information can only be reached in a _very_ specific way. That's what this document tries to start to document. Maintaining the biggest users of sysfs today, udev and that part of HAL for years now, I still don't have any better idea than to document how to use it.
If you follow the rules, it should just be "stable enough" to use it reliably, but things like the API of libsysfs, or just making assumptions based on the current state, I really don't see how that can work.
If you have any more useful words than "failure", or "stop exposing internal structures" which will help to explain things better, or change sysfs to make it easier to use, you are more than welcome to share your ideas.
Thanks,
Kay
Re: [PATCH 01/61] Rules on how to use sysfs in userspace programs
In reply to Pavel MachekQuoted 22 lines · Pavel Machek
Quoted 21 lines · Greg Kroah-Hartman
From: Kay Sievers <[email protected]>
Here's a document to help clear things up.
Signed-off-by Kay Sievers <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- Documentation/sysfs-rules.txt | 166 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 166 insertions(+), 0 deletions(-) create mode 100644 Documentation/sysfs-rules.txtDocumentation/sysfs-rules.txt new file +4
-0@@ -0,0 +1,166 @@ +Rules on how to access information in the Linux kernel sysfs + +The kernel exported sysfs exports internal kernel implementation-details +and depends on internal kernel structures and layout. It is agreed upon
Quoted 8 lines
Documentation/sysfs-rules.txt line 8
Quoted 4 lines
Documentation/sysfs-rules.txt new file +4
-0+by the kernel developers that the Linux kernel does not provide a stable +internal API. As sysfs is a direct export of kernel internal +structures, the sysfs interface can not provide a stable interface eighter, +it may always change along with internal kernel changes.It is also agreed upon by the kernel developers that the Linux kernel does have a stable user<->kernel API... so we have a small problem here.
I agree, that is why we have described the proper ways to use /sys in a manner that is acceptable to future changes in it.
Quoted 3 lines
Maybe solution is to declare /sys unstable, but... perhaps /sys can stop mirroring internal structures? I do not think we should codify our failure to keep /sys stable here.
I think that /sys is to valuable to say it can just never be used by userspace programs. With these suggestions, do you see any problems with any potential future changes in the layout that you can come up with?
thanks,
greg k-h
Re: [PATCH 01/61] Rules on how to use sysfs in userspace programs
Hi!
Quoted 14 lines
Quoted 10 lines
Documentation/sysfs-rules.txt line 8
Quoted 6 lines
Documentation/sysfs-rules.txt new file +6
-0+The kernel exported sysfs exports internal kernel implementation-details +and depends on internal kernel structures and layout. It is agreed upon +by the kernel developers that the Linux kernel does not provide a stable +internal API. As sysfs is a direct export of kernel internal +structures, the sysfs interface can not provide a stable interface eighter, +it may always change along with internal kernel changes.It is also agreed upon by the kernel developers that the Linux kernel does have a stable user<->kernel API... so we have a small problem here.
I agree, that is why we have described the proper ways to use /sys in a manner that is acceptable to future changes in it.
Quoted 8 lines
Quoted 3 lines
Maybe solution is to declare /sys unstable, but... perhaps /sys can stop mirroring internal structures? I do not think we should codify our failure to keep /sys stable here.
I think that /sys is to valuable to say it can just never be used by userspace programs. With these suggestions, do you see any problems with any potential future changes in the layout that you can come up with?
I'm afraid that userland programmers just will not read/follow this... and we will not know.
[Perhaps CONFIG_STRESS_SYSFS_PARSERS would be useful? Move stuff randomly to expose broken /sys users?]
Then, we'll get binary-only applications working okay relying on specific /sys structure, and soon, we'll be unable to change /sys.
[Perhaps we can make large parts of sysfs superuser-only, so that "normal" application can not rely on it?]
Pavel
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH 01/61] Rules on how to use sysfs in userspace programs
Quoted 20 lines · Pavel Machek
Hi!
Quoted 18 lines
Quoted 10 lines
Documentation/sysfs-rules.txt line 8
Quoted 6 lines
Documentation/sysfs-rules.txt new file +6
-0+The kernel exported sysfs exports internal kernel implementation-details +and depends on internal kernel structures and layout. It is agreed upon +by the kernel developers that the Linux kernel does not provide a stable +internal API. As sysfs is a direct export of kernel internal +structures, the sysfs interface can not provide a stable interface eighter, +it may always change along with internal kernel changes.It is also agreed upon by the kernel developers that the Linux kernel does have a stable user<->kernel API... so we have a small problem here.
I agree, that is why we have described the proper ways to use /sys in a manner that is acceptable to future changes in it.
Quoted 3 lines
Maybe solution is to declare /sys unstable, but... perhaps /sys can stop mirroring internal structures? I do not think we should codify our failure to keep /sys stable here.
Quoted 7 lines
Quoted 4 lines
I think that /sys is to valuable to say it can just never be used by userspace programs. With these suggestions, do you see any problems with any potential future changes in the layout that you can come up with?
I'm afraid that userland programmers just will not read/follow this... and we will not know.
Yes we will, when things break on their side due to normal movements around within sysfs.
Is there any other way you can imagine to get the word out on how to use this properly? I'm working with the LSB, so perhaps we can add it to their next spec for compliance testing of applications...
Quoted 2 lines
[Perhaps
CONFIG_STRESS_SYSFS_PARSERSwould be useful? Move stuff randomly to expose broken /sys users?]
Right now that is CONFIG_SYSFS_DEPRECATED :)
Quoted 5 lines
Then, we'll get binary-only applications working okay relying on specific /sys structure, and soon, we'll be unable to change /sys.
[Perhaps we can make large parts of sysfs superuser-only, so that "normal" application can not rely on it?]
Like those big "binary-only applications" don't already run as root...
thanks,
greg k-h