内核参数更改信号
Signal on Kernel parameter change
我想在内核 (3.x) 模块中使用参数:
static char param = 0xff;
module_param(param, ushort, S_IRUGO | S_IWUGO);
MODULE_PARM_DESC(param, "a parameter");
是否有可能检测到此参数的变化?是否有可用于调用服务例程的信号?
此致
亚历克斯
module_param(name,type,perm)
的附加信息:
type
的可能值:
bool
invbool
charp
int
long
short
uint
ulong
ushort
在 linux/stat.h
处为 perm
定义
#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
这里是一个完整的代码示例:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alex");
MODULE_DESCRIPTION("test module.");
MODULE_VERSION("0.1");
static int param = 1;
module_param(param, int, S_IRUGO|S_IWUGO);
static int __init mod_init(void){
printk(KERN_INFO "param %d\n", param);
return 0;
}
static void __exit mod_exit(void){
printk(KERN_INFO "Goodbye!\n");
}
module_init(mod_init);
module_exit(mod_exit);
编译器returns这个错误我不明白为什么:
make -C /lib/modules/3.19.0-47-generic/build/ M=/tmp/gt modules
make[1]: change to »/usr/src/linux-headers-3.19.0-47-generic«
CC [M] /tmp/gt/ebb.o
In file included from include/linux/thread_info.h:11:0,
from ./arch/x86/include/asm/preempt.h:6,
from include/linux/preempt.h:18,
from include/linux/spinlock.h:50,
from include/linux/seqlock.h:35,
from include/linux/time.h:5,
from include/linux/stat.h:18,
from include/linux/module.h:10,
from /tmp/gt/ebb.c:2:
include/linux/bug.h:33:45: error: negative width in bit-field ‘<anonymous>’
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
^
include/linux/kernel.h:830:3: note: in expansion of macro ‘BUILD_BUG_ON_ZERO’
BUILD_BUG_ON_ZERO((perms) & 2) + \
^
include/linux/moduleparam.h:223:31: note: in expansion of macro ‘VERIFY_OCTAL_PERMISSIONS’
= { __param_str_##name, ops, VERIFY_OCTAL_PERMISSIONS(perm), \
^
include/linux/moduleparam.h:166:2: note: in expansion of macro ‘__module_param_call’
__module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, 0)
^
include/linux/moduleparam.h:146:2: note: in expansion of macro ‘module_param_cb’
module_param_cb(name, ¶m_ops_##type, &value, perm); \
^
include/linux/moduleparam.h:125:2: note: in expansion of macro ‘module_param_named’
module_param_named(name, name, type, perm)
^
/tmp/gt/ebb.c:11:1: note: in expansion of macro ‘module_param’
module_param(param, int, S_IRUGO|S_IWUGO);
^
make[2]: *** [/tmp/gt/ebb.o] Fehler 1
make[1]: *** [_module_/tmp/gt] Fehler 2
make[1]: leaving »/usr/src/linux-headers-3.19.0-47-generic«
make: *** [all] Fehler 2
这里是 Makefile
obj-m+=ebb.o
all:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
关于@Tsyvarev
的回答
写入权限只允许root。所以这里的变化:
module_param(param, int, S_IRUGO|S_IWUSR);
现在你可以在/sys/module//parameters/下找到参数,你可以这样修改参数:
sudo echo 2 > /sys/module/ebb/parameters/param
关于@Tsyvarev 的下一步
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alex");
MODULE_DESCRIPTION("test module.");
MODULE_VERSION("0.1");
// int (*set)(const char *val, const struct kernel_param *kp);
// int (*get)(char *buffer, const struct kernel_param *kp);
int my_param_set_ushort(const char *val, const struct kernel_param *kp)
{
unsigned short* pvalue = kp->arg; // Pointer to actual parameter variable.
int res = param_set_ushort(val, kp); // Use helper for write variable
printk(KERN_INFO "setter talks\n");
if( res==0 )
{
// Here you may execute additional actions when you write parameter.
printk(KERN_INFO "set param %d\n", *pvalue);
}
return res;
}
const struct kernel_param_ops my_param_ops_ushort =
{
.set = &my_param_set_ushort, // Use our setter ...
.get = ¶m_get_ushort, // .. and standard getter
};
unsigned short param = 0xff;
module_param_cb(param, /*filename*/
&my_param_ops_ushort, /*operations*/
¶m, /* pointer to variable, contained parameter's value */
S_IRUGO | S_IWUSR /*permissions on file*/
);
static int __init mod_init(void){
printk(KERN_INFO "param %d\n", param);
return 0;
}
static void __exit mod_exit(void){
printk(KERN_INFO "Goodbye! (%d)\n",param);
}
module_init(mod_init);
module_exit(mod_exit);
作为 root 我给出了这个命令:
# insmod par.ko
# echo 146 > /sys/module/par/parameters/param
# rmmod par
和内核日志 /var/log/kernel.log 说:
Jan 23 14:27:37 alex-XMG kernel: [ 8332.492912] param 255
Jan 23 14:27:39 alex-XMG kernel: [ 8334.520044] setter talks
Jan 23 14:27:39 alex-XMG kernel: [ 8334.520052] set param 146
Jan 23 14:27:40 alex-XMG kernel: [ 8335.804338] Goodbye! (146)
工作起来很有魅力!
如果您使模块参数可写,则可以通过 sysfs 更改该参数。加载后,在 /sys 下找到您的模块,然后找到模块参数并验证它是否可写(通过 root)。尝试写入它,看看它是否有变化。
有几种方法可以检测此变量的变化。您可以使用内核线程作为一种机制。
更好的方法可能是使用 sysfs 或 procfs 条目。那些有 read/write 处理程序,在读取和写入时调用。
查看此处 sysfs
-tutorial
创建内核模块参数的通用方法是使用宏 module_param_cb:
/**
* module_param_cb - general callback for a module/cmdline parameter
* @name: a valid C identifier which is the parameter name.
* @ops: the set & get operations for this parameter.
* @perm: visibility in sysfs.
*
* The ops can have NULL set or get functions.
*/
#define module_param_cb(name, ops, arg, perm)
参数 ops
是指向结构 struct kernel_param_ops
的指针,其中包含给定参数的 操作 。写入和读取参数时调用的函数已遵循此结构中的定义:
int (*set)(const char *val, const struct kernel_param *kp);
int (*get)(char *buffer, const struct kernel_param *kp);
这里char*
参数是一个NULL-terminated字符串,是to/read从sysfs文件中写入的,表示给定参数。 kp
是指向参数描述符的指针,其中最感兴趣的字段是 .arg
:它是宏 module_param_cb
调用的第三个参数。使用这个字段,setter和getter可以实现模块参数的per-type,即模块有5个int
参数不需要为每个人写 setters 和 getters。
此外,标准参数类型的getters和setters已经实现,当你调用module_param
宏时,它们就会被实际使用。因此,如果您想 添加 参数的 setter 一些功能,您可以重用现有的助手:
int my_param_set_ushort(const char *val, const struct kernel_param *kp)
{
unsigned short* pvalue = kp->arg; // Pointer to actual parameter variable.
int res = param_set_ushort(val, kp); // Use helper for write variable
if(!res)
{
// Here you may execute additional actions when you write parameter.
printk(KERN_INFO "set param %d\n", *pvalue);
}
return res;
}
const struct kernel_param_ops my_param_ops_ushort =
{
.set = &my_param_set_ushort, // Use our setter ...
.get = ¶m_get_ushort, // .. and standard getter
};
// Usage
unsigned short param = 0xff;
module_param_cb(param, /*filename*/
&my_param_ops_ushort, /*operations*/
¶m, /* pointer to variable, contained parameter's value */
S_IRUGO | S_IWUSR /*permissions on file*/
);
出于安全原因,non-priveledged 用户通常可以写入模块参数。以及创建模块参数的内核宏,检查一下。这就是为什么您的模块参数定义中存在神秘错误的原因。请注意,在上面的示例中,使用 S_IWUSR
而不是 S_IWUGO
。
我想在内核 (3.x) 模块中使用参数:
static char param = 0xff;
module_param(param, ushort, S_IRUGO | S_IWUGO);
MODULE_PARM_DESC(param, "a parameter");
是否有可能检测到此参数的变化?是否有可用于调用服务例程的信号?
此致 亚历克斯
module_param(name,type,perm)
的附加信息:
type
的可能值:
bool
invbool
charp
int
long
short
uint
ulong
ushort
在 linux/stat.h
处为perm
定义
#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
这里是一个完整的代码示例:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alex");
MODULE_DESCRIPTION("test module.");
MODULE_VERSION("0.1");
static int param = 1;
module_param(param, int, S_IRUGO|S_IWUGO);
static int __init mod_init(void){
printk(KERN_INFO "param %d\n", param);
return 0;
}
static void __exit mod_exit(void){
printk(KERN_INFO "Goodbye!\n");
}
module_init(mod_init);
module_exit(mod_exit);
编译器returns这个错误我不明白为什么:
make -C /lib/modules/3.19.0-47-generic/build/ M=/tmp/gt modules
make[1]: change to »/usr/src/linux-headers-3.19.0-47-generic«
CC [M] /tmp/gt/ebb.o
In file included from include/linux/thread_info.h:11:0,
from ./arch/x86/include/asm/preempt.h:6,
from include/linux/preempt.h:18,
from include/linux/spinlock.h:50,
from include/linux/seqlock.h:35,
from include/linux/time.h:5,
from include/linux/stat.h:18,
from include/linux/module.h:10,
from /tmp/gt/ebb.c:2:
include/linux/bug.h:33:45: error: negative width in bit-field ‘<anonymous>’
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
^
include/linux/kernel.h:830:3: note: in expansion of macro ‘BUILD_BUG_ON_ZERO’
BUILD_BUG_ON_ZERO((perms) & 2) + \
^
include/linux/moduleparam.h:223:31: note: in expansion of macro ‘VERIFY_OCTAL_PERMISSIONS’
= { __param_str_##name, ops, VERIFY_OCTAL_PERMISSIONS(perm), \
^
include/linux/moduleparam.h:166:2: note: in expansion of macro ‘__module_param_call’
__module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, 0)
^
include/linux/moduleparam.h:146:2: note: in expansion of macro ‘module_param_cb’
module_param_cb(name, ¶m_ops_##type, &value, perm); \
^
include/linux/moduleparam.h:125:2: note: in expansion of macro ‘module_param_named’
module_param_named(name, name, type, perm)
^
/tmp/gt/ebb.c:11:1: note: in expansion of macro ‘module_param’
module_param(param, int, S_IRUGO|S_IWUGO);
^
make[2]: *** [/tmp/gt/ebb.o] Fehler 1
make[1]: *** [_module_/tmp/gt] Fehler 2
make[1]: leaving »/usr/src/linux-headers-3.19.0-47-generic«
make: *** [all] Fehler 2
这里是 Makefile
obj-m+=ebb.o
all:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
关于@Tsyvarev
的回答写入权限只允许root。所以这里的变化:
module_param(param, int, S_IRUGO|S_IWUSR);
现在你可以在/sys/module//parameters/下找到参数,你可以这样修改参数:
sudo echo 2 > /sys/module/ebb/parameters/param
关于@Tsyvarev 的下一步
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alex");
MODULE_DESCRIPTION("test module.");
MODULE_VERSION("0.1");
// int (*set)(const char *val, const struct kernel_param *kp);
// int (*get)(char *buffer, const struct kernel_param *kp);
int my_param_set_ushort(const char *val, const struct kernel_param *kp)
{
unsigned short* pvalue = kp->arg; // Pointer to actual parameter variable.
int res = param_set_ushort(val, kp); // Use helper for write variable
printk(KERN_INFO "setter talks\n");
if( res==0 )
{
// Here you may execute additional actions when you write parameter.
printk(KERN_INFO "set param %d\n", *pvalue);
}
return res;
}
const struct kernel_param_ops my_param_ops_ushort =
{
.set = &my_param_set_ushort, // Use our setter ...
.get = ¶m_get_ushort, // .. and standard getter
};
unsigned short param = 0xff;
module_param_cb(param, /*filename*/
&my_param_ops_ushort, /*operations*/
¶m, /* pointer to variable, contained parameter's value */
S_IRUGO | S_IWUSR /*permissions on file*/
);
static int __init mod_init(void){
printk(KERN_INFO "param %d\n", param);
return 0;
}
static void __exit mod_exit(void){
printk(KERN_INFO "Goodbye! (%d)\n",param);
}
module_init(mod_init);
module_exit(mod_exit);
作为 root 我给出了这个命令:
# insmod par.ko
# echo 146 > /sys/module/par/parameters/param
# rmmod par
和内核日志 /var/log/kernel.log 说:
Jan 23 14:27:37 alex-XMG kernel: [ 8332.492912] param 255
Jan 23 14:27:39 alex-XMG kernel: [ 8334.520044] setter talks
Jan 23 14:27:39 alex-XMG kernel: [ 8334.520052] set param 146
Jan 23 14:27:40 alex-XMG kernel: [ 8335.804338] Goodbye! (146)
工作起来很有魅力!
如果您使模块参数可写,则可以通过 sysfs 更改该参数。加载后,在 /sys 下找到您的模块,然后找到模块参数并验证它是否可写(通过 root)。尝试写入它,看看它是否有变化。
有几种方法可以检测此变量的变化。您可以使用内核线程作为一种机制。
更好的方法可能是使用 sysfs 或 procfs 条目。那些有 read/write 处理程序,在读取和写入时调用。
查看此处 sysfs
-tutorial
创建内核模块参数的通用方法是使用宏 module_param_cb:
/**
* module_param_cb - general callback for a module/cmdline parameter
* @name: a valid C identifier which is the parameter name.
* @ops: the set & get operations for this parameter.
* @perm: visibility in sysfs.
*
* The ops can have NULL set or get functions.
*/
#define module_param_cb(name, ops, arg, perm)
参数 ops
是指向结构 struct kernel_param_ops
的指针,其中包含给定参数的 操作 。写入和读取参数时调用的函数已遵循此结构中的定义:
int (*set)(const char *val, const struct kernel_param *kp);
int (*get)(char *buffer, const struct kernel_param *kp);
这里char*
参数是一个NULL-terminated字符串,是to/read从sysfs文件中写入的,表示给定参数。 kp
是指向参数描述符的指针,其中最感兴趣的字段是 .arg
:它是宏 module_param_cb
调用的第三个参数。使用这个字段,setter和getter可以实现模块参数的per-type,即模块有5个int
参数不需要为每个人写 setters 和 getters。
此外,标准参数类型的getters和setters已经实现,当你调用module_param
宏时,它们就会被实际使用。因此,如果您想 添加 参数的 setter 一些功能,您可以重用现有的助手:
int my_param_set_ushort(const char *val, const struct kernel_param *kp)
{
unsigned short* pvalue = kp->arg; // Pointer to actual parameter variable.
int res = param_set_ushort(val, kp); // Use helper for write variable
if(!res)
{
// Here you may execute additional actions when you write parameter.
printk(KERN_INFO "set param %d\n", *pvalue);
}
return res;
}
const struct kernel_param_ops my_param_ops_ushort =
{
.set = &my_param_set_ushort, // Use our setter ...
.get = ¶m_get_ushort, // .. and standard getter
};
// Usage
unsigned short param = 0xff;
module_param_cb(param, /*filename*/
&my_param_ops_ushort, /*operations*/
¶m, /* pointer to variable, contained parameter's value */
S_IRUGO | S_IWUSR /*permissions on file*/
);
出于安全原因,non-priveledged 用户通常可以写入模块参数。以及创建模块参数的内核宏,检查一下。这就是为什么您的模块参数定义中存在神秘错误的原因。请注意,在上面的示例中,使用 S_IWUSR
而不是 S_IWUGO
。