Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 May 2013 06:19:29 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r250694 - stable/9/sys/fs/msdosfs
Message-ID:  <201305160619.r4G6JTGe097655@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Thu May 16 06:19:29 2013
New Revision: 250694
URL: http://svnweb.freebsd.org/changeset/base/250694

Log:
  MFC r250193:
  Do a sync of the devvp vnode for the mount, which buffers, among other
  things, contain FAT blocks.  This makes fsync(2) for msdosfs more correct
  by syncing the metadata needed to read the synced data.

Modified:
  stable/9/sys/fs/msdosfs/msdosfs_denode.c
  stable/9/sys/fs/msdosfs/msdosfs_vnops.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/fs/   (props changed)

Modified: stable/9/sys/fs/msdosfs/msdosfs_denode.c
==============================================================================
--- stable/9/sys/fs/msdosfs/msdosfs_denode.c	Thu May 16 05:16:56 2013	(r250693)
+++ stable/9/sys/fs/msdosfs/msdosfs_denode.c	Thu May 16 06:19:29 2013	(r250694)
@@ -294,16 +294,20 @@ deupdat(dep, waitfor)
 	struct denode *dep;
 	int waitfor;
 {
-	int error;
+	struct direntry dir;
+	struct timespec ts;
 	struct buf *bp;
 	struct direntry *dirp;
-	struct timespec ts;
+	int error;
 
-	if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY)
+	if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY) {
+		dep->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS |
+		    DE_MODIFIED);
 		return (0);
+	}
 	getnanotime(&ts);
 	DETIMES(dep, &ts, &ts, &ts);
-	if ((dep->de_flag & DE_MODIFIED) == 0)
+	if ((dep->de_flag & DE_MODIFIED) == 0 && waitfor == 0)
 		return (0);
 	dep->de_flag &= ~DE_MODIFIED;
 	if (dep->de_Attributes & ATTR_DIRECTORY)
@@ -313,13 +317,23 @@ deupdat(dep, waitfor)
 	error = readde(dep, &bp, &dirp);
 	if (error)
 		return (error);
-	DE_EXTERNALIZE(dirp, dep);
+	DE_EXTERNALIZE(&dir, dep);
+	if (bcmp(dirp, &dir, sizeof(dir)) == 0) {
+		if (waitfor == 0 || (bp->b_flags & B_DELWRI) == 0) {
+			brelse(bp);
+			return (0);
+		}
+	} else
+		*dirp = dir;
+	if ((DETOV(dep)->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0)
+		bp->b_flags |= B_CLUSTEROK;
 	if (waitfor)
-		return (bwrite(bp));
-	else {
+		error = bwrite(bp);
+	else if (vm_page_count_severe() || buf_dirty_count_severe())
+		bawrite(bp);
+	else
 		bdwrite(bp);
-		return (0);
-	}
+	return (error);
 }
 
 /*

Modified: stable/9/sys/fs/msdosfs/msdosfs_vnops.c
==============================================================================
--- stable/9/sys/fs/msdosfs/msdosfs_vnops.c	Thu May 16 05:16:56 2013	(r250693)
+++ stable/9/sys/fs/msdosfs/msdosfs_vnops.c	Thu May 16 06:19:29 2013	(r250694)
@@ -850,9 +850,6 @@ errexit:
 
 /*
  * Flush the blocks of a file to disk.
- *
- * This function is worthless for vnodes that represent directories. Maybe we
- * could just do a sync if they try an fsync on a directory file.
  */
 static int
 msdosfs_fsync(ap)
@@ -863,9 +860,35 @@ msdosfs_fsync(ap)
 		struct thread *a_td;
 	} */ *ap;
 {
+	struct vnode *devvp;
+	int allerror, error;
 
 	vop_stdfsync(ap);
-	return (deupdat(VTODE(ap->a_vp), ap->a_waitfor == MNT_WAIT));
+
+	/*
+	* If the syncing request comes from fsync(2), sync the entire
+	* FAT and any other metadata that happens to be on devvp.  We
+	* need this mainly for the FAT.  We write the FAT sloppily, and
+	* syncing it all now is the best we can easily do to get all
+	* directory entries associated with the file (not just the file)
+	* fully synced.  The other metadata includes critical metadata
+	* for all directory entries, but only in the MNT_ASYNC case.  We
+	* will soon sync all metadata in the file's directory entry.
+	* Non-critical metadata for associated directory entries only
+	* gets synced accidentally, as in most file systems.
+	*/
+	if (ap->a_waitfor == MNT_WAIT) {
+		devvp = VTODE(ap->a_vp)->de_pmp->pm_devvp;
+		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
+		allerror = VOP_FSYNC(devvp, MNT_WAIT, ap->a_td);
+		VOP_UNLOCK(devvp, 0);
+	} else
+		allerror = 0;
+
+	error = deupdat(VTODE(ap->a_vp), ap->a_waitfor == MNT_WAIT);
+	if (allerror == 0)
+		allerror = error;
+	return (allerror);
 }
 
 static int



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201305160619.r4G6JTGe097655>