您的位置:首页 > 其它

用户空间与内核空间通讯接口之sysctl

2015-06-28 13:11 295 查看

概述

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

通常,内核的这些配置参数也出现在proc文件系统的/proc/sys

目录下,用户应用可以直接通过这个目录下的文件来实现内核配置的读写操作。使用register_sysctl_table方式实现内核数据交互。

数据结构

/* A sysctl table is an array of struct ctl_table: */
struct ctl_table
{
int ctl_name;           /* Binary ID */
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 */
ctl_handler *strategy;      /* Callback function for all r/w */
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 * /

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

字段proc_handler,表示回调函数

对于整型内核变量,应当设置为&proc_dointvec

而对于字符串内核变量,则设置为 &proc_dostring。

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

注册register_sysctl_table

注册sysctl条目使用函数register_sysctl_table,函数原型如下:

struct ctl_table_header *register_sysctl_table(struct ctl_table *table)

第一个参数为定义的struct ctl_table结构的sysctl条目或条目数组指针;

卸载unregister_sysctl_table

当模块卸载时,需要使用函数unregister_sysctl_table,其原型:

void unregister_sysctl_table(struct ctl_table_header * header)

其中struct ctl_table_header是通过函数register_sysctl_table

注册时返回的结构体指针。

事例代码

#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");


编译成ko然后装载到内核

insmod ktest.ko



成功注册到/proc文件系统。



改变kernusr的值,然后查看修改是否成功



可以看到修改的值通过proc 文件下发到内核。

卸载模块



可以看到模块被成功卸载了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: