我们已经看过一个非常简单的 /proc 文件示例,其中我们只读取了该文件/proc/helloworld。 也可以写入 /proc 文件。 它的工作方式与读取相同,当写入 /proc 文件时,会调用一个函数。 但是与读取略有不同,数据来自用户,因此您必须将数据从用户空间导入到内核空间(使用copy_from_user或get_user)
原因是copy_from_user或get_userLinux 内存(在 Intel 架构上,在其他处理器上可能有所不同)是分段的。 这意味着指针本身并不引用内存中的唯一位置,而仅引用内存段中的位置,并且您需要知道它是哪个内存段才能使用它。 内核有一个内存段,每个进程也有一个。
进程可以访问的唯一内存段是它自己的,因此当编写作为进程运行的常规程序时,无需担心分段。 当您编写内核模块时,通常您想要访问内核内存段,这由系统自动处理。 但是,当需要在当前运行的进程和内核之间传递内存缓冲区的内容时,内核函数会接收指向进程段中内存缓冲区的指针。put_user和get_user宏允许您访问该内存。 这些函数仅处理一个字符,您可以使用copy_to_user和copy_from_user。 由于缓冲区(在读取或写入函数中)位于内核空间中,因此对于写入函数,您需要导入数据,因为它来自用户空间,但对于读取函数则不需要,因为数据已在内核空间中。
示例 5-2. procfs2.c
/** * procfs2.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 */ #include <asm/uaccess.h> /* for copy_from_user */ #define PROCFS_MAX_SIZE 1024 #define PROCFS_NAME "buffer1k" /** * This structure hold information about the /proc file * */ static struct proc_dir_entry *Our_Proc_File; /** * The buffer used to store character for this module * */ static char procfs_buffer[PROCFS_MAX_SIZE]; /** * The size of the buffer * */ static unsigned long procfs_buffer_size = 0; /** * This function is called then the /proc file is read * */ int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data) { int ret; printk(KERN_INFO "procfile_read (/proc/%s) called\n", PROCFS_NAME); if (offset > 0) { /* we have finished to read, return 0 */ ret = 0; } else { /* fill the buffer, return the buffer size */ memcpy(buffer, procfs_buffer, procfs_buffer_size); ret = procfs_buffer_size; } return ret; } /** * This function is called with the /proc file is written * */ int procfile_write(struct file *file, const char *buffer, unsigned long count, void *data) { /* get buffer size */ procfs_buffer_size = count; if (procfs_buffer_size > PROCFS_MAX_SIZE ) { procfs_buffer_size = PROCFS_MAX_SIZE; } /* write data to the buffer */ if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) { return -EFAULT; } return procfs_buffer_size; } /** *This function is called when the module is loaded * */ int init_module() { /* create the /proc file */ Our_Proc_File = create_proc_entry(PROCFS_NAME, 0644, NULL); if (Our_Proc_File == NULL) { remove_proc_entry(PROCFS_NAME, &proc_root); printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", PROCFS_NAME); return -ENOMEM; } Our_Proc_File->read_proc = procfile_read; Our_Proc_File->write_proc = procfile_write; 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 "/proc/%s created\n", PROCFS_NAME); return 0; /* everything is ok */ } /** *This function is called when the module is unloaded * */ void cleanup_module() { remove_proc_entry(PROCFS_NAME, &proc_root); printk(KERN_INFO "/proc/%s removed\n", PROCFS_NAME); } |