您的位置:首页 > 运维架构 > Linux

Linux procfs开发指南(部分翻译并做了精简)

2012-10-21 21:26 597 查看
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;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: