2.4.17-xfs t-o-t ptools (Mon Jan 28 04:15:18 UTC 2002).
gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-81)
glibc-2.2.2-10
This program mimics the behaviour of BitKeeper mdbm code when expanding
the database, it hits a bug on XFS.
== xfs-bug.c
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
#define size 4096
static const char name[] = "db_main";
int main(void)
{
int fd;
void *m;
time_t t;
struct tm tm;
fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666);
// write(fd, name, 1); /* 1 */
// lseek(fd, size, SEEK_SET); /* 2 */
// write(fd, name, 1); /* 3 */
ftruncate(fd, size);
m = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
memset(m, 'A', size);
t = time(NULL);
tm = *localtime(&t);
strcpy(m, asctime(&tm));
fsync(fd);
munmap(m, size);
close(fd);
return(0);
}
gcc xfs-bug.c -o xfs-bug
../xfs-bug
cat db_main
Make a note of the timestamp then do a clean shutdown and reboot. cat
db_main, it will be garbage or it will contain data from a previous
run.
Expanding a file with ftruncate is undefined behaviour,
http://www.db.opengroup.org/cgi-bin/dbcgi?TPL=sd_fileframe&dir=xsh&file=ftruncate&TOKEN=EWJO&vendor1=1&EWJO=1.
"If the file previously was larger than length, the extra data is
discarded. If it was previously shorter than length, some systems
that conform to the Single UNIX Specification, Version 2 may change
the file or increase its size. If the file is extended, the extended
area appears as if it were zero-filled."
Note "may change the file or increase its size", ftruncate upwards is
not guaranteed to work. The mdbm code is violating standards.
Uncomment lines 2 and 3 so the file is extended first then truncated
down. The code now conforms to standards but XFS still has a bug. The
file on disk is valid but after a clean shutdown and reboot it contains
other data (check the timestamp).
Only after uncommenting line 1 as well as 2,3 does XFS generate clean
data after a reboot. Looks like a nasty interaction between mmap and
files with holes in them. What is strange is that without lines 1,2,3
the code writes valid data. After a long delay or a clean shutdown the
data suddenly gets changed.
|