歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux 根文件系統的掛載分析

Linux 根文件系統的掛載分析

日期:2017/2/28 16:04:46   编辑:Linux教程

在介紹根文件系統掛載之前先介紹一些基礎知識

initramfs

當linux內核啟動後,會找到並執行第一個用戶程序,一般是init。這個程序存在於文件系統當中,文件系統存在於設備上,但不知道init存在哪個設備上,於是有了內核命令列選項root=,用來指定root文件系統存在於哪個設備上。

然後由於後來的設備類型越來越來多,比如可能在scsi,sata,flash這些設備,還有的存在於網絡設備上,不可能把這些設備的驅動編譯進內核,這樣內核就會越來越來大。為了解決這些問題,出現了基於ram的文件系統,initramfs,這個文件系統可以包含多個目錄和程序init,然後通過這個程序,內核再用這個程序去掛載真正的要文件系統。如果沒有這個程序,內核可以來尋找和掛載一個根分區,接著執行一些/sbin/init的變種。

ramfs

ramf是一個小型的基於內存的文件系統,由於linux中頁的數據被緩存在內存中,然後標識為可用,為防止別用,ramfs就是基於這種機制產生的。只是放在ramfs中的目錄和頁的緩存,不在寫回。

rootfs

rootfs是一種特定的ramfs的實例,它一直存在於系統中,不能卸載。大部分其他的文件系統安裝於rootfs之上。

initramfs和rootfs之間的關系

當內核啟動的時候,會先注冊和掛載一個虛擬的根文件系統,也就是rootfs,然後會把做好的initramfs(這個可以自己制作)中的文件解壓到rootfs中。然後系統會掛載真的根文件系統,rootfs隱藏之後。

我的開發板上的u-boot傳送的參數為noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0,115200 mem=64M。

noinitrd的含義

(僅當內核配置了選項 CONFIG_BLK_DEV_RAM和CONFIG_BLK_DEV_INITRD)現在的內核都可以支持initrd了,引導進程首先裝載內核和一個初始化的ramdisk,然後內核將initrd轉換成普通的ramdisk,也就是讀寫模式的根文件系統設備。然後linuxrc執行,然後裝載真正的根文件系統,之後ramdisk被卸載,最後執行啟動序列,比如/sbin/init。

選項noinitrd告訴內核不執行上面的步驟,即使內核編譯了initrd,而是把initrd的數據寫到 /dev/initrd,只是這是一個一次性的設備。

01void __init vfs_caches_init(unsigned long mempages)

02{

03 unsigned long reserve;

04

05 /* Base hash sizes on available memory, with a reserve equal to

06 150% of current kernel size */

07

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

09 mempages -= reserve;

10

11 names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,

12 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);

13

14 dcache_init();

15 inode_init();

16 files_init(mempages);

17 mnt_init();

18 bdev_cache_init();

19 chrdev_init();

20}

第14行為頁目錄緩存的初始化

第15行索引結點緩存的初始化

第16行文件的初始化

第17行虛擬文件系統掛載的初始化

第18行塊設備緩存初始化。

第19行字符設備初始化

01void __init mnt_init(void)

02{

03 unsigned u;

04 int err;

05

06 init_rwsem(&namespace_sem);

07

08 mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),

09 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);

10

11 mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);

12

13 if (!mount_hashtable)

14 panic("Failed to allocate mount hash table\n");

15

16 printk("Mount-cache hash table entries: %lu\n", HASH_SIZE);

17

18 for (u = 0; u < HASH_SIZE; u++)

19 INIT_LIST_HEAD(&mount_hashtable[u]);

20

21 err = sysfs_init();

22 if (err)

23 printk(KERN_WARNING "%s: sysfs_init error: %d\n",

24 __func__, err);

25 fs_kobj = kobject_create_and_add("fs", NULL);

26 if (!fs_kobj)

27 printk(KERN_WARNING "%s: kobj create error\n", __func__);

28 init_rootfs();

29 init_mount_tree();

30}

第6行命明空間信號量的初始化

第8行分配空間

第11行掛載點哈希表分配空間

第18行初始化所有的掛載點哈希表。

第25行生成名為fs的kobject對象。

第28行初始化rootfs文件系統

第29行初始化mount樹

第一部分 rootfs文件系統的注冊

01int __init init_rootfs(void)

02{

03 int err;

04

05 err = bdi_init(&ramfs_backing_dev_info);

06 if (err)

07 return err;

08

09 err = register_filesystem(&rootfs_fs_type);

10 if (err)

11 bdi_destroy(&ramfs_backing_dev_info);

12

13 return err;

14}

第5行初始化

第9行注冊rootfs文件系統

1static struct file_system_type rootfs_fs_type = {

2 .name = "rootfs",

3 .get_sb = rootfs_get_sb,

4 .kill_sb = kill_litter_super,

5};

第二部分掛載rootfs文件和創建根目錄

01static void __init init_mount_tree(void)

02{

03 struct vfsmount *mnt;

04 struct mnt_namespace *ns;

05 struct path root;

06

07 mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);

08 if (IS_ERR(mnt))

09 panic("Can't create rootfs");

10 ns = kmalloc(sizeof(*ns), GFP_KERNEL);

11 if (!ns)

12 panic("Can't allocate initial namespace");

13 atomic_set(&ns->count, 1);

14 INIT_LIST_HEAD(&ns->list);

15 init_waitqueue_head(&ns->poll);

16 ns->event = 0;

17 list_add(&mnt->mnt_list, &ns->list);

18 ns->root = mnt;

19 mnt->mnt_ns = ns;

20

21 init_task.nsproxy->mnt_ns = ns;

22 get_mnt_ns(ns);

23

24 root.mnt = ns->root;

25 root.dentry = ns->root->mnt_root;

26 set_fs_pwd(current->fs, &root);

27 set_fs_root(current->fs, &root);

28}

這個函數的主要作用是是生成/目錄的。

第3行定義一個掛載點

第4行定義一個命名空間

第5行定義一個根路徑

第7行掛載rootfs文件系統,返回掛載點

第10行為命名空間分配空間

第13行設定命名空間的引用數為1

第14行初始化命名空間鏈表

第15行初始化等待對列

第18行命名空間的根結點指向掛載點

第19行掛載點指向命名空間

第21行第一個進程的命名空間第向剛才初始化的。

第24行路徑的掛載點為命名空間的根結點

第25行路徑的目錄為命名空間所指向的掛載點的根目錄

第26行設置/目錄為當前的目錄

第27行設置/目錄為根目錄

01struct vfsmount * do_kern_mount(const char *fstype, int flags, const char *name, void *data)

02{

03 struct file_system_type *type = get_fs_type(fstype);

04 struct vfsmount *mnt;

05

06 if (!type)

07 return ERR_PTR(-ENODEV);

08 mnt = vfs_kern_mount(type, flags, name, data);

09

10 if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&

11 !mnt->mnt_sb->s_subtype)

12 mnt = fs_set_subtype(mnt, fstype);

13 put_filesystem(type);

14 return mnt;

15}

do_kern_mount的參數介紹

fstype 要安裝的文件系統的類型名

flag 安裝的標志

name 存放文件系統的塊設備的路徑名

data 指向傳遞給文件系統中read_super方法的附加指針

第3行得到文件系統的類型,這裡是rootfs,當然也會有其它的文件系統,比如proc,pipefs等

第8行返回掛載點

第13行增加對文件系統的引用

01struct vfsmount *

02vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)

03{

04 struct vfsmount *mnt;

05 char *secdata = NULL;

06 int error;

07

08 if (!type)

09 return ERR_PTR(-ENODEV);

10

11 error = -ENOMEM;

12 mnt = alloc_vfsmnt(name);

13 if (!mnt)

14 goto out;

15

16 if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {

17 secdata = alloc_secdata();

18 if (!secdata)

19 goto out_mnt;

20

21 error = security_sb_copy_data(data, secdata);

22 if (error)

23 goto out_free_secdata;

24 }

25

26 error = type->get_sb(type, flags, name, data, mnt);

27 if (error < 0)

28 goto out_free_secdata;

29 BUG_ON(!mnt->mnt_sb);

30

31 error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);

32 if (error)

33 goto out_sb;

34

35 mnt->mnt_mountpoint = mnt->mnt_root;

36 mnt->mnt_parent = mnt;

37 up_write(&mnt->mnt_sb->s_umount);

38 free_secdata(secdata);

39 return mnt;

40out_sb:

41 dput(mnt->mnt_root);

42 deactivate_locked_super(mnt->mnt_sb);

43out_free_secdata:

44 free_secdata(secdata);

45out_mnt:

46 free_vfsmnt(mnt);

47out:

48 return ERR_PTR(error);

49}

第4行定義掛載點

第12行分配一個新的已安裝文件系統的描述符,存放在局部變量mnt中

第26行調用文件系統get_sb回調函數,這裡是rootfs_get_sb,來初始化一個新的超級塊,同時會創建/目錄.後面會單獨介紹

第35行掛載點根目錄指向與文件系統根目錄對應的目錄項對象的地址

第36行掛載點父目錄指向自己

第39行返回局部變量mnt

Copyright © Linux教程網 All Rights Reserved