分享

Linux虚拟文件系统(内核初始化<一>)

 clover_xian 2013-12-16
 Linux虚拟文件系统在内核初始化的start_kernel()函数中主要调用两个函数来实现。
  1. asmlinkage void __init start_kernel(void)  
  2. {  
  3.     ……  
  4.     vfs_caches_init_early();  
  5.     ……  
  6.     vfs_caches_init(totalram_pages);  
  7.     ……  
  8. }  

一、早期初始化

虚拟文件系统的早期初始化有函数vfs_caches_init_early()实现,主要负责dentryinodehashtable的初始化工作。

  1. /*在start_kernel中调用,用于文件系统中早期的初始化*/  
  2. void __init vfs_caches_init_early(void)  
  3. {  
  4.     /*初始化两个hashtable*/  
  5.     dcache_init_early();  
  6.     inode_init_early();  
  7. }  

1.1 dcache

  1. static void __init dcache_init_early(void)  
  2. {  
  3.     int loop;  
  4.   
  5.     /* If hashes are distributed across NUMA nodes, defer 
  6.      * hash allocation until vmalloc space is available. 
  7.      */  
  8.     if (hashdist)  
  9.         return;  
  10.     /*dentry hashtable的空间分配*/  
  11.     dentry_hashtable =  
  12.         alloc_large_system_hash("Dentry cache",  
  13.                     sizeof(struct hlist_head),  
  14.                     dhash_entries,  
  15.                     13,  
  16.                     HASH_EARLY,  
  17.                     &d_hash_shift,  
  18.                     &d_hash_mask,  
  19.                     0);  
  20.     /*hashtable的各个链表初始化*/  
  21.     for (loop = 0; loop < (1 << d_hash_shift); loop++)  
  22.         INIT_HLIST_HEAD(&dentry_hashtable[loop]);  
  23. }  

1.2  inode

  1. /* 
  2.  * Initialize the waitqueues and inode hash table. 
  3.  */  
  4. void __init inode_init_early(void)  
  5. {  
  6.     int loop;  
  7.   
  8.     /* If hashes are distributed across NUMA nodes, defer 
  9.      * hash allocation until vmalloc space is available. 
  10.      */  
  11.     if (hashdist)  
  12.         return;  
  13.     /*从cache中分配inode hashtable的内存空间*/  
  14.     inode_hashtable =  
  15.         alloc_large_system_hash("Inode-cache",  
  16.                     sizeof(struct hlist_head),  
  17.                     ihash_entries,  
  18.                     14,  
  19.                     HASH_EARLY,  
  20.                     &i_hash_shift,  
  21.                     &i_hash_mask,  
  22.                     0);  
  23.     /*初始化hashtable 的各个链表*/  
  24.     for (loop = 0; loop < (1 << i_hash_shift); loop++)  
  25.         INIT_HLIST_HEAD(&inode_hashtable[loop]);  
  26. }  

二、后期初始化

这阶段对inodedentrymount、字符设备驱动模型以及块设备驱动模型做了相应的初始化。

  1. /*vfs初始化,在start_kernel中调用*/  
  2. void __init vfs_caches_init(unsigned long mempages)  
  3. {  
  4.     unsigned long reserve;  
  5.   
  6.     /* Base hash sizes on available memory, with a reserve equal to 
  7.            150% of current kernel size */  
  8.   
  9.     reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);  
  10.     mempages -= reserve;  
  11.     /*为路径名申请的cache*/  
  12.     names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,  
  13.             SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);  
  14.     /*dentry及其相关内容初始化*/  
  15.     dcache_init();  
  16.     inode_init();/*inode初始化*/  
  17.     files_init(mempages);/*文件相关信息初始化,包括文件描述符表初始化*/  
  18.     mnt_init();/*mount 的初始化*/  
  19.     bdev_cache_init();  
  20.     /*字符设备驱动模型的初始化*/  
  21.     chrdev_init();  
  22. }  

2.1 dentry初始化

  1. static void __init dcache_init(void)  
  2. {  
  3.     int loop;  
  4.   
  5.     /*  
  6.      * A constructor could be added for stable state like the lists, 
  7.      * but it is probably not worth it because of the cache nature 
  8.      * of the dcache.  
  9.      *//*从cache中申请目录cache*/  
  10.     dentry_cache = KMEM_CACHE(dentry,  
  11.         SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD);  
  12.     /*注册一个shrinker*/  
  13.     register_shrinker(&dcache_shrinker);  
  14.   
  15.     /* Hash may have been set up in dcache_init_early */  
  16.     if (!hashdist)  
  17.         return;  
  18.     /*下面的操作在前面的初始化中已经做了*/  
  19.     dentry_hashtable =  
  20.         alloc_large_system_hash("Dentry cache",  
  21.                     sizeof(struct hlist_head),  
  22.                     dhash_entries,  
  23.                     13,  
  24.                     0,  
  25.                     &d_hash_shift,  
  26.                     &d_hash_mask,  
  27.                     0);  
  28.   
  29.     for (loop = 0; loop < (1 << d_hash_shift); loop++)  
  30.         INIT_HLIST_HEAD(&dentry_hashtable[loop]);  
  31. }  

2.2 inode初始化

  1. void __init inode_init(void)  
  2. {  
  3.     int loop;  
  4.   
  5.     /* inode slab cache */  
  6.     /*slab中分配inode缓存*/  
  7.     inode_cachep = kmem_cache_create("inode_cache",  
  8.                      sizeof(struct inode),  
  9.                      0,  
  10.                      (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|  
  11.                      SLAB_MEM_SPREAD),  
  12.                      init_once);  
  13.     /*注册icache shrinker,将参数对应的shrinker加入指定队列*/  
  14.     register_shrinker(&icache_shrinker);  
  15.   
  16.     /* Hash may have been set up in inode_init_early */  
  17.     if (!hashdist)  
  18.         return;  
  19.     /*分配数组对应空间*/  
  20.     inode_hashtable =  
  21.         alloc_large_system_hash("Inode-cache",  
  22.                     sizeof(struct hlist_head),  
  23.                     ihash_entries,  
  24.                     14,  
  25.                     0,  
  26.                     &i_hash_shift,  
  27.                     &i_hash_mask,  
  28.                     0);  
  29.     /*初始化链表组*/  
  30.     for (loop = 0; loop < (1 << i_hash_shift); loop++)  
  31.         INIT_HLIST_HEAD(&inode_hashtable[loop]);  
  32. }  

2.3 files初始化

  1. void __init files_init(unsigned long mempages)  
  2. {   
  3.     int n;   
  4.     /*申请文件cache*/  
  5.     filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,  
  6.             SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);  
  7.   
  8.     /* 
  9.      * One file with associated inode and dcache is very roughly 1K. 
  10.      * Per default don't use more than 10% of our memory for files.  
  11.      */   
  12.   
  13.     n = (mempages * (PAGE_SIZE / 1024)) / 10;  
  14.     files_stat.max_files = n; /*更新文件统计信息*/  
  15.     if (files_stat.max_files < NR_FILE)  
  16.         files_stat.max_files = NR_FILE;  
  17.     files_defer_init();/*释放文件描述符表*/  
  18.     percpu_counter_init(&nr_files, 0);  
  19. }   

2.4 mount初始化

  1. void __init mnt_init(void)  
  2. {  
  3.     unsigned u;  
  4.     int err;  
  5.   
  6.     init_rwsem(&namespace_sem);  
  7.     /*mnt cache初始化*/  
  8.     mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),  
  9.             0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);  
  10.     /*mount hashtable内存申请*/  
  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]);/*初始化hashtable链表*/  
  20.   
  21.     err = sysfs_init();/*sysfs文件系统初始化*/  
  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();/*初始化ramfs和rootfs*/  
  29.     init_mount_tree();/*初始化mount tree*/  
  30. }  
  1. static void __init init_mount_tree(void)  
  2. {  
  3.     struct vfsmount *mnt;  
  4.     struct mnt_namespace *ns;  
  5.     struct path root;  
  6.   
  7.     mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);  
  8.     if (IS_ERR(mnt))  
  9.         panic("Can't create rootfs");  
  10.     ns = create_mnt_ns(mnt);/*为mnt创建命名空间*/  
  11.     if (IS_ERR(ns))  
  12.         panic("Can't allocate initial namespace");  
  13.     /*初始化进程的相关命名空间*/  
  14.     init_task.nsproxy->mnt_ns = ns;  
  15.     get_mnt_ns(ns);/*命名空间的进程数加一*/  
  16.     /*更新root的相关字段*/  
  17.     root.mnt = ns->root;  
  18.     root.dentry = ns->root->mnt_root;  
  19.     /*设置fs的当前路径和当前root*/  
  20.     set_fs_pwd(current->fs, &root);  
  21.     set_fs_root(current->fs, &root);  
  22. }  

2.4.1 创建命名空间

  1. /** 
  2.  * create_mnt_ns - creates a private namespace and adds a root filesystem 
  3.  * @mnt: pointer to the new root filesystem mountpoint 
  4.  */  
  5. struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)  
  6. {  
  7.     struct mnt_namespace *new_ns;  
  8.   
  9.     new_ns = alloc_mnt_ns();/*分配命名空间*/  
  10.     if (!IS_ERR(new_ns)) {  
  11.         /*下面为和mnt建立关系*/  
  12.         mnt->mnt_ns = new_ns;  
  13.         new_ns->root = mnt;  
  14.         list_add(&new_ns->list, &new_ns->root->mnt_list);  
  15.     }  
  16.     return new_ns;  
  17. }  
  1. static struct mnt_namespace *alloc_mnt_ns(void)  
  2. {  
  3.     struct mnt_namespace *new_ns;  
  4.     /*从cache中分配命名空间*/     
  5.     new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);  
  6.     if (!new_ns)  
  7.         return ERR_PTR(-ENOMEM);  
  8.     /*下面为相关字段的初始化*/  
  9.     atomic_set(&new_ns->count, 1);  
  10.     new_ns->root = NULL;  
  11.     INIT_LIST_HEAD(&new_ns->list);  
  12.     init_waitqueue_head(&new_ns->poll);  
  13.     new_ns->event = 0;  
  14.     return new_ns;  
  15. }     

2.4.2 创建mount

  1. struct vfsmount *  
  2. do_kern_mount(const char *fstype, int flags, const char *name, void *data)  
  3. {  
  4.     struct file_system_type *type = get_fs_type(fstype);  
  5.     struct vfsmount *mnt;  
  6.     if (!type)  
  7.         return ERR_PTR(-ENODEV);  
  8.     mnt = vfs_kern_mount(type, flags, name, data);  
  9.     if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&  
  10.         !mnt->mnt_sb->s_subtype)  
  11.         mnt = fs_set_subtype(mnt, fstype);  
  12.     put_filesystem(type);  
  13.     return mnt;  
  14. }  
  1. <pre class="cpp" name="code">struct vfsmount *  
  2. vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)  
  3. {  
  4.     struct vfsmount *mnt;  
  5.     char *secdata = NULL;  
  6.     int error;  
  7.   
  8.     if (!type)  
  9.         return ERR_PTR(-ENODEV);  
  10.   
  11.     error = -ENOMEM;  
  12.     /*从slab中分配一个mnt*/  
  13.     mnt = alloc_vfsmnt(name);  
  14.     if (!mnt)  
  15.         goto out;  
  16.   
  17.     if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {  
  18.         secdata = alloc_secdata();  
  19.         if (!secdata)  
  20.             goto out_mnt;  
  21.   
  22.         error = security_sb_copy_data(data, secdata);  
  23.         if (error)  
  24.             goto out_free_secdata;  
  25.     }  
  26.     /*调用文件系统控制结构体的get_sb(),分配并初始化一个 
  27.     新的超级块并初始化mnt->mnt_sb字段*/  
  28.     error = type->get_sb(type, flags, name, data, mnt);  
  29.     if (error < 0)  
  30.         goto out_free_secdata;  
  31.     BUG_ON(!mnt->mnt_sb);  
  32.   
  33.     error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);  
  34.     if (error)  
  35.         goto out_sb;  
  36.   
  37.     /* 
  38.      * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE 
  39.      * but s_maxbytes was an unsigned long long for many releases. Throw 
  40.      * this warning for a little while to try and catch filesystems that 
  41.      * violate this rule. This warning should be either removed or 
  42.      * converted to a BUG() in 2.6.34. 
  43.      */  
  44.     WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "  
  45.         "negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes);  
  46.     /*初始化mnt相关字段*/  
  47.     mnt->mnt_mountpoint = mnt->mnt_root;  
  48.     mnt->mnt_parent = mnt;  
  49.     up_write(&mnt->mnt_sb->s_umount);  
  50.     free_secdata(secdata);  
  51.     return mnt;/*返回mnt*/  
  52. out_sb:  
  53.     dput(mnt->mnt_root);  
  54.     deactivate_locked_super(mnt->mnt_sb);  
  55. out_free_secdata:  
  56.     free_secdata(secdata);  
  57. out_mnt:  
  58.     free_vfsmnt(mnt);  
  59. out:  
  60.     return ERR_PTR(error);  
  61. }  
  62. </pre>  
  63. <pre></pre>  
  64. <strong><span style="font-size:18px"><span style="color:#ff9900"></span></span></strong><pre class="cpp" name="code">struct vfsmount *alloc_vfsmnt(const char *name)  
  65. {  
  66.     /*从slab中获得mnt*/  
  67.     struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);  
  68.     /*下面进行对mnt的初始化*/  
  69.     if (mnt) {  
  70.         int err;  
  71.   
  72.         err = mnt_alloc_id(mnt);  
  73.         if (err)  
  74.             goto out_free_cache;  
  75.   
  76.         if (name) {  
  77.             mnt->mnt_devname = kstrdup(name, GFP_KERNEL);  
  78.             if (!mnt->mnt_devname)  
  79.                 goto out_free_id;  
  80.         }  
  81.   
  82.         atomic_set(&mnt->mnt_count, 1);  
  83.         INIT_LIST_HEAD(&mnt->mnt_hash);  
  84.         INIT_LIST_HEAD(&mnt->mnt_child);  
  85.         INIT_LIST_HEAD(&mnt->mnt_mounts);  
  86.         INIT_LIST_HEAD(&mnt->mnt_list);  
  87.         INIT_LIST_HEAD(&mnt->mnt_expire);  
  88.         INIT_LIST_HEAD(&mnt->mnt_share);  
  89.         INIT_LIST_HEAD(&mnt->mnt_slave_list);  
  90.         INIT_LIST_HEAD(&mnt->mnt_slave);  
  91. #ifdef CONFIG_SMP  
  92.         mnt->mnt_writers = alloc_percpu(int);  
  93.         if (!mnt->mnt_writers)  
  94.             goto out_free_devname;  
  95. #else  
  96.         mnt->mnt_writers = 0;  
  97. #endif  
  98.     }  
  99.     return mnt;  
  100.   
  101. #ifdef CONFIG_SMP  
  102. out_free_devname:  
  103.     kfree(mnt->mnt_devname);  
  104. #endif  
  105. out_free_id:  
  106.     mnt_free_id(mnt);  
  107. out_free_cache:  
  108.     kmem_cache_free(mnt_cache, mnt);  
  109.     return NULL;  
  110. }  
  111.   
  112. </pre>  
  113. <p><strong><span style="font-size:18px"><span style="color:#ff9900">2.5 <span style="font-family:宋体">块设备驱动模型初始化</span></span></span></strong></p>  
  114. <pre class="cpp" name="code">void __init bdev_cache_init(void)  
  115. {  
  116.     int err;  
  117.     struct vfsmount *bd_mnt;  
  118.     /*block cache初始化*/  
  119.     bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),  
  120.             0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|  
  121.                 SLAB_MEM_SPREAD|SLAB_PANIC),  
  122.             init_once);  
  123.     /*注册block dev*/  
  124.     err = register_filesystem(&bd_type);  
  125.     if (err)  
  126.         panic("Cannot register bdev pseudo-fs");  
  127.     bd_mnt = kern_mount(&bd_type);  
  128.     if (IS_ERR(bd_mnt))  
  129.         panic("Cannot create bdev pseudo-fs");  
  130.     /* 
  131.      * This vfsmount structure is only used to obtain the 
  132.      * blockdev_superblock, so tell kmemleak not to report it. 
  133.      */  
  134.     kmemleak_not_leak(bd_mnt);  
  135.     blockdev_superblock = bd_mnt->mnt_sb;    /* For writeback */  
  136. }</pre>  
  137. <p><strong><span style="font-size:18px"><span style="color:#ff9900">2.6 <span style="font-family:宋体">字符设备驱动模型初始化</span></span></span></strong></p>  
  138. <pre class="cpp" name="code">void __init chrdev_init(void)  
  139. {  
  140.     cdev_map = kobj_map_init(base_probe, &chrdevs_lock);  
  141.     /*字符设备驱动初始化*/  
  142.     bdi_init(&directly_mappable_cdev_bdi);  
  143. }</pre>  
  144. <p><span style="font-size:18px">这里对<span style="font-family:Times New Roman">linux</span><span style="font-family:宋体">虚拟文件系统的初始化工作做了整体的梳理,后面将对涉及到的细节做补充,包括</span><span style="font-family:Times New Roman">inode</span><span style="font-family:宋体">和</span><span style="font-family:Times New Roman">dentry cache shrinker</span><span style="font-family:宋体">的注册、</span><span style="font-family:Times New Roman">sysfs</span><span style="font-family:宋体">的初始化等。</span></span></p>  
  145. <pre></pre>  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多