rootfs文件系統簡單分析

rootfs文件系統是基於內存的文件系統,也是虛擬的文件系統,在系統啓動之後,隱藏在真正的根文件系統後面,不能被卸載。
在開始介紹rootfs之前,先介紹一下,rootfs的數據結構,然後再看一下rootfs中的函數rootfs_get_sb是怎麼調用的。
rootfs的數據結構如下

  1. 1static struct file_system_type rootfs_fs_type = {  
  2. 2 .name  = "rootfs",  
  3. 3 .get_sb  = rootfs_get_sb,  
  4. 4 .kill_sb = kill_litter_super,  
  5. 5};  
第2行文件系統的名字
第3行掛載文件系統時分配超級塊
第4行卸載文件系統時回收超級塊
  1. 01static void __init init_mount_tree(void)  
  2. 02{  
  3. 03 .......  
  4. 04  mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);  
  5. 05 .......  
  6. 06}  
  7. 07struct vfsmount *  
  8. 08do_kern_mount(const char *fstype, int flags, const char *name, void *data)  
  9. 09{  
  10. 10 ....  
  11. 11 mnt = vfs_kern_mount(type, flags, name, data);  
  12. 12 ....  
  13. 13}  
  14. 14struct vfsmount *  
  15. 15vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)  
  16. 16{  
  17. 17  .....  
  18. 18 error = type->get_sb(type, flags, name, data, mnt);  
  19. 19 ......  
  20. 20}  
上面是內核在啓動時掛載rootfs文件系統的簡單流程,其中在第18行是,會調用rootfs文件系統中的rootfs_get_sb函數,其函數如下。
  1. 1static int rootfs_get_sb(struct file_system_type *fs_type,  
  2. int flags, const char *dev_name, void *data, struct vfsmount *mnt)  
  3. 3{  
  4. return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,  
  5. 5       mnt);  
  6. 6}  
 
[cpp] view plaincopyprint?
  1. 01int get_sb_nodev(struct file_system_type *fs_type,  
  2. 02 int flags, void *data,  
  3. 03 int (*fill_super)(struct super_block *, void *, int),  
  4. 04 struct vfsmount *mnt)  
  5. 05{  
  6. 06 int error;  
  7. 07 struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);  
  8. 08 if (IS_ERR(s))  
  9. 09  return PTR_ERR(s);  
  10. 10 s->s_flags = flags;  
  11. 11 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);  
  12. 12 if (error) {  
  13. 13  deactivate_locked_super(s);  
  14. 14  return error;  
  15. 15 }  
  16. 16 s->s_flags |= MS_ACTIVE;  
  17. 17 simple_set_mnt(mnt, s);  
  18. 18 return 0;  
  19. 19}  

第7行調用sget()函數分配新的超級塊,傳遞set_anon_super()函數的地址作爲參數。用合適的方式設置超級塊的s_dev字段。
第10行將flags參數的值拷到超級塊的s_flags字段中。
第11行的函數指針指向ramfs_fill_super函數,來分配索引節點對象和對應的目錄項對象,並填充超級塊字段的值。由於rootfs是一種特殊文件系統,沒有磁盤超級塊,因此只需執行這兩個超級塊的操作。

  1. 01static int ramfs_fill_super(struct super_block * sb, void * data, int silent)  
  2. 02{  
  3. 03 struct ramfs_fs_info *fsi;  
  4. 04 struct inode *inode = NULL;  
  5. 05 struct dentry *root;  
  6. 06 int err;  
  7. 07 save_mount_options(sb, data);  
  8. 08 fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);  
  9. 09 sb->s_fs_info = fsi;  
  10. 10 if (!fsi) {  
  11. 11  err = -ENOMEM;  
  12. 12  goto fail;  
  13. 13 }  
  14. 14 err = ramfs_parse_options(data, &fsi->mount_opts);  
  15. 15 if (err)  
  16. 16  goto fail;  
  17. 17 sb->s_maxbytes  = MAX_LFS_FILESIZE;  
  18. 18 sb->s_blocksize  = PAGE_CACHE_SIZE;  
  19. 19 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;  
  20. 20 sb->s_magic  = RAMFS_MAGIC;  
  21. 21 sb->s_op  = &ramfs_ops;  
  22. 22 sb->s_time_gran  = 1;  
  23. 23 inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, 0);  
  24. 24 if (!inode) {  
  25. 25  err = -ENOMEM;  
  26. 26  goto fail;  
  27. 27 }  
  28. 28 root = d_alloc_root(inode);  
  29. 29 sb->s_root = root;  
  30. 30 if (!root) {  
  31. 31  err = -ENOMEM;  
  32. 32  goto fail;  
  33. 33 }  
  34. 34 return 0;  
  35. 35fail:  
  36. 36 kfree(fsi);  
  37. 37 sb->s_fs_info = NULL;  
  38. 38 iput(inode);  
  39. 39 return err;  
  40. 40}  

第7行如果文件系統使用generic_show_options()函數,這個函數將回調fill_super()調用,特殊情況下,.remount_fs回調函數,也會處理
第17行給超級塊的文件的最長長度賦值
第18行給超級塊的字節爲單位的塊大小的字段賦值
第19行給超級塊的位爲單位的大小的字段賦值
第21行超級塊的方法指向ramfs_ops結構體的地址
第22行超級塊時間戳的粒度賦值
第23行分配一個新的索引節點,並初始化新的索引節點
第28行分配/目錄
第29行超級塊的根目錄指向/目錄
第35-40行對一些錯誤信息的處理。

  1. 01struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)  
  2. 02{  
  3. 03 struct inode * inode = new_inode(sb);  
  4. 04 if (inode) {  
  5. 05  inode->i_mode = mode;  
  6. 06  inode->i_uid = current_fsuid();  
  7. 07  inode->i_gid = current_fsgid();  
  8. 08  inode->i_mapping->a_ops = &ramfs_aops;  
  9. 09  inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;  
  10. 10  mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);  
  11. 11  mapping_set_unevictable(inode->i_mapping);  
  12. 12  inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;  
  13. 13  switch (mode & S_IFMT) {  
  14. 14  default:  
  15. 15   init_special_inode(inode, mode, dev);  
  16. 16   break;  
  17. 17  case S_IFREG:  
  18. 18   inode->i_op = &ramfs_file_inode_operations;  
  19. 19   inode->i_fop = &ramfs_file_operations;  
  20. 20   break;  
  21. 21  case S_IFDIR:  
  22. 22   inode->i_op = &ramfs_dir_inode_operations;  
  23. 23   inode->i_fop = &simple_dir_operations;  
  24. 24   /* directory inodes start off with i_nlink == 2 (for "." entry) */  
  25. 25   inc_nlink(inode);  
  26. 26   break;  
  27. 27  case S_IFLNK:  
  28. 28   inode->i_op = &page_symlink_inode_operations;  
  29. 29   break;  
  30. 30  }  
  31. 31 }  
  32. 32 return inode;  
  33. 33}  

第3行分配一個新的索引節點
第5行對索引節點的模式賦值
第6行對索引節點的所有者標識符字段賦值
第7行對索引節點的組標識符字段賦值
第10行對索引節點的指向address_space對象的方法賦值(後面會分析)
第11行對索引節點的指向address_space對象的設備信息賦值
第12行索引節點的上次訪問時間,上次寫時間,索引節點修改時間都賦值爲現在時間
第13行switch語句,用於多分支選擇,這裏面是選擇17行的代碼
第14行默認情況是使用init_special_inode函數,主要用字符設備,塊設備的索引節點
第18行索引節點的方法指向ramfs_file_inode_operations;
第19行索引節點的文件方法操作指向ramfs_file_operations。
第22行如果是文件夾操作,其方法指向ramfs_dir_inode_operations;
第23行其文件操作的方法也相應的指向simple_dir_operations;
第32行返回索引節點。

  1. 01struct dentry * d_alloc_root(struct inode * root_inode)  
  2. 02{  
  3. 03 struct dentry *res = NULL;  
  4. 04 if (root_inode) {  
  5. 05  static const struct qstr name = { .name = "/", .len = 1 };  
  6. 06  res = d_alloc(NULL, &name);  
  7. 07  if (res) {  
  8. 08   res->d_sb = root_inode->i_sb;  
  9. 09   res->d_parent = res;  
  10. 10   d_instantiate(res, root_inode);  
  11. 11  }  
  12. 12 }  
  13. 13 return res;  
  14. 14}  

第4行這裏面的root_inode爲真值
第5行對name結構體初始化
第6行分配一個dcache 目錄
第8行目錄項的超級塊指向指向索引節點的超級塊指針
第9行目錄項的父指針指向自己
第10填充索引節點信息爲根目錄。
其實,目錄項也可以當作目錄文件對待,但目錄項結構與inode結構所描述的目標是不同,目錄結構所代表的是邏輯意義上的文件,記錄的是其邏輯上的屬性。而inode結構所代表的是物理意義上的文件,記錄的是其物理上的屬性。

 

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