pipeバッファ数の更新


バージョンの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=2
CAP_SYS_RESOURCEでないならpipe_max_size[1048576]を超える更新はできない
[north@localhost v.north]$ ./set-psize.out 10
setsize:4096
writed size:4096 writed page=1

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

最終更新 2017/11/21 09:03:39 - north
(2017/11/19 12:43:47 作成)


検索

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