mknodシステムコール
mknodシステムコールは、mknodatシステムコールのsys_mknodat()を、AT_FDCWDでコールします。
user_path_create()は、filenameのdentryを作成します。この時作成するパスが無いかチェックし、may_mknod()で、引数のmodeが設定されているかチェックします。
mnt_want_write()はファイルシステム自身の書き込み有無にかかるチェックです。OKならmnt->mnt_writers++とします。security_path_mknod()はLSM(セキュアLinux)のmkmodにかかるチェックです。
すべてがOKなら、通常ファイルはvfs_creat()、キャラクタ・ブロックデバイスファイルはvfs_mknod()、ソケットはvfs_mknod()をメジャ/マイナ番号を0でコールすることで、それぞれのファイルを作成します。
O_CREATEでopenシステムコールで作成するのと、S_IFREGのmkmodで作成の違いは、openシステムコーはFILEオペレーションコールバックのcreateが呼ばれますが、mknodシステムコールはinodeコールバックのそれがコールされる事です。たいていFILEオペレーションはinodeのそれが設定されます。また、セキュリテでのFILE操作にかかる処理をスキップするという相違が出て来るかと。(たぶん)
なお、プロセスに依存するFILEオブジェクト無しにファイルが作成できる事で、LKMでのファイル作成で有効な手段かとも思います。
CONFIG_EXT2_FS_XATTRは拡張ファイル属性です。設定されているなら、inode->i_opにかかるコールバックを設定しています。
user_path_create()は、filenameのdentryを作成します。この時作成するパスが無いかチェックし、may_mknod()で、引数のmodeが設定されているかチェックします。
mnt_want_write()はファイルシステム自身の書き込み有無にかかるチェックです。OKならmnt->mnt_writers++とします。security_path_mknod()はLSM(セキュアLinux)のmkmodにかかるチェックです。
すべてがOKなら、通常ファイルはvfs_creat()、キャラクタ・ブロックデバイスファイルはvfs_mknod()、ソケットはvfs_mknod()をメジャ/マイナ番号を0でコールすることで、それぞれのファイルを作成します。
O_CREATEでopenシステムコールで作成するのと、S_IFREGのmkmodで作成の違いは、openシステムコーはFILEオペレーションコールバックのcreateが呼ばれますが、mknodシステムコールはinodeコールバックのそれがコールされる事です。たいていFILEオペレーションはinodeのそれが設定されます。また、セキュリテでのFILE操作にかかる処理をスキップするという相違が出て来るかと。(たぶん)
なお、プロセスに依存するFILEオブジェクト無しにファイルが作成できる事で、LKMでのファイル作成で有効な手段かとも思います。
SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev)
{
return sys_mknodat(AT_FDCWD, filename, mode, dev);
}
SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
unsigned, dev)
{
struct dentry *dentry;
struct path path;
int error;
if (S_ISDIR(mode))
return -EPERM;
dentry = user_path_create(dfd, filename, &path, 0);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
if (!IS_POSIXACL(path.dentry->d_inode))
mode &= ~current_umask();
error = may_mknod(mode);
if (error)
goto out_dput;
error = mnt_want_write(path.mnt);
if (error)
goto out_dput;
error = security_path_mknod(&path, dentry, mode, dev);
if (error)
goto out_drop_write;
switch (mode & S_IFMT) {
case 0: case S_IFREG:
error = vfs_create(path.dentry->d_inode,dentry,mode,NULL);
break;
case S_IFCHR: case S_IFBLK:
error = vfs_mknod(path.dentry->d_inode,dentry,mode,
new_decode_dev(dev));
break;
case S_IFIFO: case S_IFSOCK:
error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
break;
}
out_drop_write:
mnt_drop_write(path.mnt);
out_dput:
dput(dentry);
mutex_unlock(&path.dentry->d_inode->i_mutex);
path_put(&path);
return error;
}
vfs_mknod()で、ケーパビリティ/コントロールグループ/セキュリティのmknodにかかるチェックを行った後、inodeコールバックのmknodをコールします。
int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
int error = may_create(dir, dentry);
if (error)
return error;
if ((S_ISCHR(mode) || S_ISBLK(mode)) &&
!ns_capable(inode_userns(dir), 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;
error = dir->i_op->mknod(dir, dentry, mode, dev);
if (!error)
fsnotify_create(dir, dentry);
return error;
}
ext2ファイルシステムでは、mknodコールバックはext2_mknod()がコールされ、作成するファイル応じたコールバック関数をinode->i_fopに設定し、キャラクタ/ブロックデバイスファイルなら、inode->i_rdevにデバイス番号を設定します。CONFIG_EXT2_FS_XATTRは拡張ファイル属性です。設定されているなら、inode->i_opにかかるコールバックを設定しています。
static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev)
{
struct inode * inode;
int err;
dquot_initialize(dir);
inode = ext2_new_inode (dir, mode, &dentry->d_name);
err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
init_special_inode(inode, inode->i_mode, rdev);
#ifdef CONFIG_EXT2_FS_XATTR
inode->i_op = &ext2_special_inode_operations;
#endif
mark_inode_dirty(inode);
err = ext2_add_nondir(dentry, inode);
}
return err;
}
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) {
inode->i_fop = &def_chr_fops;
inode->i_rdev = rdev;
} else if (S_ISBLK(mode)) {
inode->i_fop = &def_blk_fops;
inode->i_rdev = rdev;
} else if (S_ISFIFO(mode))
inode->i_fop = &def_fifo_fops;
else if (S_ISSOCK(mode))
inode->i_fop = &bad_sock_fops;
else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
" inode %s:%lu\n", mode, inode->i_sb->s_id,
inode->i_ino);
}
EXPORT_SYMBOL(init_special_inode);
ちなみに、vfs_create()は、inodeコールバックのcreateを呼び出します。
int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
struct nameidata *nd)
{
int error = may_create(dir, dentry);
if (error)
return error;
if (!dir->i_op->create)
return -EACCES; /* shouldn't it be ENOSYS? */
mode &= S_IALLUGO;
mode |= S_IFREG;
error = security_inode_create(dir, dentry, mode);
if (error)
return error;
error = dir->i_op->create(dir, dentry, mode, nd);
if (!error)
fsnotify_create(dir, dentry);
return error;
}





