linux中proc文件系统 -- ldd3读书笔记

1./proc 文件系统概述

/proc 文件系统是由软件创建,被内核用来向外界报告信息的一个文件系统。/proc 下面的每一个文件都和一个内核函数相关联,当文件的被读取时,与之对应的内核函数用于产生文件的内容。我们已经见到了很多这样的文件,例如,/proc/modules 总是返回当前内核中加载的模块。

/proc 广泛的应用在 linux 文件系统中,现代 linux 发行版上的许多应用程序,例如 ps ,top 和 uptime 都从 /proc 获取他们所需要的信息。一些驱动程序也通过 /proc 文件系统报告信息,当然你的驱动程序也可以这么做。 /proc 文件系统是动态的,所以你的模块可以在任何时候添加或者删除入口。完全特征的 /proc 入口可能会是一个复杂的猛兽,它们既可以读也可以写。然而,大多数时候,/proc 中的文件是只读的。这里考虑的是只读的 /proc 文件。

然而,在继续之前,必须强调在 /proc 下面添加文件是不提倡的。/proc 文件系统被内核开发者看作是不可控制的混乱,这和它最初的目的--报告系统中运行的进程的信息相差十万八千里。在新的代码中推荐的获取信息的方式是通过 sysfs 。但是,使用 sysfs 是需要对 linux 设备模型有一个理解。并且,/proc 下面的文件较容易创建,并且完全符合调试的目的,所以才会学习 /proc 文件系统。

2.创建 /proc 文件

如果你定义了一个 read_proc 函数,你需要将它和 /proc 层次中的入口联系起来。这是通过一个叫做 create_proc_read_entry 的函数来实现的,这个函数的函数原型如下:

struct proc_dir_entry *create_proc_read_entry(const char *name,mode_t mode,struct proc_dir_entry *base,read_proc_t *read_proc,void *data);

上面的函数原型中,name 就是要创建的文件的名字;mode 就是文件的保护掩码,可以使用 0 来使用系统默认的掩码;base 指定了创建的文件所在的目录,如果 base 为 NULL,创建的文件就存在于 /proc 目录之下;read_proc 就是实现这个文件的函数;data 参数被内核忽略,但是却被传递给 read_proc 函数。举一个例子:

create_proc_read_entry("scullmem", 0/*default mode*/, NULL /*parent dir*/, scull_read_procmem, NULL /*client data*/);

这个例子中,我们在 /proc 下面创建了一个文件,名字为 scullmem,采用的是系统默认的保护权限。

目录入口指针可以用来在 /proc 下创建整个目录架构,然而,注意将一个文件放到 /proc 子目录中的一个更加容易的做法是将子目录的名字作为要创建的新文件名字的一部分路径,只要那个子目录已经存在。例如一个经常被忽略的惯例就是和驱动程序相关的 /proc 文件应该放到一个 driver 子目录中。例如,上面的例子中,我们想要将所创建的文件 scullmem 放到 driver 中,只需要将第一个参数修改为 "driver/scullmem" 就可以了。

/proc 中文件在模块被卸载的时候应该被删除。remove_proc_entry 所做的事情和 create_proc_read_entry 所做的事情相反。例如:

remove_proc_entry("scullmem",NULL /*parent dir*/);

不能成功的移除文件将导致这个文件在不合适的时候被调用,或者是,模块被卸载后,内核就崩溃了。当向上面一样使用 /proc 的时候,必须记住几个麻烦的事——难怪现在不推荐使用这种方式了。最重要的问题就是在删除 /proc 文件的时候了,在删除的时候文件可能仍然在使用。因为 /proc 文件没有相关的所有者,所以使用它们的时候并不会对引用计数起作用。这个问题可以简单的通过在删除文件之前使用下面的命令引起:

sleep 100  < /proc/myfile

另外一个问题是注册了两个一样名字的文件。内核信任驱动程序,并不检查文件的名字是否备注册过,所以如果你不小心,就可能会注册多个相同名字的文件。这就像在教室里发生的著名的问题一样,这些文件不能区分,不管是你在访问它们还是调用remove_proc_entry的时候。

3.在 /proc中实现文件

所有使用 /proc 的模块应该包括 <linux/proc_fs.h> 头文件来定义合适的函数。创建一个只读的 /proc 文件,你的驱动程序必须实现一个函数,当这个文件被读时,来产生一些数据。当一些进程使用 read 函数读取文件的时候,请求就通过这个函数到达了你的模块。我们会首先看一下这个函数,并且之后介绍注册的接口。当一个进程读取 /proc 文件的时候,内核就分配了一页的内存,驱动程序可以将要返回给用户空间的数据写到这个页里面。那个缓存被传递给了你的 read_proc 函数。read_proc
函数的原型如下:

int (*read_proc)(char *page,char **start,off_t offset,int count,int *eof,void *data);

参数 page 是缓冲区的指针,你可以往里面写入数据;start 被函数用来说明感兴趣的数据被写到了页的位置。offset 和 count 与 read 函数的参数意义相同;eof 指向了一个整数,必须由驱动程序来设定报告没有返回的数据了,data 是依赖于特定的驱动的数据指针,你可以用来作为内部记账。

这个函数应该返回写入到页缓冲区中的数据字节数。就像 read 函数一样。其它的输出是 *eof 和 *start 。eof 是一个简单的标记,但是 start 的使用方法是有写复杂的,它的目的视为了帮助实现大的(超过一页)的 /proc 文件。start 参数并不常用,它的目的使用来指示返回给用户空间的住局在一页中的哪个位置。当 read_proc 函数被调用的时候,*start 参数将会被设置为 NULL。如果你保留它为 NULL 的话,内核会假设数据放到页里面时,参数 offset 为 0。换句话说,内核假设了一个头脑简单的
read_proc 版本,它把虚拟文件的所有内容写到页里面,而忽略了 offset 参数。相反,如果给 *start 设置了一个不是 NULL 的值,内核就假设由 *start 指向的数据将 offset 考虑在内,并且已经准备好返回给用户空间了。一般来说,简单的 proc_read 方法返回很少量的数据常常忽略了 *start 参数。更加复杂的方法才会设置页的 *start 的值,并且仅仅将数据放到所请求的 offset 那里。

4.实例

在这里,我们写了一个简单的例子来演示一下 /proc 的使用:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>

int read_proc(char *page,char **start,off_t offset,int count,int *eof,void *data);

static int __init test_proc_init(void)
{
    create_proc_read_entry("read_proc",0,NULL,read_proc,NULL);
    return 0;
}

static void __exit test_proc_exit(void)
{
    remove_proc_entry("read_proc",NULL);
}

int read_proc(char *page,char **start,off_t offset,int count,int *eof,void *data)
{
    int len = sprintf(page,"%s\n","hello world");
    return len;
}

module_init(test_proc_init);
module_exit(test_proc_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wangxq");

当插入这个模块到内核之后,使用命令:

cat /proc/read_proc

就会看到输出 hello world。

linux中proc文件系统 -- ldd3读书笔记

时间: 2024-12-29 13:50:44

linux中proc文件系统 -- ldd3读书笔记的相关文章

Linux内核设计与实现 读书笔记 转

Linux内核设计与实现  读书笔记: http://www.cnblogs.com/wang_yb/tag/linux-kernel/ <深入理解LINUX内存管理> http://blog.csdn.net/yrj/article/category/718110 Linux内存管理和性能学习笔记(一) :内存测量与堆内存 第一篇 内存的测量 2.1. 系统当前可用内存 # cat /proc/meminfoMemTotal:        8063544 kBMemFree:       

Linux的proc文件系统

proc为一个内核数据结构接口,用户空间和内核空间可以通过该接口通信, 与普通文件不同的是,这些虚拟文件的内容都是动态创建的. proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间. 它以文件系统的方式为访问系统内核数据的操作提供接口.用户和应用程序 可以通过 proc得到系统的信息,并可以改变内核的某些参数. proc 文件系统可以被用于收集有用的关于系统和运行中的内核的信息. 对此文件系统的访问同一般文件相同. 例: 1.统计cpu个数: cat /proc/cpuinfo

进程和程序:编写shell——《Unix/Linux编程实践教程》读书笔记(第8章)

1.Unix shell的功能 shell是一个管理进程和运行程序的程序.所有常用的shell都有3个主要功能: (1)运行程序: (2)管理输入和输出 (3)可编程 shell同时也是带有变量和流程控制的编程语言. 2.Unix的进程模型 一个程序是存储在文件中的机器指令序列,一般它是由编译器将源代码编译成二进制格式的代码.运行一个程序意味着将这些机器指令序列载入内存然后让处理器(CPU)逐条执行.在Unix术语中,一个可执行程序是一些机器指令机器数据的序列.一个进程是程序运行时的内存空间和设

系统调用操作文件——《Unix/Linux编程实践教程》读书笔记

1.who命令通过读系统日志的内容显示当前已经登录的用户. 2.Unix系统把数据存放在文件中,可以通过以下系统调用操作文件: open(filename, how) creat(filename, mode) read(fd, buffer, amt) write(fd, buffer, amt) lseek(fd, distance, base) close(fd) 3.进程对文件的读/写都要通过文件描述符,文件描述符表示文件和进程之间的连接. 4.每次系统调用都会导致用户模式和内核模式的切

终端控制和和信号——《Unix/Linux编程实践教程》读书笔记(第6章)

1.有些程序处理从特定设备来的数据.这些与特定设备相关的程序必须控制与设备的连接.Unix系统中最常见的设备是终端. 2.终端驱动程序有很多设置.各个设置的特定值决定了终端驱动程序的模式.为用户编写的程序通常需要设置终端驱动程序为特定的模式. 3.键盘输入分为3类,终端驱动程序对这些输入做不同的处理.大多数建代表常规数据,它们从驱动程序传输到程序.有些键调用驱动程序中的编辑函数.如果按下删除键,驱动程序将前一个字符从它的行缓冲中删除,并将命令发送到终端屏幕,使之从显示器中删除字符.最后,有些键调

Linux内核设计与实现读书笔记——第三章

Linux内核设计与实现读书笔记——第三章 进程管理 20135111李光豫 3.1进程 1.进程即处于执行期的程序,并不局限于一个可执行的代码,是处于执行期程序以及其相关资源的总称. 2.Linux系统中,对于进程和线程并没有明显的区分,线程是一种特殊的进程. 3.Linux系统中,常用fork()进程创建子进程.调用fork()进程的成之为其子进程的父进程. 4.fork()继承实际上由clone()系统调用实现.最后通过exit()退出执行. 3.2任务描述符及任务结构 1.任务队列实质上

linux 中/proc 详解

proc 文件系统 在Linux中有额外的机制可以为内核和内核模块将信息发送给进程-- /proc 文件系统.最初设计的目的是允许更方便的对进程信息进行访问(因此得名),现在它被每一个有有趣的东西报告的内核使用,例如/proc/modules 有模块的列表/proc/meminfo 有内存使用的统计表.  使用proc 文件系统的方法和使用设备驱动程序非常相似--创建一个/proc 文件需要的所有信息的结构,包括任何处理函数的指针(在我们的例子中只有一个,当某人试图从/proc 文件读时调用的那

事件驱动编程——《Unix/Linux编程实践教程》读书笔记(第7章)

1.curses库 /* 基本curses函数 */ initscr(); // 初始化curses库和tty endwin(); // 关闭curses并重置tty refresh(); // 使屏幕按照你的意图显示 move(r, c); // 移动光标到屏幕的(r, c)位置 addstr(s); // 在当前位置画字符串s addch(c); // 在当前位置画字符c clear(); // 清屏 standout(); // 启动standout模式(一般使屏幕反色) standend

I/O重定向和管道——《Unix/Linux编程实践教程》读书笔记(第10章)

1.I/O重定向的概念与原因 及 标准输入.输出的标准错误的定义 所以的Unix I/O重定向都基于标准数据流的原理.三个数据了分别如下: 1)标准输入--需要处理的数据流 2)标准输出--结果数据流 3)标准错误输出--错误消息流 概念:所以的Unix工具都使用文件描述符0.1和2.标准输入文件的描述符是0,标准输出的文件描述符是1,而标准错误输出的文件描述符则是2.Unix假设文件描述符0.1.2已经被打开,可以分别进行读写操作. 通常通过shell命令行运行Unix系统工具时,stdin.