Subject: kern/33777: ftruncate broken on extend on ffs with large page size
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Simon Burge <simonb@netbsd.org>
List: netbsd-bugs
Date: 06/20/2006 16:30:00
Note: There was a bad value `non-critical | serious | critical ] (one line)>' for the field `Severity'.
It was set to the default value of `serious'.
>Number: 33777
>Category: kern
>Synopsis: ftruncate broken on extend on ffs with large page size
>Confidential: no
>Severity: serious
>Priority: low
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Jun 20 16:30:00 +0000 2006
>Originator: Simon Burge <simonb@netbsd.org>
>Release: All? Observerd on alpha with 1.6ZG and walnut with 3.99.21
>Organization:
>Environment:
>Description:
ftruncate has a problem where it doesn't zero-fill data when a
file is extended under some circumstances. It appears to be if
you extend a file to a page sized boundary on a filesystem where
the ffs block size is half the page size. I've observed this
on a Walnut (16kB page size on ffs with 8kB block size) running
NetBSD 3.99.21 and an Alpha (8kB page size on an ffs with 4kB
block size) running NetBSD 1.6ZG.
>How-To-Repeat:
Run the following program on a system where the pagesize is
double the size of the ffs block size, and observe output of
non-zeros.
#include <err.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#define BUFLEN 0x10
main(int argc, char **argv)
{
int fd, i, pgsize;
char buf[BUFLEN];
pgsize = getpagesize();
if (argc < 2)
errx(1, "usage");
unlink(argv[1]);
fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd < 0)
err(1, "open: %s", argv[1]);
for (i = 0; i < sizeof(buf); i++)
buf[i] = i + 'A';
pwrite(fd, buf, sizeof(buf), pgsize - 0x10);
ftruncate(fd, pgsize / 2);
ftruncate(fd, pgsize);
pread(fd, buf, sizeof(buf), pgsize - 0x10);
printf("buf =");
for (i = 0; i < BUFLEN; i++)
printf(" %02x", buf[i]);
printf("\n");
close(fd);
exit(0);
}
>Fix:
None given...
ffs_truncate() calls ufs_balloc_range() then basically returns.
The comment above ufs_balloc_range() says
* after this function returns, any page entirely contained within the range
* will map to invalid data and thus must be overwritten before it is made
* accessible to others.
which seems to indicate we should be zero'ing something
somewhere. I've no idea why this problem is showing up only
with certain specific page size and block size combinations.