对于如下程序,4.19和主线行为不一样:
unsigned pipe_size;
static void prepare_pipe(int p[2])
{
if (pipe2(p, O_DIRECT)) abort();
pipe_size = fcntl(p[1], F_GETPIPE_SZ);
static char buffer[4096];
/* fill the pipe completely; each pipe_buffer will now have
the PIPE_BUF_FLAG_PACKET flag */
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
write(p[1], buffer, n);
r -= n;
}
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
read(p[0], buffer, n);
r -= n;
}
}
int main(int argc, char **argv) {
char *data_b = malloc(pipe_size);
int fd, i;
char ret[5];
loff_t offs = 0;
int p[2];
if (!data_b)
return -ENOMEM;
prepare_pipe(p);
fd = open("file", O_RDWR | O_TRUNC);
if (fd < 0) {
perror("open fail");
return 0;
}
for (i = 0; i < pipe_size; ++i) {
data_b[i] = i;
}
if (write(fd, data_b, pipe_size) != pipe_size) {
perror("write fail");
return 0;
}
fsync(fd);
/* clear PIPE_BUF_FLAG_PACKET flags */
splice(fd, &offs, p[1], NULL, pipe_size, 0);
read(p[0], ret, 5);
printf("%d %d %d %d %d\n", ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
read(p[0], ret, 5);
printf("%d %d %d %d %d\n", ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
close(fd);
return EXIT_SUCCESS;
}
主线运行返回
4.19运行返回
Hi czh549642238, welcome to the openEuler Community.
I'm the Bot here serving you. You can find the instructions on how to interact with me at Here.
If you have any questions, please contact the SIG: Kernel, and any of the maintainers: @YangYingliang , @pi3orama , @成坚 (CHENG Jian) , @Qiuuuuu , @zhengzengkai , @gogooo , @Xie XiuQi
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
根因:
以O_DIRECT方式创建的pipe,通过pipe_write后对pipe->bufs中每个buf->flags设置了PIPE_BUF_FLAG_PACKET标志。之后调用pipe_read读取pipe数据就会以packet模式(每次读取一个packet长度[PIPE_BUF]的数据,如果传入的长度小于PIPE_BUF,则其余数据被discard掉,后续读取从下一个packet位置开始)读取。但是在splice(fd, p[1])写入数据到pipe之后,由于9d2231c5d74e("lib/iov_iter: initialize "flags" in new pipe_buffer")重置了buf->flags
合入前:
splice(fd, p[1]) // pipe对应buf填充来自fd的数据,buf->flags不变
read(p[0], 5) // 读取pipe第一个packet的前5B,其余数据被discard
read(p[0], 5) // 从pipe第二个packet读取
合入后:
splice(fd, p[1]) // pipe对应buf填充来自fd的数据,buf->flags清0
read(p[0], 5) // 读取pipe第一个packet的前5B,其余数据仍留在pipe中
read(p[0], 5) // 从pipe第一个packet的pos 5开始读取
预期的行为应该是主线的。根据引入packet pipe的补丁9883035ae7e("pipes: add a "packetized pipe" mode for writing")描述,每次write()写入的buf设置PIPE_BUF_FLAG_PACKET视为一个packet,每次read按照一个packet读取,来自splice的数据不应该被视为packet,也即packet模式是buf粒度的,并不意味着整个pipe的所有buf行为都是packet模式。
When we are in the packetized mode (marked by O_DIRECT as suggested by
Alan Cox), a write() on a pipe will not merge the new data with previous
writes, so each write will get a pipe buffer of its own. The pipe
buffer is then marked with the PIPE_BUF_FLAG_PACKET flag, which in turn
will tell the reader side to break the read at that boundary (and throw
away any partial packet contents that do not fit in the read buffer).
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/user.h>
#include <errno.h>
unsigned pipe_size;
static void prepare_pipe(int p[2])
{
if (pipe2(p, O_DIRECT)) abort();
pipe_size = fcntl(p[1], F_GETPIPE_SZ);
static char buffer[4096];
/* fill the pipe completely; each pipe_buffer will now have
the PIPE_BUF_FLAG_PACKET flag */
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
write(p[1], buffer, n);
r -= n;
}
for (unsigned r = pipe_size; r > 0;) {
unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
read(p[0], buffer, n);
r -= n;
}
}
int main(int argc, char **argv) {
int fd, i;
char ret[5];
loff_t offs = 0;
int p[2];
prepare_pipe(p);
char *data_b = malloc(pipe_size);
if (!data_b)
return -ENOMEM;
fd = open("file", O_RDWR | O_TRUNC);
if (fd < 0) {
perror("open fail");
return 0;
}
for (i = 0; i < pipe_size; ++i) {
data_b[i] = i;
}
if (write(fd, data_b, pipe_size) != pipe_size) {
perror("write fail");
return 0;
}
fsync(fd);
/* clear PIPE_BUF_FLAG_PACKET flags */
splice(fd, &offs, p[1], NULL, pipe_size, 0);
read(p[0], ret, 5);
printf("%d %d %d %d %d\n", ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
read(p[0], ret, 5);
printf("%d %d %d %d %d\n", ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
close(fd);
return EXIT_SUCCESS;
}
登录 后才可以发表评论