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; ...............パイプはプロセス間で共有されたファイル構造体を、そのファイルディスクリプターで通してやり取りするものです。従ってファイル構造体を共有するプロセス形態、すなわちプロセスグループ間での通信手段と言えそうです。