aboutsummaryrefslogtreecommitdiffstats
path: root/module/os/linux/zfs
diff options
context:
space:
mode:
authorAlexander Motin <[email protected]>2023-10-30 17:51:56 -0400
committerGitHub <[email protected]>2023-10-30 14:51:56 -0700
commitc3773de168668a5515e82d100ed6509e7d174fe9 (patch)
tree3dae009ceb5b1b83d177e43f48038cb2d59016c0 /module/os/linux/zfs
parent043c6ee3b6bfb55f8d36e1f048ff13128c279fb8 (diff)
ZIL: Cleanup sync and commit handling
ZVOL: - Mark all ZVOL ZIL transactions as sync. Since ZVOLs have only one object, it makes no sense to maintain async queue and on each commit merge it into sync. Single sync queue is just cheaper, while it changes nothing until actual commit request arrives. - Remove zsd_sync_cnt and the zil_async_to_sync() calls since we are no longer switching between sync and async queues. ZFS: - Mark write transactions as sync based only on number of sync opens (z_sync_cnt). We can not randomly jump between sync and async unless we want data corruptions due to writes reordering. - When file first opened with O_SYNC (z_sync_cnt incremented to 1) call zil_async_to_sync() for it to preserve correct ordering between past and future writes. - Drop zfs_fsyncer_key logic. Looks like it was an optimization for workloads heavily intermixing async writes with tons of fsyncs. But first it was broken 8 years ago due to Linux tsd implementation not allowing data storage between syscalls, and second, I doubt it is safe to switch from async to sync so often and without calling zil_async_to_sync(). - Rename sync argument of *_log_write() into commit, now only signalling caller's intent to call zil_commit() soon after. It allows WR_COPIED optimizations without extra other meanings. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: George Wilson <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Sponsored by: iXsystems, Inc. Closes #15366
Diffstat (limited to 'module/os/linux/zfs')
-rw-r--r--module/os/linux/zfs/zfs_vnops_os.c36
-rw-r--r--module/os/linux/zfs/zvol_os.c2
2 files changed, 24 insertions, 14 deletions
diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c
index 1770e2372..6ad75ace0 100644
--- a/module/os/linux/zfs/zfs_vnops_os.c
+++ b/module/os/linux/zfs/zfs_vnops_os.c
@@ -192,9 +192,15 @@ zfs_open(struct inode *ip, int mode, int flag, cred_t *cr)
return (SET_ERROR(EPERM));
}
- /* Keep a count of the synchronous opens in the znode */
- if (flag & O_SYNC)
- atomic_inc_32(&zp->z_sync_cnt);
+ /*
+ * Keep a count of the synchronous opens in the znode. On first
+ * synchronous open we must convert all previous async transactions
+ * into sync to keep correct ordering.
+ */
+ if (flag & O_SYNC) {
+ if (atomic_inc_32_nv(&zp->z_sync_cnt) == 1)
+ zil_async_to_sync(zfsvfs->z_log, zp->z_id);
+ }
zfs_exit(zfsvfs, FTAG);
return (0);
@@ -3826,21 +3832,14 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc,
err = sa_bulk_update(zp->z_sa_hdl, bulk, cnt, tx);
- zfs_log_write(zfsvfs->z_log, tx, TX_WRITE, zp, pgoff, pglen, 0,
- for_sync ? zfs_putpage_sync_commit_cb :
- zfs_putpage_async_commit_cb, pp);
-
- dmu_tx_commit(tx);
-
- zfs_rangelock_exit(lr);
-
+ boolean_t commit = B_FALSE;
if (wbc->sync_mode != WB_SYNC_NONE) {
/*
* Note that this is rarely called under writepages(), because
* writepages() normally handles the entire commit for
* performance reasons.
*/
- zil_commit(zfsvfs->z_log, zp->z_id);
+ commit = B_TRUE;
} else if (!for_sync && atomic_load_32(&zp->z_sync_writes_cnt) > 0) {
/*
* If the caller does not intend to wait synchronously
@@ -3850,9 +3849,20 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc,
* our writeback to complete. Refer to the comment in
* zpl_fsync() (when HAVE_FSYNC_RANGE is defined) for details.
*/
- zil_commit(zfsvfs->z_log, zp->z_id);
+ commit = B_TRUE;
}
+ zfs_log_write(zfsvfs->z_log, tx, TX_WRITE, zp, pgoff, pglen, commit,
+ for_sync ? zfs_putpage_sync_commit_cb :
+ zfs_putpage_async_commit_cb, pp);
+
+ dmu_tx_commit(tx);
+
+ zfs_rangelock_exit(lr);
+
+ if (commit)
+ zil_commit(zfsvfs->z_log, zp->z_id);
+
dataset_kstats_update_write_kstats(&zfsvfs->z_kstat, pglen);
zfs_exit(zfsvfs, FTAG);
diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c
index f94ce69fb..3dc0bb388 100644
--- a/module/os/linux/zfs/zvol_os.c
+++ b/module/os/linux/zfs/zvol_os.c
@@ -387,7 +387,7 @@ zvol_discard(zv_request_t *zvr)
if (error != 0) {
dmu_tx_abort(tx);
} else {
- zvol_log_truncate(zv, tx, start, size, B_TRUE);
+ zvol_log_truncate(zv, tx, start, size);
dmu_tx_commit(tx);
error = dmu_free_long_range(zv->zv_objset,
ZVOL_OBJ, start, size);