Sysfs文件系统是类似于proc文件系统的特殊文件系统,用于将系统的设备组织成层次结构,并向用户模式程序提供详细的内核数据结构信息.
ls /sys/
/sys 下的子目录 | 所包含的内容 |
---|---|
/sys/devices | 内核对系统中所有设备的分层次表达模型,也是 /sys 文件系统管理设备的最重要的目录结构 |
/sys/dev | 目录下维护一个按字符设备和块设备的主次号码(major:minor)链接到真实的设备(/sys/devices下)的符号链接文件,它是在内核 2.6.26 首次引入 |
/sys/bus | 内核设备按总线类型分层放置的目录结构, devices 中的所有设备都是连接于某种总线之下,在这里的每一种具体总线之下可以找到每一个具体设备的符号链接,它也是构成 Linux 统一设备模型的一部分 |
/sys/class | 按照设备功能分类的设备模型,如系统所有输入设备都会出现在 /sys/class/input 之下,而不论它们是以何种总线连接到系统。它也是构成 Linux 统一设备模型的一部分 |
/sys/block | 系统中当前所有的块设备所在,按照功能来说放置在 /sys/class 之下会更合适,但只是由于历史遗留因素而一直存在于 /sys/block, 但从 2.6.22 开始就已标记为过时,只有在打开了 CONFIG_SYSFS_DEPRECATED 配置下编译才会有这个目录的存在,并且在 2.6.26 内核中已正式移到 /sys/class/block, 旧的接口 /sys/block 为了向后兼容保留存在,但其中的内容已经变为指向它们在 /sys/devices/ 中真实设备的符号链接文件 |
/sys/firmware | 系统加载固件机制的对用户空间的接口 |
/sys/fs | 按照设计是用于描述系统中所有文件系统,包括文件系统本身和按文件系统分类存放的已挂载点,但目前只有 fuse,gfs2 等少数文件系统支持 sysfs 接口,一些传统的虚拟文件系统(VFS)层次控制参数仍然在 sysctl (/proc/sys/fs) 接口中中 |
/sys/kernel | 内核所有可调整参数的位置,目前只有 uevent_helper, kexec_loaded, mm, 和新式的 slab 分配器等几项较新的设计在使用它,其它内核可调整参数仍然位于 sysctl (/proc/sys/kernel) 接口中 |
/sys/module | 系统中所有模块的信息,不论这些模块是以内联(inlined)方式编译到内核映像文件(vmlinuz)中还是编译为外部模块(ko文件),都可能会出现在 /sys/module 中:1、编译为外部模块(ko文件)在加载后会出现对应的 /sys/module/ |
/sys/power | 系统中电源选项,这个目录下有几个属性文件可以用于控制整个机器的电源状态,如可以向其中写入控制命令让机器关机、重启等 |
/sys/slab (对应 2.6.23 内核,在 2.6.24 以后移至 /sys/kernel/slab) | 从2.6.23 开始可以选择 SLAB 内存分配器的实现,并且新的 SLUB(Unqueued Slab Allocator)被设置为缺省值;如果编译了此选项,在 /sys 下就会出现 /sys/slab ,里面有每一个 kmem_cache 结构体的可调整参数。对应于旧的 SLAB 内存分配器下的 /proc/slabinfo 动态调整接口,新式的 /sys/kernel/slab/ |
#在 /sys/devices/ 目录下是按照设备的基本总线类型分类的目录
$ ls -F /sys/devices/
isa/ LNXSYSTM:00/ pci0000:00/ platform/ pnp0/ pnp1/ system/ virtual/
#在 /sys/devices/pci0000:00/ 目录下是按照 PCI 总线接入的设备号分类存放的目录
$ ls -F /sys/devices/pci0000:00/
0000:00:00.0/ 0000:00:02.5/ 0000:00:03.1/ 0000:00:0e.0/ power/
0000:00:01.0/ 0000:00:02.7/ 0000:00:03.2/ firmware_node@ uevent
0000:00:02.0/ 0000:00:03.0/ 0000:00:03.3/ pci_bus/
#在 /sys/devices/pci0000:00/0000:00:01.0/ 目录下,其中有一个目录 0000:01:00.0/, 其它都是属性文件和属性组
$ ls -F /sys/devices/pci0000:00/0000:00:01.0/
0000:01:00.0/ device local_cpus power/ subsystem_vendor
broken_parity_status enable modalias resource uevent
class irq msi_bus subsystem@ vendor
config local_cpulist pci_bus/ subsystem_device
类型 | 所包含的内容 | 对应内核数据结构 | 对应/sys项 |
---|---|---|---|
设备(Devices) | 设备是此模型中最基本的类型,以设备本身的连接按层次组织 | struct device | /sys/devices/*/*/…/ |
设备驱动(Device Drivers) | 在一个系统中安装多个相同设备,只需要一份驱动程序的支持 | struct device_driver | /sys/bus/pci/drivers/*/ |
总线类型(Bus Types) | 在整个总线级别对此总线上连接的所有设备进行管理 | struct bus_type | /sys/bus/*/ |
设备类别(Device Classes) | 按照功能进行分类组织的设备层次树;如 USB 接口和 PS/2 接口的鼠标都是输入设备,都会出现在 /sys/class/input/ 下 | struct class | /sys/class/*/ |
Kobject结构体:
struct kobject {
char * k name; //指向设备名称的指针
char name[KOBJ NAME LEN]; //设备名称
struct kref kref; //对象引用计数
struct list_head entry; //挂接到所在 kset 中去的单元
struct kobject * parent; //指向父对象的指针
struct kset * kset; //所属 kset 的指针
struct kobj_type * ktype; //指向其对象类型描述符的指针
struct dentry * dentry; //sysfs 文件系统中与该对象对应的文件节点路径指针
};
相关函数
//kobject 初始化函数
void kobject_init(struct kobject * kobj);
//设置指定 kobject 的名称。
int kobject_set_name(struct kobject *kobj, const char *format, ...);
//将 kobj 对象的引用计数加 1,同时返回该对象的指针。
struct kobject *kobject_get(struct kobject *kobj);
//将 kobj 对象的引用计数减 1,如果引用计数降为 0,则调用 kobject release()释放该 kobject 对象。
void kobject_put(struct kobject * kobj);
//将kobj对象加入Linux设备层次。挂接该kobject对象到kset的list链中,增加父目录各级 kobject 的引用计数,在其parent指向的目录下创建文件节点,并启动该类型内核对象的hotplug函数。
int kobject_add(struct kobject * kobj);
//从 Linux 设备层次(hierarchy)中删除 kobj 对象。
void kobject_del(struct kobject * kobj);
//kobject注册函数。通过调用kobject_init()初始化kobj,再调用kobject_add()完成该内核对象的注册。
int kobject_register(struct kobject * kobj);
//kobject 注销函数。与kobject_register()相反,它首先调用kobject_del从设备层次中删除该对象,再调用 kobject_put()减少该对象的引用计数,如果引用计数降为0,则释放kobject 对象。
void kobject_unregister(struct kobject * kobj);
kobj_type数据结构
struct kobj_type {
//release方法用于释放kobject占用的资源
void (*release)(struct kobject *);
/*sysfs_ops指针指向sysfs操作表和一个sysfs文件系统缺省属性列表。
Sysfs 操作表包括两个函数store()和show()。
当用户态读取属性时,show()函数被调用,该函数编码指定属性值存入buffer中返回给用户态;
store()函数用于存储用户态传入的属性值*/
struct sysfs_ops * sysfs_ops;
struct attribute ** default_attrs;
};
/*attribute属性。它以文件的形式输出到sysfs 的目录当中。
在kobject对应的目录下面,文件名就是name。文件读写的方法对应于kobj_type中的sysfs_ops*/
attribute
struct attribute {
char * name;
struct module * owner;
mode_t mode;
};
kset数据结构
struct kset {
struct subsystem * subsys; 所在的 subsystem 的指针
struct kobj_type * ktype; 指向该 kset 对象类型描述符的指针
struct list_head list; 用于连接该 kset 中所有 kobject 的链表头
struct kobject_kobj; 嵌入的 kobject
struct kset_hotplug ops * hotplug ops; 指向热插拔操作表的指针
};
相关函数
subsystem数据结构
struct subsystem {
struct kset kset;//内嵌的 kset 对象
struct rw_semaphore rwsem;//互斥访问信号量
};
相关函数
void subsystem_init(struct subsystem *subsys);
int subsystem_register(struct subsystem *subsys);
void subsystem_unregister(struct subsystem *subsys);
struct subsystem *subsys_get(struct subsystem *subsys);
void subsys_put(struct subsystem *subsys);
bus_type数据结构
struct bus_type {
char * name; //总线类型的名称
struct subsystem subsys; //与该总线相关的subsystem
struct kset drivers; //所有与该总线相关的驱动程序集合
struct kset devices; //所有挂接在该总线上的设备集合
struct bus attribute * bus_attrs; //总线属性
struct device attribute * dev_attrs; //设备属性
struct driver attribute * drv_attrs; //驱动程序属性
int (*match)(struct device * dev, struct device_driver * drv);
int (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
int (*suspend)(struct device * dev, u32 state);
int (*resume)(struct device * dev);
};
相关函数
device数据结构
struct device {
struct list_head g_list;
struct list_head node;
struct list_head bus_list;
struct list_head driver_list;
struct list_head children;
struct device *parent;
struct kobject kobj;
char bus_id[BUS_ID_SIZE];
struct bus_type *bus;
struct device_driver *driver;
void *driver_data;
/* Several fields omitted */
};
内核提供了相应的函数用于操作 device 对象
device_driver数据结构
struct device_driver {
char *name; //设备驱动程序的名称
struct bus_type *bus; //该驱动所管理的设备挂接的总线类型
struct kobject kobj;//内嵌kobject对象
struct list_head devices;//该驱动所管理的设备链表头
int (*probe)(struct device *dev); //指向设备探测函数,用于探测设备是否可以被该驱动程序管理
int (*remove)(struct device *dev);//用于删除设备的函数
/* some fields omitted*/
};
内核提供类似的函数
struct file_operations {
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
int (*open) (struct inode *, struct file *);
...
};
struct dentry_operations {
...
};
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
int (*link) (struct dentry *,struct inode *,struct dentry *);
int (*mkdir) (struct inode *,struct dentry *,int);
int (*rmdir) (struct inode *,struct dentry *);
...
}
目录项dentry结构体
struct dentry {
struct inode *d_inode; /* Where the name belongs to - NULL is */
struct dentry *d_parent; /* parent directory */
struct list_head d_child; /* child of parent list */
struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
void *d_fsdata; /* fs-specific data */
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
......
};
索引节点inode结构体
struct inode {
unsigned long i_ino; /*在同一文件系统中是唯一的*/
/*内核根据该值,可以计算出对应的inode在介质上的位置*/
/*在硬盘上,可以计算出对应的inode属于那个块,从而找到对应的inode结构*/
atomic_t i_count;
umode_t i_mode;
unsigned int i_nlink;
uid_t i_uid;
gid_t i_gid;
dev_t i_rdev;
loff_t i_size;
struct timespec i_atime;
unsigned long i_blocks;
unsigned short i_bytes;
unsigned char _sock;
struct inode_operations *i_op;
struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct super_block *i_sb;
......
};
struct ext3_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Creation time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
......
__le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
......
}
//目录文件中记录文件名与对应的索引节点号
struct ext3_dir_entry_2 {
__u32 inode; /* Inode number */
__u16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT3_NAME_LEN]; /* File name */
};
le32 i_block[EXT2 N BLOCKS];/* Pointers to blocks */
struct vfsmount {
struct list_head mnt_hash;
struct vfsmount *mnt_parent; /* fs we are mounted on */
struct dentry *mnt_mountpoint; /* dentry of mountpoint */
struct dentry *mnt_root; /* root of the mounted tree */
struct super_block *mnt_sb; /* pointer to superblock */
..........
}