溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

linux-sysfs

發(fā)布時(shí)間:2020-06-09 06:48:01 來(lái)源:網(wǎng)絡(luò) 閱讀:596 作者:hgqxjj 欄目:編程語(yǔ)言

一、inode、dentry、sys_dirent、kobject

他們分別都有自己的一棵樹,inode和dentry就是vfs用的inode和dentry,sysfs之所以創(chuàng)建這兩個(gè)結(jié)構(gòu)就是為了與vfs交互。至于sys_dirent和kobject是sysfs維護(hù)信息用的,

sys_dirent可以對(duì)應(yīng)到文件,而kobject只能對(duì)應(yīng)到對(duì)象(目錄),其實(shí)sys_dirent比較簡(jiǎn)單,也就是個(gè)輔助結(jié)構(gòu)

struct sysfs_dirent {
atomic_t s_count;/*引用計(jì)數(shù)*/
struct list_heads_sibling;
struct list_heads_children;
void * s_element;/*對(duì)應(yīng)于某一類型的數(shù)據(jù)結(jié)構(gòu),比如如果該結(jié)構(gòu)類型是目錄,則它對(duì)應(yīng)一個(gè)kobject,如果是屬性文件,它對(duì)應(yīng)一個(gè)attribute結(jié)構(gòu)*/
int s_type;/*類型: 包括目錄、根、屬性文件、二進(jìn)制文件
鏈接*/
umode_t s_mode;
ino_t s_ino;
struct dentry * s_dentry;
struct iattr * s_iattr;
atomic_t s_event;
};

靠s_element來(lái)與kobject建立關(guān)系,而還是通過(guò)s_element可以攜帶具體文件的信息,彌補(bǔ)了kobject無(wú)法對(duì)應(yīng)的文件的缺陷。

而dentry->d_fsdata = sysfs_dirent ,這樣sysfs_dirent 和dentry就建立了關(guān)系,從而dentry和kobject也建立了關(guān)系,而且從dentry也可得到具體文件的信息了。

二、sysfs文件的操作:

統(tǒng)一接口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為例,調(diào)用關(guān)系

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函數(shù)的參數(shù),通過(guò)他找到具體文件的屬性,從而找到具體的show函數(shù)。


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;(后面會(huì)講到)
add_to_collection(buffer, inode);
file->private_data = buffer;
} else
error = -ENOMEM;
goto Done;


}

sysfs_buffer是file的private_data結(jié)構(gòu),維護(hù)著具體文件的操作以及操作所用到的內(nèi)存信息

struct sysfs_buffer {
struct list_headassociates;
size_t count;
loff_t pos;
char * page;
struct sysfs_ops* ops;
struct semaphoresem;
int orphaned;
int needs_read_fill;
int event;
};


)
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函數(shù)是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從何而來(lái)呢,他是在創(chuàng)建具體的kobject時(shí)被賦值的,以cpufreq為例:

cpufreq_add_dev函數(shù)中有

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 是通過(guò)一般屬性找到特定于某個(gè)對(duì)象文件的屬性,看懂__ATTR這個(gè)宏就明白了。

之所以層層調(diào)用組要是linux喜歡把公用的部分提取出來(lái)組成個(gè)函數(shù),私有部分再另組成個(gè)函數(shù)。

三、sysfs_create_file

該函數(shù)創(chuàng)建sysfs文件,就是創(chuàng)建一個(gè)sys_dirent的結(jié)構(gòu)。注意這里木有創(chuàng)建inode和dentry,文件的inode和dentry是被訪問(wèn)前創(chuàng)建的,既lookup時(shí)創(chuàng)建的

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 這里判斷是不是文件,如果是才往下進(jìn)行,因?yàn)閷?duì)于目錄kobject,他在創(chuàng)建時(shí)就順帶創(chuàng)建了
dentry和inode,在sysfs_create_dir函數(shù)里,所以在內(nèi)存中已經(jīng)有了,也就不會(huì)調(diào)到這個(gè)函數(shù),這個(gè)函數(shù)是內(nèi)存里沒有相應(yīng)的
dentry和inode時(shí)才調(diào)用,在這里就是創(chuàng)建sysfs的文件的dentry和inode,因?yàn)閯?chuàng)建文件時(shí)沒有創(chuàng)建
dentry和inode,只是創(chuàng)建了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就是用時(shí)才去做一些事,以此可以節(jié)省空間。


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI