歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux技術 >> Linux那些事兒之我是Sysfs(13)舉例四:sysfs讀入普通文件內容

Linux那些事兒之我是Sysfs(13)舉例四:sysfs讀入普通文件內容

日期:2017/3/3 12:41:41   编辑:Linux技術

跟上回一樣,我用這個小程序來讀

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

int main(){

char *name = "/sys/bus/ldd/version";

char buf[500];

int fd;

int size;

fd = open(name, O_RDONLY);

printf("fd:%d

",fd);

size = read(fd,buf,sizeof(buf));

printf("size:%d

",size);

printf("%s",buf);

close(fd);

return -1;

}

(1)sysfs_open_file() open() ->/*用戶空間*/

-> 系統調用->

sys_open() -> filp_open()-> dentry_open() -> sysfs_open_file()/*內核空間*/

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

{

return check_perm(inode,filp);

}

static int check_perm(struct inode * inode, struct file * file)

{

struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);

struct attribute * attr = to_attr(file->f_dentry);

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;

/* No sysfs operations, either from having no subsystem,

* or the subsystem have no operations.

*/

if (!ops)

goto Eaccess;

/* File needs write support.

* The inode's perms must say it's ok,

* and we must have a store method.

*/

if (file->f_mode & FMODE_WRITE) {

if (!(inode->i_mode & S_IWUGO) || !ops->store)

goto Eaccess;

}

/* File needs read support.

* The inode's perms must say it's ok, and we there

* must be a show method for it.

*/

if (file->f_mode & FMODE_READ) {

if (!(inode->i_mode & S_IRUGO) || !ops->show)

goto Eaccess;

}

/* No error? Great, allocate a buffer for the file, and store it

* it in file->private_data for easy access.

*/

buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL);

if (buffer) {

memset(buffer,0,sizeof(struct sysfs_buffer));

init_MUTEX(&buffer->sem);

buffer->needs_read_fill = 1;

buffer->ops = ops;

file->private_data = buffer;

} else

error = -ENOMEM;

goto Done;

Einval:

error = -EINVAL;

goto Done;

Eaccess:

error = -EACCES;

module_put(attr->owner);

Done:

if (error && kobj)

kobject_put(kobj);

return error;

}

check_perm()檢查一下權限,創建一個sysfs的緩沖區sysfs_buffer buffer,並設置其sysfs_ops sysfs_buffer->ops。在我們這個故事裡,sysfs_buffer->ops被設置成bus_sysfs_ops。最後讓file->private_data = buffer。

(2)sysfs read file()流程如下:

read()->/*用戶空間*/

-> 系統調用->

sys_read() -> vfs_read() -> sysfs_read_file()/*內核空間*/

看看sysfs_read_file()函數,

static ssize_t

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 ((retval = fill_read_buffer(file->f_dentry,buffer)))

goto out;

}

pr_debug("%s: count = %d, ppos = %lld, buf = %s

",

__FUNCTION__,count,*ppos,buffer->page);

retval = flush_read_buffer(buffer,buf,count,ppos);

out:

up(&buffer->sem);

return retval;

}

順著sysfs_read_file()往下走:

sysfs_read_file()

---> fill_read_buffer()

---> sysfs_buffer->bus_sysfs_ops->bus_attr_show()

---> bus_attribute->show_bus_version() //注意這個函數是我們在lddbus.c裡面定義的

---> flush_read_buffer()

fill_read_buffer()的是真正的讀,它把內容讀到sysfs定義的緩沖區sysfs_buffer。flush_read_buffer()是把緩沖區copy到用戶空間。詳細內容我就不貼了。

Copyright © Linux教程網 All Rights Reserved