内核参数变化信号

时间:2016-01-22 22:28:19

标签: c linux-kernel kernel kernel-module

我想在内核(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);

编译器返回此错误我不明白为什么:

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, &param_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的答案

只允许写入权限。所以这里有变化:

module_param(param, int, S_IRUGO|S_IWUSR);

现在您可以在 / sys / module //参数/ 下找到参数,您可以像这样更改参数:

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 = &param_get_ushort, // .. and standard getter
};

unsigned short param = 0xff;
module_param_cb(param,    /*filename*/
    &my_param_ops_ushort, /*operations*/
    &param,               /* 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)

像魅力一样!

2 个答案:

答案 0 :(得分:4)

创建内核模块参数的一般方法是使用宏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结尾的字符串,它从sysfs文件写入/读取,表示给定参数。 kp是指向参数描述符的指针,其中最感兴趣的字段是.arg:它是宏module_param_cb调用的第3个参数。使用此字段,setter和getter可以实现模块参数的 per-type ,即模块有5 int个参数,不需要为每个参数编写setter和getter他们。

此外,已经实现了标准参数类型的getter和setter,并且在调用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 = &param_get_ushort,     // .. and standard getter
};

// Usage
unsigned short param = 0xff;
module_param_cb(param, /*filename*/
    &my_param_ops_ushort, /*operations*/
    &param, /* pointer to variable, contained parameter's value */
    S_IRUGO | S_IWUSR /*permissions on file*/
);

由非安全用户写入模块参数通常不利于安全原因。而创建模块参数的内核宏会检查它。这就是您在模块参数定义中出现神秘错误的原因。请注意,在上面的示例中,使用S_IWUSR代替S_IWUGO

答案 1 :(得分:1)

如果使模块参数可写,则可以通过sysfs更改该参数。加载后,在/ sys下找到您的模块,然后找到模块参数并验证它是否可写(通过root)。尝试写信给它,看它是否会改变。

有几种方法可以检测此变量的更改。您可以将内核线程用作一种机制。

更好的方法可能是使用sysfs或procfs条目。那些具有读/写处理程序,在读和写时被调用。

点击此处查看sysfs-tutorial