mkfifo


Rev.4を表示中。最新版はこちら

fifoファイルのinode取得でinode->modeがfifo故にinode->i_fop=def_fifo_fop、ファイル取得でf->f_op = fops_get(inode->i_fop)、故にfifoファイルのopen()はdef_fifo_fopの.openのfifo_open()がコールされ、open()フラグに係るファイルオペレーションコールバック関数が設定される。

gccマターのfifoファイルのfopen()の引数のフラグ("r","w","r+")により、pipeファイルオペレーションコールバックとなり、故にファイル読書きは、pipeの読書きその物である。ただしrdwr_pipefifo_fopsはpipeには有していない。又pipeはfdの利用だが、fifoはfpでの利用も可能となる。

gccのファイルopen()のr,w,r+の文字列引数に係る引数で、カーネルマターは文字列でのフラグをサポートしていなく、故にgccマター
"r" ->#define O_RDONLY 00000000
"w" ->#define O_WRONLY 00000001
"r+" ->#define O_RDWR 00000002

引数のr,w,r+のfile->f_mode = modeとする属性で、係るファイルオペレーション
#define FMODE_READ ((__force fmode_t)0x1)
#define FMODE_WRITE ((__force fmode_t)0x2)

"r" :FMODE_READ :filp->f_op = &read_pipefifo_fops;
"w" :FMODE_WRITE :filp->f_op = &write_pipefifo_fops;
"r+":FMODE_READ | FMODE_WRITE:filp->f_op = &rdwr_pipefifo_fops;

const struct file_operations def_fifo_fops = {
    .open   = fifo_open,  
    .llseek = noop_llseek,
}    

int finish_open(struct file *file, struct dentry *dentry,
               int (*open)(struct inode *, struct file *),
               int *opened)
{
    int error;
    BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */

    file->f_path.dentry = dentry;
    error = do_dentry_open(file, open, current_cred());
    if (!error)
        *opened |= FILE_OPENED;

    return error;
}

static int do_dentry_open(struct file *f,
                         int (*open)(struct inode *, struct file *),
                         const struct cred *cred)
{
    static const struct file_operations empty_fops = {};
    struct inode *inode;
    int error;

    f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
                               FMODE_PREAD | FMODE_PWRITE;

    if (unlikely(f->f_flags & O_PATH))
               f->f_mode = FMODE_PATH;

    path_get(&f->f_path);
    inode = f->f_path.dentry->d_inode;
    if (f->f_mode & FMODE_WRITE) {
               error = __get_file_write_access(inode, f->f_path.mnt);
               if (error)
                       goto cleanup_file;
               if (!special_file(inode->i_mode))
                       file_take_write(f);
     }

    f->f_mapping = inode->i_mapping;
    f->f_pos = 0;
    file_sb_list_add(f, inode->i_sb);

    if (unlikely(f->f_mode & FMODE_PATH)) {
       f->f_op = &empty_fops;
               return 0;
     }

    f->f_op = fops_get(inode->i_fop);

    error = security_file_open(f, cred);
    if (error)
               goto cleanup_all;

    error = break_lease(inode, f->f_flags);
    if (error)
               goto cleanup_all;

    if (!open && f->f_op)
               open = f->f_op->open;
    if (open) {
    error = open(inode, f);
    if (error)
                       goto cleanup_all;
     }
    if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
               i_readcount_inc(inode);

    f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

    file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);

    return 0;

cleanup_all:
    fops_put(f->f_op);
    file_sb_list_del(f);
    if (f->f_mode & FMODE_WRITE) {
               put_write_access(inode);
               if (!special_file(inode->i_mode)) {
                       file_reset_write(f);
                       __mnt_drop_write(f->f_path.mnt);
              }
     }
cleanup_file:
    path_put(&f->f_path);
    f->f_path.mnt = NULL;
    f->f_path.dentry = NULL;
    return error;
}

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

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;

       /* We can only do regular read/write on fifos */
       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 {
                               if (wait_for_partner(inode, &pipe->w_counter))
                                       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) {
                       if (wait_for_partner(inode, &pipe->r_counter))
                               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;
}

サンプル

fopenでの読み書きは、バッファキャッシュでの最小サイズ4Kで実行され、FILE *fp内バッファに保存され、引数のサイズ長が引数バッファに設定される。従ってfread後に書き込みを行うと、カーネルのブロックインデックスは4kでのf_posとなっている故、lseekで先のfread読込みサイズ引数による位置にf_posを更新してFILE *fpにバッファリングしているデータキャッシュを書き込んだ後に読み込む。

fifoはpipeでlseekが実装されてないゆえ、従って、係る読み込み後に書き込みを行うと、lseek故の書き込みエラーとなる。fifoでread+writeはfpでなくfdでなくてならない。


fopenはカーネルマターだけでなく、gccマターにも依存し、fgets/fputsのファイルの読み書きサイズは、4Kでstruct FILE fpのバッファに登録され、fgetsはそのバッファから引数に係るサイズ分のデータを引数のバッファに設定する。

fgetsしてfputsしてfgetsすると、fputs後のfgets故に、fputsが4Kでなくても、係る書き込みデータをfgetsでの読み込みを考慮して、ブロックに書き込まれて後、読み込みされる。で、ブロックに書き込まれる時、fgetsの引数に係るポジションに書き込まむため、fgetsで引数に関わりなく4Kサイズを読み込んでいる故、lseekでファイルブロック位置をfgetsの引数に係るポジションに変更しての書き込みとなる。

fifoはlseekはサポートされていない故、係る操作はfputsしたデータをfgetsで書き込でのlseekのエラー故にfgetsエラーとなる。

fileのread/writeのポジションは共有

pipeのread/writeのポジションはstruct file f->f_posの実装でない
inode->i_pipe->nrbufs :読み込みデータ数
inode->i_pipe->curbuf :読み込み開始位置
inode->i_pipe->curbuf + inode->i_pipe->nrbufs :書き込み開始位置(概念)

サンプル

[root@localhost fifo]# cat file.c
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

void	file_fp_rw(void);
void	file_fd_rw(void);
void	mke_file(void);

void	fifo_fp_rw(int sel);
void	fifo_fd_rw(void);

char buf[400];
FILE *fp;
int  fd;

void	main(int argc, char* argv[])
{
    if (argc == 2) {
        if (!strcmp(argv[1], "file-fp-rw")) {
            file_fp_rw();
          }
        if (!strcmp(argv[1], "file-fd-rw")) {
            file_fd_rw();
          }
        if (!strcmp(argv[1], "fifo-fp-r")) {
            fifo_fp_rw(0);
          }
        if (!strcmp(argv[1], "fifo-fp-rw")) {
            fifo_fp_rw(1);
          }
        if (!strcmp(argv[1], "fifo-fd-rw")) {
            fifo_fd_rw();
          }
    }
}

void	file_fp_rw()
{
	mke_file();

	fp = fopen("aaa", "r+");
   if (fgets(buf, 5 + 1, fp) > 0) {
		printf("%s\n", buf);
	}

   fputs("abc", fp);

   if (fgets(buf, 5 + 1, fp) > 0) {
		printf("%s", buf);
	}
}

void	file_fd_rw()
{ 
	mke_file();

	fd = open("aaa", O_RDWR);
	int cnt = read(fd, buf, 5);
	buf[cnt] = 0;
	printf("%s\n", buf);

   write(fd, "abc", 3);

   cnt = read(fd, buf, 5);
	buf[cnt] = 0;
	printf("%s", buf);
}

void	mke_file()
{
	fp = fopen("aaa", "w+");
	fputs("1234567890\n", fp);
	fclose(fp);
}

void	fifo_fp_rw(int wr)
    {
    	int	ret;

    	fp = fopen("fifo", "w+");
    	fputs("123456789012345\n", fp);
    
        fgets(buf, 5 + 1, fp);
    	printf("%s\n", buf);
    
    	if (wr) {
    	    if (fputs("abcde", fp) < 0) {;
    			printf("fputs err\n");
    		}
    	}
    
        if (fgets(buf, 5 + 1, fp) > 0) {
    		printf("%s\n", buf);
    	}
    	else {
    		printf("fget err\n");
    	}
}

void	fifo_fd_rw()
{
    	fd = open("fifo", O_RDWR | O_CREAT);
    	write(fd, "1234567890\n", 10);

    	int cnt = read(fd, buf, 5);
    	buf[cnt] = 0;
    	printf("%s\n", buf);

        write(fd, "abc", 3);
        cnt = read(fd, buf, 5);
    	buf[cnt] = 0;
    	printf("%s\n", buf);

        cnt = read(fd, buf, 3);
    	buf[cnt] = 0;
    	printf("%s\n", buf);
    }
}

[root@localhost fifo]# ./file.out file-fd-rw
12345
90 <- writeのデータ書込み終端位置からの読込み
[root@localhost fifo]# cat aaa
12345abc90
[root@localhost fifo]# ./file.out file-fp-rw
12345
90 <- fgetsで4k読み込んでいるが、5バイト読み込んだポジションにlseekしての読み込み
[root@localhost fifo]# cat aaa
12345abc90

[root@localhost fifo]# ./file.out fifo-fd-rw
12345
67890
abc <- pipenの書き込みはデータ終端でpipe bufferは1234567890abc
[root@localhost fifo]# ./file.out fifo-fp-r
12345
67890
[root@localhost fifo]# ./file.out fifo-fp-rw
12345
fget err <- fgets前にfputsデータバッファ書込みで、4k読込んでいる故、5バイト読み込んだポジションのlseekエラー

最終更新 2018/01/09 13:51:21 - north
(2015/11/10 14:20:45 作成)


検索

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