Linux内核大讲堂 (三) 解不开的"/"情结

来源:互联网 发布:网络维护主要工作 编辑:程序博客网 时间:2024/04/29 00:08

Linux内核大讲堂 (解不开的"/"情结

最近比较忙,一直都没有抽时间写文章,还好没有事先和出版社签订协议,否则哥哥就没时间去跳舞,就没时间和朋友喝酒了,人生在世几十年,生活总才是最重要的。以失去生活为代价的学习,哥是不干的,哥是有追求的人。呵呵,扯远了,个人低下的人生观,让各位见笑了。

言归正传。前阵在BLOG中放了置顶的帖子做调查,很多同志都卡在文件系统上面,当年也卡过,后面是经过学习与思考之后,最终才搞清楚来龙去脉,其实文件系统要真正搞清楚我觉得要从两个方面着手。

一者,从上电启动后,文件系统到底是怎么一步一步挂载的?有位哥们说最首先挂载的是根文件系统?另一位哥们又问,那根文件系统又挂载在哪呢?最首先那个/到底是怎么来的呢?等等。反正啊,问完这一个又有另一个疑问,永远问不完的问题。

二者,虚拟文件系统与各种实际的文件系统的关系。这个又有很多同志开始问问题了。我们的硬盘上有没有文件系统呢?等等。

先告诉大家,你心中的疑惑十有八九全都在这一大节当中,看你能领会多少了。

我们首先来解决一个源始的问题,注意是源始,呵呵。就是开始,文件系统的头在哪?根源在哪?

话说我们上电以后,我们的CPU从一个固定的地址取下代码然后一步一步执行,经过千辛万苦,终于跑到了一个叫 start_kernel的地方,然后这个函数又调用了vfs_caches_init_early

fs/dcache.c

void __init vfs_caches_init_early(void)

{

dcache_init_early();

inode_init_early();

}

static void __init dcache_init_early(void)

{

int loop;

 

/* If hashes are distributed across NUMA nodes, defer

 * hash allocation until vmalloc space is available.

 */

if (hashdist)

return;

 

dentry_hashtable =

alloc_large_system_hash("Dentry cache",

sizeof(struct dcache_hash_bucket),

dhash_entries,

13,

HASH_EARLY,

&d_hash_shift,

&d_hash_mask,

0);

 

for (loop = 0; loop < (1 << d_hash_shift); loop++)

INIT_HLIST_BL_HEAD(&dentry_hashtable[loop].head);

}

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;

 

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]);

}

为了别把大家搞晕,这dcacheinode后面讲虚拟文件系统的时候再讲。这两个函数大概的意思就是整hash并初始化啦。要真正搞清楚,就得讲内存管理了,所以暂时先放他一马^_^

在分配了并初始化了这两张表后,我们的start_kernel又调用了vfs_caches_init()

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);

 

dcache_init();

inode_init();

files_init(mempages);

mnt_init();

bdev_cache_init();

chrdev_init();

}

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);

 

register_shrinker(&dcache_shrinker);

 

/* Hash may have been set up in dcache_init_early */

if (!hashdist)

return;

 

dentry_hashtable =

alloc_large_system_hash("Dentry cache",

sizeof(struct dcache_hash_bucket),

dhash_entries,

13,

0,

&d_hash_shift,

&d_hash_mask,

0);

 

for (loop = 0; loop < (1 << d_hash_shift); loop++)

INIT_HLIST_BL_HEAD(&dentry_hashtable[loop].head);

}

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);

register_shrinker(&icache_shrinker);

 

/* Hash may have been set up in inode_init_early */

if (!hashdist)

return;

 

inode_hashtable =

alloc_large_system_hash("Inode-cache",

sizeof(struct hlist_head),

ihash_entries,

14,

0,

&i_hash_shift,

&i_hash_mask,

0);

 

for (loop = 0; loop < (1 << i_hash_shift); loop++)

INIT_HLIST_HEAD(&inode_hashtable[loop]);

}

咦,打住,你前面在vfs_caches_init_early()中不是已经搞过两张表了吗?怎么这里又搞两张表,并且都指向同一个变量dentry_hashtableinode_hashtable

其实这里是只初始化一次的,原因就在于hashdist这个变量。

vfs_caches_init_early()vfs_caches_init()这两个函数中hashdist是一个取正,一个取反的。所以肯定有一个判断是真的并且返回。所以只可能初始化一次。

对于文件系统的理解vfs_caches_init_early()这个函数你完全可以当他不存在。

让我们继续回到dcache_init()函数中。

dentry_cache = KMEM_CACHE(dentry,

SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD);

register_shrinker(&dcache_shrinker);

这两行依然是和内存管理相关的,一个是叫缓存,一个是叫压缩机。很牛B也很唬人的两大概念。前者道上的哥们都知道缓存就是用来命中的,命中了,就不用往下跑了,自然速度就提上去了,后者压缩机是当你内存不够时,会由系统自动触发执行的。内存管理的东西不是本节的重点,这里先不讲了,想获得更多了解的同志可以看看alloc_page_buffers()这个函数。如果跟晕了就别怪我哦。呵呵。

接下来的inode_init()基本做了一样的操作,不浪费笔墨了。

接下来就是files_init(mempages)了。

void __init files_init(unsigned long mempages)

unsigned long n;

 

filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,

SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);

 

/*

 * 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 = max_t(unsigned long, n, NR_FILE);

files_defer_init();

lg_lock_init(files_lglock);

percpu_counter_init(&nr_files, 0);

}

这个传入的参数在vfs_caches_init()函数运行之初是有动过手脚的:

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

mempages -= reserve;

这个又是一个动态的小算法了,至于为什么是页面尺寸除以1024等这些细节, Linux内核的原版解释是:

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

           150% of current kernel size */

意思是说被保留的页面数等于当前已经被内核所占页面数的1.5倍,这绝对是个经验值。不用过份的追究。经过上面这么一算,mempages等于总的内存页面数减去内核占的页面数的2.5倍。接下来我们回到files_init()函数中,files_init()首先创建了一块名为filp_cachep的缓存,我顶他的肺,又是内存相关的,内存管理相关的东西无处不在啊。改天一定得好好教训教训他。接下来都是一些初始化的东西,可以先不过份追究。

接下来就是重量级的mnt_init()

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);

 

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);

 

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

INIT_LIST_HEAD(&mount_hashtable[u]);

 

br_lock_init(vfsmount_lock);

 

err = sysfs_init();

if (err)

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

__func__, err);

fs_kobj = kobject_create_and_add("fs", NULL);

if (!fs_kobj)

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

init_rootfs();

init_mount_tree();

}

在经过一些初始化之后我们又看到了一个老朋友sysfs_init()

太熟悉了,熟悉得不能再熟悉了,是你,让我能直观的感受了驱动模型,是你让我失去了一个做菜鸟的机会。这么好的朋友,我们没有道理不和他打个招呼。说不定老朋友会给我们意外的惊喜呢。以前老师告诉我们交朋友的话要交好朋友,不要和怪叔叔说话。^_^

int __init sysfs_init(void)

{

int err = -ENOMEM;

 

sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",

      sizeof(struct sysfs_dirent),

      0, 0, NULL);

if (!sysfs_dir_cachep)

goto out;

 

err = sysfs_inode_init();

if (err)

goto out_err;

 

err = register_filesystem(&sysfs_fs_type);

if (!err) {

sysfs_mnt = kern_mount(&sysfs_fs_type);

if (IS_ERR(sysfs_mnt)) {

printk(KERN_ERR "sysfs: could not mount!/n");

err = PTR_ERR(sysfs_mnt);

sysfs_mnt = NULL;

unregister_filesystem(&sysfs_fs_type);

goto out_err;

}

} else

goto out_err;

out:

return err;

out_err:

kmem_cache_destroy(sysfs_dir_cachep);

sysfs_dir_cachep = NULL;

goto out;

}

前面创建缓存的就不多说了,现在说也是白说,我们看看sysfs_inode_init()

int __init sysfs_inode_init(void)

{

return bdi_init(&sysfs_backing_dev_info);

}

static struct backing_dev_info sysfs_backing_dev_info = {

.name = "sysfs",

.ra_pages = 0, /* No readahead */

.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,

};

又出现了一个叫backing_dev_info,这个东西中文名叫后台设备信息。先买个关子,这可是一位大侠,这位大侠和雷峰叔叔一样伟大,傻傻的牺牲自已,帮助别人,只能说毛主席大人太会忽悠了,毛主席大人自已坐家里吃红烧肉,忽悠雷峰叔叔把自已不多的薪资全用来帮助别人,哎,什么世道。我们这位后台设备信息大人和雷峰叔叔是一样的,被文件系统这个高来高往的大人忽悠着干活。

static struct file_system_type sysfs_fs_type = {

.name = "sysfs",

.mount = sysfs_mount,

.kill_sb = sysfs_kill_sb,

};

register_filesystem(&sysfs_fs_type)

这个函数引入了一个重要的概念,那就是sruct file_system_type,这个东西叫文件系统对象,我们后面会讲到的,register_filesystem()会将传入的文件系统对象链入一个叫file_systems的全局文件系统对象链表中,当然,一个文件系统对象想两次链入到file_systems的话那就no way了。

接下来调用sysfs_mnt = kern_mount(&sysfs_fs_type);

 

#define kern_mount(type) kern_mount_data(type, NULL)

 

struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)

{

return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);

}

上面一直都是小打小闹,这回终于来了一个长点的函数。

struct vfsmount *

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

{

struct vfsmount *mnt;

struct dentry *root;

char *secdata = NULL;

int error;

 

if (!type)

return ERR_PTR(-ENODEV);

 

error = -ENOMEM;

mnt = alloc_vfsmnt(name);

if (!mnt)

goto out;

 

if (flags & MS_KERNMOUNT)

mnt->mnt_flags = MNT_INTERNAL;

 

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;

}

 

if (type->mount) {

root = type->mount(type, flags, name, data);

if (IS_ERR(root)) {

error = PTR_ERR(root);

goto out_free_secdata;

}

mnt->mnt_root = root;

mnt->mnt_sb = root->d_sb;

} else {

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

if (error < 0)

goto out_free_secdata;

}

BUG_ON(!mnt->mnt_sb);

WARN_ON(!mnt->mnt_sb->s_bdi);

WARN_ON(mnt->mnt_sb->s_bdi == &default_backing_dev_info);

mnt->mnt_sb->s_flags |= MS_BORN;

 

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

if (error)

goto out_sb;

 

/*

 * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE

 * but s_maxbytes was an unsigned long long for many releases. Throw

 * this warning for a little while to try and catch filesystems that

 * violate this rule. This warning should be either removed or

 * converted to a BUG() in 2.6.34.

 */

WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "

"negative value (%lld)/n", type->name, mnt->mnt_sb->s_maxbytes);

 

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);

deactivate_locked_super(mnt->mnt_sb);

out_free_secdata:

free_secdata(secdata);

out_mnt:

free_vfsmnt(mnt);

out:

return ERR_PTR(error);

}

首先调用了。alloc_vfsmnt()

struct vfsmount *alloc_vfsmnt(const char *name)

{

struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);

if (mnt) {

int err;

 

err = mnt_alloc_id(mnt);

if (err)

goto out_free_cache;

 

if (name) {

mnt->mnt_devname = kstrdup(name, GFP_KERNEL);

if (!mnt->mnt_devname)

goto out_free_id;

}

 

#ifdef CONFIG_SMP

mnt->mnt_pcp = alloc_percpu(struct mnt_pcp);

if (!mnt->mnt_pcp)

goto out_free_devname;

 

this_cpu_add(mnt->mnt_pcp->mnt_count, 1);

#else

mnt->mnt_count = 1;

mnt->mnt_writers = 0;

#endif

 

INIT_LIST_HEAD(&mnt->mnt_hash);

INIT_LIST_HEAD(&mnt->mnt_child);

INIT_LIST_HEAD(&mnt->mnt_mounts);

INIT_LIST_HEAD(&mnt->mnt_list);

INIT_LIST_HEAD(&mnt->mnt_expire);

INIT_LIST_HEAD(&mnt->mnt_share);

INIT_LIST_HEAD(&mnt->mnt_slave_list);

INIT_LIST_HEAD(&mnt->mnt_slave);

#ifdef CONFIG_FSNOTIFY

INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks);

#endif

}

return mnt;

 

#ifdef CONFIG_SMP

out_free_devname:

kfree(mnt->mnt_devname);

#endif

out_free_id:

mnt_free_id(mnt);

out_free_cache:

kmem_cache_free(mnt_cache, mnt);

return NULL;

}

可以看出这个函数纯粹是分配一块内存然后初始化,没别的。

如果name不等于NULL的话就执行:

mnt->mnt_devname = kstrdup(name, GFP_KERNEL);

就这一句最关键了。

OK,回到vfs_kern_mount()函数中。

接下来那一堆secxxx我们可以忽略不看,从字面上理解是和安全相关的,我这里对应的宏也关掉了,我也没有细看过,不发表言论。

接下来就到了:

if (type->mount) {

root = type->mount(type, flags, name, data);

if (IS_ERR(root)) {

error = PTR_ERR(root);

goto out_free_secdata;

}

mnt->mnt_root = root;

mnt->mnt_sb = root->d_sb;

}

我们回顾一下我传入的type的定义:

fs/sysfs/mount.c

static struct file_system_type sysfs_fs_type = {

.name = "sysfs",

.mount = sysfs_mount,

.kill_sb = sysfs_kill_sb,

};

很明显我们会进入sysfs_mount()中。

static struct dentry *sysfs_mount(struct file_system_type *fs_type,

int flags, const char *dev_name, void *data)

{

struct sysfs_super_info *info;

enum kobj_ns_type type;

struct super_block *sb;

int error;

 

info = kzalloc(sizeof(*info), GFP_KERNEL);

if (!info)

return ERR_PTR(-ENOMEM);

 

for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)

info->ns[type] = kobj_ns_current(type);

 

sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info);

if (IS_ERR(sb) || sb->s_fs_info != info)

kfree(info);

if (IS_ERR(sb))

return ERR_CAST(sb);

if (!sb->s_root) {

sb->s_flags = flags;

error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);

if (error) {

deactivate_locked_super(sb);

return ERR_PTR(error);

}

sb->s_flags |= MS_ACTIVE;

}

 

return dget(sb->s_root);

}

在经过一系列的处理后我们调用了sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info);

这个是得到一个超级块,超级块干嘛的我们后面再说。

接下来

if (!sb->s_root) {

sb->s_flags = flags;

error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);

if (error) {

deactivate_locked_super(sb);

return ERR_PTR(error);

}

sb->s_flags |= MS_ACTIVE;

}

 

static int sysfs_fill_super(struct super_block *sb, void *data, int silent)

{

struct inode *inode;

struct dentry *root;

 

sb->s_blocksize = PAGE_CACHE_SIZE;

sb->s_blocksize_bits = PAGE_CACHE_SHIFT;

sb->s_magic = SYSFS_MAGIC;

sb->s_op = &sysfs_ops;

sb->s_time_gran = 1;

 

/* get root inode, initialize and unlock it */

mutex_lock(&sysfs_mutex);

inode = sysfs_get_inode(sb, &sysfs_root);

mutex_unlock(&sysfs_mutex);

if (!inode) {

pr_debug("sysfs: could not get root inode/n");

return -ENOMEM;

}

 

/* instantiate and link root dentry */

root = d_alloc_root(inode);

if (!root) {

pr_debug("%s: could not get root dentry!/n",__func__);

iput(inode);

return -ENOMEM;

}

root->d_fsdata = &sysfs_root;

sb->s_root = root;

return 0;

}

首先:

struct inode *inode;

struct dentry *root;

 

sb->s_blocksize = PAGE_CACHE_SIZE;

sb->s_blocksize_bits = PAGE_CACHE_SHIFT;

sb->s_magic = SYSFS_MAGIC;

sb->s_op = &sysfs_ops;

sb->s_time_gran = 1;

这个没啥好说的,关键的就一个魔数和一个 sysfs_ops。另外块的设置就和内存的设置是一样的。sysfs_ops也没啥东西,都是“骗人”的。呵呵。

接下来就是inode = sysfs_get_inode(sb, &sysfs_root);

struct sysfs_dirent sysfs_root = {

.s_name = "",

.s_count = ATOMIC_INIT(1),

.s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT),

.s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,

.s_ino = 1,

};

struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd)

{

struct inode *inode;

 

inode = iget_locked(sb, sd->s_ino);

if (inode && (inode->i_state & I_NEW))

sysfs_init_inode(sd, inode);

 

return inode;

}

static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)

{

struct bin_attribute *bin_attr;

 

inode->i_private = sysfs_get(sd);

inode->i_mapping->a_ops = &sysfs_aops;

inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;

inode->i_op = &sysfs_inode_operations;

 

set_default_inode_attr(inode, sd->s_mode);

sysfs_refresh_inode(sd, inode);

 

/* initialize inode according to type */

switch (sysfs_type(sd)) {

case SYSFS_DIR:

inode->i_op = &sysfs_dir_inode_operations;

inode->i_fop = &sysfs_dir_operations;

break;

case SYSFS_KOBJ_ATTR:

inode->i_size = PAGE_SIZE;

inode->i_fop = &sysfs_file_operations;

break;

case SYSFS_KOBJ_BIN_ATTR:

bin_attr = sd->s_bin_attr.bin_attr;

inode->i_size = bin_attr->size;

inode->i_fop = &bin_fops;

break;

case SYSFS_KOBJ_LINK:

inode->i_op = &sysfs_symlink_inode_operations;

break;

default:

BUG();

}

 

unlock_new_inode(inode);

}

哇靠,sysfs值钱的东西全在这里。各种各样的对象操作集全在这里,我们这里就随便挑一个讲一下。

inode->i_fop = &sysfs_file_operations;

const struct file_operations sysfs_file_operations = {

.read = sysfs_read_file,

.write = sysfs_write_file,

.llseek = generic_file_llseek,

.open = sysfs_open_file,

.release = sysfs_release,

.poll = sysfs_poll,

};

static ssize_t

sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)

{

struct sysfs_buffer * buffer = file->private_data;

ssize_t retval = 0;

 

mutex_lock(&buffer->mutex);

if (buffer->needs_read_fill || *ppos == 0) {

retval = fill_read_buffer(file->f_path.dentry,buffer);

if (retval)

goto out;

}

pr_debug("%s: count = %zd, ppos = %lld, buf = %s/n",

 __func__, count, *ppos, buffer->page);

retval = simple_read_from_buffer(buf, count, ppos, buffer->page,

 buffer->count);

out:

mutex_unlock(&buffer->mutex);

return retval;

}

ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos,

const void *from, size_t available)

{

loff_t pos = *ppos;

size_t ret;

 

if (pos < 0)

return -EINVAL;

if (pos >= available || !count)

return 0;

if (count > available - pos)

count = available - pos;

ret = copy_to_user(to, from + pos, count);

if (ret == count)

return -EFAULT;

count -= ret;

*ppos = pos + count;

return count;

}

看到copy_to_user我想你一切都明白了。呵呵。

我们再回到sysfs_fill_super()函数中并往下走。

root = d_alloc_root(inode);

我的评价是:其貌不扬的一个函数。但就这个其貌不扬的函数中包含了我们本节的最终答案。

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;

d_set_d_op(res, res->d_sb->s_d_op);

res->d_parent = res;

d_instantiate(res, root_inode);

}

}

return res;

}

我们来分析一下:

static const struct qstr name = { .name = "/", .len = 1 };

/,伟大的/原来就在这里。

struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)

{

struct dentry *dentry;

char *dname;

 

dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);

if (!dentry)

return NULL;

 

if (name->len > DNAME_INLINE_LEN-1) {

dname = kmalloc(name->len + 1, GFP_KERNEL);

if (!dname) {

kmem_cache_free(dentry_cache, dentry); 

return NULL;

}

} else  {

dname = dentry->d_iname;

}

dentry->d_name.name = dname;

 

dentry->d_name.len = name->len;

dentry->d_name.hash = name->hash;

memcpy(dname, name->name, name->len);

dname[name->len] = 0;

 

dentry->d_count = 1;

dentry->d_flags = DCACHE_UNHASHED;

spin_lock_init(&dentry->d_lock);

seqcount_init(&dentry->d_seq);

dentry->d_inode = NULL;

dentry->d_parent = NULL;

dentry->d_sb = NULL;

dentry->d_op = NULL;

dentry->d_fsdata = NULL;

INIT_HLIST_BL_NODE(&dentry->d_hash);

INIT_LIST_HEAD(&dentry->d_lru);

INIT_LIST_HEAD(&dentry->d_subdirs);

INIT_LIST_HEAD(&dentry->d_alias);

INIT_LIST_HEAD(&dentry->d_u.d_child);

 

if (parent) {

spin_lock(&parent->d_lock);

/*

 * don't need child lock because it is not subject

 * to concurrency here

 */

__dget_dlock(parent);

dentry->d_parent = parent;

dentry->d_sb = parent->d_sb;

d_set_d_op(dentry, dentry->d_sb->s_d_op);

list_add(&dentry->d_u.d_child, &parent->d_subdirs);

spin_unlock(&parent->d_lock);

}

 

this_cpu_inc(nr_dentry);

 

return dentry;

}

这个不用多说了,我们之前的/就被放置在了dentry->d_iname中,最后函数返回了dentry的地址。

到这里我们的/终于有了,有了他,一切都变得美好了,你挂载文件系统的梦想也可以实现了。

别和我说我没有编译sysfs,但是我照样有"/",这是怎么回事呢?

你只要把眼光往下看一点,在接下来的代码中就可以找到答案了。

OK,本节先到这里,抽根烟,下节见。呵呵。^_^