summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2016-08-29 05:53:59 +0000
committerkib <kib@FreeBSD.org>2016-08-29 05:53:59 +0000
commit87637d7979c28fea800112c0b6f271b6db0ee56b (patch)
treec39f90bdd2fa3adf1c82d3f61bf329eddee0fd4a /sys/ufs
parent840001f858ff69f481ee7ca9b365d5fff8c9cfa9 (diff)
downloadFreeBSD-src-87637d7979c28fea800112c0b6f271b6db0ee56b.zip
FreeBSD-src-87637d7979c28fea800112c0b6f271b6db0ee56b.tar.gz
MFC r304180:
Implement VOP_FDATASYNC() for UFS.
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_extern.h5
-rw-r--r--sys/ufs/ffs/ffs_vnops.c85
2 files changed, 68 insertions, 22 deletions
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
index b4ec348..203bc66 100644
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -174,6 +174,11 @@ void softdep_freework(struct workhead *);
* deadlock when flushing snapshot inodes while holding snaplk.
*/
#define NO_INO_UPDT 0x00000001
+/*
+ * Request data sync only from ffs_syncvnode(), not touching even more
+ * metadata than NO_INO_UPDT.
+ */
+#define DATA_ONLY 0x00000002
int ffs_rdonly(struct inode *);
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index 69182850..2765480 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -103,6 +103,7 @@ __FBSDID("$FreeBSD$");
extern int ffs_rawread(struct vnode *vp, struct uio *uio, int *workdone);
#endif
static vop_fsync_t ffs_fsync;
+static vop_fdatasync_t ffs_fdatasync;
static vop_lock1_t ffs_lock;
static vop_read_t ffs_read;
static vop_write_t ffs_write;
@@ -123,6 +124,7 @@ static vop_vptofh_t ffs_vptofh;
struct vop_vector ffs_vnodeops1 = {
.vop_default = &ufs_vnodeops,
.vop_fsync = ffs_fsync,
+ .vop_fdatasync = ffs_fdatasync,
.vop_getpages = vnode_pager_local_getpages,
.vop_getpages_async = vnode_pager_local_getpages_async,
.vop_lock1 = ffs_lock,
@@ -135,6 +137,7 @@ struct vop_vector ffs_vnodeops1 = {
struct vop_vector ffs_fifoops1 = {
.vop_default = &ufs_fifoops,
.vop_fsync = ffs_fsync,
+ .vop_fdatasync = ffs_fdatasync,
.vop_reallocblks = ffs_reallocblks, /* XXX: really ??? */
.vop_vptofh = ffs_vptofh,
};
@@ -143,6 +146,7 @@ struct vop_vector ffs_fifoops1 = {
struct vop_vector ffs_vnodeops2 = {
.vop_default = &ufs_vnodeops,
.vop_fsync = ffs_fsync,
+ .vop_fdatasync = ffs_fdatasync,
.vop_getpages = vnode_pager_local_getpages,
.vop_getpages_async = vnode_pager_local_getpages_async,
.vop_lock1 = ffs_lock,
@@ -161,6 +165,7 @@ struct vop_vector ffs_vnodeops2 = {
struct vop_vector ffs_fifoops2 = {
.vop_default = &ufs_fifoops,
.vop_fsync = ffs_fsync,
+ .vop_fdatasync = ffs_fdatasync,
.vop_lock1 = ffs_lock,
.vop_reallocblks = ffs_reallocblks,
.vop_strategy = ffsext_strategy,
@@ -216,10 +221,10 @@ ffs_syncvnode(struct vnode *vp, int waitfor, int flags)
{
struct inode *ip;
struct bufobj *bo;
- struct buf *bp;
- struct buf *nbp;
+ struct buf *bp, *nbp;
ufs_lbn_t lbn;
- int error, wait, passes;
+ int error, passes;
+ bool still_dirty, wait;
ip = VTOI(vp);
ip->i_flag &= ~IN_NEEDSYNC;
@@ -238,7 +243,7 @@ ffs_syncvnode(struct vnode *vp, int waitfor, int flags)
*/
error = 0;
passes = 0;
- wait = 0; /* Always do an async pass first. */
+ wait = false; /* Always do an async pass first. */
lbn = lblkno(ip->i_fs, (ip->i_size + ip->i_fs->fs_bsize - 1));
BO_LOCK(bo);
loop:
@@ -254,15 +259,23 @@ loop:
if ((bp->b_vflags & BV_SCANNED) != 0)
continue;
bp->b_vflags |= BV_SCANNED;
- /* Flush indirects in order. */
+ /*
+ * Flush indirects in order, if requested.
+ *
+ * Note that if only datasync is requested, we can
+ * skip indirect blocks when softupdates are not
+ * active. Otherwise we must flush them with data,
+ * since dependencies prevent data block writes.
+ */
if (waitfor == MNT_WAIT && bp->b_lblkno <= -NDADDR &&
- lbn_level(bp->b_lblkno) >= passes)
+ (lbn_level(bp->b_lblkno) >= passes ||
+ ((flags & DATA_ONLY) != 0 && !DOINGSOFTDEP(vp))))
continue;
if (bp->b_lblkno > lbn)
panic("ffs_syncvnode: syncing truncated data.");
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) == 0) {
BO_UNLOCK(bo);
- } else if (wait != 0) {
+ } else if (wait) {
if (BUF_LOCK(bp,
LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
BO_LOCKPTR(bo)) != 0) {
@@ -330,31 +343,59 @@ next:
* these will be done with one sync and one async pass.
*/
if (bo->bo_dirty.bv_cnt > 0) {
- /* Write the inode after sync passes to flush deps. */
- if (wait && DOINGSOFTDEP(vp) && (flags & NO_INO_UPDT) == 0) {
- BO_UNLOCK(bo);
- ffs_update(vp, 1);
- BO_LOCK(bo);
+ if ((flags & DATA_ONLY) == 0) {
+ still_dirty = true;
+ } else {
+ /*
+ * For data-only sync, dirty indirect buffers
+ * are ignored.
+ */
+ still_dirty = false;
+ TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs) {
+ if (bp->b_lblkno > -NDADDR) {
+ still_dirty = true;
+ break;
+ }
+ }
}
- /* switch between sync/async. */
- wait = !wait;
- if (wait == 1 || ++passes < NIADDR + 2)
- goto loop;
+
+ if (still_dirty) {
+ /* Write the inode after sync passes to flush deps. */
+ if (wait && DOINGSOFTDEP(vp) &&
+ (flags & NO_INO_UPDT) == 0) {
+ BO_UNLOCK(bo);
+ ffs_update(vp, 1);
+ BO_LOCK(bo);
+ }
+ /* switch between sync/async. */
+ wait = !wait;
+ if (wait || ++passes < NIADDR + 2)
+ goto loop;
#ifdef INVARIANTS
- if (!vn_isdisk(vp, NULL))
- vn_printf(vp, "ffs_fsync: dirty ");
+ if (!vn_isdisk(vp, NULL))
+ vn_printf(vp, "ffs_fsync: dirty ");
#endif
+ }
}
BO_UNLOCK(bo);
error = 0;
- if ((flags & NO_INO_UPDT) == 0)
- error = ffs_update(vp, 1);
- if (DOINGSUJ(vp))
- softdep_journal_fsync(VTOI(vp));
+ if ((flags & DATA_ONLY) == 0) {
+ if ((flags & NO_INO_UPDT) == 0)
+ error = ffs_update(vp, 1);
+ if (DOINGSUJ(vp))
+ softdep_journal_fsync(VTOI(vp));
+ }
return (error);
}
static int
+ffs_fdatasync(struct vop_fdatasync_args *ap)
+{
+
+ return (ffs_syncvnode(ap->a_vp, MNT_WAIT, DATA_ONLY));
+}
+
+static int
ffs_lock(ap)
struct vop_lock1_args /* {
struct vnode *a_vp;
OpenPOWER on IntegriCloud