Linux.ChinaUnix.net
ChinaUnix | Linux首页 | 新闻 | 博客 | 文章 | 专栏 | 新手 | 方案 | 图书 | 下载 | 人才 | 手册 | wiki | 搜索     
Linux论坛
  会员: 密码: 免费注册 | 忘记密码 | 会员登录 | 搜索



原创精华帖子 proc文件系统剖析
首页 » CU论坛 » Linux » 汇总贴列表 » 驱动开发 »  
[打印] [订阅] [收藏] [本帖文本页] [推荐此主题给朋友,立即获积分]
  本主题由 dreamice 于 2008-11-12 15:47 设置高亮 
版主 dreamice
广告杀手-精灵使
言多必失



CU编号: 562632
注册:2007-5-11
最后登录: 2009-07-02
帖子:3895
精华:37

可用积分:6236 (富足长乐)
信誉积分:110
专家积分:70 (本版:0)
空间积分:0
推广积分:31

状态:...离线...

[个人空间] [短信] [博客]


1楼 发表于 2008-11-12 15:44 
Proc file system
dreamice.jiang@gmail.com
1、重要的数据结构:
struct proc_dir_entry {
        unsigned int low_ino;
        unsigned short namelen;
        const char *name;
        mode_t mode;
        nlink_t nlink;
        uid_t uid;
        gid_t gid;
        loff_t size;
        const struct inode_operations *proc_iops;
        /*
         * NULL ->proc_fops means "PDE is going away RSN" or
         * "PDE is just created". In either case, e.g. ->read_proc won't be
         * called because it's too late or too early, respectively.
         *
         * If you're allocating ->proc_fops dynamically, save a pointer
         * somewhere.
         */
        const struct file_operations *proc_fops;
        get_info_t *get_info;
        struct module *owner;
        struct proc_dir_entry *next, *parent, *subdir;
        void *data;
        read_proc_t *read_proc;
        write_proc_t *write_proc;
        atomic_t count;                /* use count */
        int pde_users;        /* number of callers into module in progress */
        spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
        struct completion *pde_unload_completion;
        shadow_proc_t *shadow_proc;
};

2、创建函数:
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
                                                struct proc_dir_entry *parent);
name: 要创建的文件名称;
mode: 该文件的保护掩码;
parent: 确定文件所在目录,如果置NULL,则位置为/proc下。

3、读proc:
int read_proc(char *page, char **start, off_t off,
                          int count, int *eof, void *data);
page:指示用来写入数据的缓冲区;
off和count:与read函数对应的参数相同;
start和eof:用于读取大于1个page数据时实现。

4、写proc:
int write_proc(struct file *file, const char __user *buffer,
                           unsigned long count, void *data);
filp 参数实际上是一个打开文件结构(可以忽略这个参数)。Buffer 参数是用户空间要写入的数据。缓冲区地址实际上是一个用户空间的缓冲区,不能直接读取它。len 参数定义了在 buffer 中有多少数据要被写入。data 参数是一个指向私有数据的指针。

5、实现一个proc文件
(1)调用create_proc_entry创建一个struct proc_dir_entry,作为一个全局量。
(2)对创建的struct proc_dir_entry进行赋值:read_proc,mode,owner,size,write_proc等等。
示例:
proc_hello.c
#include <linux/module.h> /* Specifically, a module */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
#define procfs_name "helloworld"

struct proc_dir_entry *Our_Proc_File;
int
procfile_read(char *buffer,
        char **buffer_location,
        off_t offset, int buffer_length, int *eof, void *data)
{
        int ret;
        printk(KERN_INFO "procfile_read (/proc/%s) called\n", procfs_name);
/*
* We give all of our information in one go, so if the
* user asks us if we have more information the
* answer should always be no.
*
* This is important because the standard read
* function from the library would continue to issue
* the read system call until the kernel replies
* that it has no more information, or until its
* buffer is filled.
*/
        if (offset > 0) {
                printk(KERN_INFO "offset > 0\n");
/* we have finished to read, return 0 */
                ret = 0;
        } else {
/* fill the buffer, return the buffer size */
                printk(KERN_INFO "offset <= 0\n");
                ret = sprintf(buffer, "HelloWorld!\n");
        }
        return ret;
}
int init_module()
{
        Our_Proc_File = create_proc_entry(procfs_name, 0644, NULL);
        if (Our_Proc_File == NULL) {
                remove_proc_entry(procfs_name, &proc_root);
                printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
                        procfs_name);
                return -ENOMEM;
        }
        Our_Proc_File->read_proc = procfile_read;
        Our_Proc_File->owner = THIS_MODULE;
        Our_Proc_File->mode = S_IFREG | S_IRUGO;
        Our_Proc_File->uid = 0;
        Our_Proc_File->gid = 0;
        Our_Proc_File->size = 37;
        printk(KERN_INFO "/proc/%s created\n", procfs_name);
        return 0; /* everything is ok */
}
void cleanup_module()
{
        remove_proc_entry(procfs_name, &proc_root);
        printk(KERN_INFO "/proc/%s removed\n", procfs_name);
}

Makefile:
obj-m := proc_hello.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
        $(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
        $(RM) *.o *.mod.c *.ko *.symvers

本示例只实现了一个简单的读proc操作。
编译后,执行:
# insmod proc_hello.ko
# dmesg
  /proc/helloworld created
# cat /proc/ helloworld
  HelloWorld!
# dmesg
  procfile_read (/proc/helloworld) called
offset <= 0
procfile_read (/proc/helloworld) called
offset > 0
procfile_read (/proc/helloworld) called
offset > 0
# rmmod proc_hello
  /proc/helloworld

为什么在调用cat /proc/ helloworld后,会看到procfile_read被执行了三次,且只有第一次读到了数据?
因为通常cat,dd等,都是通过标准库函数来实现的,标准库函数往往会多次调用系统调用来读写数据,所以我们看到调用了3次。具体cat以及dd等调用一次,读取或写数据大小,这个需要具体查证一下。
我写了一个test程序,来验证这个多次读操作不是在系统调用里面实现的:
test.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define PROC_FILE       "/proc/helloworld"

int main()
{
        char buf[50];
        int fd = open(PROC_FILE, O_RDONLY);
        if (fd == -1) {
                printf("open err\n");
                return -1;
        }
        if (read(fd, buf, sizeof("HelloWorld")) > 0) {
                printf("read: %s\n", buf);
        }
        close(fd);
}

编译:
# gcc test.c –o test
加载模块后,执行
# ./test
然后,执行:
# dmesg
  procfile_read (/proc/helloworld) called
offset <= 0
确实只执行了一次,这说明多次调用procfile_read是在系统之上做的。
6、注意点
(1)切记不能访问已经卸载的一个proc文件,否则会导致kernel panic;
(2)注意不要删除正在调用的问proc文件。因为文件的入口项不存在关联的作者,文件的调用也并没有作用到模块的引用计数上;
(3)勿注册两个同名的proc文件,这样将导致入口项无法区分。

以上这些都是proc文件的缺点,也是使用时必须注意的地方。所以,现在推荐使用seq_file 和sys_fs。



2008-11-12 15:44
  下载次数: 490
proc.pdf (73.55 KB)
  本文pdf



本帖最近评分记录
Godbach   2008-11-12 16:01  可用积分  +5   我很赞同
您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

Nothing is impossible!
版主 dreamice
广告杀手-精灵使
言多必失



CU编号: 562632
注册:2007-5-11
最后登录: 2009-07-02
帖子:3895
精华:37

可用积分:6236 (富足长乐)
信誉积分:110
专家积分:70 (本版:0)
空间积分:0
推广积分:31

状态:...离线...

[个人空间] [短信] [博客]


2楼 发表于 2008-11-12 15:46 
具体proc的介绍我就不说了,到处都可以查到。
上面我也说到了与歌德巴赫兄讨论的系统调用与标准库函数实现之间的差异。



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

Nothing is impossible!
版主 Godbach (To be 千里马!)
版主-大法师


CU奥运火炬传递手2008
CU编号: 534931
注册:2007-3-9
最后登录: 2009-07-04
帖子:8560
精华:12

可用积分:22755 (巨富豪门)
信誉积分:112
专家积分:114 (本版:10)
空间积分:2
推广积分:17

状态:...保密...

[个人空间] [短信] [博客]


3楼 发表于 2008-11-12 15:55 
剖析的很好啊。现在很多时候做模块开发还是离不开proc文件的。



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

明犯我强汉天威者,穷搜天下,万里追杀,覆其巢,断其苗裔,戮其身,追其魂,屠其魄,虽远必诛!
----------------------------------
一尺之槌,日取其半,万世不竭!
----------------------------------
欢迎光临Godbach的博客交流技术问题:
http://blog.chinaunix.net/u/33048/
----------------------------------
版主 Godbach (To be 千里马!)
版主-大法师


CU奥运火炬传递手2008
CU编号: 534931
注册:2007-3-9
最后登录: 2009-07-04
帖子:8560
精华:12

可用积分:22755 (巨富豪门)
信誉积分:112
专家积分:114 (本版:10)
空间积分:2
推广积分:17

状态:...保密...

[个人空间] [短信] [博客]


4楼 发表于 2008-11-12 15:57 
dreamice兄什么时候也研究一下sysfs,写个例程让大家学习一下啊。LDD3中比较推荐使用这个。



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

明犯我强汉天威者,穷搜天下,万里追杀,覆其巢,断其苗裔,戮其身,追其魂,屠其魄,虽远必诛!
----------------------------------
一尺之槌,日取其半,万世不竭!
----------------------------------
欢迎光临Godbach的博客交流技术问题:
http://blog.chinaunix.net/u/33048/
----------------------------------
版主 Godbach (To be 千里马!)
版主-大法师


CU奥运火炬传递手2008
CU编号: 534931
注册:2007-3-9
最后登录: 2009-07-04
帖子:8560
精华:12

可用积分:22755 (巨富豪门)
信誉积分:112
专家积分:114 (本版:10)
空间积分:2
推广积分:17

状态:...保密...

[个人空间] [短信] [博客]


5楼 发表于 2008-11-12 16:01 
dreamice兄是不是以前学习的过程中都做了很多总结,写成文章了啊。最近一下子这么多精华的文章,真是让兄弟应接不暇啊。

赞一个!



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

明犯我强汉天威者,穷搜天下,万里追杀,覆其巢,断其苗裔,戮其身,追其魂,屠其魄,虽远必诛!
----------------------------------
一尺之槌,日取其半,万世不竭!
----------------------------------
欢迎光临Godbach的博客交流技术问题:
http://blog.chinaunix.net/u/33048/
----------------------------------
llbox
新手




CU编号: 783613
注册:2008-11-12
最后登录: 2008-11-12
帖子:3
精华:0

可用积分:4 (白手起家)
信誉积分:0
专家积分:0 (本版:0)
空间积分:0
推广积分:0

状态:...离线...

[个人空间] [短信] [博客]


6楼 发表于 2008-11-12 16:08 
awesome



您对本贴的看法:鲜花[0] 臭蛋[0]
版主 dreamice
广告杀手-精灵使
言多必失



CU编号: 562632
注册:2007-5-11
最后登录: 2009-07-02
帖子:3895
精华:37

可用积分:6236 (富足长乐)
信誉积分:110
专家积分:70 (本版:0)
空间积分:0
推广积分:31

状态:...离线...

[个人空间] [短信] [博客]


7楼 发表于 2008-11-12 16:13 


QUOTE:
原帖由 Godbach 于 2008-11-12 16:01 发表
dreamice兄是不是以前学习的过程中都做了很多总结,写成文章了啊。最近一下子这么多精华的文章,真是让兄弟应接不暇啊。

赞一个!

没有,今天刚写好就拿出来分享了,我这个人是藏不住东西的,呵呵。
争取明天分析个seq_file,sysfs稍后再说,呵呵。多谢支持。



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

Nothing is impossible!
版主 dreamice
广告杀手-精灵使
言多必失



CU编号: 562632
注册:2007-5-11
最后登录: 2009-07-02
帖子:3895
精华:37

可用积分:6236 (富足长乐)
信誉积分:110
专家积分:70 (本版:0)
空间积分:0
推广积分:31

状态:...离线...

[个人空间] [短信] [博客]


8楼 发表于 2008-11-12 16:17 
呵呵,你可以给我加分啊,权限真大,哈哈



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

Nothing is impossible!
版主 Godbach (To be 千里马!)
版主-大法师


CU奥运火炬传递手2008
CU编号: 534931
注册:2007-3-9
最后登录: 2009-07-04
帖子:8560
精华:12

可用积分:22755 (巨富豪门)
信誉积分:112
专家积分:114 (本版:10)
空间积分:2
推广积分:17

状态:...保密...

[个人空间] [短信] [博客]


9楼 发表于 2008-11-12 17:32 


QUOTE:
原帖由 dreamice 于 2008-11-12 16:17 发表
呵呵,你可以给我加分啊,权限真大,哈哈

呵呵,好像是积分达到一定程度就可以给被人加分减分。我头一次使用,呵呵。



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

明犯我强汉天威者,穷搜天下,万里追杀,覆其巢,断其苗裔,戮其身,追其魂,屠其魄,虽远必诛!
----------------------------------
一尺之槌,日取其半,万世不竭!
----------------------------------
欢迎光临Godbach的博客交流技术问题:
http://blog.chinaunix.net/u/33048/
----------------------------------
版主 dreamice
广告杀手-精灵使
言多必失



CU编号: 562632
注册:2007-5-11
最后登录: 2009-07-02
帖子:3895
精华:37

可用积分:6236 (富足长乐)
信誉积分:110
专家积分:70 (本版:0)
空间积分:0
推广积分:31

状态:...离线...

[个人空间] [短信] [博客]


10楼 发表于 2008-11-12 17:50 


QUOTE:
原帖由 Godbach 于 2008-11-12 17:32 发表


呵呵,好像是积分达到一定程度就可以给被人加分减分。我头一次使用,呵呵。


你的处女分都给我了啊



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

Nothing is impossible!

首页 » CU论坛 » Linux » 汇总贴列表 » 驱动开发 »

 


Copyright © 2001-2008 ChinaUnix.net All Rights Reserved     联系我们:

感谢所有关心和支持过ChinaUnix的朋友们    转载本站内容请注明原作者名及出处

京ICP证041476号


清除 Cookies - Linux时代 - Archiver - WAP - TOP

Processed in 0.089375 second(s), 8 queries , Gzip enabled