sysfs

来源:互联网 发布:淘宝天猫店windstyle 编辑:程序博客网 时间:2024/06/05 22:43

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

分类: Linux那些事儿 之 我是Sysfs  4238人阅读 评论(0) 收藏 举报
跟上回一样,我用这个小程序来读
#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到用户空间。详细内容我就不贴了。

原创粉丝点击