1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-17 10:26:15 +00:00

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
This commit is contained in:
Konstantin Belousov 2013-05-02 20:00:11 +00:00
parent 57f37a2584
commit 293e4eb67d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=250193
2 changed files with 50 additions and 13 deletions

View File

@ -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);
}
/*

View File

@ -850,9 +850,6 @@ msdosfs_write(ap)
/*
* 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