From 8acf168aab4ef7a95d91305a8b2cdb51ab71a1c7 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Tue, 1 Nov 2016 16:03:31 +0000 Subject: [PATCH] Fix ZIL records ordering when ZVOL opened both with and without FSYNC. Before this an earlier writes to a ZVOL opened without FSYNC could get to ZIL after later writes to the same ZVOL opened with FSYNC. Fix this by replicating functionality of ZPL (zv_sync_cnt equivalent to z_sync_cnt), marking all log records sync if anybody opened the ZVOL with FSYNC. MFC after: 2 weeks --- .../opensolaris/uts/common/fs/zfs/sys/zil.h | 1 + .../contrib/opensolaris/uts/common/fs/zfs/zil.c | 4 +--- .../contrib/opensolaris/uts/common/fs/zfs/zvol.c | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h index 1642da08197..8887aa8d925 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h @@ -405,6 +405,7 @@ extern itx_t *zil_itx_create(uint64_t txtype, size_t lrsize); extern void zil_itx_destroy(itx_t *itx); extern void zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx); +extern void zil_async_to_sync(zilog_t *zilog, uint64_t oid); extern void zil_commit(zilog_t *zilog, uint64_t oid); extern int zil_vdev_offline(const char *osname, void *txarg); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c index dbff8bd66db..6d58078a5d9 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c @@ -90,8 +90,6 @@ SYSCTL_INT(_vfs_zfs_trim, OID_AUTO, enabled, CTLFLAG_RDTUN, &zfs_trim_enabled, 0 static kmem_cache_t *zil_lwb_cache; -static void zil_async_to_sync(zilog_t *zilog, uint64_t foid); - #define LWB_EMPTY(lwb) ((BP_GET_LSIZE(&lwb->lwb_blk) - \ sizeof (zil_chain_t)) == (lwb->lwb_sz - lwb->lwb_nused)) @@ -1421,7 +1419,7 @@ zil_get_commit_list(zilog_t *zilog) /* * Move the async itxs for a specified object to commit into sync lists. */ -static void +void zil_async_to_sync(zilog_t *zilog, uint64_t foid) { uint64_t otxg, txg; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c index afaf4ffb53e..908de12a46c 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c @@ -169,6 +169,7 @@ typedef struct zvol_state { uint32_t zv_open_count[OTYPCNT]; /* open counts */ #endif uint32_t zv_total_opens; /* total open count */ + uint32_t zv_sync_cnt; /* synchronous open count */ zilog_t *zv_zilog; /* ZIL handle */ list_t zv_extents; /* List of extents for dump */ znode_t zv_znode; /* for range locking */ @@ -1441,7 +1442,9 @@ zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, offset_t off, ssize_t resid, BP_ZERO(&lr->lr_blkptr); itx->itx_private = zv; - itx->itx_sync = sync; + + if (!sync && (zv->zv_sync_cnt == 0)) + itx->itx_sync = B_FALSE; zil_itx_assign(zilog, itx, tx); @@ -2083,7 +2086,7 @@ zvol_log_truncate(zvol_state_t *zv, dmu_tx_t *tx, uint64_t off, uint64_t len, lr->lr_offset = off; lr->lr_length = len; - itx->itx_sync = sync; + itx->itx_sync = (sync || zv->zv_sync_cnt != 0); zil_itx_assign(zilog, itx, tx); } @@ -3075,6 +3078,11 @@ zvol_d_open(struct cdev *dev, int flags, int fmt, struct thread *td) #endif zv->zv_total_opens++; + if (flags & (FSYNC | FDSYNC)) { + zv->zv_sync_cnt++; + if (zv->zv_sync_cnt == 1) + zil_async_to_sync(zv->zv_zilog, ZVOL_OBJ); + } mutex_exit(&zfsdev_state_lock); return (err); out: @@ -3105,6 +3113,8 @@ zvol_d_close(struct cdev *dev, int flags, int fmt, struct thread *td) * You may get multiple opens, but only one close. */ zv->zv_total_opens--; + if (flags & (FSYNC | FDSYNC)) + zv->zv_sync_cnt--; if (zv->zv_total_opens == 0) zvol_last_close(zv); -- 2.45.2