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でのファイル作成で有効な手段かとも思います。
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;
}

最終更新 2012/11/17 19:44:16 - north
(2012/11/17 19:44:16 作成)


検索

アクセス数
3689384
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。