FAT32 corruption (related to kern/39043)

Axel Gonzalez loox at e-shell.net
Sat Oct 1 11:16:09 PDT 2005


I had noticed some strange behaviour with some programs on FAT32 partitions, 
then I got into kern/39043 (moving files over samba), wich has been open for 
over 3 years.

Then I decided to do some research.

I made a simple program, that opens some files, write some data, and close the 
file (included at end).

Inmediately after the program is done, the files are ok, all data is plain 
text, and they have what is expected.

But after some time, or some disk access (unrelated to the files), the files 
are corrupted!, with lots of garbage.

By looking at the uncorrupted text (specially formated for this), it seems 
that the corruption is in blocks of 4096 (the size of the partition's 
clusters).

This leads me to belive there is a problem flushing cache entries to the 
directory structure (so directory entries get corrupted, by pointing to 
unrelated clusters).

Sometimes files are ok, but its easy to get a corrupted one.


This is what I did:

$ uname -a
FreeBSD moonlight.e-shell.net 5.4-STABLE FreeBSD 5.4-STABLE #1: Fri Sep 30 
01:02:32 CDT 2005     loox at ...:/usr/obj/usr/src/sys/LXAMD64  amd64

$ ./fat32
/mnt/wina5/tmp/test0
/mnt/wina5/tmp/test1
/mnt/wina5/tmp/test2
/mnt/wina5/tmp/test3
/mnt/wina5/tmp/test4
/mnt/wina5/tmp/test5
/mnt/wina5/tmp/test6
/mnt/wina5/tmp/test7

Files are created ok

$ cat test0 | grep -v file00
$

file is ok.. no weird data

do some disk access:

$ find / > /dev/null
$

test the file again:

$ cat test0 | grep -v file00
(lots of binary garbage)
$


The program I used to test:
**************************************************
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

#define _PATH "/mnt/wina5/tmp"

#define BLOCK 8192
#define NUM 1024
#define FN 8

int main()
{
        int i, j, k;
        int fd[FN];
        char file[128];
        char name[128] = "test";
        char str[BLOCK + 1];

        for (j = 0; j < FN; j++) {

                sprintf(file, "%s/%s%d", _PATH, name, j);

                printf("%s\n", file);

                fd[j] = open(file, O_RDWR | O_TRUNC | O_CREAT);

                for (i = NUM; i >= 0; i--) {

                        for (k = 0; k < BLOCK; k += 32)
                                sprintf(str + k, "file%02d | Block: %06d 
[%06d]\n", j, i, k);

                        lseek(fd[j], i * BLOCK, SEEK_SET);
                        write(fd[j], str, BLOCK);
                }
        }

        for (j = 0; j < FN; j++)
                close(fd[j]);
}


More information about the freebsd-stable mailing list