mkfifo
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;
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
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はカーネルマターだけでなく、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してabcを書き込んでの読み込み [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エラー