Linux param_parse模块参数解析与type_ops转换

发布时间:2026/6/14 12:25:08

Linux param_parse模块参数解析与type_ops转换 Linux param_parse模块参数解析与type_ops转换模块参数是Linux内核模块与用户空间交互的最基本接口通过module_param()宏定义参数后用户可以在insmod/modprobe时传递参数值或通过sysfs运行时修改。param_parse()函数是字符串参数值到内核变量类型转换的核心引擎。模块参数通过struct kernel_param定义struct kernel_param {const char *name;struct module *mod;const struct kernel_param_ops *ops;const u16 perm;s8 level;u8 flags;union {void *arg;const struct kparam_string *str;const struct kparam_array *arr;};};每种数据类型对应一组kernel_param_ops操作集定义类型转换逻辑struct kernel_param_ops {unsigned int flags;int (*set)(const char *val, const struct kernel_param *kp);int (*get)(char *buffer, const struct kernel_param *kp);void (*free)(void *arg);};内核为基本类型预定义了一系列param_ops_xxxstatic const struct kernel_param_ops param_ops_int {.flags KERNEL_PARAM_OPS_FL_NOARG,.set param_set_int,.get param_get_int,};module_param_cb(int, ¶m_ops_int, int_var, 0644);param_parse()位于kernel/params.c是从参数字符串到内核变量的转换入口int param_parse(const char *param, const char *val,const struct kernel_param *kp){const struct kernel_param_ops *ops kp-ops;int ret;if (!val !(ops-flags KERNEL_PARAM_OPS_FL_NOARG)) {pr_debug(%s: missing value\n, param);return -EINVAL;}if (!val (ops-flags KERNEL_PARAM_OPS_FL_NOARG)) {/* 布尔类型无值参数 */ret ops-set(val, kp);return ret;}if (val (ops-flags KERNEL_PARAM_OPS_FL_NOARG)) {/* 有值但类型不接受值 */return -EINVAL;}ret ops-set(val, kp);return ret;}param_set_int()的类型转换实现int param_set_int(const char *val, const struct kernel_param *kp){int l;if (!val)return -EINVAL;l simple_strtol(val, NULL, 0);if (l INT_MIN || l INT_MAX)return -EINVAL;/* 写入目标变量 */*(int *)kp-arg l;return 0;}对于更复杂的类型如int数组param_set_array()需要处理逗号分隔的多个值int param_set_array(const char *val, const struct kernel_param *kp){const struct kparam_array *arr kp-arr;unsigned int temp_num;int ret;if (!val) {/* 无值参数仅初始化数组 */arr-num 0;return 0;}/* 解析逗号分隔的数值 */while (val *val) {char *next;int num;next strchr(val, ,);if (next)*next \0;num simple_strtol(val, NULL, 0);/* 写入数组元素 */((int *)arr-elem)[arr-num] num;arr-num;if (next)val next 1;elsebreak;if (arr-num arr-max)return -ENOSPC;}return 0;}字符串类型的处理涉及内存分配param_set_charp()的实现int param_set_charp(const char *val, const struct kernel_param *kp){char *old, *new;if (!val)return -EINVAL;new kstrdup(val, GFP_KERNEL);if (!new)return -ENOMEM;old *(char **)kp-arg;*(char **)kp-arg new;/* 释放旧值 */if (old)kfree(old);return 0;}module_param_call()宏允许驱动程序注册自定义转换操作#define module_param_call(name, _set, _get, arg, perm)__module_param_call(MODULE_PARAM_PREFIX, name, _set, _get, arg, perm, -1, 0)内核通过parse_args()入口遍历所有参数其原型为char *parse_args(const char *doing,char *args,const struct kernel_param *params,unsigned num,s16 min_level,s16 max_level,void *arg,int (*unknown)(char *param, char *val,const char *doing, void *arg));parse_args()对输入字符串按空格或逗号分割对每个参数调用parse_one()parse_one()在参数表中查找匹配名称找到后调用param_parse()进行类型转换。参数解析的完整调用链路以模块加载场景为例init_module()- load_module()- parse_args(module, mod-args, mod-kp, mod-num_kp, ...)- parse_one()- param_parse()- ops-set()module_param()宏封装了大部分细节开发者只需声明变量的module_param即可。默认支持的ops类型包括byte, short, ushort, int, uint, long, ulong, charp, bool, invbool。在内核启动参数boot params场景下__setup()和early_param()使用独立的解析路径不经过param_parse()而是在start_kernel()早期通过parse_early_params()和parse_args(Booting kernel, ...)分别处理。

相关新闻