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

Linux那些事儿之我是Sysfs(13)举例四:sysfs读入普通文件内容

2016-05-17 17:50 441 查看
跟上回一样,我用这个小程序来读


#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到用户空间。详细内容我就不贴了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: