pipefsを追ってみる
パイプはモジュールロード時にpipefsと言うファイルシステム名で、カーネルに登録され同時にマウントされます。pipe_mnt変数にそのvfsmount構造体のポインターが設定されています。
pipefsにマウントできないこともありますが、パイプはファイルディスクリプターのみから操作するということで、ファイル名を有しないノードとして、pipefsファイルシステム下のroot下に作成されます。当然ですが親ディレクトリへの登録もいたしません。
static struct file_system_type pipe_fs_type = {
.name = "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);
パイプ作成は読み込み用と書き込み用の2つのファイルディスクリプターを取得しfile構造体を作成します。従ってinodeベースでの読み書きといえます。
int do_pipe_flags(int *fd, int flags)
{
fw = create_write_pipe(flags);
fr = create_read_pipe(fw, flags);
error = get_unused_fd_flags(flags);
error = get_unused_fd_flags(flags);
fd_install(fdr, fr);
fd_install(fdw, fw);
fd[0] = fdr;
fd[1] = fdw;
パイプinodeの作成は、書き込み用パイプ作成時に取得します。この時pipe_inode_info構造体を取得し、それをinode->i_pipeに設定しています。このpipe_inode_info構造体はパイプのデータバッファーとなります。パイプは実データブロックを有していないからです。pipefsにマウントできないこともありますが、パイプはファイルディスクリプターのみから操作するということで、ファイル名を有しないノードとして、pipefsファイルシステム下のroot下に作成されます。当然ですが親ディレクトリへの登録もいたしません。
struct file *create_write_pipe(int flags)
{
struct dentry *dentry;
struct qstr name = { .name = "" };
inode = get_pipe_inode();
if (!inode)
goto err;
err = -ENOMEM;
dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name);
dentry->d_op = &pipefs_dentry_operations;
f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipefifo_fops);
f->f_mapping = inode->i_mapping;
f->f_flags = O_WRONLY | (flags & O_NONBLOCK);
f->f_version = 0;
return f;
static struct inode * get_pipe_inode(void)
{
struct inode *inode = new_inode(pipe_mnt->mnt_sb);
struct pipe_inode_info *pipe;
pipe = alloc_pipe_info(inode);
inode->i_pipe = pipe;
inodeは書き込み用と読み込みようとで共有しています。読み込み用パイプのfileの構造体のf_pathメンバーとf_mappingメンバーに書き込みパイプ作成で取得したfile構造体の該当するメンバーを設定することにより、読み込み用file構造体を作成しています。
struct file *create_read_pipe(struct file *wrf, int flags)
{
f->f_path = wrf->f_path;
f->f_mapping = wrf->f_path.dentry->d_inode->i_mapping;
従って2つのファイルディスクリプターが操作するバッファは同じバッファということになります。読み込み用、書き込み用のファイルオペレーションはそれぞれのオペレーションが設定されており、たとえば読み込み用のファイルオペレーションの.writeにはエラーを返すbad_pipe_wというコールバック関数が設定されていて、読み込み用ファイルディスクリプターで書き込んでもエラーとなってしまいます。
static ssize_t
bad_pipe_w(struct file *filp, const char __user *buf, size_t count,
loff_t *ppos)
{
return -EBADF;
}
先にパイプはファイル名を有していないと言いましたが、/proc/pid/fd/下ではパイプの場合pipe:[2043]というファイル名で表示されます。[]の中の数値はinode番号です。これは実際のファイルでなくdentry_operationsの.d_dnameで設定されるpipefs_dnameコールバックで動的に作成されたものです。
static struct dentry_operations pipefs_dentry_operations = {
.d_delete = pipefs_delete_dentry,
.d_dname = pipefs_dname,
};
static char *pipefs_dname(struct dentry *dentry, char *buffer, int buflen)
{
return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]", dentry->d_inode->i_ino);
}
struct file *create_write_pipe(int flags)
{
...............
dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name);
if (!dentry)
goto err_inode;
dentry->d_op = &pipefs_dentry_operations;
...............
パイプはプロセス間で共有されたファイル構造体を、そのファイルディスクリプターで通してやり取りするものです。従ってファイル構造体を共有するプロセス形態、すなわちプロセスグループ間での通信手段と言えそうです。




