sysctl内核变量驱动实现分析

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

通常,内核的这些配置参数也出现在proc文件系统的/proc/sys目录下,用户应用可以直接通过这个目录下的文件来实现内核配置的读写操作。

使用 register_sysctl_table 方式注册实现内核数据交互,就不得不用提到struct ctl_table,下面来介绍一下这个结构体。

1. 结构体ctl_table

struct ctl_table
{
    const char *procname; /* 表示在proc/sys/下显示的文件名称 */
    void *data; /* 表示对应于内核中的变量名称 */
    int maxlen; /* 表示条目允许的最大长度 */
    umode_t mode; /* 条目在proc文件系统下的访问权限 */
    struct ctl_table *child;    /* Deprecated */
    proc_handler *proc_handler; /* 格式化回调函数,一般整型使用&proc_dointvec,字符串类型使用&proc_dostring */
    struct ctl_table_poll *poll;
    void *extra1; //额外作用,比如整型时用于表示允许的最大值和最小值
    void *extra2;
};

字段maxlen,它主要用于字符串内核变量,以便在对该条目设置时,对超过该最大长度的字符串截掉后面超长的部分.
字段proc_handler,表示回调函数,对于整型内核变量,应当设置为&proc_dointvec,而对于字符串内核变量,则设置为 &proc_dostring。

2.注册

struct ctl_table_header *register_sysctl_table(struct ctl_table *table)

3.卸载

void unregister_sysctl_table(struct ctl_table_header * header)

4.例子

可以参考kernel/sysctl.c里面的实现sched_boost文件的实现。

(1) 在ctl_table总表中定义自己

static struct ctl_table kern_table[] = { //kernel/sysctl.c
    ......
    {
        .procname    = "sched_boost",
        .data        = &sysctl_sched_boost, //相当于初始值,设置后也体现在这个值上
        .maxlen        = sizeof(unsigned int),
        .mode        = 0644,
        .proc_handler    = sched_boost_handler,
        .extra1         = &zero, //最小值指定为0
        .extra2        = &three,//最大值指定为3
    },
    ......
};

(2) 回调函数sysctl_sched_boost解析

/*参数write用来判断是否是写,为真比表示写,假表示读*/
int sched_boost_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
{
    int ret;
    unsigned int *data = (unsigned int *)table->data; /*此时还是原来的值,新值在buffer中,此时还是ASCII码*/
    unsigned int old_val;

    mutex_lock(&boost_mutex);

    old_val = *data;
    /*这个的存在,检测值的范围是否合法,将ASCII码转换为数值,
     *转换完之后的数据还存放在table->data里。
     *这里面还兼容做了对读取的处理逻辑。*/
    ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);

    if (ret || !write) /*如果失败了或是读取这里就返回了*/
        goto done;

    /*对写/proc/sys/kernel/sched_boost做的实际的动作*/
    if (verify_boost_params(old_val, *data)) {
        _sched_set_boost(old_val, *data);
    } else {
        *data = old_val;
        ret = -EINVAL;
    }

done:
    mutex_unlock(&boost_mutex);
    return ret;
}
原文地址:https://www.cnblogs.com/hellokitty2/p/13876055.html