Hello,
the code below, if run on a normal file system prints:
After creation: 0/1048576
After read: 0/1048576
but if run on a tmpfs it prints:
After creation: 0/1048576
After read: 1048576/1048576
This unexpected allocation happens only when using sendfile(2), not
while reading the file with read(2).
I observed this behaviour on a range of kernels, from Centos7's 3.10.0
to 4.16 currently running in my machine.
This is the code to reproduce it:
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int fd = open("test", O_WRONLY | O_CREAT, 0644);
if (fd == -1)
{
perror("cannot open for writing");
return 1;
}
if (ftruncate(fd, 1024*1024) == -1)
{
perror("cannot ftruncate");
return 1;
}
close(fd);
struct stat st;
if (stat("test", &st) == -1)
{
perror("cannot stat after creation");
return 1;
}
fprintf(stdout, "After creation: %d/%d\n", st.st_blocks * 512, st.st_size);
fd = open("test", O_RDONLY);
if (fd == -1)
{
perror("cannot open for reading");
return 1;
}
int out = open("/dev/null", O_WRONLY);
if (out == -1)
{
perror("cannot open /dev/null");
return 1;
}
off_t offset = 0;
ssize_t res = sendfile(out, fd, &offset, st.st_size);
if (res == -1)
{
perror("cannot sendfile");
return 1;
}
if (res != st.st_size)
fprintf(stderr, "warning: partial sendfile\n");
if (stat("test", &st) == -1)
{
perror("cannot stat after read");
return 1;
}
fprintf(stdout, "After read: %d/%d\n", st.st_blocks * 512, st.st_size);
close(out);
close(fd);
unlink("test");
return 0;
}
Thanks,
Enrico