边学边实践:打印VFS中的结构体

2010年11月27日 由 edsionte 留言 »

学习了VFS的基本原理,我们很有必要对这些理论知识进行验证和实践。本文所分析的几个小程序将更具体、直观的展现VFS中一些数据结构之间的逻辑关系。

1.打印超级块和索引结点

通过前面的分析我们知道,系统中所有的超级块都内嵌一个struct list_head类型的字段s_list。通过该字段将系统中所有的超级块链接成一个双联表。因此,如果我们知道这个双联表的头指针以及了解相关便利宏的使用方法,那么我们就可以遍历整个系统中的所有超级块了。
为了解释方便,我们将内嵌的list_head结构体称为内部结构体;将super_block结构体称为外部结构体;

具体的,我们可以通过 list_for_each宏来遍历一个list_head类型的双联表。该宏的定义如下:

 364#define list_for_each(pos, head) \
 365        for (pos = (head)->next; prefetch(pos->next), pos != (head); \
 366                pos = pos->next)

使用该宏时,需要向head参数中传递要遍历双联表的头指针;而每次遍历得到的list_head类型的结点地址会保存在pos这个参数中。不过,这个宏只能遍历内嵌于超级块中的那个list_head结构的链表,并不能得到正在被遍历的那个超级块的地址(也就是指向当前正被遍历的超级块的指针)。也就是说,每次遍历时并不能得到超级块中的其他字段。因此,还应该使用 list_entry宏。该宏通过指向list_head结点的地址来得到外部超级块的首地址。

345#define list_entry(ptr, type, member) \
346        container_of(ptr, type, member)

这个宏的第一个参数是指向内部结构体list_head的指针,第二个参数是外部结构体的类型,第三个参数是list_head类型的变量在外部结构体中的名称。这个宏最后会返回指向当前外部结构体的指针。比如,在super_block结构体中,list_head结构类型的字段名称为s_list,因此可以如下使用该宏:

sb = list_entry(pos, struct super_block, s_list);

对于超级块形成的双联表来说,它的头指针是super_blocks。但是很遗憾,super_blocks这个变量并没有被导出。所谓导出,就是通过EXPORT_SYMBOL将某个函数或者变量对全部内核代码公开。也就是说,使用 EXPORT_SYMBOL可以将一个函数以符号的方式导出给其他模块使用 。为了解决这个问题,我们可以在包含super_blocks的这个文件中将这个变量导出,并且重新编译内核。对于我们这里的这个小程序而言,这样做有些不值得。幸好,在/proc/kallsyms文件中,记录了内核中所有符号以及符号的地址。因此,在该文件中查找相应符号就可以得到其地址。

我们使用下述两条命令:

edsionte@edsionte-desktop:~/code/vfs/print_sb$ grep super_blocks /proc/kallsyms
c0772a30 D super_blocks
edsionte@edsionte-desktop:~/code/vfs/print_sb$ grep " sb_lock" /proc/kallsyms
c08c9d60 B sb_lock

就可以得到super_blocks变量的地址。另外,sb_lock超级块对应的自旋锁。

上述都准备好后,我们就可以进行遍历了。关键代码如下:

#define SUPER_BLOCKS_ADDRESS 0xc0772a30
#define SB_LOCK_ADDRESS 0xc08c9d60

static int __init my_init(void)
{
struct super_block *sb;
struct list_head *pos;
struct list_head *linode;
struct inode *pinode;
unsigned long long count = 0;

printk("print some fields of super blocks:\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("fs_name:%s\n",sb->s_type->name);
printk("\n");
}

spin_unlock((spinlock_t *)SB_LOCK_ADDRESS);
printk("the number of inodes:%llu\n",sizeof(struct inode)*count);

return 0;
}

另外,需要注意的是,每次重启电脑后,都要重新查找上述两个变量的地址。

对于一个超级块中所有的inode,有专门一个链表将所有的inode链接起来。这个链表的头结点是超级块中的s_inode字段。而inode之间是其内部的i_sb_list字段进行链接的。了解了这些,我们可以在上述程序的基础上,再打印每个超级块中的所有inode:

	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("fs_name:%s\n",sb->s_type->name);

		list_for_each(linode, &sb->s_inodes){

			pinode = list_entry(linode, struct inode, i_sb_list);
			count ++;
			printk("%lu\t",pinode->i_ino);
		}

		printk("\n");
	}

在上面代码的基础上,我们再加深一步。一个索引结点可能对应若干个dentry,这些dentry自身通过其内部的d_alias链接在一起;而整个链表的头结点是inode中的i_dentry字段。因此,根据上面的方法,我们可以在遍历每个inode的同时,继续遍历这个inode对应的所有dentry。部分代码如下:

	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("fs_name:%s\n",sb->s_type->name);

		list_for_each(linode, &sb->s_inodes){
			pinode = list_entry(linode, struct inode, i_sb_list);
			count ++;
			printk("%lu[",pinode->i_ino);

			list_for_each(ldentry, &pinode->i_dentry){
				pdentry = list_entry(ldentry, struct dentry, d_alias);
				printk("%s->",pdentry->d_name.name);
			}
			printk("]\t");
		}
		
		printk("\n");
	}

上出程序的完整的代码在这里

2.打印文件类型结构体

同样的道理,通过下述的代码可以打印file_system_type结构体。

#define FILE_SYSTEM_ADDRESS 0xc08ca3a4 /* grep file_systems /proc/kallsyms */
#define FILE_SYSTEM_LOCK_ADDRESS 0xc0772de0 /* grep file_systems_lock /proc/kallsyms */

static int __init printfs_init(void)
{
	struct file_system_type **pos;

	printk("\n\nprint file_system_type:\n");

	read_lock((rwlock_t *)FILE_SYSTEM_LOCK_ADDRESS);
	pos = (struct file_system_type **)FILE_SYSTEM_ADDRESS;

	while(*pos){
		printk("name: %s\n",(*pos)->name);
		pos = &((*pos)->next);
	}

	read_unlock((rwlock_t *)FILE_SYSTEM_LOCK_ADDRESS);

	return 0;
}

更多的打印信息可以按照上述方法继续添加。开始吧!

广告位

发表评论

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key