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

原创 2007年09月14日 17:57:00
跟上回一样,我用这个小程序来读
#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到用户空间。详细内容我就不贴了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

Linux那些事儿之我是Sysfs(12)举例三:sysfs读入文件夹内容

上回我们说到,如何创建文件夹和文件。我们发现,在sysfs中,inode并不那么重要。这是因为我们所要读写的信息已经就在内存中,并且已经形成了层次结构。我们只需有dentry,就可以dentry->f...
  • xie0812
  • xie0812
  • 2016年05月17日 17:49
  • 343

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

跟上回一样,我用这个小程序来读 #include stdio.h> #include fcntl.h> #include unistd.h> int main(){           ...
  • xie0812
  • xie0812
  • 2016年05月17日 17:50
  • 200

Linux那些事儿之我是Sysfs(1)sysfs初探

"sysfs is a ram-based filesystem initially based on ramfs. It provides a means to export kernel dat...
  • xie0812
  • xie0812
  • 2016年05月17日 17:36
  • 513

sysfs 文件系统详解

sysfs是用于表现设备驱动模型的文件系统,它基于ramfs。要学习linux的设备驱动模型,就要先做好底层工作,总结sysfs提供给外界的API就是其中之一。sysfs文件系统中提供了四类文件的创建...
  • LinuxEngineer
  • LinuxEngineer
  • 2014年01月09日 16:15
  • 2400

linux内核sysfs详解-1

sysfs 是 Linux 内核中设计较新的一种虚拟的基于内存的文件系统,它的作用与 proc 有些类似,但除了与 proc 相同的具有查看和设定内核参数功能之外,还有为 Linux 统一设备模型...
  • u014213012
  • u014213012
  • 2016年11月12日 17:17
  • 898

建立驱动sysfs接口

原文地址 http://blog.sina.com.cn/s/blog_6a16c0ae0101b93s.html 在调试驱动,或驱动涉及一些参数的输入输出时,难免需要对驱动里的某些变量进行读写,或...
  • lqxandroid2012
  • lqxandroid2012
  • 2015年10月26日 15:22
  • 593

linux内核sysfs详解

"sysfs is a ram-based filesystem initially based on ramfs. It provides a means to export kernel data...
  • u013562393
  • u013562393
  • 2016年06月25日 01:22
  • 712

kernel与用户层接口之sysfs属性接口

字符设备文件,以这个虚拟设备上的 read/write/ioctl 等接口与用户交互;但 read/write 一般只能做一件事情, ioctl 可以根据 cmd 参数做多个功能,但其缺点是很明显的:...
  • zbunix
  • zbunix
  • 2013年04月21日 22:38
  • 2992

用户空间与内核空间的接口:sysfs

在调试驱动,或驱动涉及一些参数的输入输出时,难免需要对驱动里的某些变量或内核参数进行读写,或函数调用。此时sysfs接口就很有用了,它可以使得可以在用户空间直接对驱动的这些变量读写或调用驱动的某些函数...
  • wuyuwei45
  • wuyuwei45
  • 2013年05月27日 10:18
  • 1563

linux内核sysfs详解

"sysfs is a ram-based filesystem initially based on ramfs. It provides a means to export kernel dat...
  • skyflying2012
  • skyflying2012
  • 2013年09月17日 18:35
  • 19718
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux那些事儿之我是Sysfs(13)举例四:sysfs读入普通文件内容
举报原因:
原因补充:

(最多只允许输入30个字)