linux内核模块编程5

Chapter 5. The /proc File System
关于 /proc 文件系统
在Linux中有另一种内核和内核模块向进程传递信息的方法,那就是通过 /proc文件系统。它原先设计的目的是为查看进程信息 提供一个方便的途径,现在它被用来向用户提供各种内核中被感兴趣的内容。像文件 /proc/modules里是已加载模块的列表,文件/proc/meminfo 里是关于内存使用的信息。

使用 proc 文件系统的方法同使用设备文件很相似。你建立一个包含 /proc文件需要的所有信息的结构体, 这其中包括处理各种事务的函数的指针(在我们的例子中,只用到从/proc文件读取信息的函数)。然后在init_module 时向内核注册这个结构体,在cleanup_module时注销这个结构体。

我们使用proc_register_dynamic[1]的原因是我们不用去设置inode,而留给 内核去自动分配从而避免系统冲突错误。 普通的文件系统是建立在磁盘上的,而 /proc 的文件仅仅是建立在内存中的。 在前种情况中,inode的数值是一个指向存储在磁盘某个位置的文件的索引节点(inode就是index-node的缩写)。 该索引节点储存着文件的信息,像文件的权限;同时还有在哪儿能找到文件中的数据。

因为我们无法得知该文件是被打开的或关闭的,我们也无法去使用宏 try_module_get和try_module_put在下面的模块中, 我们无法避免该文件被打开而同时模块又被卸载。在下章中我将介绍一个较难实现,却更灵活,更安全的处理 /proc文件的方法。

Example 5-1. procfs.c

/*
*  procfs.c -  create a "file" in /proc
*/

#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 */

struct proc_dir_entry *Our_Proc_File;

/* Put data into the proc fs file.

* Arguments
* =========
* 1. The buffer where the data is to be inserted, if
*    you decide to use it.
* 2. A pointer to a pointer to characters. This is
*    useful if you don't want to use the buffer
*    allocated by the kernel.
* 3. The current position in the file
* 4. The size of the buffer in the first argument.
* 5. Write a "1" here to indicate EOF.
* 6. A pointer to data (useful in case one common 
*    read for multiple /proc/... entries)
*
* Usage and Return Value
* ======================
* A return value of zero means you have no further
* information at this time (end of file). A negative
* return value is an error condition.
*
* For More Information
* ====================
* The way I discovered what to do with this function
* wasn't by reading documentation, but by reading the
* code which used it. I just looked to see what uses
* the get_info field of proc_dir_entry struct (I used a
* combination of find and grep, if you're interested),
* and I saw that  it is used in <kernel source
* directory>/fs/proc/array.c.
*
* If something is unknown about the kernel, this is
* usually the way to go. In Linux we have the great
* advantage of having the kernel source code for
* free - use it.
*/
ssize_t
procfile_read(char *buffer,
              char **buffer_location,
              off_t offset, int buffer_length, int *eof, void *data)
{
        printk(KERN_INFO "inside /proc/test : procfile_read\n" );

        int len = 0;                /* The number of bytes actually used */
        static int count = 1;

        /* 
         * 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 %d : /proc/test : procfile_read, \
                       wrote %d Bytes\n", (int)(offset), len);
                *eof = 1;
                return len;
        }

        /* 
         * Fill the buffer and get its length 
         */
        len = sprintf(buffer,
                      "For the %d%s time, go away!\n", count,
                      (count % 100 > 10 && count % 100 < 14) ? "th" :
                      (count % 10 == 1) ? "st" :
                      (count % 10 == 2) ? "nd" :
                      (count % 10 == 3) ? "rd" : "th" );
        count++;

        /* 
         * Return the length 
         */
        printk(KERN_INFO
               "leaving /proc/test : procfile_read, wrote %d Bytes\n", len);
        return len;
}

int init_module()
{
        int rv = 0;
        Our_Proc_File = create_proc_entry("test", 0644, NULL);
        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 "Trying to create /proc/test:\n" );

        if (Our_Proc_File == NULL) {
                rv = -ENOMEM;
                remove_proc_entry("test", &proc_root);
                printk(KERN_INFO "Error: Could not initialize /proc/test\n" );
        } else {
                printk(KERN_INFO "Success!\n" );
        }

        return rv;
}

void cleanup_module()
{
        remove_proc_entry("test", &proc_root);
        printk(KERN_INFO "/proc/test removed\n" );
}
Notes
[1] 这是在2.0版本中的做法, 在版本2.2中,当我们把inode设为0时,就已经这样自动处理了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值