您的位置:首页 > 运维架构 > Linux

linux2.6内核文件系统与设备模型

2009-08-29 10:53 405 查看
Udev设备文件系统:linux2.6内核中,devfs被认为是过时的。
1. udev完全工作在用户态工作,利用设备加入或移除锁发送的热插拔时间(hotplug event)工作。在热插拔时,设备的详细信息会由内核输出到位于/sys的sysfs文件系统,由于udev根据硬件动态更新设备文件,进行设备文件的创建和删除,所以在/dev目录下就会只包含真正存在的设备。Devfs和udev明显区别;采用devfs当一个并不存在的/dev节点被打开适合会自动加载驱动,而udev认为在设备被发现时候才加载驱动模块。
Sysfs文件系统与linux设备模型
Sysfs文件系统:把连接到系统上的设备和总线组织成为一个分级文件,可以由用户空间存取,向用户空间导出内核数据及其他们的属性,sysfs的一个目的就是展示涉笔驱动模型中各组件的层次关系。

设备模型中的关键数据结构:
struct kobject {
char * k_name;//
char name[KOBJ_NAME_LEN];//xx对象名称
struct kref kref;//对象引用计数
struct list_head entry;// 用于挂接给kobject对象到kset链表
struct kobject * parent;//指向父对象的指针
struct kset * kset;//所属kset的指针
struct kobj_type * ktype;指向对象类型描述符的指针
struct dentry * dentry;//sysfs文件系统中与该对象对应文件节点入口
};
是构成设备管理能力的核心结构,一个kobject对应于一个sysfs文件系统的一个目录。
Kref成员实现对象应用计数器管理,提供kobject_get(),kobject_put()分别用于增加和减少应用计数器,当引用计数器为0时,该对象使用资源被释放。
Ktype指向kobj_type结构指针,标识该对象类型。
Struct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops * sysfs_ops;
struct attribute ** default_attrs;
};包括了释放kobject占用资源的release()函数,指向sysfs操作的sysfs_ops指针和sysfs文件系统默认属性列表。
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
}; 分别用于属性的读和写

一系列的kobject操作函数:
Kobject_init用于初始kobject,设置kobject引用计数器为以,entry指向自身,其所属kset引用计数器加1.
Kobject_add(struct kobject *kobj);//该函数将kobject对象加入linux设备层次,挂接到kobject对象到所属的kset的list链表中,增加kobject引用计数器,在parent指向的目录下创建文件节点,并启动该类型内核对象的hotplug函数。对应有kobject_del()从linux设备层次(hierarchy)中删除kobject对象。
Kobject_register()先调用kobject_init初始化,然后调用kobject_add(),对应相反的是kobject_unregister

2.kset:kobject通过kset组织成为层次化的结构,kset是具有相同类型的kobject的集合。
struct kset {
struct subsystem * subsys;//所在的子系统指针
struct kobj_type * ktype;//kset对象描述符指针
struct list_head list;//用于连接所有object对象的链表头
struct kobject kobj;//所以属于该kset的object对象的parent都指向该结构
struct kset_hotplug_ops * hotplug_ops;//事件操作集
};//与kobject相似,linux提供了一系列的函数操作kset,kset_init完成指定的kset初始化,kset_get()和kset_put()分别增加和减少kset对象引用计数器,kset_add()和kset_del()函数把指定的kset对象加入设备层次和从其中删除,kset_register()函数完成kset的注册和kset_unregister函数则完成kset的注销。Kobject被创建或删除时能产生event,kobject所属的kset可以过滤event或者为用户空间添加消息。Kset的uevent_ops成员执行该kset事件集合kset_uevent_ops指针。
3.
struct subsystem {
struct kset kset;
struct rw_semaphore rwsem;
};//一系列kset的集合,描述一类子系统,如字符设备,块设备等等。每个kset必须属于某个subsystem,设置kset结构中的subsys域指向指定的subsystem可以将kset加入到该subsystem,所有挂接到同一个subsystem的kset共享同一个rwsem信号量,用于同步访问kset中的链表。内核提供类似kset和kobject的函数操作subsystem操作。

1. linux设备模型组件:任一设备都在设备模型中有一个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 intf_list;
struct list_head children;
struct device * parent;
char name[DEVICE_NAME_SIZE];
char bus_id[BUS_ID_SIZE];
spinlock_t lock;
atomic_t refcount;
struct bus_type * bus;
struct driver_dir_entry dir;
u32 class_num;
struct device_driver *driver;
void *driver_data;
void *platform_data;
u32 current_state;
unsigned char *saved_state;
void (*release)(struct device * dev); };
Fields ~~~~~~ g_list: Node in the global device list.
node: Node in device's parent's children list.
bus_list: Node in device's bus's devices list.
driver_list: Node in device's driver's devices list.
intf_list: List of intf_data. There is one structure allocated for each interface that the device supports.
children: List of child devices.
parent: *** FIXME ***
name: ASCII description of device. Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]"
bus_id: ASCII representation of device's bus position. This field should be a name unique across all devices on the
bus type the device belongs to.
Example: PCI bus_ids are in the form of
<bus number>:<slot number>.<function number>
This name is unique across all PCI devices in the system.
lock: Spinlock for the device.
refcount: Reference count on the device.
bus: Pointer to struct bus_type that device belongs to.
dir: Device's sysfs directory.
class_num: Class-enumerated value of the device.
driver: Pointer to struct device_driver that controls the device.
driver_data: Driver-specific data.
platform_data: Platform data specific to the device.
current_state: Current power state of the device.
saved_state: Pointer to saved state of the device. This is usable by the device driver controlling the device.
release: Callback to free the device after all references have gone away. This should be set by the allocator of the
device (i.e. the bus driver that discovered the device).
Device结构体用于描述设备相关的信息设备之间的层次关系,以及设备与总线,驱动的关系。内核提供函数device_resgister()函数将一个新的device对象插入设备模型,并自动在/sys/device下创建一个对应的目录。通常device结构体不单独使用,而包含于更大的机构体中,比如struct pci_dev.驱动程序由device_driver对象描述,对应的机构如下:
struct device_driver {
const char *name;
struct bus_type *bus;

struct module *owner;
const char *mod_name; /* used for built-in modules */

int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
struct attribute_group **groups;

struct dev_pm_ops *pm;

struct driver_private *p;
};//通过内嵌的kobject对象实现引用计数器管理和层次结构组织。Driver_register()用于相设备模型插入新的driver对象,同时在sysfs文件系统中创建相应目录。

系统中的总线由struct bus_type描述
Definition
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, pm_message_t state);
int (*resume)(struct device * dev); };
每个bus_type对象都内嵌一个subsystem对象,bus_subsys对象管理系统中所有总线类型的subsystem对象,每个bus_type对象都对应/sys/bus目录下的一个子目录,该目录下都存在两个子目录:devices和drivers(分别对应bus_type机构中的devices和drivers域)

系统中的设备类由struct class描述,表示一类设备,所有的class对象都属于class_subsys子系统,对应于sysfs文件系统中的/sys/class目录。
/*
* device classes
*/
struct class {
const char *name;
struct module *owner;

struct class_attribute *class_attrs;
struct device_attribute *dev_attrs;
struct kobject *dev_kobj;

int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);

void (*class_release)(struct class *class);
void (*dev_release)(struct device *dev);

int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);

struct dev_pm_ops *pm;
struct class_private *p;
};
struct device_class {
char * name;
rwlock_t lock;
u32 devnum;
struct list_head node;
struct list_head drivers;
struct list_head intf_list;
struct driver_dir_entry dir;
struct driver_dir_entry device_dir;
struct driver_dir_entry driver_dir;
devclass_add add_device;
devclass_remove remove_device; };
每个class对象包括一个class——device链表,每个class_device对象表示一个逻辑设备,并通过struct class_device中的dev成员并联一个物理设备。这样,一个逻辑设备总对应一个物理设备,但是一个物理设备却却可能对应多个逻辑设备。

属性
在bus,device,driver,class层次上都分别定义了其属性结构体,包括bus_attribute ,driver_attribute, class_device_attribute.这几个结构本质完全相同

udev组成:设计目标:
1. 用户空间中执行
2. 动态建立/删除设备文件
3. 允许每个人都不关心主/次设备号
4. 提供LSB标准名称
5. 如果需要,提供固定的名称
Udev由下面3部分分割计划发展,namedev,libsysfs,udev,namedev为设备命名子系统,libsysfs提供访问sysfs文件系统从中获取消息的标准接口,udev提供/dev设备节点文件的动态创建和删除策略。
原理:内核检测到系统新设备后,内核在sysfs文件系统中为新设备生产记录并导出设备信息及其所发生的事件。Udev获取内核导出信息,调用namedev决定设备指定名称,udev调用libsysfs决定应该为该设备的是被文件指定主/次设备号,并用分析获取设备名称和主/次设备号创建/dev设备文件。
Namedev规则:
1. 标签/序号:检查设备是否有唯一的识别标号。
2. 设备设备号:进一步检查总线设备编号,如果找到规则,那么规则中的名字被使用
3. 总线上的拓扑:当设备在总线位置匹配用户指定规则,则使用该该规则指定名称。
4. 替代名称:内核提供的名称匹配指定的替代字符串时,就会使用替代字符串指定的名称。
5. 内核提供的名称:以上步骤规则没有提供,缺省的内核规则将被指定给该设备。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: