|
Posted on 2008-02-10 18:53 ZelluX 阅读(907) 评论(0) 编辑 收藏 所属分类: Linux 、 System
/proc文件系统不是直接从内核的存储区中读写数据,二是通过回调函数实现文件读写的。struct proc_dir_entry有一对读写操作函数指针read_proc_t, write_proc_t。
一个编写内核模块操作proc文件系统的例子,书上的源程序是在2.4.18下跑起来的,改了三个地方在2.6.23下成功运行。当然Makefile也按照2.6中make modules的方式写了。
1. 去掉MODULE_VERSION宏的定义,和头文件冲突。
2. 去掉MOD_INC_USE_COUNT和MOD_DEC_USE_COUNT,2.6中的改变
Preventing premature unloading
In 2.4 modules, the MOD_INC_USE_COUNT macro is used to prevent unloading of the module while there is an open file. The 2.6 kernel, however, knows not to unload a module that owns a character device that's currently open.
However, this requires that the module be explicit in specifying ownership of character devices, using the THIS_MODULE macro. You also have to take out all calls to MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT .
The 2.6 kernel considers modules that use the deprecated facility to be unsafe, and does not permit their unloading, even with rmmod -f .
3. 去掉proc_mknod增加一个tty设备文件那部分代码,2.6中去掉了这个函数,貌似要用udev代替,以后再看了。
修改后代码:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#define MODULE_NAME "proc_example"
#define FOOBAR_LEN 8
struct fb_data_t {
char name[FOOBAR_LEN + 1];
char value[FOOBAR_LEN + 1];
};
static struct proc_dir_entry *example_dir, *foo_file,
*bar_file, *jiffies_file, *tty_device, *symlink;
struct fb_data_t foo_data, bar_data;
static int proc_read_jiffies(char *page, char **start,
off_t off, int count, int *eof, void *data)
{
int len;
// MOD_INC_USE_COUNT;
len = sprintf(page, "jiffies = %ld\n", jiffies);
// MOD_DEC_USE_COUNT;
return len;
}
static int proc_read_foobar(char *page, char **start,
off_t off, int ocunt, int *eof, void *data)
{
int len;
struct fb_data_t *fb_data = (struct fb_data_t *) data;
// MOD_INC_USE_COUNT;
len = sprintf(page, "%s = '%s'\n", fb_data->name, fb_data->value);
// MOD_DEC_USE_COUNT;
return len;
}
static int proc_write_foobar(struct file *file, const char *buffer,
unsigned long count, void *data)
{
int len;
struct fb_data_t *fb_data = (struct fb_data_t *) data;
// MOD_INC_USE_COUNT;
if (count > FOOBAR_LEN)
len = FOOBAR_LEN;
else
len = count;
if (copy_from_user(fb_data->value, buffer, len)) {
// MOD_DEC_USE_COUNT;
return -EFAULT;
}
fb_data->value[len] = '\0';
// MOD_DEC_USE_COUNT;
return len;
}
int init_module()
{
int rv = 0;
/**//* Create directory */
example_dir = proc_mkdir(MODULE_NAME, NULL);
if (example_dir == NULL) {
rv = -ENOMEM;
goto out;
}
example_dir->owner = THIS_MODULE;
jiffies_file = create_proc_read_entry("jiffies", 0444,
example_dir, proc_read_jiffies, NULL);
if (jiffies_file == NULL) {
rv = -ENOMEM;
goto no_jiffies;
}
jiffies_file->owner = THIS_MODULE;
/**//* Create regular files foo and bar */
foo_file = create_proc_entry("foo", 0644, example_dir);
if (foo_file == NULL) {
rv = -ENOMEM;
goto no_foo;
}
strcpy(foo_data.name, "foo");
strcpy(foo_data.value, "foo");
foo_file->data = &foo_data;
foo_file->read_proc = proc_read_foobar;
foo_file->write_proc = proc_write_foobar;
foo_file->owner = THIS_MODULE;
bar_file = create_proc_entry("bar", 0644, example_dir);
if (bar_file == NULL) {
rv = -ENOMEM;
goto no_bar;
}
strcpy(bar_data.name, "bar");
strcpy(bar_data.value, "bar");
bar_file->data = &bar_data;
bar_file->read_proc = proc_read_foobar;
bar_file->write_proc = proc_write_foobar;
bar_file->owner = THIS_MODULE;
/**//* Create device file tty */
// tty_device = proc_mknod("tty", S_IFCHR | 0666, example_dir, MKDEV(5,0));
// if (tty_device == NULL) {
// rv = -ENOMEM;
// goto no_tty;
// }
//
// tty_device->owner = THIS_MODULE;
/**//* Create linkage file jiffies_too */
symlink = proc_symlink("jiffies_too", example_dir, "jiffies");
if (symlink == NULL) {
rv = -ENOMEM;
goto no_symlink;
}
symlink->owner = THIS_MODULE;
printk(KERN_INFO "%s 1.0 initialized\n", MODULE_NAME);
return 0;
no_symlink:
remove_proc_entry("tty", example_dir);
// no_tty:
// remove_proc_entry("bar", example_dir);
no_bar:
remove_proc_entry("foo", example_dir);
no_foo:
remove_proc_entry("jiffies", example_dir);
no_jiffies:
remove_proc_entry("MODULE_NAME", NULL);
out:
return rv;
}
void cleanup_module()
{
remove_proc_entry("jiffies_too", example_dir);
// remove_proc_entry("tty", example_dir);
remove_proc_entry("bar", example_dir);
remove_proc_entry("foo", example_dir);
remove_proc_entry("jiffies", example_dir);
remove_proc_entry(MODULE_NAME, NULL);
printk(KERN_INFO "%s 1.0 removed\n", MODULE_NAME);
}
MODULE_DESCRIPTION("proc examples");
EXPORT_NO_SYMBOLS;
|