pipeバッファ数の更新
Rev.8を表示中。最新版はこちら。
バージョンのgccとカーネルマター故の実装fcntl.h fcntl()が定義されているがF_SETPIPE_SZが定義されていない。
linux/fcntl.h F_SETPIPE_SZが定義されているがfcntl()が定義されていない。
サンプル
[root@localhost v.north]# cat set-psize.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <linux/fcntl.h>
/*
#include <fcntl.h>
#define F_LINUX_SPECIFIC_BASE 1024
#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
*/
#define PAGE_SIZE 4096
void allbuff_write(int pfd);
void main(int argc, char *argv[])
{
int i, res, psize, pfd[2];
psize = atoi(argv[1]);
pipe2(pfd, O_NONBLOCK);
if (!psize) {
allbuff_write(pfd[1]);
}
if (psize > 0) {
res = fcntl(pfd[1], F_SETPIPE_SZ, psize);
printf(" setsize:%d\n", res);
allbuff_write(pfd[1]);
}
if (psize < 0) {
for (i = 0; i < PAGE_SIZE + 1; i++) {
write(pfd[1], "1", 1);
}
res = fcntl(pfd[1], F_SETPIPE_SZ, 1);
if (res < 0) {
printf(" not update pipe-size because do not write data into new aloc buff\n");
}
}
}
void allbuff_write(int pfd)
{
int cnt, tcnt=0;
while(1) {
cnt = write(pfd, "1", 1);
if(cnt <= 0) {
break;
}
tcnt += cnt;
}
printf(" writed size:%d writed page=%d\n", tcnt, tcnt/PAGE_SIZE);
}
[root@localhost v.north]# ./set-psize.out 0 <=デフォルトpipeのサイズ/page数 writed size:65536 writed page=16 [root@localhost v.north]# ./set-psize.out 10 <=pipeサイズをPAGE_SIZE単位での更新 setsize:4096 writed size:4096 writed page=1 [root@localhost v.north]# ./set-psize.out 4096 setsize:4096 writed size:4096 writed page=1 [root@localhost v.north]# ./set-psize.out 4097 setsize:8192 writed size:8192 writed page=2CAP_SYS_RESOURCEでないならpipe_max_size[1048576]を超える更新はできない
[north@localhost v.north]$ ./set-psize.out 1048577 setsize:-1 writed size:65536 writed page=16 [north@localhost v.north]$ su [root@localhost v.north]# [root@localhost v.north]# ./set-psize.out 1048577 setsize:2097152 writed size:2097152 writed page=512 [root@localhost v.north]# ./set-psize.out -1 <=2PAGE_SIZE利用時の1PAGE_SIZEバッファ変更は、バッファデータを複写できない故、変更できない not update pipe-size because do not write data into new aloc buff
カーネル
unsigned int pipe_max_size = 1048576;
static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
struct file *filp)
{
long err = -EINVAL;
switch (cmd) {
case F_DUPFD:
err = f_dupfd(arg, filp, 0);
break;
case F_DUPFD_CLOEXEC:
err = f_dupfd(arg, filp, O_CLOEXEC);
break;
case F_GETFD:
err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
break;
case F_SETFD:
err = 0;
set_close_on_exec(fd, arg & FD_CLOEXEC);
break;
case F_GETFL:
err = filp->f_flags;
break;
case F_SETFL:
err = setfl(fd, filp, arg);
break;
case F_GETLK:
err = fcntl_getlk(filp, (struct flock __user *) arg);
break;
case F_SETLK:
case F_SETLKW:
err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg);
break;
case F_GETOWN:
err = f_getown(filp);
force_successful_syscall_return();
break;
case F_SETOWN:
err = f_setown(filp, arg, 1);
break;
case F_GETOWN_EX:
err = f_getown_ex(filp, arg);
break;
case F_SETOWN_EX:
err = f_setown_ex(filp, arg);
break;
case F_GETOWNER_UIDS:
err = f_getowner_uids(filp, arg);
break;
case F_GETSIG:
err = filp->f_owner.signum;
break;
case F_SETSIG:
if (!valid_signal(arg)) {
break;
}
err = 0;
filp->f_owner.signum = arg;
break;
case F_GETLEASE:
err = fcntl_getlease(filp);
break;
case F_SETLEASE:
err = fcntl_setlease(fd, filp, arg);
break;
case F_NOTIFY:
err = fcntl_dirnotify(fd, filp, arg);
break;
case F_SETPIPE_SZ:
case F_GETPIPE_SZ:
err = pipe_fcntl(filp, cmd, arg);
break;
default:
break;
}
return err;
}
long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct pipe_inode_info *pipe;
long ret;
pipe = get_pipe_info(file);
if (!pipe)
return -EBADF;
mutex_lock(&pipe->inode->i_mutex);
switch (cmd) {
case F_SETPIPE_SZ: {
unsigned int size, nr_pages;
size = round_pipe_size(arg);
nr_pages = size >> PAGE_SHIFT;
ret = -EINVAL;
if (!nr_pages)
goto out;
if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) {
ret = -EPERM;
goto out;
}
ret = pipe_set_size(pipe, nr_pages);
break;
}
case F_GETPIPE_SZ:
ret = pipe->buffers * PAGE_SIZE;
break;
default:
ret = -EINVAL;
break;
}
out:
mutex_unlock(&pipe->inode->i_mutex);
return ret;
}
pipe->buffers ---->バッファの総数pipe->curbuf ---->読込み開始pageインデックス
pipe->nrbufs ---->読込まれていないpage数
end-position = pipe->curbuf + pipe->nrbufs ---->複写するバッファの終端pageインデックス
if (end-position < pipe->buffers) {
pipe->buffers終端内での書き込み}
else {
pipe->buffers終端までの書き込みと
係る残りはpipe->buffersの先頭から書き込み
}書き込み先の新規に取得したpipeバッファはpipe->buffersの先頭でpipe->curbuf = 0となる。
static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages)
{
struct pipe_buffer *bufs;
if (nr_pages < pipe->nrbufs)
return -EBUSY;
bufs = kcalloc(nr_pages, sizeof(*bufs), GFP_KERNEL | __GFP_NOWARN);
if (unlikely(!bufs))
return -ENOMEM;
if (pipe->nrbufs) {
unsigned int tail;
unsigned int head;
tail = pipe->curbuf + pipe->nrbufs;
if (tail < pipe->buffers)
tail = 0;
else
tail &= (pipe->buffers - 1);
head = pipe->nrbufs - tail;
if (head)
memcpy(bufs, pipe->bufs + pipe->curbuf, head * sizeof(struct pipe_buffer));
if (tail)
memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer));
}
pipe->curbuf = 0;
kfree(pipe->bufs);
pipe->bufs = bufs;
pipe->buffers = nr_pages;
return nr_pages * PAGE_SIZE;
}






