分类: LINUX
2010-01-28 16:58:50
本文解决以下两个问题:
1.跟踪内核数据结构,实时观察结构体中各字段的值,加深对其的理解
2.不用导出(EXPORT_SYMBOL( ))使用内核符号
在读Linux内核源代码时,总是会被里面的数据结构搞的晕头转向,每一个数据结构都和其他相关联,拥有很多字段,这个时候就想看看它在内核中是如何存在的,字段的值又是多少,这样就可以实时的跟踪观察这个数据结构了,借此来加深理解。最近在看文件系统时,看到超级块结构(struct super_block,这里对此结构不做解释,可参考VFS相关内容),书上的解释是一个文件系统对应一个超级块,但还是感觉不是很实在,所以就想到写个模块程序将此结构体的某些字段打印出来仔细观察,此结构体在内核中是由一个链表来组织的,链表头是super_blocks,所以可以遍历此链表,然后打印超级块的信息,模块程序如下(省略Makefile文件):
#include
#include
#include
#include
#include
#include
static int __init my_init(void)
{
struct super_block *sb;
struct list_head *pos;
printk(”\nprint super_blocks:\n”);
spin_lock(&sb_lock);
list_for_each(pos, &super_blocks) {
sb = list_entry(pos, struct super_block, s_list);
printk(”dev_t:%d:%d”, MAJOR(sb->s_dev),MINOR(sb->s_dev));
printk(”count:%d file_type name:%s\n”, sb->s_count, sb->s_type->name);
}
spin_unlock(&sb_lock);
return 0;
}
static void __exit my_exit(void)
{
printk(”unloading….\n”);
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE(”GPL”);
但是在make 的过程中发现了一个问题:
“super_blocks” ,”sb_lock” undefined!
原来是因为内核并没有将super_blocks和sb_lock变量导出(EXPORT_SYMBOL),所以不能在模块中直接使用此符号,为了解决这个问题可以修改内核,将此变量导出,然后重新编译内核,但这样就得每次想观察内核数据时编译一次内核,这代价太大了!最后在陈老师的指导下,发现内核所有的符号包括函数、变量地址都在/proc/kallsyms文件中导出,虽然符号不能用,但是可以在模块中直接用它的地址,因为编译模块的地址空间和内核是相同的,所以可以这样使用!此时就不会出现符号未定义的错误了!模块程序如下:
#define SUPER_BLOCKS_ADDRESS 0xc03f83ac
//find the varl super_blocks address from /proc/kallsyms
#define SB_LOCK_ADDRESS 0xc03f83b4
// find the varl sb_lock address from /proc/kallsyms
static int __init my_init(void)
{
struct super_block *sb;
struct list_head *pos;
printk(”\nprint super_block:\n”);
spin_lock((spinlock_t *)SB_LOCK_ADDRESS);
list_for_each(pos, (struct list_head *)SUPER_BLOCKS_ADDRESS) {
sb = list_entry(pos, struct super_block, s_list);
printk(”dev_t:%d:%d “, MAJOR(sb->s_dev),MINOR(sb->s_dev));
printk(”count:%d file_type name:%s\n”, sb->s_count, sb->s_type->name);
}
spin_unlock((spinlock_t *)SB_LOCK_ADDRESS);
return 0;
}
此程序中将原来的super_blocks和sb_lock换成了宏定义SUPER_BLOCKS_ADDRESS和SB_LOCK_ADDRESS,其中的地址是从/proc/kallsyms文件中获得,如:
$cat /proc/kallsyms | grep super_blocks
c03f83ac D super_blocks
$ cat /proc/kallsyms | grep sb_lock
c03f83b4 D sb_lock
这样就可以编译通过,加载模块了。观察结果(dmesg)
print super_block:
dev_t:0:0 count:1073741824 file_type name:sysfs
dev_t:0:1 count:1073741824 file_type name:rootfs
dev_t:0:2 count:1073741824 file_type name:bdev
dev_t:0:3 count:1073741824 file_type name:proc
dev_t:0:4 count:1073741824 file_type name:sockfs
dev_t:0:5 count:1073741824 file_type name:pipefs
dev_t:0:6 count:1073741824 file_type name:anon_inodefs
dev_t:0:7 count:1073741824 file_type name:securityfs
dev_t:0:8 count:1073741824 file_type name:futexfs
dev_t:0:9 count:1073741824 file_type name:tmpfs
dev_t:0:10 count:1073741824 file_type name:inotifyfs
dev_t:0:11 count:1073741824 file_type name:devpts
dev_t:0:12 count:1073741824 file_type name:mqueue
dev_t:0:13 count:1073741824 file_type name:debugfs
dev_t:0:14 count:1073741824 file_type name:tmpfs
dev_t:0:15 count:1073741824 file_type name:fusectl
dev_t:0:16 count:1073741824 file_type name:usbfs
dev_t:8:8 count:1073741824 file_type name:ext3
dev_t:0:17 count:1073741824 file_type name:tmpfs
dev_t:0:18 count:1073741824 file_type name:tmpfs
dev_t:0:19 count:1073741824 file_type name:tmpfs
dev_t:0:20 count:1073741824 file_type name:tmpfs
dev_t:0:21 count:1073741824 file_type name:binfmt_misc
dev_t:0:22 count:1073741824 file_type name:fuse
dev_t:8:1 count:1073741824 file_type name:vfat
dev_t:8:6 count:1073741824 file_type name:vfat
dev_t:8:5 count:1073741824 file_type name:vfat
对以上结果进行分析:
1.超级块结构和文件系统结构是多对一的关系,即多个超级块包含了同样的文件系统,比如上面的多个超级块包含了vfat文件系统
2.通过超级块的设备号就可以看到系统中已经挂载的文件系统所在的分区,如上面有3个vfat文件系统,可以查看/dev/下的分区,如:
ls -l /dev/sda*
brw-rw—- 1 root disk 8, 0 /dev/sda
brw-rw—- 1 root disk 8, 1 /dev/sda1
brw-rw—- 1 root disk 8, 2 /dev/sda2
brw-rw—- 1 root disk 8, 5 /dev/sda5
brw-rw—- 1 root disk 8, 6 /dev/sda6
brw-rw—- 1 root disk 8, 7 /dev/sda7
brw-rw—- 1 root disk 8, 8 /dev/sda8
这说明每一个分区都是一个超级块!
3.主设备号为0 的没有和物理设备相关联。
4.超级块中的s_count字段为什么都一样?还没搞明白。。。