在前面 介绍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);
我们来看下mknod系统调用的实现
SYSCALL_DEFINE3(mknod, const char __user *, filename, int, mode, unsigned, dev) { return sys_mknodat(AT_FDCWD, filename, mode, dev); }
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("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("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));
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);//调用具体的mknod函数 if (!error) fsnotify_create(dir, dentry); return error; }
static struct file_system_type tmpfs_fs_type = { .owner = THIS_MODULE, .name = "tmpfs", .get_sb = shmem_get_sb, .kill_sb = kill_litter_super, };
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); }
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; /* Round up to L1_CACHE_BYTES to resist false sharing */ 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 /* * Per default we only allow half of the physical ram per * tmpfs instance, limiting inodes to one per page of lowmem; * but the internal instance is left unlimited. */ 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; }
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); /* Some things misbehave if size == 0 on a directory */ inode->i_size = 2 * BOGO_DIRENT_SIZE; inode->i_op = &shmem_dir_inode_operations; inode->i_fop = &simple_dir_operations; break; case S_IFLNK: /* * Must not load anything in the rbtree, * mpol_free_shared_policy will not be called. */ mpol_shared_policy_init(&info->policy, NULL); break; } } else shmem_free_inode(sb); return inode; }
case S_IFDIR: inc_nlink(inode); /* Some things misbehave if size == 0 on a directory */ inode->i_size = 2 * BOGO_DIRENT_SIZE; inode->i_op = &shmem_dir_inode_operations; inode->i_fop = &simple_dir_operations; break;