Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1069135
  • 博文数量: 277
  • 博客积分: 8313
  • 博客等级: 中将
  • 技术积分: 2976
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-22 11:25
文章分类

全部博文(277)

文章存档

2013年(17)

2012年(66)

2011年(104)

2010年(90)

我的朋友

分类: LINUX

2011-07-10 22:52:06

/*
** arm、linux2.6.29
** 该文件不是内核中的文件,只是为了方便分析单独从 linux2.6 ramfs机制解析 中提取出来
** 主要分析的是start_kernel()函数中的vfs_caches_init_early()和vfs_caches_init(num_physpages)
** 他们实现了rootfs的初始化
*/
asmlinkage void __init start_kernel(void)
{
    ...
    vfs_caches_init_early();                    // note 1
    ...
    vfs_caches_init(num_physpages);        // note 2
    ...
}

/** note 1 **/
void __init vfs_caches_init_early(void)
{
    dcache_init_early();                            // 对目录项哈希表进行早期的初始化 note 1-1
    inode_init_early();                                // 对文件节点哈希表进行早期初始化 note 1-2
}

/**** note 1-1 ****/
// fs/dcache.c
static void __init dcache_init_early(void)
{
    int loop;

    /* If hashes are distributed across NUMA nodes, defer
     * hash allocation until vmalloc space is available.
     * 如果hashes需要布局(NUMA),那么就需要在vmalloc空间有效之后再分配hash
     */
    if (hashdist)        // note 1-1-1
        return;
    /* 返回hash表头地址
     * hash table 名字是Dentry cache
     * 哈希表入口项数目numentries值2的对数,保存到d_hash_shif变量。
   * d_hash_mask保存入口项的掩码。
    */
    dentry_hashtable =    // dentry_hashtable是fs/dcache.c中的全局变量  // note 1-1-2
        alloc_large_system_hash("Dentry cache",
                    sizeof(struct hlist_head),
                    dhash_entries,    // note 1-1-3
                    13,
                    HASH_EARLY,
                    &d_hash_shift,
                    &d_hash_mask,
                    0);
    // 对哈希表的每项的链表头进行初始化,->NULL
    for (loop = 0; loop < (1 << d_hash_shift); loop++)
        INIT_HLIST_HEAD(&dentry_hashtable[loop]);
}

/****** note 1-1-1 ******/
// hashdist的历史
// include/linux/bootmem.h
...
/* Only NUMA needs hash distribution.
     只有NUMA才需要hash布局
 * IA64 and x86_64 have sufficient vmalloc space.
      IA64和x86_64拥有充足的vamalloc空间
 */
#if defined(CONFIG_NUMA) && (defined(CONFIG_IA64) || defined(CONFIG_X86_64))
#define HASHDIST_DEFAULT 1
#else
#define HASHDIST_DEFAULT 0
#endif
...
// mm/page_allloc.c定义了hashdist
int hashdist = HASHDIST_DEFAULT;
/*
该值可以采用默认值HASHDIST_DEFAULT,也可以通过cmdline来传递,hashdist=
*/
// page_alloc.c
#ifdef CONFIG_NUMA
static int __init set_hashdist(char *str)
{
    if (!str)
        return 0;
    hashdist = simple_strtoul(str, &str, 0);
    return 1;
}
__setup("hashdist=", set_hashdist);
#endif
/****** note 1-1-1 ******/

/****** note 1-1-2 ******/
// fs/dcache.c z中的静态变量
static struct hlist_head *dentry_hashtable __read_mostly;
// include/liunx/list.h
struct hlist_head {
    struct hlist_node *first;
};
struct hlist_node {
    struct hlist_node *next, **pprev;
};
/****** note 1-1-2 ******/

/****** note 1-1-3 ******/
static __initdata unsigned long dhash_entries;
static int __init set_dhash_entries(char *str)
{
    if (!str)
        return 0;
    dhash_entries = simple_strtoul(str, &str, 0);
    return 1;
}
__setup("dhash_entries=", set_dhash_entries);
/*
这个dhash_entries变量表示目录项哈希表入口数目,默认为0。
可以通过命令行传递参数dhash_entries= 0xxx来指定。
*/
/****** note 1-1-3 ******/
/**** note 1-1 ****/

/**** note 1-2 ****/
// fs/inode.c
static __initdata unsigned long ihash_entries;
static int __init set_ihash_entries(char *str)
{
    if (!str)
        return 0;
    ihash_entries = simple_strtoul(str, &str, 0);
    return 1;
}
__setup("ihash_entries=", set_ihash_entries);

void __init inode_init_early(void)
{
    int loop;

    /* If hashes are distributed across NUMA nodes, defer
     * hash allocation until vmalloc space is available.
     */
    if (hashdist)
        return;
    // alloc_large_system_hash()  // note 1-2-1
    inode_hashtable =
        alloc_large_system_hash("Inode-cache",
                    sizeof(struct hlist_head),
                    ihash_entries,
                    14,
                    HASH_EARLY,
                    &i_hash_shift,
                    &i_hash_mask,
                    0);

    for (loop = 0; loop < (1 << i_hash_shift); loop++)
        INIT_HLIST_HEAD(&inode_hashtable[loop]);
    // #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
}
// 与对目录项哈希表早期初始化类似,只不过这里是对文件节点inode哈希表初始化
// 该hash的入口项可以通过cmdline参数传递进来,ihash_entries=

/****** note 1-2-1 ******/
/*
参数含义:
tablename         哈希表名字
bucketsize        这个是每个元素的大小
numentries        哈希表入口数,可以取0,或者由cmdline中传入。这时可能即使你给了值,系统也会把它变为最接
                                    近的2的幂
scale                取值有 13、14、15、17 之类的,如果numentries不为0,这个参数没有作用。
lags              可取HASH_EARLY或0,分配内存的地方根据这个有不同
_hash_shift            用于返回元素个数的以2为底的对数,也就是表示元素个数这个数值所用的比特数
_hash_mask        用于返回*_hash_shift个比特所能表示的最大数-1
limit                哈希表表元数上限,不是分配内存的总尺寸,不要弄混了。
                  如果给个0值,那么系统使用1/16内存所能容纳的元素数作为哈希表表元数。    

参数numentries和limit有关系的,参数numentries的值不能超出limit的值
*/
// 下面函数注释中的所有数据均代表创建Inode-cache时所用的数据,所传参数如下:
// ("Inode-cache", 4, 0, 14, HASH_EARLY, &i_hash_shift, &i_hash_mask, 0)
void *__init alloc_large_system_hash(const char *tablename,
                     unsigned long bucketsize,
                     unsigned long numentries,
                     int scale,
                     int flags,
                     unsigned int *_hash_shift,
                     unsigned int *_hash_mask,
                     unsigned long limit)
{
    unsigned long long max = limit;
    unsigned long log2qty, size;
    void *table = NULL;

    /* allow the kernel cmdline to have a say */
    // 如果传递进来的参数numentries==0,进入if体内执行
    if (!numentries) {
        /* round applicable memory size up to nearest megabyte */
        /*
         这个nr_kernel_pages 变量在free_area_init_core() 函数中赋值,
         表示不包含高端内存的系统内存共有的内存页面数。
         PAGE_SHIFT=12
         计算不包含高端内存的系统内存共有多少MB(不足1MB,以1MB 计算)。
        */
        numentries = nr_kernel_pages;
        numentries += (1UL << (20 - PAGE_SHIFT)) - 1;   // +上1MB中包含的页数
        numentries >>= 20 - PAGE_SHIFT;                                    // 向上对1MB取整
        //取得不足1MB,以1MB计算后的页面数目
        numentries <<= 20 - PAGE_SHIFT;

        /* limit to 1 bucket per 2^scale bytes of low memory */
        // scale = 14 对numentries进行缩放
        if (scale > PAGE_SHIFT)
            numentries >>= (scale - PAGE_SHIFT);                    // numentries >> 2
        else
            numentries <<= (PAGE_SHIFT - scale);

        /* Make sure we've got at least a 0-order allocation.. */
        // 如果numentries个hash入口所占空间不足一个页面的空间,以一个页面的空间来计算出numentries
        if (unlikely((numentries * bucketsize) < PAGE_SIZE))
            numentries = PAGE_SIZE / bucketsize;
    }
    // 向上取最接近目前numentries的2的幂次方的值给numentries
    numentries = roundup_pow_of_two(numentries);

    /* limit allocation size to 1/16 total memory by default */
    //这个max等于limit,如果等于0,就计算numentries的最大值max 
    if (max == 0) {
        /*
        这个nr_all_pages 变量表示所有内存的页面,即哈希表的内存最大为整个内存的1/16的空间。
        */
        max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4;
        //do_div()宏, 使max除以bucketsize,并把结果赋值给max变量
        do_div(max, bucketsize);
    }
    // 变量numentries不能够大于max变量,即哈希表的入口不能够大于max变量
    if (numentries > max)
        numentries = max;

    log2qty = ilog2(numentries);  //对numentries取2的对数

    do {
        size = bucketsize << log2qty;    /*取得要分配空间的大小*/
        if (flags & HASH_EARLY)
            // 当flags为HASH_EARLY标志时,表示内核没有启动完毕,使用启动内存分配器来分配空间
            table = alloc_bootmem_nopanic(size);
        else if (hashdist)
            // 如果hashdist不等于0 ,从vmalloc空间分配内存
            table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL);
        else {
            // 下面的在系统启动完毕后,从buddy内存管理器上分配页面
            unsigned long order = get_order(size);
            table = (void*) __get_free_pages(GFP_ATOMIC, order);
            /*
             * If bucketsize is not a power-of-two, we may free
             * some pages at the end of hash table.
             */
            if (table) {
                unsigned long alloc_end = (unsigned long)table +
                        (PAGE_SIZE << order);
                unsigned long used = (unsigned long)table +
                        PAGE_ALIGN(size);
                split_page(virt_to_page(table), order);
                while (used < alloc_end) {
                    free_page(used);
                    used += PAGE_SIZE;
                }
            }
        }
    } while (!table && size > PAGE_SIZE && --log2qty);

    if (!table)    /* 如果table等于NULL,表示没有足够的空间来进行分配 */
        panic("Failed to allocate %s hash table/n", tablename);

    printk(KERN_INFO "%s hash table entries: %d (order: %d, %lu bytes)/n",
           tablename,
           (1U << log2qty),
           ilog2(size) - PAGE_SHIFT,
           size);
// 返回哈希表入口项数目numentries值2的对数
    if (_hash_shift)
        *_hash_shift = log2qty;
    if (_hash_mask)
        *_hash_mask = (1 << log2qty) - 1;

    return table;            // 返回哈希表入口地址
}

/****** note 1-2-1 ******/

/**** note 1-2 ****/

/*
struct hlist_head {
    struct hlist_node *first;
};

struct hlist_node {
    struct hlist_node *next, **pprev;
};
总结:
    inode_hashtable就是一数组,每个数组元素都是一个struct hlist_head结构体,该结构体实际上就只有一个
指向struct hlist_node对象的指针first,所有指针在arm体系上都是4字节,所以这个函数实际上只是为数组
inode_hashtable分配了一段内存空间,该数组是实际上就是一个指针数组,每个元素都是指向struct hlist_node
对象的指针。然后最后将这些指针全部置成NULL。至于后续怎么使用还没涉及到。
    同样对于Dentry cache哈希表(dentry_hashtable)也是一样的,只是创建了一个指针数组而已。
    参考:http://qgjie456.blog.163.com/blog/static/3545136720081126102615685/
*/
/** note 1 **/

++++++++++++++++++++++++++++++++  vfs_caches_init(num_physpages)  +++++++++++++++++++++
/** note 2 **/
// fs/dcache.c
// 注意:该版本代码是2.6.29 ,和2.6.14的代码该处关于内存分配器有一些差别,就像前文说的,2.6.29引入了
// slub分配器,而2.6.14还是使用的slab,但是接口被保留,实现的功能一样。以下还是以slab称呼
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);
    // 创建slab高速缓存组names_cache,其中缓存的结构体对象大小是PATH_MAX = 4096
    // 这里与2.6.14版本不同的是,filp高速缓存组没有被创建。
    // 返回描述该高速缓存的一个结构体指针names_cachep

    dcache_init();        // slab高速缓存组创建,注册dcache页面回收函数 note 2-1
    inode_init();            // slab高速缓存组创建,注册icache页面回收函数 note 2-2
    files_init(mempages); // note 2-3
    mnt_init();                        /* 重要函数,挂载rootfs文件系统 */ // note 2-4
    bdev_cache_init();
    chrdev_init();
}

/**** note 2-1 ****/
static void __init dcache_init(void)
{
    int loop;

    /* 
     * A constructor could be added for stable state like the lists,
     * but it is probably not worth it because of the cache nature
     * of the dcache. 
     */
    dentry_cache = KMEM_CACHE(dentry,
        SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD);
    /*
        static struct kmem_cache *dentry_cache __read_mostly;
        #define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,/
                sizeof(struct __struct), __alignof__(struct __struct),/
                (__flags), NULL)
                
        可以看出,这里是创建了一个名字为dentry的slab高速缓存组,由指针dentry_cache指向的结构体描述
    */
    
    register_shrinker(&dcache_shrinker);
    // 注册dcache页面回收函数shrink_dcache_memory,由页面回收算法(PFRA)来执行

    /* Hash may have been set up in dcache_init_early */
    if (!hashdist)
        return;

...    // 该部分的工作在dcache_init_early中完成
}
/**** note 2-1 ****/

/**** note 2-2 ****/
void __init inode_init(void)
{
    int loop;

    /* inode slab cache */
    inode_cachep = kmem_cache_create("inode_cache",
                     sizeof(struct inode),
                     0,
                     (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
                     SLAB_MEM_SPREAD),
                     init_once);
    // 创建了一个名字为inode_cache的slab高速缓存组,由指针inode_cachep指向的结构体描述
    register_shrinker(&icache_shrinker);
    // 注册icache页面回收函数shrink_icache_memory,由页面回收算法(PFRA)来执行

    /* Hash may have been set up in inode_init_early */
    if (!hashdist)
        return;
...    // 该部分的工作在icache_init_early中完成
}
/**** note 2-2 ****/

/**** note 2-3 ****/
void __init files_init(unsigned long mempages)

    int n; 

    filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
            SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
            // 创建名为filp的slab高速缓存组,格式化成struct file,由指针filp_cachep指向的结构体描述该高缓

    /*
     * One file with associated inode and dcache is very roughly 1K.
     * Per default don't use more than 10% of our memory for files. 
     */ 

    n = (mempages * (PAGE_SIZE / 1024)) / 10;
    files_stat.max_files = n; 
    if (files_stat.max_files < NR_FILE)
        files_stat.max_files = NR_FILE;
    files_defer_init();                                        // 这两个函数做什么用的,暂时不管
    percpu_counter_init(&nr_files, 0);

/**** note 2-3 ****/

/**** note 2-4 ****/
void __init mnt_init(void)
{
    unsigned u;
    int err;

    init_rwsem(&namespace_sem);

    mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),
            0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
    // 创建名为mnt_cache的slab高速缓存,格式化成struct vfsmount,由指针mnt_cache指向的结构体描述

    mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
    // 必须分配到一页物理内存

    if (!mount_hashtable)
        panic("Failed to allocate mount hash table/n");

    printk("Mount-cache hash table entries: %lu/n", HASH_SIZE);
    // HASH_SIZE = 512
    for (u = 0; u < HASH_SIZE; u++)
        INIT_LIST_HEAD(&mount_hashtable[u]);
    // 初始化next和prev均指向其自身
    
    err = sysfs_init();    /* sysfs文件系统注册 in fs/sysfs/mount.c*/
    if (err)
        printk(KERN_WARNING "%s: sysfs_init error: %d/n",
            __func__, err);
    fs_kobj = kobject_create_and_add("fs", NULL);
    // 在sysfs目录下创建fs目录,主要是创建名为fs的kobject及相关初始化
    if (!fs_kobj)
        printk(KERN_WARNING "%s: kobj create error/n", __func__);
    init_rootfs();    /* rootfs文件系统注册 in fs/ramfs/inode.c*/
    init_mount_tree();/* 为VFS建立根目录 "/" */   // note 2-4-1
    /* 挂载rootfs文件系统。它的挂载点默认为"/",最后切换进程的根目录和当前目录为"/" */
}

/**** note 2-4 ****/
/****** note 2-4-1 init_mount_tree()******/
static void __init init_mount_tree(void)
{
    struct vfsmount *mnt;
    struct mnt_namespace *ns;
    struct path root;

    mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);    // note 2-4-1-1
    /* 重要函数 挂载前面已经注册进内核的rootfs文件系统*/
    if (IS_ERR(mnt))
        panic("Can't create rootfs");
    ns = kmalloc(sizeof(*ns), GFP_KERNEL);
    if (!ns)
        panic("Can't allocate initial namespace");
    atomic_set(&ns->count, 1);
    // 设置引用计数
    INIT_LIST_HEAD(&ns->list);
    init_waitqueue_head(&ns->poll);
    ns->event = 0;
    list_add(&mnt->mnt_list, &ns->list);
    // 将该vfsmount结构体挂接到namespace结构体的链表中
    ns->root = mnt;
    // 该命名空间的root目录为刚刚建立的vfsmount结构体
    mnt->mnt_ns = ns;
    // 该vfsmount结构体的命名空间为ns

    init_task.nsproxy->mnt_ns = ns;
    get_mnt_ns(ns);
    /* 
        init_mount_tree() 函数会为系统最开始的进程(即 init_task 进程)
        准备它的进程数据块中的namespace 域,主要目的是将 do_kern_mount()
        函数中建立的 mnt 和 dentry 信息记录在了 init_task 进程的进程数据块中,
        这样所有以后从 init_task 进程 fork 出来的进程也都先天地继承了这一信息
    */

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

    set_fs_pwd(current->fs, &root);
    set_fs_root(current->fs, &root);
    /*
    最后两行便是将 do_kern_mount() 函数中建立的 mnt 和 dentry 信息记录在了当前进程的 fs结构中
    */
}
/******** note 2-4-1-1 do_kern_mount() ********/
struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{
    struct file_system_type *type = get_fs_type(fstype);    // 获取全局链表file_system中名为fstype的文件系统
                                                                                                                // 结构体指针
    struct vfsmount *mnt;
    
    if (!type)
        return ERR_PTR(-ENODEV);
    mnt = vfs_kern_mount(type, flags, name, data);                // note 2-4-1-1-1
            // 重要函数
    if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
        !mnt->mnt_sb->s_subtype)
        mnt = fs_set_subtype(mnt, fstype);
    put_filesystem(type);        // wake_up_process()
    return mnt;
}

/********** note 2-4-1-1-1 vfs_kern_mount() **********/
struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
    struct vfsmount *mnt;
    char *secdata = NULL;
    int error;

    if (!type)
        return ERR_PTR(-ENODEV);        // 参数验证

    error = -ENOMEM;
    mnt = alloc_vfsmnt(name);
    /*在slab高速缓存组mnt_cache中分配一个vfsmount对象,并对其进行初始化*/
    if (!mnt)
        goto out;

    if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
        secdata = alloc_secdata();
        if (!secdata)
            goto out_mnt;

        error = security_sb_copy_data(data, secdata);
        if (error)
            goto out_free_secdata;
    }

    error = type->get_sb(type, flags, name, data, mnt);    // note 2-4-1-1-1-1 ,以rootfs为例
    /* 文件系统超级块的回调函数 */
    /* rootfs_get_sb
    一般的伪文件系统或叫内存文件系统分配超级块都是调用get_sb_nodev()或者
    get_sb_single(); 而实际文件系统如磁盘文件系统,在分配超级块的时候则调
    用get_sb_bdev()需要在具体块设备上建立超级块。
    因为rootfs是内存文件系统所以调用get_sb_nodev();
    */
    if (error < 0)
        goto out_free_secdata;
    BUG_ON(!mnt->mnt_sb);

     error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);    
     if (error)
         goto out_sb;

    mnt->mnt_mountpoint = mnt->mnt_root;    //指明挂载点,其实就是刚才建立的”/”目录
    mnt->mnt_parent = mnt;                                //父对象是自己
    up_write(&mnt->mnt_sb->s_umount);
    free_secdata(secdata);
    return mnt;
out_sb:
    dput(mnt->mnt_root);
    up_write(&mnt->mnt_sb->s_umount);
    deactivate_super(mnt->mnt_sb);
out_free_secdata:
    free_secdata(secdata);
out_mnt:
    free_vfsmnt(mnt);
out:
    return ERR_PTR(error);
}
/************ note 2-4-1-1-1-1 超级块回调函数 ************/
// rootfs文件系统的超级块回调函数是rootfs_get_sb()
static int rootfs_get_sb(struct file_system_type *fs_type,
    int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
    return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,
                mnt);    // note 2-4-1-1-1-1-1
}
// ramfs_fill_super()是超级块填充函数
/************** note 2-4-1-1-1-1-1 get_sb_nodev() **************/
int get_sb_nodev(struct file_system_type *fs_type,
    int flags, void *data,
    int (*fill_super)(struct super_block *, void *, int),
    struct vfsmount *mnt)
{
    int error;
    struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
    /* 在内存中分配一个超级块,并做相应初始化*/
    // set_anon_super为回调函数
    if (IS_ERR(s))
        return PTR_ERR(s);

    s->s_flags = flags;      // flags = MS_NOUSER

    error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);    // note 2-4-1-1-1-1-1-1
    // 执行填充超级块的回调函数 ramfs_fill_super
    if (error) {
        up_write(&s->s_umount);
        deactivate_super(s);
        return error;
    }
    s->s_flags |= MS_ACTIVE;
    return simple_set_mnt(mnt, s);    /* 超级块和文件系统挂载结构体简单关联 */
                                                                    // mnt->mnt_sb = sb;
                                                                    // mnt->mnt_root = dget(sb->s_root);
}
/**************** note 2-4-1-1-1-1-1-1 fill_super = ramfs_fill_super() ****************/
static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
{
    struct inode * inode;
    struct dentry * root;

    sb->s_maxbytes = MAX_LFS_FILESIZE;    /* 文件的最大值 */
    sb->s_blocksize = PAGE_CACHE_SIZE;    /* 以字节为单位的块的大小 */
    sb->s_blocksize_bits = PAGE_CACHE_SHIFT;    /* 以位为单位的块的大小 */
    sb->s_magic = RAMFS_MAGIC;    /* 文件系统的魔数 0x858458f6 */
    sb->s_op = &ramfs_ops;            /* 超级块的方法 ,在处理inode的时候会有用 */
    sb->s_time_gran = 1;
    inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);/* 建立根目录索引节点 */ // note 2-4-1-1-1-1-1-1-1
    if (!inode)
        return -ENOMEM;

    root = d_alloc_root(inode);/* 建立根目录目录对象,并关联上inode */ // note 2-4-1-1-1-1-1-1-2
    if (!root) {
        iput(inode);
        return -ENOMEM;
    }
    sb->s_root = root;                /* 超级块的s_root指向刚建立的根目录对象 */
    return 0;
}
/****************** note 2-4-1-1-1-1-1-1-1 ramfs_get_inode() ******************/
struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
{
    struct inode * inode = new_inode(sb);
    /* 在索引节点高速缓存inode_cachep中创建一个inode, 并初始化话相应的域*/

    if (inode) {
        inode->i_mode = mode;/* 文件的类型 */
        inode->i_uid = current->fsuid;
        inode->i_gid = current->fsgid;
        inode->i_blksize = PAGE_CACHE_SIZE;
        inode->i_blocks = 0;//文件的块数
        inode->i_mapping->a_ops = &ramfs_aops;
        inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        switch (mode & S_IFMT) {//判断文件类型
        default:
            init_special_inode(inode, mode, dev);
            //特殊文件;如:字符~块设备文件,FIFO,SOCKET文件
            break;
        case S_IFREG://普通文件
            inode->i_op = &ramfs_file_inode_operations;//索引节点的操作方法
            inode->i_fop = &ramfs_file_operations;// 缺省普通文件的操作方法
            break;
        case S_IFDIR:// 目录文件
            inode->i_op = &ramfs_dir_inode_operations;
            inode->i_fop = &simple_dir_operations; // 目录文件的操作方法

            /* directory inodes start off with i_nlink == 2 (for "." entry) */
            inode->i_nlink++;
            break;
        case S_IFLNK: //符号链接
            inode->i_op = &page_symlink_inode_operations;
            break;
        }
    }
    return inode;             //返回创建的inode与对应的目录项对象关联
}
/****************** note 2-4-1-1-1-1-1-1-1 ramfs_get_inode() ******************/
/****************** note 2-4-1-1-1-1-1-1-2 d_alloc_root() ******************/
struct dentry * d_alloc_root(struct inode * root_inode)
{
    struct dentry *res = NULL;

    if (root_inode) {
        static const struct qstr name = { .name = "/", .len = 1 };
        /* 看到根目录的符号了吧 */
        res = d_alloc(NULL, &name);
        if (res) {
            res->d_sb = root_inode->i_sb;    //指向该文件系统的超级块
            res->d_parent = res;                    //根目录的父亲当然是它自己了
            d_instantiate(res, root_inode); // note 2-4-1-1-1-1-1-1-2-1
            //将dentry 和 inode关联上
        }
    }
    return res;
}

/******************** note 2-4-1-1-1-1-1-1-2-1 d_instantiate() ********************/
void d_instantiate(struct dentry *entry, struct inode * inode)
{
    if (!list_empty(&entry->d_alias)) BUG();
    //一个目录项对象只能关联一个索引节点
    spin_lock(&dcache_lock);
    if (inode)
        list_add(&entry->d_alias, &inode->i_dentry);
        //一个索引节点可以关联多个目录项对象
    entry->d_inode = inode;
    spin_unlock(&dcache_lock);
    security_d_instantiate(entry, inode);
}
/******************** note 2-4-1-1-1-1-1-1-2-1 d_instantiate() ********************/

/****************** note 2-4-1-1-1-1-1-1-2 d_alloc_root() ******************/

/**************** note 2-4-1-1-1-1-1-1 fill_super = ramfs_fill_super() ****************/



/************** note 2-4-1-1-1-1-1 get_sb_nodev() **************/

/************ note 2-4-1-1-1-1 超级块回调函数 ************/

/********** note 2-4-1-1-1 vfs_kern_mount() **********/


/******** note 2-4-1-1 do_kern_mount() ********/
/****** note 2-4-1 init_mount_tree()******/

/** note 2 **/
阅读(774) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~