LDM数据结构
总线
总线是设备核处理器之间额通道链路。
管理总线并将其协议输出到设备的硬件实体称为总线控制器。
自身作为设备的总线控制器必须像任何设备那样注册。它是总线上设备的父设备。
结构体struct bus_type
struct bus_type {
const char *name;
const char *dev_name;
struct device *dev_root;
const struct attribute_group **bus_groups;
const struct attribute_group **dev_groups;
const struct attribute_group **drv_groups;
//每当新设备或驱动程序添加到总线中时调用它。
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);//在新设备或驱动程序添加到总线,并且匹配发生时调用它
int (*remove)(struct device *dev);//当设备从总线上移除时调用它。
void (*shutdown)(struct device *dev);
int (*online)(struct device *dev);
int (*offline)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);//总线上的设备进入睡眠模式时
int (*resume)(struct device *dev);//总线上的设备退出睡眠模式时
int (*num_vf)(struct device *dev);
int (*dma_configure)(struct device *dev);
const struct dev_pm_ops *pm;
const struct iommu_ops *iommu_ops;
struct subsys_private *p;
struct lock_class_key lock_key;
bool need_parent_lock;
};
结构体struct kobject
</include/linux/kobject.h>
struct kobject {
const char *name;//object的名称,可使用kobject_set_name函数修改
struct list_head entry;
struct kobject *parent;//指向kobject父项的指针,用于构建描述对象之间关系的层次结构。
struct kset *kset;
struct kobj_type *ktype;//描述该对象,kset说明这个对象属于哪套对象
struct kernfs_node *sd; /* sysfs directory entry */
struct kref kref; //提供kobject上的引用计数
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
接口函数
</include/linux/kobject.h>
kobject * kobject_create(void);//分配kobject
void kobject_init(struct kobject *kobj, struct kobj_type *ktype);//初始化kobject
int kobject_add(struct kobject *kobj, struct kobject *parent,
const char *fmt, ...);//添加kobject到系统
void kobject_del(struct kobject *kobj)//将kobject从系统中删除
void kobject_put(struct kobject *kobj)//与kobject_init和kobject_add过程相反
//这里创建的kobject无法嵌入到其它结构,是独立存在的,所以用到的地方很少
struct kobject * kobject_create_and_add(const char *name,struct kobject *parent);//create与add结合
int kobject_init_and_add(struct kobject *kobj,
struct kobj_type *ktype, struct kobject *parent,
const char *fmt, ...);//将kobject初始化后并添加到kobject的层次结构中去。
/*例
* 如果 kobject_create_and_add中 kobject 的父项为NULL,那么kobject_add
* 将其父项设置为 kset.如果两者均为 NULL,对象将成为顶级 sys 目录的子成员。
*/
int __init devices_init(void)
{
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
if (!devices_kset)
return -ENOMEM;
//创建/sys/dev
dev_kobj = kobject_create_and_add("dev", NULL);
if (!dev_kobj)
goto dev_kobj_err;
//创建/sys/dev/block
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
if (!sysfs_dev_block_kobj)
goto block_kobj_err;
return 0;
}
struct kobj_type与sysfs_ops
描述kobject的行为,它将控制在创建和销毁kobject时,以及读取或写入属性时发生的操作。
</include/linux/kobject.h>
struct kobj_type {
void (*release)(struct kobject *kobj);//需要释放对象时由kobject_put函数调用的回调函数。
const struct sysfs_ops *sysfs_ops;//指向sysfs操作,访问sysfs属性时调用的一组回调函数
struct attribute **default_attrs;//定义与此kobject关联的默认属性,指向attribute的元素列表
的指针
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
};
</include/linux/sysfs.h>
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);//读取具有该kobj_type的所有kobject的属性时调用它。
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);//写入
};
</include/linux/kobject.h>
static inline struct kobj_type *get_ktype(struct kobject *kobj)//获取指定koject的kobj_type
内核对象集合(struct kset)
内核对象集合主要将相关的内核对象组合在一起,kset是kobject的集合,换句话说,kset将相关的kobject收集到一个位置,例如所有的块设备
</include/linux/kobject.h>
struct kset {
struct list_head list;//kset中所有kobject的链表
spinlock_t list_lock;//保护链表访问的自旋锁
struct kobject kobj;//该集合的基类
const struct kset_uevent_ops *uevent_ops;//此kset的uevent操作函数集
} ;
每个注册的kset对应于sysfs目录
</include/linux/kobject.h>
struct kset * kset_create_and_add(const char *name,
const struct kset_uevent_ops *u,
struct kobject *parent_kobj);//创建kset
void kset_unregister(struct kset *kset);//删除kset
//例
static struct kobject foo_kobj;
//创建/sys/kset_example目录
example_kset = kset_create_and_add("kset_example",NULL,kernel_kobj);
//创建/sys/kset_example/foo_name
foo_kobj.kset = example_kset;
retval = kobject_init_and_add(&foo_kobj,&foo_ktype,NULL,"foo_name");
属性(struct attribute)
属性是由kobject导出到用户空间的sysfs文件。属性表示可以从用户空间读取、写入或同时具有两者的对象属性。也就是说,嵌入 struct kobject 的每个数据结构都可以公开由 kobject 自身(如果有)提供的默认属性或自定义属性。换话说,属性将内核数据映射到sysfs中。
</include/linux/sysfs.h>
struct attribute {
const char *name;
umode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
bool ignore_lockdep:1;
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
接口函数
</include/linux/sysfs.h>
int sysfs_create_files(struct kobject *kobj,
const struct attribute * const *attr); //从文件系统添加属性
void sysfs_remove_files(struct kobject *kobj, const struct attribute * const *attr);//删除属性
//示例
structv d_attr {
struct attribute attr;
int value;
};
static struct d_attr foo = {
.attr.name = "foo",
.attr.mode = "0644",
.value = 0,
};
static struct d_attr bar = {
.attr.name = "bar",
.attr.mode = "0644",
.value = 0,
};
sysfs_create_files(mykobj,&foo.attr);
sysfs_create_files(mykobj,&bar.attr);
属性组(struct attribute_group)
帮助包装器,以便更轻松地管理多个属性
</include/linux/sysfs.h>
struct attribute_group {
const char *name;
umode_t (*is_visible)(struct kobject *,
struct attribute *, int);
umode_t (*is_bin_visible)(struct kobject *,
struct bin_attribute *, int);
struct attribute **attrs;
struct bin_attribute **bin_attrs;
};
接口函数
</include/linux/sysfs.h>
int sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp);//向文件系统添加组属性
void sysfs_remove_group(struct kobject *kobj,
const struct attribute_group *grp);//向文件系统删除组属性
//示例
structv d_attr {
struct attribute attr;
int value;
};
static struct d_attr foo = {
.attr.name = "foo",
.attr.mode = "0644",
.value = 0,
};
static struct d_attr bar = {
.attr.name = "bar",
.attr.mode = "0644",
.value = 0,
};
static struct attribute *attrs [] = {
&foo.attr,
&bar.attr,
NULL,
};
static struct attribute_group my_attr_group = {
.attrs = attrs,
};
sysfs_create_group(mykobj,&my_attr_group);
设备模型和sysfs
sysfs是非持久性虚拟文件系统,它提供系统的全局试图,并通过它们的kobject显示内核对象的层次结构,每个kobject显示为目录和目录中的文件。
/sys目录中的每一个都对应于koject,其中一些作为内核符号导出。
kernel_kobj //对应于/sys/kernel
power_kobj //对应于/sys/power
firmware_kobj //对应于/sys/firmware,导出在drivers/base/firmware.c源文件中
hypervisor_kobj //对应于/sys/hypervisor,到处在drivers/base/hypervisor.c中
fs_kobj //对应于/sys/fs,导出在fs/namespace.c文件中
然而,class/、dev/、devices/是在启动期间由内核源代码内drivers/base/core.c中的 devices_init 函数创建的,block在block/genhd,c中创建,bus在drivers/base/bus.c 中被创建为 kset。
kobiect目录被添加到 sysfs (使用 kobject add)时其添加位置取决于 kobiect的父项。如果其父指针已设置,则它将被添加为父目录内的子目录。如果父指针为 NULL则将其添加为 kset-> kobj 内的子目录。如果其父和 kset 字段都未设置,它将映射到sysfs 内的根目录(/sys)
创建/删除现有对象(目录)上的符号链接
</include/linux/sysfs.h>
int sysfs_create_link(struct kobject *kobj, struct kobject *target,
const char *name);
void sysfs_remove_link(struct kobject *kobj, const char *name);
sysfs文件和属性
文件的默认设置是通过 kobject 和 kset 中的 ktype 字段、kobj_type 的 default.attrs 字段提供的。在大多数情况下,默认属性足够了。但有时 ktype 实例可能需要其自己的属性来提供不被更通用的 ktype所共享的数据或功能。
当前接口
目前在 sysfs 中存在接口层。除了创建自己的 ktype 或 kobject 来添加属性外,还可以使用当前存在的设备、驱动程序、总线和类属性。它们的描述如下。
设备属性(struct device_attribute)
除嵌入设备结构中的 kobject 提供的默认属性之外,还可以创建自定义属性。执行止操作使用的结构是struct device_attribute,它只是对标准struct attribute的封装,以及一组用于显示/存储属性值的回调:
</include/linux/device.h>
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);
};
//声明通过DEVICE_ATTR宏完成
</include/linux/device.h>
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
</include/linux/device.h>
int device_create_file(struct device *device,
const struct device_attribute *entry); //在device中添加属性
void device_remove_file(struct device *dev,
const struct device_attribute *attr);在device中删除属性
总线属性(struct bus_attribute)、设备驱动属性(driver_attribute)、类属性
</include/linux/device.h>
//2. bus
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *bus, char *buf);
ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
};
#define BUS_ATTR(_name, _mode, _show, _store) \
struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
int bus_create_file(struct bus_type *,
struct bus_attribute *);
void bus_remove_file(struct bus_type *, struct bus_attribute *);
//3. driver
struct driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *driver, char *buf);
ssize_t (*store)(struct device_driver *driver, const char *buf,
size_t count);
};
#define DRIVER_ATTR_RW(_name) \
struct driver_attribute driver_attr_##_name = __ATTR_RW(_name)
#define DRIVER_ATTR_RO(_name) \
struct driver_attribute driver_attr_##_name = __ATTR_RO(_name)
#define DRIVER_ATTR_WO(_name) \
struct driver_attribute driver_attr_##_name = __ATTR_WO(_name)
int driver_create_file(struct device_driver *driver,
const struct driver_attribute *attr);
void driver_remove_file(struct device_driver *driver,
const struct driver_attribute *attr);
//class