mkfifo
Rev.3を表示中。最新版はこちら。
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エラー






