【内核模块参数基础】

内核模块参数基础

  • 本文主要介绍内核开发中常用的模块传参手段,通过模块参数传递可以通过用户态来获取内核的一些信息,
    也可以通过用户态写入一些值来控制内核相关行为。一般内核开发者很喜欢使用模块传参来调试内核功能,
    如damon模块(数据访问监控器)。

常用的内核mod-api

1 module_param

modules_param
是最常规的传参方式,支持对普通数据类型的参数的读写。
name :表示模块参数名 (模块中定义和sysfs中显示的都是这个名字)
type:表示数据类型,如uint表示unsigned int
perm:sysfs文件中参数文件的访问权限 (一般8进制表示)
eg:
在这里插入图片描述
通过以下方式可以设置这个参数:
1)加载模块时
insmod module_param_test.ko param_uint=100
2)cmdline传递
cmdline中加入 module_param_test.param_uint=100 字段
3)通过写sysfs节点
echo 100 > /sys/module/module_param_test/parameters/param_uint
通过sysfs查看模块参数:
cat /sys/module/module_param_test/parameters/param_uint

2 module_param_array

在这里插入图片描述
name:表示数组名
type:数组元素类型
nump:一个整型变量,用于存储数组中元素的数量,可选(不关心可以写为NULL)
perm:sysfs文件中参数文件的权限 (一般8进制表示)
eg:
在这里插入图片描述
1)加载模块时传递
insmod module_param_test.ko param_array=1,2,3,4,4
2)通过cmdline传递
cmdline中加入 module_param_test.param_array=1,2,3,4,4 字段
3)通过写sysfs节点
echo 1,2,3,4,4 > /sys/module/module_param_test/parameters/param_array
通过sysfs查看模块参数:
cat /sys/module/module_param_test/parameters/param_array

3 module_param_cb

在这里插入图片描述
name :表示模块参数名 (模块中定义和sysfs中显示的都是这个名字)
ops:参数的 set&get 操作集
arg:用于操作集的参数 perm:sysfs文件中参数文件的权限 (一般8进制表示)
eg:
在这里插入图片描述
读写参数方式和上面介绍的类似,这里需要注意的是:当读参数param_int_cb时就会回调param_int_cb_show函数,写参数param_int_cb时就会回调param_int_cb_store,使得我们能有机会拦截参数来做一些操作。

4 module_param_named

在这里插入图片描述
name:表示参数的别名/重命名,会在sysfs中显示
value:表示参数名,在模块中定义的变量名
type:表示数据类型
perm:sysfs文件中参数文件的权限
eg:
在这里插入图片描述
读写参数方式和上面介绍的类似,这里需要注意的是:模块中定义为param_bool1这个变量名,但是sysfs中使用的是这个param_bool1_named别名。

注:都在include/linux/moduleparam.h文件中定义

2 内核参数数据类型

在这里插入图片描述
byte :表示字节大小,是无符号char类型 ,unsigned char
hexint:读的时候会显示16进制, 表示无符号的 int类型,即是 unsigned int
short:表示有符号的short类型,即是 short
ushort:表示无符号的short类型,即是 unsigned short
int:表示有符号的int类型,即是 int
uint:表示无符号的 int类型,即是 unsigned int
long:表示有符号的long类型,即是 long
ulong:表示无符号的long类型,即是 unsigned long
charp:char 指针类型,也就是字符串
bool:布尔类型
invbool:反布尔类型
此外还支持llong (long long)和ullong (unsigned long long)类型。

3 参数文件的访问权限

0 :无任何权限 ,在sysfs中不显示这个参数文件
0666: -rwxrwxrwx 即是用户、组、其他 都可读可写 会编译错误,权限比较高,禁止使用。权限0666意味着任何用户都可以读写该文件。在内核模块中,通常需要保护模块的参数不被恶意修改,以避免潜在的安全风险。
0444: -r–r–r-- -> 用户、组、其他都只读
0600:-rw------- 用户可读可写,组、其他无权限
0644:-rw-r–r-- 用户可读可写,组、其他只读
当然也可以使用形如S_IRUSR这样的表示方法。

4 示例代码


```c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

/********** case 1: base type **********/
/* bool eg: echo 0/1/n/y/N/Y  > param_bool*/
static bool param_bool;
//module_param(param_bool, bool, 0);//no permission, no file in sysfs
//module_param(param_bool, bool, 0666);//-rwxrwxrwx -> forbit
//module_param(param_bool, bool, 0644);//-rw-rw-rw-
module_param(param_bool, bool, 0600);
MODULE_PARM_DESC(param_bool, "This is a bool parameter!");

/* bool eg: echo 0/1/n/y/N/Y  > param_bool1_named */
static bool param_bool1;
module_param_named(param_bool1_named, param_bool1, bool, 0600);
MODULE_PARM_DESC(param_bool1_named, "This is a bool parameter!");

/* byte  eg:  echo 0-255 > param_char */
static unsigned char param_char;
module_param(param_char, byte, 0600);
MODULE_PARM_DESC(param_char, "This is a char parameter!");

/* short eg: echo -100 > param_short */
static short param_short;
module_param(param_short, short, 0600);
MODULE_PARM_DESC(param_short, "This is a short parameter!");

/* unsigned short eg: echo 100 > param_short */
static unsigned short param_ushort;
module_param(param_ushort, ushort, 0600);
MODULE_PARM_DESC(param_ushort, "This is a ushort parameter!");

/* int eg: echo -100 > param_int */
static int param_int;
module_param(param_int, int, 0600);
MODULE_PARM_DESC(param_int, "This is a int parameter!");

/* unsigned int eg: echo 100 > param_unint */
static unsigned int param_uint;
module_param(param_uint, uint, 0600);
MODULE_PARM_DESC(param_uint, "This is a uint parameter!");

/* long eg: echo -100 > param_long*/
static long param_long;
module_param(param_long, long, 0600);
MODULE_PARM_DESC(param_long, "This is a long parameter!");

/* unsigned long eg: echo 100 > param_ulong */
static unsigned long param_ulong;
module_param(param_ulong, ulong, 0600);
MODULE_PARM_DESC(param_ulong, "This is a ulong parameter!");

/* unsigned long long eg: echo 100 > param_ullong */
static unsigned long long param_ullong;
module_param(param_ullong, ullong, 0600);
MODULE_PARM_DESC(param_ullong, "This is a unsigned long long parameter!");

/* character pointer : eg: echo hello > param_charp */
static char *param_charp;
module_param(param_charp, charp, 0600);
MODULE_PARM_DESC(param_bool, "This is a charp parameter!");

/********** case 2: array **********/
/* array: echo "1,2,3,4,4" > param_array */
static int param_array[5];
static int array_num;
//module_param_array(param_char_array, int, NULL, 0600);
module_param_array(param_array, int, &array_num, 0600);
MODULE_PARM_DESC(param_bool, "This is a array parameter!");

/********** case 3: use call back **********/
static int param_int_cb;
int param_int_cb_store(const char *val, const struct kernel_param *kp)
{
        int value;
        int err;
        //把字符串转换为int类型
        err = kstrtoint(val, 0, &value);
        if (err)
                return err;
        if (value > 0)
                pr_info("value:%d\n", value);
        //将用户态传过来的参数值设置到模块参数中,由于这里是基础的int类型,所以可以直接调用param_set_int api
        //param_set_uint_minmax 这个api会在设置时考虑最小和最大值
        //return param_set_int(val, kp);
        return param_set_uint_minmax(val, kp, 0, 1000);
}

int param_int_cb_show(char *buffer, const struct kernel_param *kp)
{
        int value = *((int *)kp->arg);

        //用户态最终通过buffer来获得参数的信息,所以这里通过sprintf 做格式化操作写到buffer中
        if (value > 0)
                return sprintf(buffer, "value:%d > 0\n", value);
        else
                return sprintf(buffer, "value:%d <= 0\n", value);
}

static const struct kernel_param_ops param_int_cb_ops = {
        .set = param_int_cb_store,
        //.get = param_get_int, /* default */
        .get = param_int_cb_show,
};
module_param_cb(param_int_cb, &param_int_cb_ops, &param_int_cb, 0600);
MODULE_PARM_DESC(param_int_cb, "This is param_int_cb\n");


static int __init module_test_init(void)
{
        pr_emerg("module_test_init\n");
        return 0;
}

static void __exit module_test_exit(void)
{
        pr_emerg("module_test_exit\n");
}


module_init(module_test_init);
module_exit(module_test_exit);
MODULE_LICENSE("GPL");
参考:

include/linux/moduleparam.h
kernel/params.c
mm/damon/reclaim.c
https://mp.weixin.qq.com/s/yEkRgJIkgfLtmllifaPx4w

  • 25
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值