mkfifo
Rev.1を表示中。最新版はこちら。
mkfifoコマンドは、modeをS_IFIFOでmknodシステムコールをコールし、vfs_mknod()でinodeをS_IFIFOとするデバイスファイルの様なファイルを作成する事にあります。引数devは、メジャ/マイナ番号でキャラクラ/ブロックデバイスファイル作成時の参照引数です。SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, unsigned, dev) { struct dentry *dentry; struct path path; int error; if (S_ISDIR(mode)) return -EPERM; dentry = user_path_create(dfd, filename, &path, 0); if (IS_ERR(dentry)) return PTR_ERR(dentry); if (!IS_POSIXACL(path.dentry->d_inode)) mode &= ~current_umask(); error = may_mknod(mode); if (error) goto out_dput; error = mnt_want_write(path.mnt); if (error) goto out_dput; error = security_path_mknod(&path, dentry, mode, dev); if (error) goto out_drop_write; switch (mode & S_IFMT) { case 0: case S_IFREG: error = vfs_create(path.dentry->d_inode,dentry,mode,NULL); break; case S_IFCHR: case S_IFBLK: error = vfs_mknod(path.dentry->d_inode,dentry,mode, new_decode_dev(dev)); break; case S_IFIFO: case S_IFSOCK: error = vfs_mknod(path.dentry->d_inode,dentry,mode,0); break; } out_drop_write: mnt_drop_write(path.mnt); out_dput: dput(dentry); mutex_unlock(&path.dentry->d_inode->i_mutex); path_put(&path); return error; } SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev) { return sys_mknodat(AT_FDCWD, filename, mode, dev); }ディレクトリinodeのmknodコールバックから、init_special_inode()でmodeに応じた属性のファイルシステムのinode(ファイル)が作成されます。
int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { int error = may_create(dir, dentry); if (error) return error; if ((S_ISCHR(mode) || S_ISBLK(mode)) && !ns_capable(inode_userns(dir), CAP_MKNOD)) return -EPERM; if (!dir->i_op->mknod) return -EPERM; error = devcgroup_inode_mknod(mode, dev); if (error) return error; error = security_inode_mknod(dir, dentry, mode, dev); if (error) return error; error = dir->i_op->mknod(dir, dentry, mode, dev); if (!error) fsnotify_create(dir, dentry); return error; } static int ext3_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev) { handle_t *handle; struct inode *inode; int err, retries = 0; if (!new_valid_dev(rdev)) return -EINVAL; dquot_initialize(dir); retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); if (IS_DIRSYNC(dir)) handle->h_sync = 1; inode = ext3_new_inode (handle, dir, &dentry->d_name, mode); err = PTR_ERR(inode); if (!IS_ERR(inode)) { init_special_inode(inode, inode->i_mode, rdev); #ifdef CONFIG_EXT3_FS_XATTR inode->i_op = &ext3_special_inode_operations; #endif err = ext3_add_nondir(handle, dentry, inode); } ext3_journal_stop(handle); if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) goto retry; return err; }inode作成時でmodeがFIFOなら、inodeコールバックはdef_fifo_fopsが設定され、このファイルオープン時、fifo_open()がコールされる事になります。
const struct file_operations def_fifo_fops = { .open = fifo_open, .llseek = noop_llseek, }; void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) { inode->i_mode = mode; if (S_ISCHR(mode)) { inode->i_fop = &def_chr_fops; inode->i_rdev = rdev; } else if (S_ISBLK(mode)) { inode->i_fop = &def_blk_fops; inode->i_rdev = rdev; } else if (S_ISFIFO(mode)) inode->i_fop = &def_fifo_fops; else if (S_ISSOCK(mode)) inode->i_fop = &bad_sock_fops; else printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for" " inode %s:%lu\n", mode, inode->i_sb->s_id, inode->i_ino); }新規オープンは、inode->i_pipe=NULLで、inode->i_pipe = pipeとし、そうでない場合のinodeはキャッシュ上のinodeを取得し、pipeのバッファとなるinode->i_pipeは共有されます。通常ファイルopenのfilp->f_opは、inode->i_fopが設定されるのですが、filp->f_modeのread/write/read-writeに応じてファイルコールバックがread_pipefifo_fops/write_pipefifo_fops/rdwr_pipefifo_fopsのpipeのコールバックが設定されます。
static int fifo_open(struct inode *inode, struct file *filp) { struct pipe_inode_info *pipe; int ret; mutex_lock(&inode->i_mutex); pipe = inode->i_pipe; if (!pipe) { ret = -ENOMEM; pipe = alloc_pipe_info(inode); if (!pipe) goto err_nocleanup; inode->i_pipe = pipe; } filp->f_version = 0; filp->f_mode &= (FMODE_READ | FMODE_WRITE); switch (filp->f_mode) { case FMODE_READ: filp->f_op = &read_pipefifo_fops; pipe->r_counter++; if (pipe->readers++ == 0) wake_up_partner(inode); if (!pipe->writers) { if ((filp->f_flags & O_NONBLOCK)) { filp->f_version = pipe->w_counter; } else { wait_for_partner(inode, &pipe->w_counter); if(signal_pending(current)) goto err_rd; } } break; case FMODE_WRITE: ret = -ENXIO; if ((filp->f_flags & O_NONBLOCK) && !pipe->readers) goto err; filp->f_op = &write_pipefifo_fops; pipe->w_counter++; if (!pipe->writers++) wake_up_partner(inode); if (!pipe->readers) { wait_for_partner(inode, &pipe->r_counter); if (signal_pending(current)) goto err_wr; } break; case FMODE_READ | FMODE_WRITE: filp->f_op = &rdwr_pipefifo_fops; pipe->readers++; pipe->writers++; pipe->r_counter++; pipe->w_counter++; if (pipe->readers == 1 || pipe->writers == 1) wake_up_partner(inode); break; default: ret = -EINVAL; goto err; } mutex_unlock(&inode->i_mutex); return 0; err_rd: if (!--pipe->readers) wake_up_interruptible(&pipe->wait); ret = -ERESTARTSYS; goto err; err_wr: if (!--pipe->writers) wake_up_interruptible(&pipe->wait); ret = -ERESTARTSYS; goto err; err: if (!pipe->readers && !pipe->writers) free_pipe_info(inode); err_nocleanup: mutex_unlock(&inode->i_mutex); return ret; }