kern/47628: msdosfs file corruption fix

Tor Egge Tor.Egge at cvsup.no.freebsd.org
Wed Aug 27 20:31:43 UTC 2008


I recently stumbled onto the same issue when setting up a backup disk with a
msdosfs scratch area for transfer of files.  I used rsync with the 'S' option
to copy the files to the FAT32 file system, resulting in corrupted blocks.  The
cluster size was 32K.

Looking at the badness in a file, blocks 5 and 6 contained NULs instead of the
correct file data.  Those were the only blocks where the first byte should be a
NUL.

A few extra debug messages in the file system code (e.g. in msdosfs_strategy)
when reproducing the problem showed that blocks 5 and 6 were correctly written,
but later blocks 320 and 384 were written to the same location with NULs.  The
file was 319488 bytes long, and should only have blocks in the range [0..9].

This problem seems to have been introduced in revision 1.17 of
src/sys/fs/msdosfs/msdosfs_fat.c, where file relative cluster numbers were
replaced by file relative sector numbers as the buffer block number when
zero-padding a file during extension.

With the enclosed patch applied, I no longer got corrupted files, but I 
only tested with clustering disabled, using 

  mount -t msdosfs -o large -o noclusterr -o noclusterw /dev/da6s1 /mnt

to mount the file system.

As an alternative to initializing nvp->v_bufobj.bo_bsize to the cluster size
for regular files, mp->mnt_stat.f_iosize could be initialized to the cluster
size in mountmsdosfs().  The cluster size would then be copied to new vnodes in
getnewvnode().

- Tor Egge
-------------- next part --------------
Index: sys/fs/msdosfs/msdosfs_denode.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/msdosfs/msdosfs_denode.c,v
retrieving revision 1.99
diff -u -r1.99 msdosfs_denode.c
--- sys/fs/msdosfs/msdosfs_denode.c	24 Jan 2008 12:34:26 -0000	1.99
+++ sys/fs/msdosfs/msdosfs_denode.c	26 Aug 2008 04:52:06 -0000
@@ -163,6 +163,8 @@
 	}
 	bzero((caddr_t)ldep, sizeof *ldep);
 	nvp->v_data = ldep;
+	if ((ldep->de_Attributes & ATTR_DIRECTORY) == 0)
+		nvp->v_bufobj.bo_bsize = pmp->pm_bpcluster;
 	ldep->de_vnode = nvp;
 	ldep->de_flag = 0;
 	ldep->de_dirclust = dirclust;
Index: sys/fs/msdosfs/msdosfs_fat.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/msdosfs/msdosfs_fat.c,v
retrieving revision 1.49
diff -u -r1.49 msdosfs_fat.c
--- sys/fs/msdosfs/msdosfs_fat.c	25 Oct 2007 08:23:08 -0000	1.49
+++ sys/fs/msdosfs/msdosfs_fat.c	26 Aug 2008 04:09:26 -0000
@@ -1065,13 +1065,13 @@
 					    pmp->pm_bpcluster, 0, 0, 0);
 				else {
 					bp = getblk(DETOV(dep),
-					    de_cn2bn(pmp, frcn++),
+						    frcn++,
 					    pmp->pm_bpcluster, 0, 0, 0);
 					/*
 					 * Do the bmap now, as in msdosfs_write
 					 */
 					if (pcbmap(dep,
-					    de_bn2cn(pmp, bp->b_lblkno),
+						   bp->b_lblkno,
 					    &blkno, 0, 0))
 						bp->b_blkno = -1;
 					if (bp->b_blkno == -1)


More information about the freebsd-bugs mailing list