Skip to content

Commit 5584fca

Browse files
committed
FreeBSD: zfs_putpage: handle page writeback errors
Page writeback is considered completed when the associated itx callback completes. A syncing writeback will receive the error in its callback directly, but an in-flight async writeback that was promoted to sync by the ZIL may also receive an error. Writeback errors, even syncing writeback errors, are not especially serious on their own, because the error will ultimately be returned to the zil_commit() caller, either zfs_fsync() for an explicit sync op (eg msync()) or to zfs_putpage() itself for a syncing (VM_PAGER_PUT_SYNC) writeback. The only thing we need to do when a page writeback fails is to skip marking the page clean ("undirty"), since we don't know if it made it to disk yet. This will ensure that it gets written out again in the future, either some scheduled async writeback or another explicit syncing call. On the other side, we need to make sure that if a syncing op arrives, any changes on dirty pages are written back to the DMU and/or the ZIL first. We do this by starting an async writeback on the vnode cache first, so any dirty data has been recorded in the ZIL, ready for the followup zfs_sync()->zil_commit() to find. Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Signed-off-by: Rob Norris <[email protected]>
1 parent ae62587 commit 5584fca

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

module/os/freebsd/zfs/zfs_vnops_os.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4092,15 +4092,24 @@ typedef struct {
40924092
static void
40934093
zfs_putpage_commit_cb(void *arg, int err)
40944094
{
4095-
(void) err;
40964095
putpage_commit_arg_t *pca = arg;
40974096
vm_object_t object = pca->pca_pages[0]->object;
40984097

40994098
zfs_vmobject_wlock(object);
41004099

41014100
for (uint_t i = 0; i < pca->pca_npages; i++) {
41024101
vm_page_t pp = pca->pca_pages[i];
4103-
vm_page_undirty(pp);
4102+
4103+
if (err == 0) {
4104+
/*
4105+
* Writeback succeeded, so undirty the page. If it
4106+
* fails, we leave it in the same state it was. That's
4107+
* most likely dirty, so it will get tried again some
4108+
* other time.
4109+
*/
4110+
vm_page_undirty(pp);
4111+
}
4112+
41044113
vm_page_sunbusy(pp);
41054114
}
41064115

@@ -4741,6 +4750,11 @@ struct vop_fsync_args {
47414750
static int
47424751
zfs_freebsd_fsync(struct vop_fsync_args *ap)
47434752
{
4753+
/*
4754+
* Push any dirty mmap()'d data out to the DMU and ZIL, ready for
4755+
* zil_commit() to be called in zfs_fsync().
4756+
*/
4757+
vn_flush_cached_data(ap->a_vp, B_FALSE);
47444758

47454759
return (zfs_fsync(VTOZ(ap->a_vp), 0, ap->a_td->td_ucred));
47464760
}

0 commit comments

Comments
 (0)