主题:《Linux内核模块编程指南》(四)
《Linux内核模块编程指南》
《Linux Kernel Module Programming Guide》
作者:Ori Pomerantz 中译者:谭志(lkmpg@21cn.com)
译者注:
1、LKMPG是一本免费的书,英文版的发行和修改遵从GPL version 2的许可。为了
节省时间,我只翻译了其中的大部分的大意,或者说这只是我学习中的一些中文
笔记吧,不能算是严格上的翻译,但我认为这已经足够了。本文也允许免费发布
,但发布前请和我联系,但不要把本文用于商业目的。鉴于本人的水平,文章中
难免有错误,请大家不吝指正。
2、本文中的例子在Linux(kernel version 2.2.10)上调试通过。你用的Linux必
须支持内核模块的加载,如果不支持,请在编译内核时选上内核模块的支持或升
级你的内核到一个支持内核模块的版本。
第四章 /proc文件系统
Linux有一个特别的机制来供内核和内核模块传输信息到用户进程,那就是/
proc文件系统。/proc文件系统本来是为易于访问进程的信息而设计的,也因此而
得名proc,现在大多用于内核显示一些系统信息,例如/proc/modules列出内核中
的模块,/proc/meminfo列出内存的使用统计等等。
使用/proc文件系统的方式和设备驱动程序的方式很相似:你需要有一个包含
了/proc文件所需的信息的结构体,包括函数指针(本章的例子仅为一个函数,这
个函数将会在尝试读/proc的文件时被调用)。init_module向内核注册这个结构而
cleanup_module则注销它。
我们使用proc_register_dynamic的原因(译者注:proc_register_dynamic可
能是早期版本提供的函数,这里用proc_register代替,proc_register可以动态
分配i节点号)是我们不需要知道我们所访问的文件的i节点号(inode number),但
要让内核知道i节点号(inode number)以防冲突。普通的文件系统是建立在磁盘上
的,而不是内存里(/proc是建立在内存里的),这种情况下,i节点号是一个指向
磁盘上文件的i节点的位置的一个指针。一个文件的i节点包含了这个文件的信息
,例如文件的权限和文件的数据在磁盘上的位置等等。
由于无须打开和关闭/proc的文件,所以我们的模块中没有使用两个宏定义:
MOD_INC_USE_COUNT和MOD_DEC_USE_COUNT。因此我们没有方法避免当打开/proc里
的文件时移去内核模块的做法。在下一章,我们会看到一个更难些的,但又更灵
活的可以避免这种问题的实现。
例子procfs.c
/* procfs.c - create a "file" in /proc
* Copyright (C) 1998 by Ori Pomerantz
* 版权所有 (C) 2000 by Kevin T.Z
*/
/* kevintz注:
* /usr/include/linux是指向/usr/src/linux/include/linux
* 的符号连接
*/
/* The necessary header files */
/* Standard in kernel modules */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif
/* Necessary because we use the proc fs */
#include <linux/proc_fs.h>
/* 把数据放到proc文件系统的文件里
参数
=========
1. 数据被插入的缓冲区,如果你要使用它的话。
2. 字符指针的指针。如果你不想使用内核分配的缓冲区的时候用。
3. 文件的当前位置。
4. 第一个参数缓冲区的大小。
5. 零,为以后保留
使用和返回值
======================
如果你用自己的缓冲区,就将缓冲区的位置放到第二个参数里。
缓冲区里将是结果,并返回结果的字节数。
返回值为零表示没有数据(end of file),负数表示出错。
*/
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;
/* 我们只给我们的信息一次给用户,如果调用了第二次,则返回0(EOF)
* 这很重要,因为标准的read调用等到EOF或它的缓冲区被填入数据
* 才返回 */
if (offset > 0)
return 0;
/* 生成信息并计算长度*/
len = sprintf(my_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++;
/* 保存信息的指针到buffer_localtion*/
*buffer_location = my_buffer;
/* Return the length */
return len;
}
struct proc_dir_entry Our_Proc_File =
{
0, /* Inode number - ignore, it will be filled by
* proc_register_dynamic */
4, /* Length of the file name */
"test", /* The file name */
S_IFREG | S_IRUGO,
/* File mode - this is a regular file which can
* be read by its owner, its group, and everybody*/
1, /* Number of links */
0, 0, /* The uid and gid - we give it to root */
80, /* The size of the file reported by ls. */
NULL,
/* functions which can be done on the inode*/
procfile_read,
/* The read function for this file, the function called
* when somebody tries to read something from it. */
NULL
/* We could have here a function to fill the file's inode, to
* enable us to play with permissions, ownership, etc. */
};
/* Initialize the module - register the proc file */
int init_module()
{
/* kevintz注:proc_root为全局的proc_dir_entry结构体*/
/*return proc_register_dynamic(&proc_root, &Our_Proc_File);*/
/*可能proc_register_dynamic是早期版本所提供的,
我这里找不到,用proc_register代替*/
return proc_register(&proc_root, &Our_Proc_File);
}
/* Cleanup - unregister our file from /proc */
void cleanup_module()
{
proc_unregister(&proc_root, Our_Proc_File.low_ino);
}
编译:
cc -D__KERNEL__ -DLINUX -DMODULE -DDEBUG -O6 -c procfs.c
测试:
当我们insmod procfs后,可以在/proc下看到文件test,用ls -l test可以
看到文件的属性。用cat /proc/test和vi /proc/test都可以读出文件的内容。不
过执行more /proc/test时显示Segmentation fault (core dumped),这应该是m
ore命令的问题。
我们现在设想一下cat /proc/test时发生了什么动作:cat打开文件/proc/t
est并开始读,引发了read系统调用,而/proc/test是proc文件系统的文件,所以
引发了proc文件系统的读动作,这个动作调用了get_info(看后面的结构)所指向
的函数,就是我们的procfile_read函数,proc文件系统把结果返回到用户进程(
cat),cat就显示出了信息。
下一章将给出一个可以读写的proc文件的例子。
译者注:
完整的proc_dir_entry结构体的定义是:
struct proc_dir_entry {
unsigned short low_ino;
unsigned short namelen;
const char *name;
mode_t mode;
nlink_t nlink;
uid_t uid;
gid_t gid;
unsigned long size;
struct inode_operations * ops;
int (*get_info)(char *, char **, off_t, int, int);
void (*fill_inode)(struct inode *, int);
struct proc_dir_entry *next, *parent, *subdir;
void *data;
int (*read_proc)(char *page, char **start, off_t off,
int count, int *eof, void *data);
int (*write_proc)(struct file *file, const char *buffer,
unsigned long count, void *data);
int (*readlink_proc)(struct proc_dir_entry *de, char *page);
unsigned int count; /* use count */
int deleted; /* delete flag */
};
get_info所指的函数是被/usr/src/linux/fs/proc/array.c中很多
实现proc文件系统的函数所调用,以生成给用户的信息。
发信人: kevintz() 整理人: kevintz(2000-06-24 00:40:46), 站内信件 |
《Linux Kernel Module Programming Guide》
作者:Ori Pomerantz 中译者:谭志(lkmpg@21cn.com)
译者注:
1、LKMPG是一本免费的书,英文版的发行和修改遵从GPL version 2的许可。为了
节省时间,我只翻译了其中的大部分的大意,或者说这只是我学习中的一些中文
笔记吧,不能算是严格上的翻译,但我认为这已经足够了。本文也允许免费发布
,但发布前请和我联系,但不要把本文用于商业目的。鉴于本人的水平,文章中
难免有错误,请大家不吝指正。
2、本文中的例子在Linux(kernel version 2.2.10)上调试通过。你用的Linux必
须支持内核模块的加载,如果不支持,请在编译内核时选上内核模块的支持或升
级你的内核到一个支持内核模块的版本。
第四章 /proc文件系统
Linux有一个特别的机制来供内核和内核模块传输信息到用户进程,那就是/
proc文件系统。/proc文件系统本来是为易于访问进程的信息而设计的,也因此而
得名proc,现在大多用于内核显示一些系统信息,例如/proc/modules列出内核中
的模块,/proc/meminfo列出内存的使用统计等等。
使用/proc文件系统的方式和设备驱动程序的方式很相似:你需要有一个包含
了/proc文件所需的信息的结构体,包括函数指针(本章的例子仅为一个函数,这
个函数将会在尝试读/proc的文件时被调用)。init_module向内核注册这个结构而
cleanup_module则注销它。
我们使用proc_register_dynamic的原因(译者注:proc_register_dynamic可
能是早期版本提供的函数,这里用proc_register代替,proc_register可以动态
分配i节点号)是我们不需要知道我们所访问的文件的i节点号(inode number),但
要让内核知道i节点号(inode number)以防冲突。普通的文件系统是建立在磁盘上
的,而不是内存里(/proc是建立在内存里的),这种情况下,i节点号是一个指向
磁盘上文件的i节点的位置的一个指针。一个文件的i节点包含了这个文件的信息
,例如文件的权限和文件的数据在磁盘上的位置等等。
由于无须打开和关闭/proc的文件,所以我们的模块中没有使用两个宏定义:
MOD_INC_USE_COUNT和MOD_DEC_USE_COUNT。因此我们没有方法避免当打开/proc里
的文件时移去内核模块的做法。在下一章,我们会看到一个更难些的,但又更灵
活的可以避免这种问题的实现。
例子procfs.c
/* procfs.c - create a "file" in /proc
* Copyright (C) 1998 by Ori Pomerantz
* 版权所有 (C) 2000 by Kevin T.Z
*/
/* kevintz注:
* /usr/include/linux是指向/usr/src/linux/include/linux
* 的符号连接
*/
/* The necessary header files */
/* Standard in kernel modules */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif
/* Necessary because we use the proc fs */
#include <linux/proc_fs.h>
/* 把数据放到proc文件系统的文件里
参数
=========
1. 数据被插入的缓冲区,如果你要使用它的话。
2. 字符指针的指针。如果你不想使用内核分配的缓冲区的时候用。
3. 文件的当前位置。
4. 第一个参数缓冲区的大小。
5. 零,为以后保留
使用和返回值
======================
如果你用自己的缓冲区,就将缓冲区的位置放到第二个参数里。
缓冲区里将是结果,并返回结果的字节数。
返回值为零表示没有数据(end of file),负数表示出错。
*/
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;
/* 我们只给我们的信息一次给用户,如果调用了第二次,则返回0(EOF)
* 这很重要,因为标准的read调用等到EOF或它的缓冲区被填入数据
* 才返回 */
if (offset > 0)
return 0;
/* 生成信息并计算长度*/
len = sprintf(my_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++;
/* 保存信息的指针到buffer_localtion*/
*buffer_location = my_buffer;
/* Return the length */
return len;
}
struct proc_dir_entry Our_Proc_File =
{
0, /* Inode number - ignore, it will be filled by
* proc_register_dynamic */
4, /* Length of the file name */
"test", /* The file name */
S_IFREG | S_IRUGO,
/* File mode - this is a regular file which can
* be read by its owner, its group, and everybody*/
1, /* Number of links */
0, 0, /* The uid and gid - we give it to root */
80, /* The size of the file reported by ls. */
NULL,
/* functions which can be done on the inode*/
procfile_read,
/* The read function for this file, the function called
* when somebody tries to read something from it. */
NULL
/* We could have here a function to fill the file's inode, to
* enable us to play with permissions, ownership, etc. */
};
/* Initialize the module - register the proc file */
int init_module()
{
/* kevintz注:proc_root为全局的proc_dir_entry结构体*/
/*return proc_register_dynamic(&proc_root, &Our_Proc_File);*/
/*可能proc_register_dynamic是早期版本所提供的,
我这里找不到,用proc_register代替*/
return proc_register(&proc_root, &Our_Proc_File);
}
/* Cleanup - unregister our file from /proc */
void cleanup_module()
{
proc_unregister(&proc_root, Our_Proc_File.low_ino);
}
编译:
cc -D__KERNEL__ -DLINUX -DMODULE -DDEBUG -O6 -c procfs.c
测试:
当我们insmod procfs后,可以在/proc下看到文件test,用ls -l test可以
看到文件的属性。用cat /proc/test和vi /proc/test都可以读出文件的内容。不
过执行more /proc/test时显示Segmentation fault (core dumped),这应该是m
ore命令的问题。
我们现在设想一下cat /proc/test时发生了什么动作:cat打开文件/proc/t
est并开始读,引发了read系统调用,而/proc/test是proc文件系统的文件,所以
引发了proc文件系统的读动作,这个动作调用了get_info(看后面的结构)所指向
的函数,就是我们的procfile_read函数,proc文件系统把结果返回到用户进程(
cat),cat就显示出了信息。
下一章将给出一个可以读写的proc文件的例子。
译者注:
完整的proc_dir_entry结构体的定义是:
struct proc_dir_entry {
unsigned short low_ino;
unsigned short namelen;
const char *name;
mode_t mode;
nlink_t nlink;
uid_t uid;
gid_t gid;
unsigned long size;
struct inode_operations * ops;
int (*get_info)(char *, char **, off_t, int, int);
void (*fill_inode)(struct inode *, int);
struct proc_dir_entry *next, *parent, *subdir;
void *data;
int (*read_proc)(char *page, char **start, off_t off,
int count, int *eof, void *data);
int (*write_proc)(struct file *file, const char *buffer,
unsigned long count, void *data);
int (*readlink_proc)(struct proc_dir_entry *de, char *page);
unsigned int count; /* use count */
int deleted; /* delete flag */
};
get_info所指的函数是被/usr/src/linux/fs/proc/array.c中很多
实现proc文件系统的函数所调用,以生成给用户的信息。