/proc/sys/fs/pipe-max-size
Rev.2を表示中。最新版はこちら。
pipe作成時のバッファは、get_pipe_inode()のpipe inode取得のPIPE_DEF_BUFFERS=16のPAGE(4096)*16=65536バイトで、/proc/sys/fs/pipe-max-sizeに係る実装でない。/proc/sys/fs/pipe-max-sizeはpipeバッファサイズ変更fctrl(F_SETPIPE_SZ)の上限値のstatic unsigned int pipe_max_sizeで、デフォルトは1048576。CP_SYSを有さないrootでないユーザのfctrl(F_SETPIPE_SZ)のpipeバッファサイズの更新上限値で、pipe作成時のpipバッファでない。
pipeバッファサイズ /proc/sys/fs/pipe-max-sizeのサイズは、PAGE(4096)の2のべき乗単位。
[root@localhost mnt7]# cat /proc/sys/fs/pipe-max-size 1048576 [root@localhost mnt7]# ./set-psize.out 0 <= 1048576でなくデフォルトpipeバッファ writed size:65536 writed page=16 [root@localhost mnt7]# echo 4096 > /proc/sys/fs/pipe-max-size [root@localhost mnt7]# cat /proc/sys/fs/pipe-max-size 4096 [root@localhost mnt7]# ./set-psize.out 0 <= pipe-max-size=4096を超えるデフォルトpipeバッファサイズ writed size:65536 writed page=16 [root@localhost mnt7]# ./set-psize.out 4097 <= rootはpipe-max-size=4096の制限は掛からない setsize:8192 writed size:8192 writed page=2 [root@localhost mnt7]# su north [north@localhost mnt7]$ ./set-psize.out 4096 <= pipe-max-size=4096 setsize:4096 writed size:4096 writed page=1 [north@localhost mnt7]$ ./set-psize.out 4097 <= pipe-max-size=4096 fctrl(F_SETPIPE_SZ)エラー setsize:-1 writed size:65536 writed page=16
[north@localhost mnt7]$ su [root@localhost mnt7]# printf "%x\n" 2147483647 7fffffff [root@localhost mnt7]# printf "%x\n" 2147483648 80000000 [root@localhost mnt7]# echo 2147483647 > /proc/sys/fs/pipe-max-size [root@localhost mnt7]# echo 2147483648 > /proc/sys/fs/pipe-max-size bash: echo: 書き込みエラー: 無効な引数です [root@localhost mnt7]# echo 0x7fffffff > /proc/sys/fs/pipe-max-size [root@localhost mnt7]# echo 0x80000000 > /proc/sys/fs/pipe-max-size bash: echo: 書き込みエラー: 無効な引数です
カーネルイメージ
#define PAGE_SHIFT 12
#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) = 4096
unsigned int pipe_max_size = 1048576;
unsigned int pipe_min_size = PAGE_SIZE;
static struct ctl_table fs_table[] = {
:
{
.procname = "file-nr",
.data = &files_stat,
.maxlen = sizeof(files_stat),
.mode = 0444,
.proc_handler = proc_nr_files,
},
{
.procname = "file-max",
.data = &files_stat.max_files,
.maxlen = sizeof(files_stat.max_files),
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
},
{
.procname = "nr_open",
.data = &sysctl_nr_open,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &sysctl_nr_open_min,
.extra2 = &sysctl_nr_open_max,
},
:
{
.procname = "pipe-max-size",
.data = &pipe_max_size, <- pipe_proc_fn(write)で.dataのpipe_max_sizeを更新
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &pipe_proc_fn,
.extra1 = &pipe_min_size,
},
{ }
};
struct proc_inode {
struct pid *pid;
int fd;
union proc_op op;
struct proc_dir_entry *pde;
struct ctl_table_header *sysctl;
struct ctl_table *sysctl_entry;
void *ns;
const struct proc_ns_operations *ns_ops;
struct inode vfs_inode;
};
int i=0;
struct proc_inode *inode;
inode = get_proc_inode(/proc/sys/fs/pipe-max-size);
while (1) {
if (!strcmp("ctl_table fs_table[i++].procname,"pipe-max-size")) {
break;
}
}
inode->sysctl_entry=&ctl_table fs_table[i];
inode->sysctl_entry.proc_handler()------>pipe_proc_fn()
pipe-max-sizeは上限限度のextra2に設定されいない故、係る条件は.extra1= &pipe_min_sizeより小さい場合のみ設定できない。valはunsinged でないゆえ設定値がマイナスとなる値はエラー。
struct ctl_table table
{
.procname = "pipe-max-size",
.data = &pipe_max_size,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &pipe_proc_fn,
.extra1 = &pipe_min_size,
},
int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf,
size_t *lenp, loff_t *ppos)
{
int ret;
ret = proc_dointvec_minmax(table, write, buf, lenp, ppos);
if (ret < 0 || !write)
return ret;
pipe_max_size = round_pipe_size(pipe_max_size);
return ret;
}
int proc_dointvec_minmax(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
struct do_proc_dointvec_minmax_conv_param param = {
.min = (int *) table->extra1, <---- &pipe_min_size
.max = (int *) table->extra2, <---- NULL
};
return do_proc_dointvec(table, write, buffer, lenp, ppos,
do_proc_dointvec_minmax_conv, ¶m);
}
staticのparam->maxは設定されてない故param->max=NULL、param->min=pipe_min_size>val故サイン型intのマイナスとなる値はエラー。
static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp, int *valp, int write, void *data)
{
struct do_proc_dointvec_minmax_conv_param *param = data;
if (write) {
int val = *negp ? -*lvalp : *lvalp;
if ((param->min && *param->min > val) ||
(param->max && *param->max < val))
return -EINVAL;
*valp = val;
} else {
int val = *valp;
if (val < 0) {
*negp = true;
*lvalp = (unsigned long)-val;
} else {
*negp = false;
*lvalp = (unsigned long)val;
}
}
return 0;
}
cmd=F_SETPIPE_SZdでrootでないならpipe_max_sizeを超えるpipeバッファの設定はできない。
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作成のpipeバッファは、pipe->buffers = PIPE_DEF_BUFFERS
static struct inode * get_pipe_inode(void)
{
struct inode *inode = new_inode_pseudo(pipe_mnt->mnt_sb);
struct pipe_inode_info *pipe;
if (!inode)
goto fail_inode;
inode->i_ino = get_next_ino();
pipe = alloc_pipe_info(inode);
if (!pipe)
goto fail_iput;
inode->i_pipe = pipe;
pipe->readers = pipe->writers = 1;
inode->i_fop = &rdwr_pipefifo_fops;
inode->i_state = I_DIRTY;
inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
return inode;
fail_iput:
iput(inode);
fail_inode:
return NULL;
}
struct pipe_inode_info * alloc_pipe_info(struct inode *inode)
{
struct pipe_inode_info *pipe;
pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
if (pipe) {
pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * PIPE_DEF_BUFFERS, GFP_KERNEL);
if (pipe->bufs) {
init_waitqueue_head(&pipe->wait);
pipe->r_counter = pipe->w_counter = 1;
pipe->inode = inode;
pipe->buffers = PIPE_DEF_BUFFERS;
return pipe;
}
kfree(pipe);
}
return NULL;
}
set-psize.out
[root@localhost mnt7]# cat set-psize.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <linux/fcntl.h>
#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/4096);
}





