Sysfs
What is Sysfs
SYSFS is a file system that exports kernel data structures, objects, and properties to user space, providing not only the ability to view the internal data structures of the kernel, but also the modification of these data structures. Of particular importance is the highly hierarchical organization of the filesystem: the SYSFS data items come from kernel object kobject, and the hierarchical organization of the kernel objects is directly reflected in the SYSFS directory layout.
If the SYSFS is enabled, it is necessary to select CONFIG_SYSFS when compiling the kernel; In general, the default is to SYSFS. The standard mount point for Sysfs is/sys. /sys Directory Creation
For each kobject that is registered to the system, the corresponding directory is created in/sys. Creating a new directory is a subdirectory of the parent kobject of the corresponding kobject in this directory, showing the hierarchy between them within the user layer. The directory at the top of the/sys is the ancestor of similar kobject. attribute Attributes
In the SYS file system, all Koject properties are exported as normal files, SYSFS provides methods for reading and writing kernel properties, and defines attributes by I/O operations that extend these files. The file for the output attribute value should be an ASCII file, preferably a file that holds a value or an array of the same type. Each kobject is represented as a directory in Sysfs, and the files that appear in that directory are properties of the object. The operations used to export and set properties are provided by the subsystem to which the object belongs.
Attribute definition in kernel:
Linux/sysfs.h
struct attribute{
char *name//provides the name of the property, which is used as the filename in Sysfs umode_t The
access rights are specified ...
};
/* Create or remove attributes for kobj/
int sysfs_create_file (struct kobject *kobj,
const struct attribute *attr);
void Sysfs_remove_file (struct kobject *kobj,
const struct attribute *attr);
The struct attribute in the system does not include a method of reading and writing property values, and the system encourages the developer to customize the attribute structure (which needs to be embedded in the attribute structure) and to customize the method for reading and writing the attribute, as well as the methods of adding and removing attributes.
For example, the property data structure of struct Device_attribute is customized in the driver module:
/* Custom DEVICE Property Structure * * struct Device_attribute {struct attribute attr;
/* The method for reading and writing this property is associated with a custom property * * ssize_t (*show) (struct device *dev, struct device_attribute *attr, char *buf);
ssize_t (*store) (struct device *dev, struct device_attribute *attr, const char *BUF, size_t count); */* Use Sysfs_create_file or Sysfs_remove_flie to create or remove attributes for dev/int device_create_file (struct device *dev, cons
t struct Device_attribute *attr);
void Device_remove_file (struct device *dev, const struct device_attribute); linux/device.h int device_create_file (struct device *dev, const struct Device_attribute *attr) {... if (d
EV) {... error = Sysfs_create_file (&dev->kobj, &attr->attr);
...
}
} void Device_remove_file (struct device *dev, const struct Device_attribute *attr) {if (dev)
Sysfs_remove_file (&dev->kobj, &attr->attr); }
Defining drive properties can be implemented quickly by macro definitions:
#define DEVICE_ATTR (_name, _mode, _show, _store) \
struct Device_attribute dev_attr_# #_name = __attr (_name, _mode, _s how, _store)
When a subsystem defines a new attribute type, it is necessary to implement a set of SYSFS operations that define the methods of reading and writing attribute values (defining the show and store functions in the device_attribute structure). SYSFS_OPS Data Structure
struct Sysfs_ops {
ssize_t (*show) (struct kobject *kobj, struct
attribute *attr, char *buf);
ssize_t (*store) (sturct kobject *kobj,
strcut atrribute *attr, const char *BUF,
size_t count);
The system defines the KOBJ_TYPE data structure as a kobject type, and Kobj_type also contains a pointer to Sysfs_ops (see Kobj_type for details).
when a file is read and written, SYSFS calls the read or write system, and then the read or write system calls pointers to this type (Kobj_type) relative to read-write functions (show and store in sysfs_ops structure) , and finally transformed into a corresponding method in a particular kobject and attribute structure.
The following is a simple example to illustrate:
#define TO_DEV (obj) container_of (obj, struct device, kobj)
#define TO_DEV_ATTR (_attr) container_of (_attr, struct Device_attribute, attr)
/* Dev_attr_show is the specific method for show pointing in Sysfs_ops
/static ssize_t dev_attr_show (struct Kobject *kobj, struct attribute *attr,char *buf) {struct Device_attribute *dev_attr
= to_dev_attr (attr);
struct Device *dev = To_dev (kobj);
ssize_t ret =-eio;
if (dev_attr->show)
ret = dev_attr->show (Dev, dev_attr, buf),/* explicitly invokes the show in the custom attribute to read the property value/
if (Ret >= ( ssize_t) page_size {
Print_symbol ("Dev_attr_show:%s returned bad count\n",
(unsigned long) dev_attr-> show);
return ret;
}
Read and write property values
&NBSP in order to read and write property values, the show and store methods must be defined when declaring a custom attribute, with parameters such as objects, properties of objects, pointers to buffers, and so on. such as struct Device_attr_foo:
struct Device_attribute_foo {
struct attribute attr;
/* The method for reading and writing this property is associated with a custom property * *
ssize_t (*show) (struct device *dev, struct Device_attribute *attr
, Char *buf);
ssize_t (*store) (struct device *dev,
struct Device_attribute *attr,
const char *BUF, size_t count);
Sysfs allocates a page size buffer and passes it to show and store, which will be invoked when reading and writing properties. The system will do the following:
In the read system call, show fills the entire buffer. Recall that a property will only export a value, or a similar set of values, so it takes a little time. and allows partial read and random reads.
In the write system call, in the first read-write, SYSFS expects the entire buffer to be passed to the system, then SYSFS passes the entire buffer to the store method and adds null at the end of the data.
When reading and writing property values, the read-write method should manipulate the same buffer.
Attention:
The show () method overload caused by the write operation ignores the current file location.
The buffer should always be page_size size. For i386, this value is 4KB.
The show () method should return the number of bytes written to the buffer, which is the return value of snprintf ().
snprintf () cannot be used when the property value is formalized to the user layer. You can use sprintf () if you can guarantee that the overflow will not occur, otherwise you can only use snprintf ().
The store () should return the number of words that have been read from the buffer. If the entire cache is filled, simply return the Count parameter.
Show () or store () can return an error value. When an illegal value is obtained, an error value must be returned.
By referencing a count nested within an object, Sysfs the object passed to show or store in memory. However, a physical entity, such as a device, that a possible object represents does not already exist. If necessary, a detection mechanism should be implemented. Top level directory structure
We know the relationship between kernel data through the SYSFS directory hierarchy. Top-level SYSFS directories include: blocks, bus, class, Dev, devices, firmaware, NET, FS subdirectory.
Devices contains a file system representation of a device tree. He mapped the inner kernel directly.
Device tree, which reflects the hierarchy of the device
The bus contains a flat directory layout for various types of buses in the kernel. Each bus directory contains two subdirectories: devices, drivers subdirectory. Devices contains symbolic links for each device that appears in the system, pointing to the device directory in the root directory. Drivers contains a directory for each driver that is mounted to a device on a specific bus (assuming that the driver does not span multiple bus types)
FS contains a directory that is set up for the file system. Now each file system that wants to export attributes must create its own hierarchy under the FS directory
Dev contains two subdirectories: char/and block/. In these two subdirectories, there are symbolic links named in: format. These symbolic links point to the corresponding SYSFS directory for a given device. By stat system calls,/sys/dev provides a Sysfs interface method for quick lookup devices. some SYSFS interfaces in the kernel:
devices (include/linux/device.h)
/* Device Property structure body *
/struct Device_attribute {
struct attribute attr;
ssize_t (*show) (struct device *dev, struct Device_attribute *attr,
char *buf);
ssize_t (*store) (struct device *dev, struct Device_attribute *attr,
const char *BUF, size_t count);
/* Declare DEVICE attribute structure variable * *
device_attr (_name, _mode, _show, _store);
/* Add or remove device properties */
int device_create_file (struct device *dev, const struct Device_attribute * attr);
void Device_remove_file (struct device *dev, const struct Device_attribute * attr);
Bus Drivers (include/linux/device.h)
/* Bus Property Structure Body * *
struct Bus_attribute {
struct attribute attr;
ssize_t (*show) (struct bus_type *, char * buf);
ssize_t (*store) (struct bus_type *, const char * buf, size_t count);
/* Declare bus attribute structure variable
/bus_attr (_name, _mode, _show, _store)
* * Add or remove bus properties/
int bus_create_file (struct BUS_ Type *, struct bus_attribute *);
void Bus_remove_file (struct bus_type *, struct bus_attribute *);
device Drivers (include/linux/device.h)
/* Device Property structure body *
/struct Driver_attribute {
struct attribute attr;
ssize_t (*show) (struct device_driver *, char * buf);
ssize_t (*store) (struct device_driver *, const char * buf, size_t count);
/* Declare device Property structure body
/driver_attr (_name, _mode, _show, _store)
/* Add or remove device attributes/
int driver_create_file (struct device_driver *, const struct driver_attribute *);
void Driver_remove_file (struct device_driver *, const struct driver_attribute *);
Reference: Linux/documentation/filesystem/sysfs.txt
Deep Linux kernel architecture "Linux kernel design and implementation"