kern/62762: Fsync for msdos fs does not sync entries
Amit Khivesara
khivi at psyche.nj.us.utstar.com
Thu Feb 12 16:10:14 PST 2004
>Number: 62762
>Category: kern
>Synopsis: Fsync for msdos fs does not sync entries
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Thu Feb 12 16:10:13 PST 2004
>Closed-Date:
>Last-Modified:
>Originator: Amit Khivesara
>Release: FreeBSD 4.9-RELEASE i386
>Organization:
>Environment:
System: FreeBSD mobo11 4.9-XOS-kernel-4.9-dev Build 44281 2004/02/12 16:34:09, khivi at psyche 2004/02/12 18:53:46 FreeBSD root at psyche.nj.us.utstar.com:/usr/home/khivi/p4/mobo-4.9/kernel/build/kernel/DISKLESS i386
>Description:
Fsync on a file should sync all the data and meta-data blocks
for the file. For the msdos fs, the fat enteries do not get synced.
>How-To-Repeat:
Do multiple file writes on a file and fsync the file.
Reboot really fast (pull power plug or reboot -q -n ). Basically you
do not want the syncher to come in and sync the dirty blocks.
On power up the files will contain a partial file or a bad file.
>Fix:
diff -ur msdosfs.old/fat.h msdosfs.new/fat.h
--- msdosfs.old/fat.h Thu Feb 12 18:39:32 2004
+++ msdosfs.new/fat.h Thu Feb 12 18:36:13 2004
@@ -104,5 +104,6 @@
int freeclusterchain __P((struct msdosfsmount *pmp, u_long startchain));
int extendfile __P((struct denode *dep, u_long count, struct buf **bpp, u_long *ncp, int flags));
void fc_purge __P((struct denode *dep, u_int frcn));
+void fat_sync __P((struct vnode * , struct denode *dep));
#endif /* _KERNEL */
diff -ur msdosfs.old/msdosfs_fat.c msdosfs.new/msdosfs_fat.c
--- msdosfs.old/msdosfs_fat.c Thu Feb 12 18:39:32 2004
+++ msdosfs.new/msdosfs_fat.c Thu Feb 12 18:49:38 2004
@@ -322,6 +322,80 @@
}
}
+
+/*
+ * Sync the fat cache in denode dep of all entries relating to file
+ */
+void
+fat_sync(vnode,dep)
+ struct vnode *vnode;
+ struct denode *dep;
+{
+ u_long cn;
+ u_long prevcn;
+
+ u_long byteoffset;
+ u_long bsize;
+ u_long bo;
+ u_long bn;
+ u_long bp_bn = -1;
+ int error;
+ struct buf *bp = NULL;
+ struct msdosfsmount *pmp = dep->de_pmp;
+
+ u_int pm_flags=pmp->pm_flags;
+ pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
+
+ cn=dep->de_StartCluster;
+ while (1){
+ /*
+ * Stop with all reserved clusters, not just with EOF.
+ */
+ if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
+ goto hiteof;
+ byteoffset = FATOFS(pmp, cn);
+ fatblock(pmp, byteoffset, &bn, &bsize, &bo);
+ if (bn != bp_bn) {
+ if (bp) {
+ updatefats(pmp, bp, bp_bn);
+ }
+ error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ goto func_ret;
+ }
+ bp_bn = bn;
+ }
+
+ prevcn = cn;
+ if (FAT32(pmp))
+ cn = getulong(&bp->b_data[bo]);
+ else
+ cn = getushort(&bp->b_data[bo]);
+ if (FAT12(pmp) && (prevcn & 1))
+ cn >>= 4;
+ cn &= pmp->pm_fatmask;
+
+ /*
+ * Force the special cluster numbers
+ * to be the same for all cluster sizes
+ * to let the rest of msdosfs handle
+ * all cases the same.
+ */
+ if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
+ cn |= ~pmp->pm_fatmask;
+ }
+
+
+hiteof:
+ if (bp) {
+ updatefats(pmp, bp, bp_bn);
+ }
+func_ret:
+ pmp->pm_flags=pm_flags;
+ return;
+}
+
/*
* Update the fat.
* If mirroring the fat, update all copies, with the first copy as last.
diff -ur msdosfs.old/msdosfs_vnops.c msdosfs.new/msdosfs_vnops.c
--- msdosfs.old/msdosfs_vnops.c Thu Feb 12 18:39:32 2004
+++ msdosfs.new/msdosfs_vnops.c Thu Feb 12 18:50:37 2004
@@ -875,6 +875,7 @@
(void) bwrite(bp);
goto loop;
}
+ fat_sync(vp,VTODE(vp));
while (vp->v_numoutput) {
vp->v_flag |= VBWAIT;
(void) tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "msdosfsn", 0);
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list