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; <= ここ