splice 和管道¶
splice API¶
splice 是一种在内核内部移动数据块的方法,无需在内核和用户空间之间不断传输数据。
-
ssize_t splice_to_pipe(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)¶
将传递的数据填充到管道中
参数
struct pipe_inode_info *pipe
要填充的管道
struct splice_pipe_desc *spd
要填充的数据
描述
spd 包含页面映射和 len/offset 元组,以及与这些页面关联的 struct pipe_buf_operations。此函数会将这些数据链接到管道。
-
ssize_t copy_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags)¶
从文件中复制数据并将副本拼接到管道中
参数
struct file *in
要读取的文件
loff_t *ppos
指向要读取的文件位置的指针
struct pipe_inode_info *pipe
要拼接到的管道
size_t len
要拼接的数量
unsigned int flags
SPLICE_F_* 标志
描述
此函数分配足够的页面以保存请求的数据量(但受剩余管道容量的限制),将其传递给文件的 ->read_iter() 以读取到其中,然后将使用的页面拼接进管道。
返回
成功时,将返回读取的字节数,如果适用,则会更新 *ppos;如果没有更多数据要读取,则返回 0;如果管道没有空间,则返回 -EAGAIN,如果发生错误,则返回其他负错误代码。如果管道空间不足、到达数据末尾或遇到空洞,则可能发生短读。
-
int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd, splice_actor *actor)¶
将管道中的可用数据馈送到文件
参数
struct pipe_inode_info *pipe
要拼接的管道
struct splice_desc *sd
有关 actor 的信息
splice_actor *actor
拼接数据的处理程序
描述
此函数循环遍历管道并调用 actor 来实际移动单个
struct pipe_buffer
到目标位置。当管道中没有更多缓冲区或已复制请求的字节数(sd->total_len)时,它将返回。如果管道需要填充更多数据,则返回正数(1),如果已复制所需的字节数,则返回零,如果发生错误,则返回 -errno。此函数与 splice_from_pipe_{begin,end,next} 一起,可用于在需要围绕将管道缓冲区复制到目标位置进行锁定时,实现
__splice_from_pipe()
的功能。
-
int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)¶
等待一些数据进行拼接
参数
struct pipe_inode_info *pipe
要拼接的管道
struct splice_desc *sd
有关拼接操作的信息
描述
如果管道缓冲区可用,此函数将等待一些数据并返回正值(1)。如果没有更多数据需要拼接,它将返回零或 -errno。
-
void splice_from_pipe_begin(struct splice_desc *sd)¶
开始从管道拼接
参数
struct splice_desc *sd
有关拼接操作的信息
描述
此函数应在包含
splice_from_pipe_next()
和splice_from_pipe_feed()
的循环之前调用,以初始化 sd 的必要字段。
-
void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd)¶
完成从管道的拼接
参数
struct pipe_inode_info *pipe
要拼接的管道
struct splice_desc *sd
有关拼接操作的信息
描述
如果需要,此函数将唤醒管道写入器。它应在包含
splice_from_pipe_next()
和splice_from_pipe_feed()
的循环之后调用。
-
ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd, splice_actor *actor)¶
将数据从管道拼接到给定的 actor
参数
struct pipe_inode_info *pipe
要拼接的管道
struct splice_desc *sd
有关 actor 的信息
splice_actor *actor
拼接数据的处理程序
描述
此函数所做的只是循环遍历管道并调用 actor 以实际移动单个
struct pipe_buffer
到目标位置。请参阅 pipe_to_file、pipe_to_sendmsg 或 pipe_to_user。
-
ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags, splice_actor *actor)¶
将数据从管道拼接到文件
参数
struct pipe_inode_info *pipe
要拼接的管道
struct file *out
要拼接到的文件
loff_t *ppos
out 中的位置
size_t len
要拼接的字节数
unsigned int flags
拼接修饰符标志
splice_actor *actor
拼接数据的处理程序
描述
请参阅 __splice_from_pipe。此函数会锁定管道 inode,否则它与
__splice_from_pipe()
相同。
-
ssize_t iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags)¶
将数据从管道拼接到文件
参数
struct pipe_inode_info *pipe
管道信息
struct file *out
要写入的文件
loff_t *ppos
out 中的位置
size_t len
要拼接的字节数
unsigned int flags
拼接修饰符标志
描述
根据 flags 选项的设置,将给定管道 inode 中的页面移动或复制到给定文件中。此函数基于 ->write_iter。
-
ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags)¶
将管道中的数据拼接至套接字
参数
struct pipe_inode_info *pipe
要拼接的管道
struct file *out
要写入的套接字
loff_t *ppos
out 中的位置
size_t len
要拼接的字节数
unsigned int flags
拼接修饰符标志
描述
将管道中的 len 个字节发送到网络套接字。不涉及数据复制。
-
ssize_t vfs_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags)¶
从文件中读取数据并将其拼接至管道
参数
struct file *in
要从中拼接的文件
loff_t *ppos
输入文件偏移量
struct pipe_inode_info *pipe
要拼接至的管道
size_t len
要拼接的字节数
unsigned int flags
拼接修饰符标志 (SPLICE_F_*)
描述
将请求的数据量从输入文件拼接至管道。这是同步操作,因为调用者必须在整个操作过程中持有管道锁。
如果成功,则返回拼接的数据量;如果到达 EOF 或空洞,则返回 0;否则返回负错误代码。
-
ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, splice_direct_actor *actor)¶
在两个非管道之间直接拼接数据
参数
struct file *in
要从中拼接的文件
struct splice_desc *sd
有关拼接位置的 actor 信息
splice_direct_actor *actor
处理数据拼接
描述
这是一个特殊的辅助函数,用于在两个点之间直接拼接数据,而无需显式管道。内部会在进程中缓存一个已分配的管道,并在该进程的生命周期内重复使用。
-
ssize_t do_splice_direct(struct file *in, loff_t *ppos, struct file *out, loff_t *opos, size_t len, unsigned int flags)¶
在两个文件之间直接拼接数据
参数
struct file *in
要从中拼接的文件
loff_t *ppos
输入文件偏移量
struct file *out
要拼接到的文件
loff_t *opos
输出文件偏移量
size_t len
要拼接的字节数
unsigned int flags
拼接修饰符标志
描述
供 do_sendfile() 使用。splice 可以轻松模拟 sendfile,但在应用程序中执行此操作会产生额外的系统调用(splice in + splice out,而 sendfile() 只有一个系统调用)。因此,此辅助函数可以直接通过进程私有管道进行拼接。
调用者已在整个范围内调用了 rw_verify_area()。
-
ssize_t splice_file_range(struct file *in, loff_t *ppos, struct file *out, loff_t *opos, size_t len)¶
在两个文件之间拼接数据,用于 copy_file_range()
参数
struct file *in
要从中拼接的文件
loff_t *ppos
输入文件偏移量
struct file *out
要拼接到的文件
loff_t *opos
输出文件偏移量
size_t len
要拼接的字节数
描述
供 ->copy_file_range() 方法使用。与
do_splice_direct()
类似,但 vfs_copy_file_range() 已经在 out 文件上持有 start_file_write()。
调用者已在整个范围内调用了 rw_verify_area()。
管道 API¶
管道接口全部供内核内部(内置镜像)使用。它们不导出供模块使用。
-
struct pipe_buffer¶
一个 Linux 内核管道缓冲区
定义:
struct pipe_buffer {
struct page *page;
unsigned int offset, len;
const struct pipe_buf_operations *ops;
unsigned int flags;
unsigned long private;
};
成员
page
包含管道缓冲区数据的页面
offset
page 内数据的偏移量
len
page 内数据的长度
ops
与此缓冲区关联的操作。请参见 pipe_buf_operations。
flags
管道缓冲区标志。请参见上面。
private
ops 拥有的私有数据。
-
struct pipe_inode_info¶
一个 Linux 内核管道
定义:
struct pipe_inode_info {
struct mutex mutex;
wait_queue_head_t rd_wait, wr_wait;
unsigned int head;
unsigned int tail;
unsigned int max_usage;
unsigned int ring_size;
unsigned int nr_accounted;
unsigned int readers;
unsigned int writers;
unsigned int files;
unsigned int r_counter;
unsigned int w_counter;
bool poll_usage;
#ifdef CONFIG_WATCH_QUEUE;
bool note_loss;
#endif;
struct page *tmp_page;
struct fasync_struct *fasync_readers;
struct fasync_struct *fasync_writers;
struct pipe_buffer *bufs;
struct user_struct *user;
#ifdef CONFIG_WATCH_QUEUE;
struct watch_queue *watch_queue;
#endif;
};
成员
mutex
保护整个管道的互斥锁
rd_wait
管道为空时的读取器等待点
wr_wait
管道满时的写入器等待点
head
缓冲区生产点
tail
缓冲区消费点
max_usage
环中可以使用的最大槽位数
ring_size
缓冲区总数(应为 2 的幂)
nr_accounted
此管道在 user->pipe_bufs 中占用的量
readers
此管道的当前读取器数量
writers
此管道的当前写入器数量
files
引用此管道的
struct file
数量(受 ->i_lock 保护)r_counter
读取器计数器
w_counter
写入器计数器
poll_usage
此管道是否用于 epoll(具有疯狂的唤醒)?
note_loss
下一次 read() 应该插入一条数据丢失消息
tmp_page
缓存的已释放页面
fasync_readers
读取器端的 fasync
fasync_writers
写入器端的 fasync
bufs
管道缓冲区的循环数组
user
创建此管道的用户
watch_queue
如果此管道是 watch_queue,则这是用于该队列的东西
-
bool pipe_has_watch_queue(const struct pipe_inode_info *pipe)¶
检查管道是否为 watch_queue,即是否使用 O_NOTIFICATION_PIPE 创建。
参数
const struct pipe_inode_info *pipe
要检查的管道。
返回
如果管道是 watch queue,则为 true,否则为 false。
-
bool pipe_empty(unsigned int head, unsigned int tail)¶
如果管道为空,则返回 true。
参数
unsigned int head
管道环的头部指针。
unsigned int tail
管道环的尾部指针。
-
unsigned int pipe_occupancy(unsigned int head, unsigned int tail)¶
返回管道中已使用的槽位数量。
参数
unsigned int head
管道环的头部指针。
unsigned int tail
管道环的尾部指针。
-
bool pipe_full(unsigned int head, unsigned int tail, unsigned int limit)¶
如果管道已满,则返回 true。
参数
unsigned int head
管道环的头部指针。
unsigned int tail
管道环的尾部指针。
unsigned int limit
可用槽位的最大数量。
-
struct pipe_buffer *pipe_buf(const struct pipe_inode_info *pipe, unsigned int slot)¶
返回管道环中指定槽位的管道缓冲区。
参数
const struct pipe_inode_info *pipe
要访问的管道。
unsigned int slot
感兴趣的槽位。
-
struct pipe_buffer *pipe_head_buf(const struct pipe_inode_info *pipe)¶
返回管道环头部的管道缓冲区。
参数
const struct pipe_inode_info *pipe
要访问的管道。
-
bool pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)¶
获取对 pipe_buffer 的引用。
参数
struct pipe_inode_info *pipe
缓冲区所属的管道。
struct pipe_buffer *buf
要获取引用的缓冲区。
返回
如果成功获取引用,则为 true
。
-
void pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf)¶
释放对 pipe_buffer 的引用。
参数
struct pipe_inode_info *pipe
缓冲区所属的管道。
struct pipe_buffer *buf
要释放引用的缓冲区。
-
int pipe_buf_confirm(struct pipe_inode_info *pipe, struct pipe_buffer *buf)¶
验证管道缓冲区的内容。
参数
struct pipe_inode_info *pipe
缓冲区所属的管道。
struct pipe_buffer *buf
要确认的缓冲区。
-
bool pipe_buf_try_steal(struct pipe_inode_info *pipe, struct pipe_buffer *buf)¶
尝试获取 pipe_buffer 的所有权。
参数
struct pipe_inode_info *pipe
缓冲区所属的管道。
struct pipe_buffer *buf
要尝试窃取的缓冲区。
-
bool generic_pipe_buf_try_steal(struct pipe_inode_info *pipe, struct pipe_buffer *buf)¶
尝试获取
pipe_buffer
的所有权。
参数
struct pipe_inode_info *pipe
缓冲区所属的管道。
struct pipe_buffer *buf
要尝试窃取的缓冲区。
描述
此函数尝试窃取附加到 buf 的
struct page
。如果成功,此函数返回 0 并返回锁定的页面。调用者可以随后将页面重用于他想要的任何目的;典型的用途是将其插入到不同的文件页面缓存中。
-
bool generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)¶
获取对
struct pipe_buffer
的引用。
参数
struct pipe_inode_info *pipe
缓冲区所属的管道。
struct pipe_buffer *buf
要获取引用的缓冲区。
描述
当我们将一个管道中的缓冲区复制到另一个管道中时,此函数用于 tee() 系统调用中,以抓取 buf 的额外引用。
-
void generic_pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf)¶
释放对
struct pipe_buffer
的引用。
参数
struct pipe_inode_info *pipe
缓冲区所属的管道。
struct pipe_buffer *buf
要释放引用的缓冲区。
描述
此函数释放对 buf 的引用。