ZIL: allow zil_commit() to fail with error

This changes zil_commit() to have an int return, and updates all callers
to check it. There are no corresponding internal changes yet; it will
always return 0.

Since zil_commit() is an indication that the caller _really_ wants the
associated data to be durability stored, I've annotated it with the
__warn_unused_result__ compiler attribute (via __must_check), to emit a
warning if it's ever ussd without doing something with the return code.
I hope this will mean we never misuse it in the future.

Sponsored-by: Klara, Inc.
Sponsored-by: Wasabi Technology, Inc.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com>
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Closes #17398
This commit is contained in:
Rob Norris
2025-02-24 15:14:23 +11:00
committed by Brian Behlendorf
parent 1f8c39ddb2
commit 967b15b888
16 changed files with 147 additions and 85 deletions
+2 -2
View File
@@ -288,10 +288,10 @@ zfs_sync(struct super_block *sb, int wait, cred_t *cr)
return (SET_ERROR(EIO));
}
zil_commit(zfsvfs->z_log, 0);
err = zil_commit(zfsvfs->z_log, 0);
zfs_exit(zfsvfs, FTAG);
return (0);
return (err);
}
static void
+35 -27
View File
@@ -841,8 +841,8 @@ out:
*zpp = zp;
}
if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zilog, 0);
if (error == 0 && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
error = zil_commit(zilog, 0);
zfs_exit(zfsvfs, FTAG);
return (error);
@@ -1203,8 +1203,8 @@ out:
zfs_zrele_async(xzp);
}
if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zilog, 0);
if (error == 0 && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
error = zil_commit(zilog, 0);
zfs_exit(zfsvfs, FTAG);
return (error);
@@ -1392,14 +1392,15 @@ out:
zfs_dirent_unlock(dl);
if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zilog, 0);
if (error != 0) {
zrele(zp);
} else {
zfs_znode_update_vfs(dzp);
zfs_znode_update_vfs(zp);
if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
error = zil_commit(zilog, 0);
}
zfs_exit(zfsvfs, FTAG);
return (error);
@@ -1528,8 +1529,8 @@ out:
zfs_znode_update_vfs(zp);
zrele(zp);
if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zilog, 0);
if (error == 0 && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
error = zil_commit(zilog, 0);
zfs_exit(zfsvfs, FTAG);
return (error);
@@ -2630,8 +2631,8 @@ out:
}
out2:
if (os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zilog, 0);
if (err == 0 && os->os_sync == ZFS_SYNC_ALWAYS)
err = zil_commit(zilog, 0);
out3:
kmem_free(xattr_bulk, sizeof (sa_bulk_attr_t) * bulks);
@@ -3235,8 +3236,8 @@ out:
zfs_dirent_unlock(sdl);
zfs_dirent_unlock(tdl);
if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zilog, 0);
if (error == 0 && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
error = zil_commit(zilog, 0);
zfs_exit(zfsvfs, FTAG);
return (error);
@@ -3436,7 +3437,7 @@ top:
*zpp = zp;
if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zilog, 0);
error = zil_commit(zilog, 0);
} else {
zrele(zp);
}
@@ -3670,18 +3671,20 @@ top:
zfs_dirent_unlock(dl);
if (!is_tmpfile && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zilog, 0);
if (error == 0) {
if (!is_tmpfile && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
error = zil_commit(zilog, 0);
if (is_tmpfile && zfsvfs->z_os->os_sync != ZFS_SYNC_DISABLED) {
txg_wait_flag_t wait_flags =
spa_get_failmode(dmu_objset_spa(zfsvfs->z_os)) ==
ZIO_FAILURE_MODE_CONTINUE ? TXG_WAIT_SUSPEND : 0;
error = txg_wait_synced_flags(dmu_objset_pool(zfsvfs->z_os),
txg, wait_flags);
if (error != 0) {
ASSERT3U(error, ==, ESHUTDOWN);
error = SET_ERROR(EIO);
if (is_tmpfile && zfsvfs->z_os->os_sync != ZFS_SYNC_DISABLED) {
txg_wait_flag_t wait_flags =
spa_get_failmode(dmu_objset_spa(zfsvfs->z_os)) ==
ZIO_FAILURE_MODE_CONTINUE ? TXG_WAIT_SUSPEND : 0;
error = txg_wait_synced_flags(
dmu_objset_pool(zfsvfs->z_os), txg, wait_flags);
if (error != 0) {
ASSERT3U(error, ==, ESHUTDOWN);
error = SET_ERROR(EIO);
}
}
}
@@ -3939,8 +3942,13 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc,
zfs_rangelock_exit(lr);
if (need_commit)
zil_commit(zfsvfs->z_log, zp->z_id);
if (need_commit) {
err = zil_commit(zfsvfs->z_log, zp->z_id);
if (err != 0) {
zfs_exit(zfsvfs, FTAG);
return (err);
}
}
dataset_kstats_update_write_kstats(&zfsvfs->z_kstat, pglen);
+11 -1
View File
@@ -22,6 +22,7 @@
/*
* Copyright (c) 2011, Lawrence Livermore National Security, LLC.
* Copyright (c) 2015 by Chunwei Chen. All rights reserved.
* Copyright (c) 2025, Klara, Inc.
*/
@@ -495,9 +496,18 @@ zpl_writepages(struct address_space *mapping, struct writeback_control *wbc)
if ((result = zpl_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
return (result);
if (zfsvfs->z_log != NULL)
zil_commit(zfsvfs->z_log, zp->z_id);
result = -zil_commit(zfsvfs->z_log, zp->z_id);
zpl_exit(zfsvfs, FTAG);
/*
* If zil_commit() failed, it's unclear what state things
* are currently in. putpage() has written back out what
* it can to the DMU, but it may not be on disk. We have
* little choice but to escape.
*/
if (result != 0)
return (result);
/*
* We need to call write_cache_pages() again (we can't just
* return after the commit) because the previous call in
+11 -5
View File
@@ -208,8 +208,14 @@ zvol_write(zv_request_t *zvr)
disk = zv->zv_zso->zvo_disk;
/* bio marked as FLUSH need to flush before write */
if (io_is_flush(bio, rq))
zil_commit(zv->zv_zilog, ZVOL_OBJ);
if (io_is_flush(bio, rq)) {
error = zil_commit(zv->zv_zilog, ZVOL_OBJ);
if (error != 0) {
rw_exit(&zv->zv_suspend_lock);
zvol_end_io(bio, rq, -error);
return;
}
}
/* Some requests are just for flush and nothing else. */
if (io_size(bio, rq) == 0) {
@@ -273,8 +279,8 @@ zvol_write(zv_request_t *zvr)
dataset_kstats_update_write_kstats(&zv->zv_kstat, nwritten);
task_io_account_write(nwritten);
if (sync)
zil_commit(zv->zv_zilog, ZVOL_OBJ);
if (error == 0 && sync)
error = zil_commit(zv->zv_zilog, ZVOL_OBJ);
rw_exit(&zv->zv_suspend_lock);
@@ -361,7 +367,7 @@ zvol_discard(zv_request_t *zvr)
zfs_rangelock_exit(lr);
if (error == 0 && sync)
zil_commit(zv->zv_zilog, ZVOL_OBJ);
error = zil_commit(zv->zv_zilog, ZVOL_OBJ);
unlock:
rw_exit(&zv->zv_suspend_lock);