まず、目的
この記事では、主にlinux3.10ファイルシステムの初期化プロセスの最初の段階であるrootfsファイルシステムのマウントについて説明します。
Rootfsはメモリベースのファイルシステムであり、すべての操作はメモリ内で完了します。実際のストレージデバイスがないため、デバイスドライバは必要ありません。上記の理由により、Linuxは起動段階でrootfsファイルシステムを使用します。ディスクドライバとディスクファイルシステムが正常にロードされると、Linuxシステムはシステムルートディレクトリをrootfsからディスクファイルシステムに切り替えます。
次に、メインの関数呼び出しプロセス
図1は、マウントrootfs(図の赤い部分)の関数呼び出し関係を示しています。これは、後続の分析に便利です。
この図から、rootfsがマウントされる前にsysfsがマウントされることがわかります。これは、sysfsがデバイスドライバーモデルを完全に記録できるようにするためです。
sysfs_init()は、sysfsファイルシステムの登録とマウントの機能を完了します。init_rootfs()はrootfsの登録を担当し、init_mount_tree()はrootfsのマウントを担当し、init_taskの名前空間をそれにリンクします。
図1
3、Linuxファイルシステムの初期化
vfs_cache_init()は、最初にディレクトリハッシュテーブルdentry_hashtableとiノードハッシュテーブルinode_hashtableを確立して初期化し、次にカーネルが開くことができるファイルの最大数を設定します。最後にmnt_init()を呼び出して、sysfsおよびrootfsファイルシステムの登録とマウントを完了します。 。
Linuxは、ハッシュテーブルを使用してディレクトリとインデックスノードを格納し、ディレクトリとインデックスノードの検索効率を向上させます。dentry_hashtableはディレクトリハッシュテーブル、inode_hashtableはインデックスノードハッシュテーブルです。
第四に、sysfsファイルシステムをマウントします
sysfsは、Linuxドライバーモデルを記録および表示するために使用されます。sysfsはrootfsの前にマウントされ、Linuxドライバーモデルの包括的な表示の準備をします。
mnt_init()はsysfs_init()を呼び出してsysfsファイルシステムを登録およびマウントし、次にkobject_create_and_add()を呼び出して「fs」ディレクトリを作成します。
2735 err = sysfs_init(); 2736 if(err) 2737 printk(KERN_WARNING "%s:sysfs_init error:%d \ n"、 2738 __func __、err); 2739 fs_kobj = kobject_create_and_add( "fs"、NULL); 2740 if(!fs_kobj) 2741 printk(KERN_WARNING "%s:kobj create error \ n"、__ func__);
以下に、sysfsファイルシステムのマウントプロセスの詳細を示します。
1. sysfs_init()はregister_filesystem()を呼び出して、ファイルシステムタイプsysfs_fs_typeを登録し、それをグローバルな単一リンクリストfile_systemsに追加します。sysfs_fs_typeは、次のように定義されています。.mountメンバー関数は、スーパーブロック、ルートディレクトリ、およびインデックスノードの作成と初期化を担当します。
173 err = register_filesystem(&sysfs_fs_type); 174 if(!err){ 175 sysfs_mnt = kern_mount(&sysfs_fs_type); 176 if(IS_ERR(sysfs_mnt)){ 177 printk(KERN_ERR "sysfs:マウントできませんでした!\ n"); 178エラー= PTR_ERR(sysfs_mnt); 179 sysfs_mnt = NULL; 180 unregister_filesystem(&sysfs_fs_type); 181 goto out_err; 182}
152 static struct file_system_type sysfs_fs_type = { 153 .name = "sysfs"、 154 .mount = sysfs_mount、 155 .kill_sb = sysfs_kill_sb、 156 .fs_flags = FS_USERNS_MOUNT、 157};
2. sysfs_init()-> kern_mount()-> vfs_kern_mount()は、structマウントマウントポイントを作成して初期化し、グローバル変数sysfs_mntを使用してマウントポイントのマウントアイテム(mntメンバー)を保存します。
783 mnt = alloc_vfsmnt(name); 784 if(!mnt) 785 return ERR_PTR(-ENOMEM);
3. kern_mount()は、sysfs_fs_typeの.mountメンバーsysfs_mount()を呼び出して、スーパーブロック、ルートディレクトリ '/'、ルートディレクトリのインデックスノードなどのデータ構造を作成および初期化し、スーパーブロックをに追加します。インデックスノードを追加するグローバル単一リンクリストsuper_blocksハッシュテーブルinode_hashtableおよびスーパーブロックのiノードリンクリストに追加します。
現在、重要な結論を導き出すことができます。kern_mount()は、主にマウントポイント、スーパーブロック、ルートディレクトリ、およびインデックスノードの作成と初期化を完了します。これはアトミック操作と見なすことができます。この関数は、未来。
790ルート= mount_fs(type、flags、name、data); 1091 struct dentry * 1092 mount_fs(struct file_system_type * type、int flags、const char * name、void * data) 1093 { 1094 struct dentry * root; ... 1108 1109 root = type-> mount(type、flags、name、data);
107 static struct dentry * sysfs_mount(struct file_system_type * fs_type、 108 int flags、const char * dev_name、void * data) 109 {... 112 struct super_block * sb; ... 125 sb = sget(fs_type、sysfs_test_super、sysfs_set_super、 flags、info); ... 130 if(!sb-> s_root){ 131 error = sysfs_fill_super(sb、data、flags&MS_SILENT?1:0); 4. vfs_kern_mount()はルートディレクトリとマウントのスーパーを初期化しますポイントピース。
796 mnt-> mnt.mnt_root =ルート; 797 mnt-> mnt.mnt_sb = root-> d_sb; 798 mnt-> mnt_mountpoint = mnt-> mnt.mnt_root; 799 mnt-> mnt_parent = mnt; 5、mnt_init()调用kobject_create_and_add()创建 "fs"目录。
上記の手順により、VFS内のsysfsファイルシステムのビューを図2に示します。マウントポイントはスーパーブロックとルートディレクトリを指します。スーパーブロックはsuper_blocksの単一リンクリストにあり、すべてのインデックスノードはファイルシステムにリンクされます。ルートディレクトリ「/」とディレクトリ「fs」はそれぞれのインデックスノードを指します。検索効率を向上させるために、インデックスノードはハッシュテーブルに格納されます。
図2
5、rootfsファイルシステムをマウントします
mnt_init()はinit_rootfs()を呼び出してrootfsを登録し、次にinit_mount_tree()を呼び出してrootfsをマウントします。
以下に、rootfsファイルシステムのマウントプロセスの詳細を示し
ます。1。mnt_init()はinit_rootfs()を呼び出して、ファイルシステムタイプrootfs_fs_typeを登録し、それをグローバル単一リンクリストfile_systemsに追加します。
rootfs_fs_typeは次のように定義されます。マウントメンバー関数は、スーパーブロック、ルートディレクトリ、およびインデックスノードの確立と初期化を担当します。
265 static struct file_system_type rootfs_fs_type = { 266 .name = "rootfs"、 267 .mount = rootfs_mount、 268 .kill_sb = kill_litter_super、 269};
2. Init_mount_tree()はvfs_kern_mount()を呼び出してrootfsファイルシステムをマウントします。詳細なマウントプロセスはsysfsファイルシステムのプロセスと同様であり、繰り返されません。
3. Init_mount_tree()はcreate_mnt_ns()を呼び出して名前空間を作成し、名前空間のマウントポイントをrootfsのマウントポイントに設定すると同時に、rootfsのマウントポイントを名前空間の二重リンクリストにリンクします。
2459 static struct mnt_namespace * create_mnt_ns(struct vfsmount * m) 2460 { 2461 struct mnt_namespace * new_ns = alloc_mnt_ns(&init_user_ns); 2462 if(!IS_ERR(new_ns)){ 2463 struct mount * mnt = real_mount(m); 2464 mnt-> mnt_ns = new_ns; 2465 new_ns-> root = mnt; 2466 list_add(&mnt-> mnt_list、&new_ns-> list); 2467}
4. Init_mount_tree()はinit_taskの名前空間を設定し、set_fs_pwd()とset_fs_root()を呼び出して、init_taskタスクの現在のディレクトリとルートディレクトリをrootfsのルートディレクトリ「/」に設定します。
2696 ns = create_mnt_ns(mnt); 2697 if(IS_ERR(ns)) 2698 panic( "初期名前空間を割り当てることができません"); 2699 2700 init_task.nsproxy-> mnt_ns = ns; 2701 get_mnt_ns(ns); 2702 2703 root.mnt = mnt; 2704 root.dentry = mnt-> mnt_root; 2705 2706 set_fs_pwd(current-> fs、&root); 2707 set_fs_root(current-> fs、&root);
上記の分析を通じて、sysfsとrootfsの違いは、システムにはsysfsファイルシステムとrootfsファイルシステムの両方がマウントされているにもかかわらず、rootfsのみがinit_taskプロセスの名前空間にあることです。つまり、システムは現在rootfsを使用しています。ファイルシステム。
このとき、VFSでのsysfsとrootfsのビューを図3に示します。主な関係を強調するために、スーパーブロックとルートディレクトリを指すマウントポイントは省略されています。
この図から、rootfsはプロセスの名前空間にあり、プロセスのfs_structデータ構造のrootとpwdはrootfsのルートディレクトリ「/」を指していることがわかります。したがって、ユーザーは実際にrootfsファイルシステムを使用します。 。さらに、rootfsはVFSの「/」ルートディレクトリを提供するため、ファイル操作とファイルシステムのマウント操作をVFSで実行できます。
画像3
6、まとめ
linuxファイルシステムが初期化されると、sysfsファイルシステムとrootfsファイルシステムが同時にマウントされますが、プロセスの名前空間にはrootfsのみがあり、プロセスのルートディレクトリとpwdディレクトリは両方ともルートディレクトリを指します。 rootfsの。この時点で、Linux VFSのルートディレクトリ(rootfs '/'のルートディレクトリ)が準備されており、ユーザーはシステムコールを使用してVFSツリーを展開できます。