ファイルシステム--mknodシステム呼び出し
前にandroidのinitプロセスを紹介したとき、次のコードがありました.
ルートファイルシステムをマウントした後/dev,/proc...一般的にはありますが、ここでは主にマウントが行われています.ここではtmpfsが/devディレクトリの下にマウントされていることに注意してください.
mknodシステム呼び出しの実装を見てみましょう
ダイレクトコールsys_mknodat関数実装
トレースvfs_mknod
ここでいくつかの検査をした後、対応するファイルシステムのmknod関数を呼び出しました.前に/devディレクトリがtmpfsファイルシステムに属していることを知っていました.tmpfsをマウントするとき、get_を呼び出します.sb関数
ここではshmem_に対応get_sb
対応するスーパーブロックを埋め込む関数はshmem_です.fill_super
もう一度shmem_を見てみましょうget_inode、それを埋め込むinodeノードに対応
/devディレクトリを作成すると、ここでは
対応するi_opはshmem_dir_inode_operations
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.
", filename);
printk("mode = 0x%x.
", mode);
error = user_path_parent(dfd, filename, &nd, &tmp);//
if (error)
return error;
printk("before lookup_create.
");
dentry = lookup_create(&nd, 0);//
printk("after lookup_create.
");
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 .
");
error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
break;
case S_IFCHR: case S_IFBLK:
printk("S_IFCHR: case S_IFBLK.
");
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.
");
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.
");
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.
");
printk(" vfs_mknod.filesystem = %s.
",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.
");
error = dir->i_op->mknod(dir, dentry, mode, dev);// mknod
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;
/* 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;
}
もう一度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);
/* 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;
}
/devディレクトリを作成すると、ここでは
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;
対応するi_opはshmem_dir_inode_operations