pipefsを追ってみる


パイプはモジュールロード時にpipefsと言うファイルシステム名で、カーネルに登録され同時にマウントされます。pipe_mnt変数にそのvfsmount構造体のポインターが設定されています。
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;
...............
パイプはプロセス間で共有されたファイル構造体を、そのファイルディスクリプターで通してやり取りするものです。従ってファイル構造体を共有するプロセス形態、すなわちプロセスグループ間での通信手段と言えそうです。


最終更新 2010/03/01 00:03:49 - north
(2010/01/19 19:44:54 作成)


検索

アクセス数
2503880
最近のコメント
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。