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