/proc/sys/fs/pipe-max-size


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 でないゆえ設定値がマイナスとなる値はエラー。
static const struct file_operations proc_sys_file_operations = {
       .open           = proc_sys_open,
       .poll           = proc_sys_poll,
       .read           = proc_sys_read,
       .write          = proc_sys_write,
       .llseek         = default_llseek,
};

static ssize_t proc_sys_read(struct file *filp, char __user *buf,
                               size_t count, loff_t *ppos)
{
       return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0);
}

static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
                               size_t count, loff_t *ppos)
{
       return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1);
}

static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
               size_t count, loff_t *ppos, int write)
{
       struct inode *inode = filp->f_path.dentry->d_inode;
       struct ctl_table_header *head = grab_header(inode);
       struct ctl_table *table = PROC_I(inode)->sysctl_entry;
       ssize_t error;
       size_t res;

       if (IS_ERR(head))
               return PTR_ERR(head);

       error = -EPERM;
       if (sysctl_perm(head->root, table, write ? MAY_WRITE : MAY_READ))
               goto out;

       error = -EINVAL;
       if (!table->proc_handler)
               goto out;

       res = count;
       error = table->proc_handler(table, write, buf, &res, ppos);
       if (!error)
               error = res;
out:
       sysctl_head_finish(head);

       return error;
}

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, &param);
}

staticのparam->maxは設定されてない故param->max=NULL、param->min=pipe_min_size>val故サイン型intのマイナスとなる値はエラー。

static int do_proc_dointvec(struct ctl_table *table, int write,
                 void __user *buffer, size_t *lenp, loff_t *ppos,
                 int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
                             int write, void *data),
                 void *data)
{
       return __do_proc_dointvec(table->data, table, write,
                       buffer, lenp, ppos, conv, data);
}

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

最終更新 2017/11/28 14:15:10 - north
(2017/11/28 13:04:09 作成)


検索

アクセス数
3570039
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。