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