Help with filing a [maybe] ZFS/mmap bug.
Andriy Gapon
avg at FreeBSD.org
Thu Nov 14 12:00:58 UTC 2013
on 14/11/2013 13:48 Andriy Gapon said the following:
> HOWEVER. I think that there is a bug that I introduced in r246293.
> Specifically I changed
> vm_page_undirty(pp);
> to
> pmap_remove_write(pp);
> vm_page_clear_dirty(pp, off, nbytes);
>
> vm_page_undirty() would be a very serious (and probably obvious) bug, if it were
> not a NOP in effect. The details are explained in the commit message.
> But when I used vm_page_clear_dirty I completely missed the fact that *extends*
> the range to DEV_BSIZE aligned boundaries[*]. So, given the described behavior
> and that pmap_remove_write clears the page modified bit, it is possible that the
> data dirty data in the extended areas will be marked as clean.
I should also add that the above information is consistent with the corruption
that George observed and analyzed (thanks!) -- a few bytes at the end of a page.
In fact, I am able to reproduce the bug with the following program.
#include <sys/param.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
static const off_t len = PAGE_SIZE;
static const off_t len2 = PAGE_SIZE - DEV_BSIZE + 1;
int main (int argc, char *argv[])
{
char dummy[len2];
char *p;
off_t i;
int fd;
if (argc < 2) {
fprintf (stderr, "usage: %s <file>\n", argv[0]);
return (1);
}
fd = open(argv[1], O_CREAT | O_EXCL | O_RDWR, 0660);
if (fd == -1) {
perror ("open");
return (1);
}
if (ftruncate(fd, len) == -1) {
perror ("ftruncate");
return (1);
}
p = mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED) {
perror ("mmap");
return (1);
}
for (i = 0; i < len; i++)
p[i] = '0';
if (msync(p, len, MS_SYNC) != 0) {
perror ("msync");
return (1);
}
printf("file filled with 0s and synced\n");
for (i = 0; i < len; i++)
p[i] = '1';
printf("file filled with 1s\n");
for (i = 0; i < len2; i++)
dummy[i] = 'x';
if (write(fd, dummy, len2) != len2) {
perror ("write");
return (1);
}
printf("first %ju bytes are overwritten with 'x'\n",
(uintmax_t)len2);
if (munmap(p, len) == -1) {
perror ("munmap");
return (1);
}
if (close(fd) == -1) {
perror ("close");
return (1);
}
printf("file is unmapped and closed\n");
printf("please unmount and remount filesystem and check file content\n");
return (0);
}
--
Andriy Gapon
More information about the freebsd-stable
mailing list