http://blog.csdn.net/new_abc/article/details/7694453
在前面 介绍android的init进程的时候,我们看到其中有如下代码 - mkdir("/dev", 0755);
- mkdir("/proc", 0755);
- mkdir("/sys", 0755);
-
- mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");
- mkdir("/dev/pts", 0755);
- mkdir("/dev/socket", 0755);
- mount("devpts", "/dev/pts", "devpts", 0, NULL);
- mount("proc", "/proc", "proc", 0, NULL);
- mount("sysfs", "/sys", "sysfs", 0, NULL);
在挂载完根文件系统后/dev , /proc...一般都是有的,这里主要是进行了挂载,注意这里挂载了tmpfs到/dev目录下面我们来看下mknod系统调用的实现 - SYSCALL_DEFINE3(mknod, const char __user *, filename, int, mode, unsigned, dev)
- {
- return sys_mknodat(AT_FDCWD, filename, mode, dev);
- }
直接调用sys_mknodat函数实现- SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode,
- unsigned, dev)
- {
- int error;
- char *tmp;
- struct dentry *dentry;
- struct nameidata nd;
-
- if (S_ISDIR(mode))
- return -EPERM;
- printk("filename = %s.\n", filename);
- printk("mode = 0x%x.\n", mode);
- error = user_path_parent(dfd, filename, &nd, &tmp);
- if (error)
- return error;
- printk("before lookup_create.\n");
- dentry = lookup_create(&nd, 0);
- printk("lijj after lookup_create.\n");
- if (IS_ERR(dentry)) {
- error = PTR_ERR(dentry);
- goto out_unlock;
- }
- if (!IS_POSIXACL(nd.path.dentry->d_inode))
- mode &= ~current_umask();
- error = may_mknod(mode);
- if (error)
- goto out_dput;
- error = mnt_want_write(nd.path.mnt);
- if (error)
- goto out_dput;
- error = security_path_mknod(&nd.path, dentry, mode, dev);
- if (error)
- goto out_drop_write;
- switch (mode & S_IFMT) {
- case 0: case S_IFREG:
- printk("lijj S_IFREG .\n");
- error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
- break;
- case S_IFCHR: case S_IFBLK:
- printk("S_IFCHR: case S_IFBLK.\n");
- error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,
- new_decode_dev(dev));
- break;
- case S_IFIFO: case S_IFSOCK:
- printk("S_IFIFO: case S_IFSOCK.\n");
- error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
- break;
- }
- out_drop_write:
- mnt_drop_write(nd.path.mnt);
- out_dput:
- dput(dentry);
- out_unlock:
- mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
- path_put(&nd.path);
- putname(tmp);
-
- return error;
- }
这里首先查找要创建文件路径的最后一项的父目录的目录项,然后建立要创建文件的目录项最后根据相应的类型调用相应的vfs函数,以字符设备为例,这里会调用- case S_IFCHR: case S_IFBLK:
- printk("S_IFCHR: case S_IFBLK.\n");
- error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,
- new_decode_dev(dev));
跟踪vfs_mknod- int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
- {
- int error = may_create(dir, dentry);
- printk(" vfs_mknod.\n");
- printk(" vfs_mknod.filesystem = %s.\n",dir->i_sb->s_type->name);
- if (error)
- return error;
-
- if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
- return -EPERM;
-
- if (!dir->i_op->mknod)
- return -EPERM;
-
- error = devcgroup_inode_mknod(mode, dev);
- if (error)
- return error;
-
- error = security_inode_mknod(dir, dentry, mode, dev);
- if (error)
- return error;
- printk(" before dir->i_op->mknod.\n");
- error = dir->i_op->mknod(dir, dentry, mode, dev);
- if (!error)
- fsnotify_create(dir, dentry);
- return error;
- }
在这里做一些检查之后,就调用相应文件系统的mknod函数了,前面我们知道/dev目录属于tmpfs文件系统,我们看在挂载tmpfs的时候,会调用它的get_sb函数- static struct file_system_type tmpfs_fs_type = {
- .owner = THIS_MODULE,
- .name = "tmpfs",
- .get_sb = shmem_get_sb,
- .kill_sb = kill_litter_super,
- };
这里对应shmem_get_sb- static int shmem_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, data, shmem_fill_super, mnt);
- }
对应的填充超级块的函数是shmem_fill_super- int shmem_fill_super(struct super_block *sb, void *data, int silent)
- {
- struct inode *inode;
- struct dentry *root;
- struct shmem_sb_info *sbinfo;
- int err = -ENOMEM;
-
-
- sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info),
- L1_CACHE_BYTES), GFP_KERNEL);
- if (!sbinfo)
- return -ENOMEM;
-
- sbinfo->mode = S_IRWXUGO | S_ISVTX;
- sbinfo->uid = current_fsuid();
- sbinfo->gid = current_fsgid();
- sb->s_fs_info = sbinfo;
-
- #ifdef CONFIG_TMPFS
-
-
-
-
-
- if (!(sb->s_flags & MS_NOUSER)) {
- sbinfo->max_blocks = shmem_default_max_blocks();
- sbinfo->max_inodes = shmem_default_max_inodes();
- if (shmem_parse_options(data, sbinfo, false)) {
- err = -EINVAL;
- goto failed;
- }
- }
- sb->s_export_op = &shmem_export_ops;
- #else
- sb->s_flags |= MS_NOUSER;
- #endif
-
- spin_lock_init(&sbinfo->stat_lock);
- sbinfo->free_blocks = sbinfo->max_blocks;
- sbinfo->free_inodes = sbinfo->max_inodes;
-
- sb->s_maxbytes = SHMEM_MAX_BYTES;
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
- sb->s_magic = TMPFS_MAGIC;
- sb->s_op = &shmem_ops;
- sb->s_time_gran = 1;
- #ifdef CONFIG_TMPFS_POSIX_ACL
- sb->s_xattr = shmem_xattr_handlers;
- sb->s_flags |= MS_POSIXACL;
- #endif
-
- inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
- if (!inode)
- goto failed;
- inode->i_uid = sbinfo->uid;
- inode->i_gid = sbinfo->gid;
- root = d_alloc_root(inode);
- if (!root)
- goto failed_iput;
- sb->s_root = root;
- return 0;
-
- failed_iput:
- iput(inode);
- failed:
- shmem_put_super(sb);
- return err;
- }
再来看一下shmem_get_inode,对应填充它的inode节点- static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,
- int mode, dev_t dev, unsigned long flags)
- {
- struct inode *inode;
- struct shmem_inode_info *info;
- struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
-
- if (shmem_reserve_inode(sb))
- return NULL;
-
- inode = new_inode(sb);
- if (inode) {
- inode_init_owner(inode, dir, mode);
- inode->i_blocks = 0;
- inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_generation = get_seconds();
- info = SHMEM_I(inode);
- memset(info, 0, (char *)inode - (char *)info);
- spin_lock_init(&info->lock);
- info->flags = flags & VM_NORESERVE;
- INIT_LIST_HEAD(&info->swaplist);
- cache_no_acl(inode);
-
- switch (mode & S_IFMT) {
- default:
- inode->i_op = &shmem_special_inode_operations;
- init_special_inode(inode, mode, dev);
- break;
- case S_IFREG:
- inode->i_mapping->a_ops = &shmem_aops;
- inode->i_op = &shmem_inode_operations;
- inode->i_fop = &shmem_file_operations;
- mpol_shared_policy_init(&info->policy,
- shmem_get_sbmpol(sbinfo));
- break;
- case S_IFDIR:
- inc_nlink(inode);
-
- inode->i_size = 2 * BOGO_DIRENT_SIZE;
- inode->i_op = &shmem_dir_inode_operations;
- inode->i_fop = &simple_dir_operations;
- break;
- case S_IFLNK:
-
-
-
-
- mpol_shared_policy_init(&info->policy, NULL);
- break;
- }
- } else
- shmem_free_inode(sb);
- return inode;
- }
当我们创建/dev目录时,这里对应- case S_IFDIR:
- inc_nlink(inode);
-
- inode->i_size = 2 * BOGO_DIRENT_SIZE;
- inode->i_op = &shmem_dir_inode_operations;
- inode->i_fop = &simple_dir_operations;
- break;
对应的i_op就是shmem_dir_inode_operations
|