深入浅出Flashcache(三)

前文简单介绍了block devicedevice mapper。有了这两个基础,再来看flashcache的代码,就容易理解多了。Flashcache是一个内核模块,要更清晰的理解代码,还需要了解一下内核模块编写的一些基础知识。好吧,虽然对于内核编程我完全是个门外汉,这里还是需要现学现卖下。所以这一篇还是不会切入正题,已经熟悉Linux内核模块的同学请忽略并耐心等待。

Linux内核支持动态的加载模块(Loadable Kernel Module,LKM)以完成某些特定的功能,模块编程需要按照一定的格式以便可以和内核交互。

5. 内核符号表

内核模块之间的交互需要通过特定的共享变量和函数,这些都需要输出到内核符号表。在模块编程中使用EXPORT_SYMBOL来进行定义。在内核中则使用了kernel_symbol结构来保存符号表信息。

# 内核编程基本上都需要包含如下三个头文件。
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>

#内核符号表结构体
struct kernel_symbol
{
    unsigned long value; #函数地址
    const char *name;    #函数名
};

# 导出符号的宏定义
#define EXPORT_SYMBOL(sym) __EXPORT_SYMBOL(sym, "")

#define __EXPORT_SYMBOL(sym, sec)                               \
        extern typeof(sym) sym;                                 \
        __CRC_SYMBOL(sym, sec)                                  \
        static const char __kstrtab_##sym[]                     \
        __attribute__((section("__ksymtab_strings"), aligned(1))) \
        = MODULE_SYMBOL_PREFIX #sym;                            \
        static const struct kernel_symbol __ksymtab_##sym       \
        __used                                                  \
        __attribute__((section("__ksymtab" sec), unused))       \
        = { (unsigned long)&sym, __kstrtab_##sym }

输出的符号表可以在/proc/kallsyms查看到。

6. 模块入口/退出函数

一般的c程序的入口函数是main,但模块的入口函数是module_init,退出函数则是module_exit。当内核启动或者执行insmod时执行module_init定义的函数,到内核关闭或者rmmod时执行module_exit定义的函数。

#define module_init(x)  __initcall(x);
#define module_exit(x)  __exitcall(x);

当然,还有一些宏定义了模块的一些信息,如
MODULE_AUTHOR
MODULE_DESCRIPTION
MODULE_ALIAS
MODULE_LICENSE
MODULE_PARM_DESC

7. 内存分配

内核中不能使用用户空间的malloc()和free()来分配/回收内存。而需要使用内核空间的内存分配/回收工作,常用的有kmalloc/kfree,基于slab内存分配算法:

void *kmalloc(size_t size, gfp_t flags)
void kfree(const void *objp)

对于slab内存分配器,这里不再详细展开。通过/proc/slabinfo或者slabtop可以查看slab内存分配的一些情况。

另外,在内核中也不能使用用户态的printf来输出信息,而需要使用内核态的printk。

8. 模块工具

8.1 insmod
Linux模块编译好以后一般是.ko文件,通过执行insmod可以将编译好的模块加载到内核中。在装载内核模块时,用户可以向模块传递一些参数:

$ sudo insmod mod_name var=key

8.2 rmmod
rmmod则用来卸载已经加载到内核的模块

$sudo rmmod mod_name

8.3 lsmod
lsmod可以列出已经加载到内核中的模块

lsmod
Module                  Size  Used by
nf_conntrack_ipv6       8785  1 
aes_i586                7244  2 
aes_generic            26755  1 aes_i586
ipt_MASQUERADE          1315  0 
xt_state                 930  2 
...

也可以通过/proc/modules来获取内核模块列表。

8.4 modinfo

查看某个模块的信息

$ modinfo raid0
filename:       /lib/modules/2.6.36-ningoo/kernel/drivers/md/raid0.ko
alias:          md-level-0
alias:          md-raid0
alias:          md-personality-2
description:    RAID0 (striping) personality for MD
license:        GPL
srcversion:     2CFE19548162CD6E80EE58B
depends:        
vermagic:       2.6.36-ningoo SMP mod_unload modversions CORE2

8.5 modprobe

modprobe是一个比较强大的工具,既可以列出已经安装的模块信息,也可以用来加载/卸载模块,并且能够处理同时将依赖的模块自动进行加载。

$ modprobe -l

$ sudo modprobe -r mod_name
$ sudo modprobe mod_name

/etc/modprobe.conf/etc/modprobe.d/保存了一些modprobe可能用到的配置。

未完待续

参考:
[1] 2.6内核模块编程实例指导
[2] 小白学Linux之内核模块编程



无觅相关文章插件,快速提升流量

一条评论

  • At 2011.12.14 17:27, 好看的电影 said:

    呵呵,轻轻的,来看看你,我会回来的!


    (Required)
    (Required, will not be published)