svn commit: r250193 - head/sys/fs/msdosfs

Konstantin Belousov kib at FreeBSD.org
Thu May 2 20:00:11 UTC 2013


Author: kib
Date: Thu May  2 20:00:11 2013
New Revision: 250193
URL: http://svnweb.freebsd.org/changeset/base/250193

Log:
  The fsync(2) call should sync the vnode in such way that even after
  system crash which happen after successfull fsync() return, the data
  is accessible.  For msdosfs, this means that FAT entries for the file
  must be written.
  
  Since we do not track the FAT blocks containing entries for the
  current file, just do a sloppy sync of the devvp vnode for the mount,
  which buffers, among other things, contain FAT blocks.
  
  Simultaneously, for deupdat():
  - optimize by clearing the modified flags before short-circuiting a
    return, if the mount is read-only;
  - only ignore the rest of the function for denode with DE_MODIFIED
    flag clear when the waitfor argument is false.  The directory buffer
    for the entry might be of delayed write;
  - microoptimize by comparing the updated directory entry with the
    current block content;
  - try to cluster the write, fall back to bawrite() if low on
    resources.
  
  Based on the submission by:	bde
  MFC after:	2 weeks

Modified:
  head/sys/fs/msdosfs/msdosfs_denode.c
  head/sys/fs/msdosfs/msdosfs_vnops.c

Modified: head/sys/fs/msdosfs/msdosfs_denode.c
==============================================================================
--- head/sys/fs/msdosfs/msdosfs_denode.c	Thu May  2 19:47:36 2013	(r250192)
+++ head/sys/fs/msdosfs/msdosfs_denode.c	Thu May  2 20:00:11 2013	(r250193)
@@ -288,16 +288,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)
@@ -307,13 +311,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: head/sys/fs/msdosfs/msdosfs_vnops.c
==============================================================================
--- head/sys/fs/msdosfs/msdosfs_vnops.c	Thu May  2 19:47:36 2013	(r250192)
+++ head/sys/fs/msdosfs/msdosfs_vnops.c	Thu May  2 20:00:11 2013	(r250193)
@@ -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


More information about the svn-src-head mailing list