FIFO


fifoはmodeフラグ=S_IFIFOでmknodシステムコールが呼ばれ、user_path_create()でFIFOファイルを作成し、inodeコールバック関数dir->i_op->mknodがコールされます。
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;
}

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;
}
ramfsのmknodコールバック関数です。ramfs_get_inode()でinodeを取得しますが、FIFOの時init_special_inode()がコールされ、def_fifo_fopsがinodeコールバックオペレーションに設定されます。inodeコールバック関数は、ファイルopen時FILEオペレーションコールバックとなります。
static int
ramfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
       struct inode * inode = ramfs_get_inode(dir->i_sb, dir, mode, dev);
       int error = -ENOSPC;

       if (inode) {
               d_instantiate(dentry, inode);
               dget(dentry);   /* Extra count - pin the dentry in core */
               error = 0;
               dir->i_mtime = dir->i_ctime = CURRENT_TIME;
       }
       return error;
}

struct inode *ramfs_get_inode(struct super_block *sb,
                               const struct inode *dir, umode_t mode, dev_t dev)
{
       struct inode * inode = new_inode(sb);

       if (inode) {
               inode->i_ino = get_next_ino();
               inode_init_owner(inode, dir, mode);
               inode->i_mapping->a_ops = &ramfs_aops;
               inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
               mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
               mapping_set_unevictable(inode->i_mapping);
               inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
               switch (mode & S_IFMT) {
               default:
                       init_special_inode(inode, mode, dev);
                       break;
               case S_IFREG:
                       inode->i_op = &ramfs_file_inode_operations;
                       inode->i_fop = &ramfs_file_operations;
                       break;
               case S_IFDIR:
                       inode->i_op = &ramfs_dir_inode_operations;
                       inode->i_fop = &simple_dir_operations;

                       /* directory inodes start off with i_nlink == 2 (for "." entry) */
                       inc_nlink(inode);
                       break;
               case S_IFLNK:
                       inode->i_op = &page_symlink_inode_operations;
                       break;
               }
       }
       return inode;
}

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);
}
def_fifo_fopsは.open/.llseekのみ有するコールバックです。読み書き用のコールバックは? 読み書き用のコールバックはファイルopen時、.openコールバックで再設定します。これはFIFOファイルopen時の属性によって処理内容が異なるからです。

FMODE_READの時read_pipefifo_fops、FMODE_WRITEの時write_pipefifo_fops、FMODE_READ | FMODE_WRITEの時rdwr_pipefifo_fopsとなります。従ってFIFOはpipeそのものと言うことで、名前つきpipeと言われる所以です。
const struct file_operations def_fifo_fops = {
       .open           = fifo_open,    /* will set read_ or write_pipefifo_fops */
       .llseek         = noop_llseek,
}

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)) {
                               /* suppress POLLHUP until we have
                                * seen a writer */
                               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;
}

loff_t noop_llseek(struct file *file, loff_t offset, int origin)
{
       return file->f_pos;
} 

最終更新 2014/03/31 17:01:56 - north
(2010/02/28 22:56:44 作成)


検索

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