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

本文详细介绍了Linux内核配置参数的管理机制,包括sysctl的使用方式、数据结构和注册过程,以及如何通过sysctl系统调用进行内核配置参数的读取和写入。通过实例代码展示了如何注册和卸载sysctl条目,实现内核参数的动态调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

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 文件下发到内核。

卸载模块
这里写图片描述

可以看到模块被成功卸载了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值