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 _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"