linux-sysfs

一、inode、dentry、sys_dirent、kobject

创新互联主打移动网站、成都网站设计、成都网站制作、网站改版、网络推广、网站维护、国际域名空间、等互联网信息服务,为各行业提供服务。在技术实力的保障下,我们为客户承诺稳定,放心的服务,根据网站的内容与功能再决定采用什么样的设计。最后,要实现符合网站需求的内容、功能与设计,我们还会规划稳定安全的技术方案做保障。

他们分别都有自己的一棵树,inode和dentry就是vfs用的inode和dentry,sysfs之所以创建这两个结构就是为了与vfs交互。至于sys_dirent和kobject是sysfs维护信息用的,

sys_dirent可以对应到文件,而kobject只能对应到对象(目录),其实sys_dirent比较简单,也就是个辅助结构

struct sysfs_dirent {
atomic_ts_count;/*引用计数*/
struct list_heads_sibling;
struct list_heads_children;
void * s_element;/*对应于某一类型的数据结构,比如如果该结构类型是目录,则它对应一个kobject,如果是属性文件,它对应一个attribute结构*/
ints_type;/*类型: 包括目录、根、属性文件、二进制文件
链接*/
umode_ts_mode;
ino_ts_ino;
struct dentry* s_dentry;
struct iattr* s_iattr;
atomic_ts_event;
};

靠s_element来与kobject建立关系,而还是通过s_element可以携带具体文件的信息,弥补了kobject无法对应的文件的缺陷。

而dentry->d_fsdata = sysfs_dirent ,这样sysfs_dirent 和dentry就建立了关系,从而dentry和kobject也建立了关系,而且从dentry也可得到具体文件的信息了。

二、sysfs文件的操作:

统一接口sysfs_file_operations:

const struct file_operations sysfs_file_operations = {
.read= sysfs_read_file,
.write= sysfs_write_file,
.llseek= generic_file_llseek,
.open= sysfs_open_file,
.release= sysfs_release,
.poll= sysfs_poll,
};

以sysfs_read_file为例,调用关系

sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct sysfs_buffer * buffer= file->private_data;
ssize_t retval = 0;


down(&buffer->sem);
if (buffer->needs_read_fill) {
if (buffer->orphaned)
retval = -ENODEV;
else
retval = fill_read_buffer(file->f_path.dentry,buffer);
if (retval)
goto out;
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
__FUNCTION__, count, *ppos, buffer->page);
retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
buffer->count);
out:
up(&buffer->sem);
return retval;
}

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);

(static inline struct attribute * to_attr(struct dentry * dentry)

{
struct sysfs_dirent * sd = dentry->d_fsdata;
return ((struct attribute *) sd->s_element);
}

attr是show函数的参数,通过他找到具体文件的属性,从而找到具体的show函数。


struct kobject * kobj = to_kobj(dentry->d_parent);
struct sysfs_ops * ops = buffer->ops;

(

static int sysfs_open_file(struct inode *inode, struct file *file)
{

...

...

       buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
if (buffer) {
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;
} else
error = -ENOMEM;
goto Done;


}

sysfs_buffer是file的private_data结构,维护着具体文件的操作以及操作所用到的内存信息

struct sysfs_buffer {
struct list_headassociates;
size_tcount;
loff_tpos;
char* page;
struct sysfs_ops* ops;
struct semaphoresem;
intorphaned;
intneeds_read_fill;
intevent;
};

)
int ret = 0;
ssize_t count;


if (!buffer->page)
buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
if (!buffer->page)
return -ENOMEM;


buffer->event = atomic_read(&sd->s_event);
count = ops->show(kobj,attr,buffer->page);
BUG_ON(count > (ssize_t)PAGE_SIZE);
if (count >= 0) {
buffer->needs_read_fill = 0;
buffer->count = count;
} else {
ret = count;
}
return ret;
}

sysfs_read_file --- >  ops->show(该show函数是kobject里ktype的sysfs_ops,在sysfs_open_file中可以查到 ,)

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_buffer_collection *set;
struct sysfs_buffer * buffer;
struct sysfs_ops * ops = NULL;
int error = 0;


if (!kobj || !attr)
goto Einval;


/* Grab the module reference for this attribute if we have one */
if (!try_module_get(attr->owner)) {
error = -ENODEV;
goto Done;
}


/* if the kobject has no ktype, then we assume that it is a subsystem
* itself, and use ops for it.
*/
if (kobj->kset && kobj->kset->ktype)
ops = kobj->kset->ktype->sysfs_ops;
else if (kobj->ktype)
ops = kobj->ktype->sysfs_ops;
else
ops = &subsys_sysfs_ops;

...

...

而sysfs_ops从何而来呢,他是在创建具体的kobject时被赋值的,以cpufreq为例:

cpufreq_add_dev函数中有

policy->kobj.ktype= &ktype_cpufreq;
strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
ret = kobject_register(&policy->kobj);

static struct kobj_type ktype_cpufreq = {
.sysfs_ops= &sysfs_ops,
.default_attrs= default_attrs,
.release= cpufreq_sysfs_release,
};

static struct sysfs_ops sysfs_ops = {
.show=show,
.store= store,
};

static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf)
{
struct cpufreq_policy * policy = to_policy(kobj);
struct freq_attr * fattr = to_attr(attr);
ssize_t ret;
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
return -EINVAL;


if (lock_policy_rwsem_read(policy->cpu) < 0)
return -EINVAL;


if (fattr->show)
ret = fattr->show(policy, buf);
else
ret = -EIO;


unlock_policy_rwsem_read(policy->cpu);


cpufreq_cpu_put(policy);
return ret;
}

 to_attr 是通过一般属性找到特定于某个对象文件的属性,看懂__ATTR这个宏就明白了。

之所以层层调用组要是linux喜欢把公用的部分提取出来组成个函数,私有部分再另组成个函数。

三、sysfs_create_file

该函数创建sysfs文件,就是创建一个sys_dirent的结构。注意这里木有创建inode和dentry,文件的inode和dentry是被访问前创建的,既lookup时创建的

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;
/**
#define list_for_each_entry(pos, head, member)\
for (pos = list_entry((head)->next, typeof(*pos), member);\
    prefetch(pos->member.next), &pos->member != (head);\
    pos = list_entry(pos->member.next, typeof(*pos), member))
**/
list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
if (sd->s_type & SYSFS_NOT_PINNED) {/*hgq 这里判断是不是文件,如果是才往下进行,因为对于目录kobject,他在创建时就顺带创建了
dentry和inode,在sysfs_create_dir函数里,所以在内存中已经有了,也就不会调到这个函数,这个函数是内存里没有相应的
dentry和inode时才调用,在这里就是创建sysfs的文件的dentry和inode,因为创建文件时没有创建
dentry和inode,只是创建了sysfs_dirent*/
const unsigned char * name = sysfs_get_name(sd);


if (strcmp(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);
break;
}
}

}

linux就是用时才去做一些事,以此可以节省空间。



网站栏目:linux-sysfs
标题路径:http://ybzwz.com/article/poospg.html