Linux Kernel Procfs Guide
Chapter 1. Introduction
    /proc文件系统(procfs)在linux内核中是一个特殊的文件系统,是一个虚拟的文件系统,只存在于内存中
    注:proc/sys是sysctl文件,不属于procfs
Chapter 2. Managing procfs entries
    要使用procfs,需包含#include <linux/proc_fs.h>
    1.Creating a regular file
        struct proc_dir_entry* create_proc_entry(const char* name,mode_t mode, struct proc_dir_entry* parent);
            parent为NULL时,表示文件建立在/proc目录下,失败返回NULL
            create_proc_read_entry:创建并初始化一个procfs入口in one single call
    2. Creating a symlink        
        struct proc_dir_entry* proc_symlink(const char* name, struct proc_dir_entry* parent, const char* dest);
        在parent目录下创建一个从name到dest的符号链接,像:ln -s dest name
    3. Creating a device    
        struct proc_dir_entry* proc_mknod(const char* name, mode_t mode,struct proc_dir_entry* parent, kdev_t rdev);
        创建一个名为name设备文件,mode参数必须包含S_IFBLK或者S_IFCHR,像:mknod --mode=mode name rdev
    4. Creating a directory    
        struct proc_dir_entry* proc_mkdir(const char* name, struct proc_dir_entry* parent);
        在parent目录下创建名为name的目录
    5.Removing an entry
        void remove_proc_entry(const char* name, struct proc_dir_entry* parent);      
        从procfs中移除parent目录下的name入口。注意它不会递归移除
Chapter 3. Communicating with userland             
    procfs对文件的读写并不是直接的,而是通过call back函数来操作read_proc and/or write_proc
    在create_proc_entry函数返回一个proc_dir_entry* entry,然后设置
        entry->read_proc = read_proc_foo;
        entry->write_proc = write_proc_foo;
    1. Reading data    
        kernel向用户返回数据    
        int read_func(char* page, char** start, off_t off, int count,int* eof, void* data);
        从start处的off偏移处开始写最多count个字节的内容到page中。
    2. Writing data    
        用户写数据到kernel
        int write_func(struct file* file, const char* buffer, unsigned long count, void* data);
        从buffer中读count字节,buffer不存在于kernel memory空间,所以需要使用copy_from_user函数,file常NULL
    3.A single call back for many files    
        struct proc_dir_entry* entry;
        struct my_file_data *file_data;
        file_data = kmalloc(sizeof(struct my_file_data), GFP_KERNEL);
        entry->data = file_data;
        int foo_read_func(char *page, char **start, off_t off,
        int count, int *eof, void *data)
        {
        int len;
        if(data == file_data) {
        /* special case for this file */
        } else {
        /* normal processing */
        }
        return len;
        }
        在 remove_proc_entry是要free掉data
Chapter 4. Tips and tricks
    1. Convenience functions            
        struct proc_dir_entry* create_proc_read_entry(const char* name,mode_t mode, struct proc_dir_entry* parent, read_proc_t* read_proc, void* data);
        将只需要读操作的create_proc_entry简化掉了
    2. Modules
        struct proc_dir_entry* entry;
        entry->owner = THIS_MODULE;
        目前发现没有这个owner参数了,不用关注。
    3. Mode and ownership    
        设置模式和权限
        struct proc_dir_entry* entry;
        entry->mode = S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH;
        entry->uid = 0;
        entry->gid = 100;
Chapter 5. Example
    board (http://www.lart.tudelft.nl/), which is
* sponsored by the Mobile Multi-media Communications
* (http://www.mmc.tudelft.nl/) and Ubiquitous Communications
* (http://www.ubicom.tudelft.nl/) projects.
*
* The author can be reached at:
*
* Erik Mouw
* Information and Communication Theory Group
* Faculty of Information Technology and Systems
* Delft University of Technology
* P.O. Box 5031
* 2600 GA Delft
* The Netherlands
*
*
* This program is free software; you can redistribute
* it and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place,* Suite 330, Boston, MA 02111-1307 USA
*
*/
#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_VERSION "1.0"
#define MODULE_NAME "procfs_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 count,
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;
}
static int __init init_procfs_example(void)
{
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;
/* create jiffies using convenience function */
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 foo and bar files using same callback
* functions
*/
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 tty device */
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 symlink */
symlink = proc_symlink("jiffies_too", example_dir,
"jiffies");
if(symlink == NULL) {
rv = -ENOMEM;
goto no_symlink;
}
symlink->owner = THIS_MODULE;
/* everything OK */
printk(KERN_INFO "%s %s initialised\n",
MODULE_NAME, MODULE_VERSION);
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;
}
static void __exit cleanup_procfs_example(void)
{
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 %s removed\n",
MODULE_NAME, MODULE_VERSION);
}
module_init(init_procfs_example);
module_exit(cleanup_procfs_example);
MODULE_AUTHOR("Erik Mouw");
MODULE_DESCRIPTION("procfs examples");
EXPORT_NO_SYMBOLS;        
 
 
 
 
 
 
The Linux Kernel Module Programming Guide
Chapter 5. The /proc File System
    1. The /proc File System
        proc_register_dynamic防止kernel节点号冲突
        1.定义一个文件结构
            struct proc_dir_entry *OurProcFile;
        2.创建一个proc文件
            OurProcFile = create_proc_entry(PROCFS_NAME,0644,NULL);
        3.给proc文件结构赋值
            OurProcFile->read_proc = procfile_read;        //指定相应读函数
            OurProcFile->write_proc = procfile_write;    //指定相应写函数
            OurProcFile->mode = S_IFREG | S_IRUGO;
            OurProcFile->uid = 0;
            OurProcFile->gid = 0;
            OurProcFile->size = 37;
        初始化完成。    
    2. Read and Write a /proc File
        从用户空间到kernel空间数据传递使用copy_from_user or get_user,因为linux内存是分段的,不是一个独立的地址,每一个进程都有一个独立的地址空间。比如:A有0x1234,B也有0x1234;
        系统会自动处理kernel的访问和写。
        int procfile_read(char *buffer,char **buffer_location,off_t offset, int buffer_length, int *eof, void *data)
        {
            ........................
            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;
        }
        int procfile_write(struct file *file, const char *buffer, unsigned long count,void *data)
        {
            ...............
            if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) )  
            {
                return ?EFAULT;
            }
            return procfs_buffer_size;
        }
    3. Manage /proc file with standard filesystem
        两个结构体比较重要
        struct inode_operations    包含了struct file_operations指针
            static struct inode_operations Inode_Ops_4_Our_Proc_File =  
            {
                .permission = module_permission, /* check for permissions */
            };
            int init_module()
            {
                .............
                Our_Proc_File?>proc_iops = &Inode_Ops_4_Our_Proc_File;
                Our_Proc_File?>mode = S_IFREG | S_IRUGO | S_IWUSR;
                .............
            }
        static int module_permission(struct inode *inode, int op, struct nameidata *foo)
        {
            /*
            * We allow everybody to read from our module, but
            * only root (uid 0) may write to it
            */
            if (op == 4 || (op == 2 && current?>euid == 0))
            return 0;
            /*
            * If it's anything else, access is denied
            */
            return ?EACCES;
        }
    4. Manage /proc file with seq_file    
            使用seq_file库来管理proc
        头文件:#include <linux/seq_file.h> /* for seq_file */
        static struct seq_operations my_seq_ops = {
            .start = my_seq_start,
            .next = my_seq_next,
            .stop = my_seq_stop,
            .show = my_seq_show
            };
        static struct file_operations my_file_ops = {
            .owner = THIS_MODULE,
            .open = my_open,
            .read = seq_read,
            .llseek = seq_lseek,
            .release = seq_release
        };
        static int my_open(struct inode *inode, struct file *file)
        {
            return seq_open(file, &my_seq_ops);
        }
        static int my_seq_show(struct seq_file *s, void *v)
        {
            loff_t *spos = (loff_t *) v;
            seq_printf(s, "%Ld\n", *spos);
            return 0;
        }
        static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos)
        {
            unsigned long *tmp_v = (unsigned long *)v;
            (*tmp_v)++;
            (*pos)++;
            return NULL;
        }
        static void *my_seq_start(struct seq_file *s, loff_t *pos)
        {
            static unsigned long counter = 0;
            /* beginning a new sequence ? */
            if ( *pos == 0 )
            {
                /* yes => return a non null value to begin the sequence */
                return &counter;
            }
            else
            {
                /* no => it's the end of the sequence, return end to stop reading */
                *pos = 0;
                return NULL;
            }
        }
       

Logo

更多推荐