sendfile 不适用于空标准输入

sendfile 不适用于空标准输入

strace非空 stdin的输出:

execve("./cat", ["./cat"], 0x7fff610af090 /* 37 vars */) = 0
sendfile(1, 0, NULL, 1048576)           = 4
sendfile(1, 0, NULL, 1048576)           = 0
close(0)                                = 0
exit(0)                                 = ?
+++ exited with 0 +++

strace空标准输入的输出:

execve("./cat", ["./cat"], 0x7fff610af090 /* 37 vars */) = 0
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
sendfile(1, 0, NULL, 1048576)           = -1 EINVAL (Invalid argument)
...

uname -a5.3.8-arch1-1 #1 SMP PREEMPT @1572357769 x86_64 GNU/Linux

答案1

这似乎是sendfile通话的预期行为。让我引用 Linus Torvalds 的话:

sendfile() 故意仅适用于使用页面缓存的内容。 EINVAL 基本上是 sendfile 的表达方式:“我会依靠执行读+写操作,所以您最好自己在用户空间中执行此操作,因为这样实际上可能会更有效”。
https://yarchive.net/comp/linux/sendfile.html

因此,sendfile只有stdin当内核知道这stdin实际上一个文件,而不是管道、块设备或其他任何东西。

我自己写了一个简单的程序来检查一下:

#include <stdio.h>
#include <sys/sendfile.h>

int main() {
    sendfile(fileno(stdout), fileno(stdin), NULL, 8);
    perror("sendfile failed");
}

使用各种重定向运行它清楚地表明,sendfile只有当输入直接绑定到常规文件(无论是否为空)时,调用才会成功:

$ ./sendfile-test
sendfile failed: Invalid argument

$ ./sendfile-test < empty.txt
sendfile failed: Success

$ ./sendfile-test < non-empty.txt
(...)
sendfile failed: Success

$ ./sendfile-test < /dev/null
sendfile failed: Invalid argument

$ cat empty.txt | ./sendfile-test
sendfile failed: Invalid argument

$ cat non-empty.txt | ./sendfile-test
sendfile failed: Invalid argument

$ cat /dev/null | ./sendfile-test
sendfile failed: Invalid argument

相关内容