linux文件系統的系統分析--(二)文件系統類型的註冊

 

因爲linux支持模塊機制,所以我們可以將文件系統編譯爲模塊,所以文件系統系統類型的註冊的註冊有多種方式:要麼已經包含在內核映像中,要麼作爲一個模塊被動態加載。我們關注的重點是rootfs和sysfs,他們其實在系統初始化的時候就註冊並安裝好了,沒有rootfs,linux就沒法玩了。以rootfs的註冊爲例,來分析一下文件系統類型的註冊:

        在start_kernel-->vfs_caches_init(totalram_pages);

        vfs_caches_init函數如下:

void __init vfs_caches_init(unsigned long mempages)
{
	unsigned long reserve;

	/* Base hash sizes on available memory, with a reserve equal to
           150% of current kernel size */

	reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);
	mempages -= reserve;

	names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
			SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);

	dcache_init();
	inode_init();
	files_init(mempages);
	mnt_init();
	bdev_cache_init();
	chrdev_init();
}
        其中: dcache_init();   //目錄項的緩存
                inode_init();      //索引節點的緩存
                files_init(mempages);   //file的緩存
                mnt_init();
                bdev_cache_init();       //塊設備的緩存
                chrdev_init();             //字符設備的初始化,在《linux設備模型之字符設備》中會看到字符設備文件是如何建立的。

        目前我們關注的重點是mnt_init(),其中有這麼幾行代碼:

	err = sysfs_init();
	if (err)
		printk(KERN_WARNING "%s: sysfs_init error: %d\n",
			__func__, err);
	fs_kobj = kobject_create_and_add("fs", NULL);
	if (!fs_kobj)
		printk(KERN_WARNING "%s: kobj create error\n", __func__);
	init_rootfs();
	init_mount_tree();
         可以看到,sysfs_init還在init_rootfs之前,是不是有點奇怪,沒有root fs,哪有其他的fs啊?這個在後面我們會明白。

         這一次我們只看init_rootfs():

         在fs/ramfs/inode.c中:

int __init init_rootfs(void)
{
	int err;

	err = bdi_init(&ramfs_backing_dev_info);
	if (err)
		return err;

	err = register_filesystem(&rootfs_fs_type);
	if (err)
		bdi_destroy(&ramfs_backing_dev_info);

	return err;
}
          register_filesystem(&rootfs_fs_type);完成文件系統的註冊:

static struct file_system_type rootfs_fs_type = {
	.name		= "rootfs",
	.get_sb		= rootfs_get_sb,
	.kill_sb	= kill_litter_super,
};
          rootfs_fs_type是一個file_system_type類型的結構體,主要的函數是get_sb--rootfs_get_sb函數,作用是獲取rootfs文件系統的超級塊對象。

          其實這個註冊過程很簡單,其實就是加入鏈表的過程:

          爲了證明鏈表的存在:還是要給出file_system_type結構體的全貌:

          

struct file_system_type {
	const char *name;
	int fs_flags;
	int (*get_sb) (struct file_system_type *, int,
		       const char *, void *, struct vfsmount *);
	void (*kill_sb) (struct super_block *);
	struct module *owner;
	struct file_system_type * next;
	struct list_head fs_supers;

	struct lock_class_key s_lock_key;
	struct lock_class_key s_umount_key;

	struct lock_class_key i_lock_key;
	struct lock_class_key i_mutex_key;
	struct lock_class_key i_mutex_dir_key;
	struct lock_class_key i_alloc_sem_key;
};

          仔細看一下這個結構體,可以看到貌似有兩個鏈表:struct file_system_type * next;單項鍊表和struct list_head fs_supers;這個linux內核經典的雙向鏈表。

          往後,我們會看到這兩個鏈表各自是怎麼串的,串的是什麼內容。而在register_filesystem中我們就可以看到struct file_system_type * next;單項鍊表的形成。

          register_filesystem函數如下:

int register_filesystem(struct file_system_type * fs)
{
	int res = 0;
	struct file_system_type ** p;

	BUG_ON(strchr(fs->name, '.'));
	if (fs->next)
		return -EBUSY;       //1
	INIT_LIST_HEAD(&fs->fs_supers);      //2
	write_lock(&file_systems_lock);
	p = find_filesystem(fs->name, strlen(fs->name));   //3
	if (*p)
		res = -EBUSY;
	else
		*p = fs;//4
	write_unlock(&file_systems_lock);
	return res;
}
           1、如果文件系統的next字段不爲NULL,則說明不是新的文件系統類型,因此返回失敗。
如果文件系統已經註冊了,那麼無法在註冊了。每種類型的文件系統只能註冊一次,但是可以有多種設備使用同一個類型的文件系統,也可以將同一類型的文件系統              掛載在不同的路徑下。

           2、初始化fs->fs_supers;

           3、查找已經註冊過的文件系統,查看準備要註冊的文件系統是否已經註冊過了,如果註冊過,則返回錯誤。

           4、如果沒有註冊過,則將新的文件系統type添加文件系統列表中。

           find_filesystem函數如下:

static struct file_system_type **find_filesystem(const char *name, unsigned len)
{
	struct file_system_type **p;
	for (p=&file_systems; *p; p=&(*p)->next)
		if (strlen((*p)->name) == len &&
		    strncmp((*p)->name, name, len) == 0)
			break;
	return p;
}

            可以清楚的看到:通過二級指針來遍歷當前的鏈表,如果將要註冊的文件系統存在,則返回p的指針,p不爲空,如果找不到,則返回next,並且next爲空指針。後續會將新的文件系統類型添加在這裏。

           







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章