linux sysfs属性,linux-sysfs

他们分别都有自己的一棵树,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就是用时才去做一些事,以此可以节省空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值