register_sysctl_table实现内核数据交互

作者:Younger Liu,

本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。 

       Sysctl是一种用户应用来设置和获得运行时内核的配置参数的一种有效方式,通过这种方式,用户应用可以在内核运行的任何时刻来改变内核的配置参数,也可以在任何时候获得内核的配置参数。

通常,内核的这些配置参数也出现在proc文件系统的/proc/sys
目录下,用户应用可以直接通过这个目录下的文件来实现内核配置的读写操作。
使用register_sysctl_table方式实现内核数据交互,就不得不用提到struct ctl_table
。下面来介绍一下这个结构体。
1 结构体ctl_table
每一个sysctl条目对应一个 struct ctl_table 结构,在该结构体定义在文件./include/
linux/sysctl.h中,定义及解释如下:
/* A sysctl table is an array of struct ctl_table: */
struct ctl_table
{
    const char *procname; /* Text ID for /proc/sys, or zero */
    void *data;
    int maxlen;
    mode_t mode;
    struct ctl_table *child;
    struct ctl_table *parent; /* Automatically set */
    proc_handler *proc_handler; /* Callback for text         formatting */
    void *extra1;
    void *extra2;
};
 
成员变量解释:
const char *procname; /* 表示在proc/sys/下显示的文件名称 */
void *data;           /* 表示对应于内核中的变量名称    */
int maxlen;           /* 表示条目允许的最大长度         */
mode_t mode;             /* 条目在proc文件系统下的访问权限 */
struct ctl_table *child;
struct ctl_table *parent; /* Automatically set */
proc_handler *proc_handler; /*回调函数&proc_dointvec/&proc_dostring */
void *extra1;
void *extra2;

字段maxlen,它主要用于字符串内核变量,以便在对该条目设置时,对超过该最大长度的字符串截掉后面超长的部分.

字段proc_handler,表示回调函数,对于整型内核变量,应当设置为&proc_dointvec,而对于字符串内核变量,则设置为 &proc_dostring。

 

Sysctl 条目也可以是目录,此时 mode 字段应当设置为 0555,否则通过 sysctl 系统调用将无法访问它下面的 sysctl 条目,child 则指向该目录条目下面的所有条目,对于在同一目录下的多个条目,不必一一注册,用户可以把它们组织成一个 struct ctl_table 类型的数组,然后一次注册就可以。

2 注册register_sysctl_table
注册sysctl条目使用函数register_sysctl_table,函数原型如下:
struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
第一个参数为定义的struct ctl_table结构的sysctl条目或条目数组指针;
 
3 卸载unregister_sysctl_table
当模块卸载时,需要使用函数unregister_sysctl_table,其原型:
void unregister_sysctl_table(struct ctl_table_header * header)
其中struct ctl_table_header是通过函数register_sysctl_table
注册时返回的结构体指针。
 
4 实例
 
/**********************************************
  * Author: lewiyon@hotmail.com
  * File name: sysctl_example.c
  * Description: sysctl example
  * Date: 2013-04-24
  *********************************************/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sysctl.h>

static int sysctl_kernusr_data = 1024;

static int kernusr_callback(ctl_table *table, int write,
        void __user *buffer, size_t *lenp, loff_t *ppos)
{
    int rc;
    int *data = table->data;

    printk(KERN_INFO "original value = %d\n", *data);

    rc = proc_dointvec(table, write, buffer, lenp, ppos);
    if (write)
        printk(KERN_INFO "this is write operation, current value = %d\n", *
data);

    return rc;
}

static struct ctl_table kernusr_ctl_table[] = {
    {
        .procname       = "kernusr",
        .data           = &sysctl_kernusr_data,
        .maxlen         = sizeof(int),
        .mode           = 0644,
        .proc_handler   = kernusr_callback,
    },
    {
        /* sentinel */
    },
};

static struct ctl_table_header *sysctl_header;

static int __init sysctl_example_init(void)
{
    sysctl_header = register_sysctl_table(kernusr_ctl_table);
    if (sysctl_header == NULL) {
        printk(KERN_INFO "ERR: register_sysctl_table!");
        return -1;
    }

    printk(KERN_INFO "sysctl register success.\n");
    return 0;

}

static void __exit sysctl_example_exit(void)
{
    unregister_sysctl_table(sysctl_header);
    printk(KERN_INFO "sysctl unregister success.\n");
}

module_init(sysctl_example_init);
module_exit(sysctl_example_exit);
MODULE_LICENSE("GPL");
5 参考文献
http://www.ibm.com/developerworks/cn/linux/l-kerns-usrs/
http://blog.chinaunix.net/uid-7210505-id-146429.html
 

posted on 2013-09-05 22:17  YoungerChina  阅读(3222)  评论(0编辑  收藏  举报

导航