Panic with msdosfs vs 1.3TB FAT32

Kostik Belousov kostikbel at gmail.com
Wed Oct 6 20:01:09 UTC 2010


On Wed, Oct 06, 2010 at 03:02:03PM +0000, Paul B Mahol wrote:
> On 10/6/10, Mario Sergio Fujikawa Ferreira <lioux-list at uol.com.br> wrote:
> > On 06/10/2010 00:36, Paul B Mahol wrote:
> >> On 10/6/10, Mario Sergio Fujikawa Ferreira<lioux-list at uol.com.br>  wrote:
> >>> Hi,
> >>>
> >>> 	I mounted a 1.3TB FAT32 (32k cluster) filesystem on esata
> >>> /dev/ada4s1 under /media/esata/ with the '-l' (large option).
> What FreeBSD version is this and how many files that fs have?
> 
> >>>
> >>> 	I tried to create a directory and files but got errors:
> 
> If you mount it read only, can you read all files?
> 
> This could eat all memory if there are many small files....
> But it can be useful to know if you can read files with different
> inodes (or whatever FAT calls it)
> >>>
> >>> ------
> >>>
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247646208, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247646208, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247613440, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247646208, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247613440, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247580672, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247646208, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247613440, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247580672, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247646208, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247613440, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247580672, length=32768)]error = 5
> >>>
> >>> ------
> >>>
> >>> 	Then, I tried unmounting the filesystem which resulted on
> >>>
> >>> ------
> >>>
> >>> fsync: giving up on dirty
> >>> 0xffffff01bad6e1d8: tag devfs, type VCHR
> >>>      usecount 1, writecount 0, refcount 38253 mountedhere
> >>> 0xffffff00ac899600
> >>>      flags ()
> >>>      v_object 0xffffff008b839ca8 ref 0 pages 44786
> >>>      lock type devfs: EXCL by thread 0xffffff016506cba0 (pid 76462)
> >>>          dev ada4s1
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247646208, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247613440, length=32768)]error = 5
> >>> g_vfs_done():ada4s1[WRITE(offset=-980247580672, length=32768)]error = 5
> >>> fsync: giving up on dirty
> >>> 0xffffff01bad6e1d8: tag devfs, type VCHR
> >>>      usecount 1, writecount 0, refcount 38253 mountedhere
> >>> 0xffffff00ac899600
> >>>      flags ()
> >>>      v_object 0xffffff008b839ca8 ref 0 pages 44786
> >>>      lock type devfs: UNLOCKED
> >>>          dev ada4s1
> >>>
> >>> Fatal trap 12: page fault while in kernel mode
> >>> cpuid = 1; apic id = 01
> >>> fault virtual address   = 0x4
> >>> fault code              = supervisor read data, page not present
> >>> instruction pointer     = 0x20:0xffffffff803e60e4
> >>> stack pointer           = 0x28:0xffffff80e79ba860
> >>> frame pointer           = 0x28:0xffffff80e79ba8a0
> >>> code segment            = base 0x0, limit 0xfffff, type 0x1b
> >>>                          = DPL 0, pres 1, long 1, def32 0, gran 1
> >>> processor eflags        = interrupt enabled, resume, IOPL = 0
> >>> current process         = 25 (syncer)
> >>>
> >>> ------
> >>>
> >>> 	The filesystem is clean since I find no errors under Windows
> >>> ('chkdsk /f').
> >>>
> >>> 	I can otherwise mount, read and write on smaller FAT32
> >>> filesystems.  I think there might be a problem with the handling
> >>> of such a big FAT32 filesystem.
> >>>
> >>> 	A complete textdump is available at
> >>>
> >>> http://people.freebsd.org/~lioux/panic/2010100500/textdump.tar.2
> >>>
> >>> 	Is this kind of error expected? Is there anything I can do
> >>> to help?
> >>>
> >>> 	I can reproduce this error with the 1.3TB fs easily.
> >>
> >> Comment in source claims that support for large fs are experimental
> >> and safe only in read only mode.
> >>
> >> Looking at your output it is obvious that offset should not be negative...
> >
> >    Now that you mention it... :)
> >
> >    I guess I might have overflown some internal variable, possibly a 32
> > bit integer.
> >
> >    I checked
> >
> > http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/fs/msdosfs/msdosfs_vfsops.c?rev=1.199
> >
> > but it did not make much sense to me. :(
> >
> >    Any ideas where I might look or for a patch? Unfortunately, I am not
> > kernel knowledgeable but I'll help however I can.
> 
> Something is very buggy with msdosfs and vfs.
> 
> kern/93634 is clear example. I can reproduce it on i386.
> 
> Note that I'm freebsd vfs/vm noob. So do not expect anything from me.

This is a consequence of case-insensitive nature of msdosfs, and the fact
that our namecache is case-sensitive. When doing a rename, lookup of the
fvp (the vnode which is to be renamed) is performed with DELETE operation,
that clears namecache from the entry for the vnode that was specified to
lookup. If any alias exists due to case-insensitive lookup done earlier,
it will not be removed.

The simplest fix seems to purge the cache for the fvp if rename was
successfull. Patch below contains the change and an optimization for
msdosfs that I apparently had long enough in my local tree. Namely,
I get a reference to the root vnode to prevent its constant recycling
after each lookup.

diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
index a0801bd..964cc2d 100644
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -421,6 +421,7 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp)
 	int ronly, error;
 	struct g_consumer *cp;
 	struct bufobj *bo;
+	struct vnode *rootvp;
 
 	bp = NULL;		/* This and pmp both used in error_exit. */
 	pmp = NULL;
@@ -758,7 +759,13 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp)
 	if (pmp->pm_flags & MSDOSFS_LARGEFS)
 		msdosfs_fileno_init(mp);
 
-	return 0;
+	error = msdosfs_root(mp, LK_EXCLUSIVE, &rootvp);
+	if (error == 0) {
+		pmp->pm_root_refs = 1;
+		VOP_UNLOCK(rootvp, 0);
+	}
+
+	return (0);
 
 error_exit:
 	if (bp)
@@ -793,10 +800,10 @@ msdosfs_unmount(struct mount *mp, int mntflags)
 	flags = 0;
 	if (mntflags & MNT_FORCE)
 		flags |= FORCECLOSE;
-	error = vflush(mp, 0, flags, curthread);
-	if (error && error != ENXIO)
-		return error;
 	pmp = VFSTOMSDOSFS(mp);
+	error = vflush(mp, pmp->pm_root_refs, flags, curthread);
+	if (error != 0 && error != ENXIO)
+		return (error);
 	if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) {
 		error = markvoldirty(pmp, 0);
 		if (error && error != ENXIO) {
diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
index 7a19412..416e702 100644
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -1258,6 +1258,7 @@ abortit:
 		}
 	}
 
+	cache_purge(fvp);
 	VOP_UNLOCK(fvp, 0);
 bad:
 	if (xp)
diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h
index 2951b2c..7e6b234 100644
--- a/sys/fs/msdosfs/msdosfsmount.h
+++ b/sys/fs/msdosfs/msdosfsmount.h
@@ -112,6 +112,7 @@ struct msdosfsmount {
 	RB_HEAD(msdosfs_filenotree, msdosfs_fileno)
 	    pm_filenos; /* 64<->32-bit fileno mapping */
 	struct lock pm_fatlock;	/* lockmgr protecting allocations and rb tree */
+	int pm_root_refs;	/* Did we obtained root reference ? */
 };
 
 /*
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-fs/attachments/20101006/4ad609aa/attachment.pgp


More information about the freebsd-fs mailing list