pipe_buffer
/include/linux/pipe_fs_i.h
struct pipe_buffer {
struct page *page;
unsigned int offset, len;
const struct pipe_buf_operations *ops;
unsigned int flags;
unsigned long private;
};
summary
[struct pipe_buffer] [struct page]
/*=========================================*/ ┌---> 0xffffea000010ee00|+0x00: 0x0100000000000000
0xffffea000010ee40 0x0000000800000000 | 0xffffea000010ee08|+0x08: 0x0000000000000000
| | | | 0xffffea000010ee10|+0x10: 0xdead000000000122
| | └-unsigned int offset | 0xffffea000010ee18|+0x18: 0x0000000000000000
| └-unsigned int len; | 0xffffea000010ee20|+0x20: 0x0000000000000000
└-struct page *page ---------------------------------┘ 0xffffea000010ee28|+0x28: 0x0000000000000000
0xffffffff8221e980 0x0000000000000010 0xffffea000010ee30|+0x30: 0x00000001ffffffff
| | 0xffffea000010ee38|+0x38: 0x0000000000000000
| └-unsigned int flags ┌---> 0xffffea000010ee40|+0x40: 0x0100000000000000
└-const struct pipe_buf_operations *ops | 0xffffea000010ee48|+0x48: 0x0000000000000000
0x0000000000000000 0x0000000000000000 | 0xffffea000010ee50|+0x50: 0xdead000000000122
| | 0xffffea000010ee58|+0x58: 0x0000000000000000
└-unsigned long private | 0xffffea000010ee60|+0x60: 0x0000000000000000
| 0xffffea000010ee68|+0x68: 0x0000000000000000
/*=========================================*/ | 0xffffea000010ee70|+0x70: 0x00000001ffffffff
0xffffea000010ee80 0x0000000800000000 | 0xffffea000010ee78|+0x78: 0x0000000000000000
| | | |
| | └-unsigned int offset |
| └-unsigned int len; | [struct pipe_buf_operations]
└-struct page *page ---------------------------------┘
0xffffffff8221e980 0x0000000000000010 0xffffffff8221e980|+0x00: 0x0000000000000000
| | 0xffffffff8221e988|+0x08: 0xffffffff81292cd0 -> 0x48fa8948fa1e0ff3
| └-unsigned int flags 0xffffffff8221e990|+0x10: 0xffffffff81292d90 -> 0x48068b48fa1e0ff3
└-const struct pipe_buf_operations *ops 0xffffffff8221e998|+0x18: 0xffffffff81292b90 -> 0x48068b48fa1e0ff3
0x0000000000000000 0x0000000000000000
|
└-unsigned long private
allocate
alloc_pipe_info(), kmalloc-1024
SYSCALL_DEFINE1()->do_pipe2()->do_pipe_flags()->__do_pipe_flags()->create_pipe_files()->get_pipe_inode()->alloc_pipe_info()
allocated when user create pipe. pipe(p_fd)
https://elixir.bootlin.com/linux/v6.14/source/fs/pipe.c#L812
// sizeof(struct pipe_buffer) == 0x28
// #define PIPE_DEF_BUFFERS 16
unsigned long pipe_bufs = PIPE_DEF_BUFFERS;
/* ............. */
pipe->bufs = kcalloc(pipe_bufs, sizeof(struct pipe_buffer),
GFP_KERNEL_ACCOUNT);
pipe_resize_ring(), arbitrary size
set_pipe_size()->pipe_resize_ring()
allocated when user request setting the size. fcntl(p_fd[0], F_SETPIPE_SZ, n*0x1000)
numbers how many struct pipe_buffer
will be allocated depend on the n
. struct pipe_buffer
is responsible for 0x1000 bytes each (page size). since sizeof(struct pipe_buffer) == 0x28
, size request with 0x40*0x1000
allocate 0x40 linear struct pipe_buffer
(==0xa00 bytes, kmalloc-4098).
https://elixir.bootlin.com/linux/v6.6.94/source/fs/pipe.c#L1267
bufs = kcalloc(nr_slots, sizeof(*bufs),
GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
capability
https://elixir.bootlin.com/linux/v6.14/source/include/linux/pipe_fs_i.h#L131
struct pipe_buf_operations {
/*
* ->confirm() verifies that the data in the pipe buffer is there
* and that the contents are good. If the pages in the pipe belong
* to a file system, we may need to wait for IO completion in this
* hook. Returns 0 for good, or a negative error value in case of
* error. If not present all pages are considered good.
*/
int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *);
/*
* When the contents of this pipe buffer has been completely
* consumed by a reader, ->release() is called.
*/
void (*release)(struct pipe_inode_info *, struct pipe_buffer *);
/*
* Attempt to take ownership of the pipe buffer and its contents.
* ->try_steal() returns %true for success, in which case the contents
* of the pipe (the buf->page) is locked and now completely owned by the
* caller. The page may then be transferred to a different mapping, the
* most often used case is insertion into different file address space
* cache.
*/
bool (*try_steal)(struct pipe_inode_info *, struct pipe_buffer *);
/*
* Get a reference to the pipe buffer.
*/
bool (*get)(struct pipe_inode_info *, struct pipe_buffer *);
};
helper
int **pipe_alloc(int n_pipes) {
int **ret = (int **)calloc(n_pipes,sizeof(int *));
rep(i, n_pipes) {
ret[i] = (int *)calloc(2,sizeof(int));
SYSCHK(pipe(ret[i]));
}
return ret;
}
int **pipe_alloc_2(int n_pipes, int start, int end) {
int **ret = (int **)calloc(n_pipes,sizeof(int *));
for(int i=start;i<end;i++) {
ret[i] = (int *)calloc(2,sizeof(int));
SYSCHK(pipe(ret[i]));
}
return ret;
}
void pipe_alloc_3(int **pp, int start, int end) {
for(int i=start;i<end;i++) {
pp[i] = (int *)calloc(2,sizeof(int));
SYSCHK(pipe(pp[i]));
}
}
char *pipe_read(int *p, int len) {
char *ret = (char *)malloc(sizeof(char)*len);
SYSCHK(read(p[0],ret,len));
return ret;
}
void pipe_write(int *p, char *buf, int len) {
SYSCHK(write(p[1],buf,len));
}
void pipe_set_size(int *p, unsigned long sz) {
SYSCHK(fcntl(p[0], F_SETPIPE_SZ, sz));
}
void pipe_close(int *p) {
SYSCHK(close(p[0]));
SYSCHK(close(p[1]));
}
Last modified: 13 July 2025