pipefsを追ってみる
Rev.4を表示中。最新版はこちら。
- モジュールインストール時pipe_fs_typeをregister_filesystemでファイルシステムとして登録。
- kern_mountでvfsmount構造体を作成。そのポインタをスタティック変数pipe_mntにセット。(ただしEXPORTされてないためモジュールから参照できない。)
- pipefsはdo_add_mountでネームスペースに登録しない。(マウントする必要ないため。)
- スーパブロック取得コールバックpipefs_get_sbは、get_sb_pseudoをコール。処理はマウントされないスーパブロック情報を設定するヘルパー関数みたいなもの
fs/pipe.c
static struct file_system_type pipe_fs_type = {
.name = "pipefs", <= ファイルシステム名はpipefs
.get_sb = pipefs_get_sb,
.kill_sb = kill_anon_super,
};
static int __init init_pipe_fs(void)
{
int err = register_filesystem(&pipe_fs_type);
if (!err) {
pipe_mnt = kern_mount(&pipe_fs_type);
if (IS_ERR(pipe_mnt)) {
err = PTR_ERR(pipe_mnt);
unregister_filesystem(&pipe_fs_type);
}
}
return err;
}
補足mount処理はkern_mount,do_add_mount関数でファイルシステム上に現れます。(lsで見れる。)しかし、pipefsはその必要がないためvsfmountだけをシステム内に作成しています。ファイルシステム上には見えなくてものファイルシステムはカーネル内には存在することになります。
- pipeもpipe2も do_pipe_flagsを処理の主体。create_write_pipeで書き込み用のパイプ、create_read_pipeで読み込みようパイプ作成。
- get_unused_fd_flagsで未使用なファイルディスクリプターを2つ取得
- audit_fd_pairでtask_struct->audit_contextにこの2つのファイルディスクリプターをセット(理由不明)
- fd_installでfdtable構造体を作成してプロセス->files_struct->fdtableにパイプのfile構造体を結びつける。
- 呼び出し側に帰り値としてそのァイルディスクリプターをセットする。
int do_pipe_flags(int *fd, int flags)
{
struct file *fw, *fr;
int error;
int fdw, fdr;
if (flags & ~(O_CLOEXEC | O_NONBLOCK))
return -EINVAL;
fw = create_write_pipe(flags);
if (IS_ERR(fw))
return PTR_ERR(fw);
fr = create_read_pipe(fw, flags);
error = PTR_ERR(fr);
if (IS_ERR(fr))
goto err_write_pipe;
error = get_unused_fd_flags(flags);
if (error < 0)
goto err_read_pipe;
fdr = error;
error = get_unused_fd_flags(flags);
if (error < 0)
goto err_fdr;
fdw = error;
error = audit_fd_pair(fdr, fdw);
if (error < 0)
goto err_fdw;
fd_install(fdr, fr);
fd_install(fdw, fw);
fd[0] = fdr;
fd[1] = fdw;
return 0;
}
- get_pipe_inodeでパイプ用inodeを作成。(下記参照)
- d_allocでpipefsのvfsmountのs_rootでdentry作成、pipefs_dentry_operationsでdentryコールバックをセット
- pipefsのスーパブロック、dentry,およびinodeコールバックを引数にしてalloc_fileでfile構造体を作成。
struct file *create_write_pipe(int flags)
{
int err;
struct inode *inode;
struct file *f;
struct dentry *dentry;
struct qstr name = { .name = "" };
err = -ENFILE;
inode = get_pipe_inode();
if (!inode)
goto err;
err = -ENOMEM;
dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name);
if (!dentry)
goto err_inode;
dentry->d_op = &pipefs_dentry_operations;
dentry->d_flags &= ~DCACHE_UNHASHED;
d_instantiate(dentry, inode);
err = -ENFILE;
f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipefifo_fops);
if (!f)
goto err_dentry;
f->f_mapping = inode->i_mapping;
f->f_flags = O_WRONLY | (flags & O_NONBLOCK);
f->f_version = 0;
return f;
}
- inodeで設定できない属性をpipe_inode_infoで設定するためpipe_inode_infoでinodeを包んでいます。
static struct inode * get_pipe_inode(void)
{
struct inode *inode = new_inode(pipe_mnt->mnt_sb);
struct pipe_inode_info *pipe;
if (!inode)
goto fail_inode;
pipe = alloc_pipe_info(inode);
struct pipe_inode_info * alloc_pipe_info(struct inode *inode)
{
struct pipe_inode_info *pipe;
pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
if (pipe) {
init_waitqueue_head(&pipe->wait);
pipe->r_counter = pipe->w_counter = 1;
pipe->inode = inode; <= ここ






