Since kernel v3.7 the RTM_NEWLINK message now accepts nonzero
values in ifi_index field. Mention this fact in the respective
rtnetlink.7 section.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
SO_BINDTODEVICE is readable since since kernel 3.8.
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
See https://bugzilla.kernel.org/show_bug.cgi?id=23282
Reported-by: Graham Gower <graham.gower@gmail.com>
Acked-by: Graham Gower <graham.gower@gmail.com>
Signed-off-by: Marshel Abraham <Marshel.Abraham@in.bosch.com>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
Since in some cases (e.g. libguestfs's guestmount) it also has the
semantics where files can appear owned by root, but are actually
mutable by the user, despite what one might infer from the Unix
permissions.
Signed-off-by: Colin Walters <walters@verbum.org>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This adds a note about Linux behavior with partial page at the end
of the object. The problem here is that a page that contains only
part of a file (because the file size is not multiple of PAGE_SIZE)
stays in page cache even after the mapping is unmapped and the file
is closed. So if some process dirties such page, other mappings
will see the changes rather than zeroes.
I've also attached a reproducer which is a stripped down version of
the LTP test. The child creates a file of the size of PAGE_SIZE/2,
maps it, changes the content after the PAGE_SIZE/2. The parent
waits for the child to exit, maps the same file, and checks the
content after PAGE_SIZE/2. Uncommenting the msync() makes the test
succeed.
==========
int main(void)
{
char tmpfname[256];
long page_size;
void *pa;
size_t len;
int fd;
pid_t child;
char *ch;
int exit_val;
page_size = sysconf(_SC_PAGE_SIZE);
len = page_size / 2;
snprintf(tmpfname, sizeof(tmpfname), "/tmp/test");
child = fork();
switch (child) {
case 0:
/* Create shared object */
unlink(tmpfname);
fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL,
S_IRUSR | S_IWUSR);
if (fd == -1) {
printf("Error at open(): %s\n", strerror(errno));
return 1;
}
if (ftruncate(fd, len) == -1) {
printf("Error at ftruncate(): %s\n", strerror(errno));
return 1;
}
pa = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pa == MAP_FAILED) {
printf("Error at mmap(): %s\n", strerror(errno));
return 1;
}
/* Check the partial page is ZERO filled */
ch = pa + len + 1;
if (*ch != 0) {
printf("Test FAILED: "
"The partial page at the end of an object "
"is not zero-filled\n");
return 1;
}
/* Write the partial page */
*ch = 'b';
//msync(pa, len, MS_SYNC);
munmap(pa, len);
close(fd);
return 0;
case -1:
printf("Error at fork(): %s\n", strerror(errno));
return 1;
default:
break;
}
wait(&exit_val);
if (!(WIFEXITED(exit_val) && (WEXITSTATUS(exit_val) == 0))) {
unlink(tmpfname);
printf("Child exited abnormally\n");
return 1;
}
fd = open(tmpfname, O_RDWR, 0);
unlink(tmpfname);
pa = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pa == MAP_FAILED) {
printf("Error at 2nd mmap(): %s\n", strerror(errno));
return 1;
}
ch = pa + len + 1;
if (*ch == 'b') {
printf("Test FAILED: Modification of the partial page "
"at the end of an object is written out\n");
return 1;
}
close(fd);
munmap(pa, len);
printf("Test PASSED\n");
return 0;
}
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>