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;
}

補足

ファイルのオープンは、ファイル参照の属性及びバッファを有したstruct fileを取得し、このstruct fileを介してファイル毎に独立した参照を行います。fifoファイルも独自のstruct fileを取得しますが、掛かるバッファは共有され、又ファイルコールバックはpipeのそれとなり、実装はpipeその物であり、故に名前付きパイプと言われる所以です。


最終更新 2015/11/10 14:20:45 - north
(2015/11/10 14:20:45 作成)


検索

アクセス数
3023161
最近のコメント
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
Adsense
広告情報が設定されていません。