当前位置:操作系统 > Unix/Linux >>

Linux内核模块编程/proc文件系统

/proc 文件系统

  在Linux中有额外的机制可以为内核和内核模块将信息发送给进程 -- /proc 文件系统。最初设计的目的是允许更方便的对进程信息进行访问(因此得名),现在它被每一个有有趣的东西报告的内核使用,例如 /proc/modules 有模块的列表 /proc/meminfo 有内存使用的统计表。

  使用proc 文件系统的方法和使用设备驱动程序非常相似--创建一个 /proc 文件需要的所有信息的结构,包括任何处理函数的指针(在我们的例子中只有一个,当某人试图从 /proc 文件读时调用的那一个)。然后,init_module 在内核中登记该结构而cleanup_module 注销它。

  我们使用 proc_register_dynamic(这是在 2.0 版中的情况,在 2.2 版中如果我们将节点设置为0系统将自动为我们做到) 的原因是我们不想预先决定我们的文件的节点数字,而是为防止冲突而由内核决定它。通常的文件系统存在于磁盘上而不是内存中(/proc 在内存中),在这中情况下,节点数是是指向文件的索引节点所在的磁盘位置的指针。节点包含文件的信息(例如文件的存取权限)和指向磁盘位置或文件数据可以被找到的几个位置的指针。

  因为当文件被打开或关闭的时候不能得到调用,所以在这个模块中没有地方放置 MOD_INC_USE_COUNT 和 MOD_DEC_USE_COUNT,并且,如果文件被打开随后模块被移除,我们没有办法避免后果。在下一 章我们会看到一个艰难的但更灵活的可以处理/proc文件的实现方式,它也可以让我们防止那个问题。

  范例 procfs.c

  /* procfs.c - create a "file" in /proc* Copyright (C) 1998-1999 by Ori Pomerantz*//* 必要的头文件 *//* 内核模块标准头文件 */#include /* 内核工作 */#include /* 明确指定是模块 *//* 处理CONFIG_MODVERSIONS */#if CONFIG_MODVERSIONS==1#define MODVERSIONS#include#endif/* 使用proc 文件系统所必要的 */#include/* 在 2.2.3 版/usr/include/linux/version.h 中包含这个宏* 但 2.0.35 版不包含 - 因此我在此加入这个以防需要。 */#ifndef KERNEL_VERSION#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))#endif/* 将数据放入 proc 文件参数====1. 如果你决定使用缓冲区,数据应该被插入它。2. 字符指针的指针。如果你不想使用由内核分配的缓冲区时这将有用。3. 文件的当前位置。4. 第一个参数中的缓冲区的大小。5. Zero (为将来使用?)。用法和返回值============如果你像我那样使用自己的缓冲区,将它放在第二个参数的位置并返回在那个缓冲区中使用的字节数。返回值为0 意味着这次没有更多信息(文件尾)。负数返回值是错误条件。更多信息========我不是通过读文档而发现用这个函数去做什么的,而是通过读使用它的代码。我只想看看什么使用了proc_dir_entry的get_info成员(如果你有兴趣的话,我使用了一个查找和搜索的组合),我发现它被<内核源文件目录>/fs/proc/array.c使用。如果有什么关于内核的事情不清楚,这是一个通常的办法。在 Linux 中我们有自由的获取源代码的巨大优势--使用它。*/int procfile_read(char *buffer,char **buffer_location,off_t offset,int buffer_length,int zero){int len; /* The number of bytes actually used *//* 这是静态的,因此当我们离开这个函数时它还会待在内存中 */static char my_buffer[80];static int count = 1;/* 我们将所有的信息放在一个里面,所以如果用户问是否有更多的信息,答案总是“没有”。** 这是很重要的,因为来自库的标准读函数将持续发布读系统调用直到内核答复没有更多信息* 或它的缓冲区被填满。*/if (offset > 0)return 0;/* 填充缓冲区并得到长度 */len = sprintf(my_buffer,"For the %d%s time, go away!

  ", count,(count % 100 > 10 && count % 100 < 14) ? "th" :(count % 10 == 1) ? "st" :(count % 10 == 2) ? "nd" :(count % 10 == 3) ? "rd" : "th" );count++;/* 告诉调用函数缓冲区在哪儿*/*buffer_location = my_buffer;/* 返回长度 */return len;}struct proc_dir_entry Our_Proc_File ={0, /* 节点数 - 忽略,它将被 proc_register[_dynamic] 填充*/4, /* 文件名长度 */"test", /* 文件名*/S_IFREG | S_IRUGO, /* 文件模式 - 这是一个可以被拥有者,用户组和其他所有的用户读取的* 普通文件 */1, /* 连接数 (文件被引用的目录数) */0, 0, /* 文件的UID和GID - 我们将它赋予 root */80, /* 用ls报告的文件大小。 */NULL, /* 使用节点的函数(连接,删除,等等)--我们不支持 */procfile_read, /* 对这个文件的读函数,当某人试图葱它读入什么时被调用。 */NULL /* 我们能够在这儿有一个填充文件节点的函数,允许我们修改权限和拥有权,等等。 */};/* 初始化模块--登记 proc 文件 */int init_module(){/* proc_register[_dynamic] 成功则成功,否则失败。 */#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)/* 在 2.2版中,如果在这个结构中它为0则 proc_register 自动的分配一个动态的节点数* 因此不再需要proc_register_dynamic*/return proc_register(&proc_root, &Our_Proc_File);#elsereturn proc_register_dynamic(&proc_root, &Our_Proc_File);#endif/* proc_root 是 proc文件系统的根目录。这是我们想让我们的文件所处的位置 */}/* 清除 - 从 /proc中注销我们的文件 */void cleanup_module(){proc_unregister(&proc_root, Our_Proc_File.low_ino);}
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,