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)已被复制时,它会返回。如果管道需要填充更多数据,它会返回一个正数(一);如果所需的字节数已被复制,则返回零;如果发生错误,则返回 -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
有关拼接操作的信息
描述
此函数将等待一些数据,如果管道缓冲区可用,则返回一个正值(一)。如果没有更多数据需要拼接,它将返回零或 -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
拼接修饰符标志
描述
将从给定的管道 inode 移动或复制页面(由 flags 选项确定)到给定的文件。这一个基于 ->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;
union {
unsigned long head_tail;
struct {
pipe_index_t head;
pipe_index_t 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[2];
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
满管道情况下写入器等待点
{unnamed_union}
anonymous
head_tail
head 和 tail 的 unsigned long 联合
{unnamed_struct}
anonymous
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 队列,则为 true;否则为 false。
-
unsigned int pipe_occupancy(unsigned int head, unsigned int tail)¶
返回管道中使用的槽数
参数
unsigned int head
管道环头指针
unsigned int tail
管道环尾指针
-
bool pipe_empty(unsigned int head, unsigned int tail)¶
如果管道为空,则返回 true
参数
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
可用槽位的最大数量。
-
bool pipe_is_full(const struct pipe_inode_info *pipe)¶
如果管道已满,则返回 true
参数
const struct pipe_inode_info *pipe
管道
-
bool pipe_is_empty(const struct pipe_inode_info *pipe)¶
如果管道为空,则返回 true
参数
const struct pipe_inode_info *pipe
管道
-
unsigned int pipe_buf_usage(const struct pipe_inode_info *pipe)¶
返回正在使用的管道缓冲区数量
参数
const struct pipe_inode_info *pipe
管道
-
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
要获取引用的缓冲区
描述
此函数获取对 buf 的额外引用。它用于 tee() 系统调用,当我们复制一个管道中的缓冲区到另一个管道中时。
-
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 的引用。