Skip to content

FreeBSD: zfs_putpages: don't undirty pages until after write completes #17445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/os/freebsd/spl/sys/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
extern const int zfs_vm_pagerret_bad;
extern const int zfs_vm_pagerret_error;
extern const int zfs_vm_pagerret_ok;
extern const int zfs_vm_pagerret_pend;
extern const int zfs_vm_pagerput_sync;
extern const int zfs_vm_pagerput_inval;

Expand Down
1 change: 1 addition & 0 deletions module/os/freebsd/spl/spl_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
const int zfs_vm_pagerret_bad = VM_PAGER_BAD;
const int zfs_vm_pagerret_error = VM_PAGER_ERROR;
const int zfs_vm_pagerret_ok = VM_PAGER_OK;
const int zfs_vm_pagerret_pend = VM_PAGER_PEND;
const int zfs_vm_pagerput_sync = VM_PAGER_PUT_SYNC;
const int zfs_vm_pagerput_inval = VM_PAGER_PUT_INVAL;

Expand Down
60 changes: 45 additions & 15 deletions module/os/freebsd/zfs/zfs_vnops_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2017 Nexenta Systems, Inc.
* Copyright (c) 2025, Klara, Inc.
*/

/* Portions Copyright 2007 Jeremy Teo */
Expand Down Expand Up @@ -4084,6 +4085,33 @@ zfs_freebsd_getpages(struct vop_getpages_args *ap)
ap->a_rahead));
}

typedef struct {
uint_t pca_npages;
vm_page_t pca_pages[];
} putpage_commit_arg_t;

static void
zfs_putpage_commit_cb(void *arg)
{
putpage_commit_arg_t *pca = arg;
vm_object_t object = pca->pca_pages[0]->object;

zfs_vmobject_wlock(object);

for (uint_t i = 0; i < pca->pca_npages; i++) {
vm_page_t pp = pca->pca_pages[i];
vm_page_undirty(pp);
vm_page_sunbusy(pp);
}

vm_object_pip_wakeupn(object, pca->pca_npages);

zfs_vmobject_wunlock(object);

kmem_free(pca,
offsetof(putpage_commit_arg_t, pca_pages[pca->pca_npages]));
}

static int
zfs_putpages(struct vnode *vp, vm_page_t *ma, size_t len, int flags,
int *rtvals)
Expand Down Expand Up @@ -4185,10 +4213,12 @@ zfs_putpages(struct vnode *vp, vm_page_t *ma, size_t len, int flags,
}

if (zp->z_blksz < PAGE_SIZE) {
for (i = 0; len > 0; off += tocopy, len -= tocopy, i++) {
tocopy = len > PAGE_SIZE ? PAGE_SIZE : len;
vm_ooffset_t woff = off;
size_t wlen = len;
for (i = 0; wlen > 0; woff += tocopy, wlen -= tocopy, i++) {
tocopy = MIN(PAGE_SIZE, wlen);
va = zfs_map_page(ma[i], &sf);
dmu_write(zfsvfs->z_os, zp->z_id, off, tocopy, va, tx);
dmu_write(zfsvfs->z_os, zp->z_id, woff, tocopy, va, tx);
zfs_unmap_page(sf);
}
} else {
Expand All @@ -4209,19 +4239,19 @@ zfs_putpages(struct vnode *vp, vm_page_t *ma, size_t len, int flags,
zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime);
err = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
ASSERT0(err);
/*
* XXX we should be passing a callback to undirty
* but that would make the locking messier
*/
zfs_log_write(zfsvfs->z_log, tx, TX_WRITE, zp, off,
len, commit, B_FALSE, NULL, NULL);

zfs_vmobject_wlock(object);
for (i = 0; i < ncount; i++) {
rtvals[i] = zfs_vm_pagerret_ok;
vm_page_undirty(ma[i]);
}
zfs_vmobject_wunlock(object);
putpage_commit_arg_t *pca = kmem_alloc(
offsetof(putpage_commit_arg_t, pca_pages[ncount]),
KM_SLEEP);
pca->pca_npages = ncount;
memcpy(pca->pca_pages, ma, sizeof (vm_page_t) * ncount);

zfs_log_write(zfsvfs->z_log, tx, TX_WRITE, zp,
off, len, commit, B_FALSE, zfs_putpage_commit_cb, pca);

for (i = 0; i < ncount; i++)
rtvals[i] = zfs_vm_pagerret_pend;

VM_CNT_INC(v_vnodeout);
VM_CNT_ADD(v_vnodepgsout, ncount);
}
Expand Down
7 changes: 5 additions & 2 deletions module/zfs/zfs_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,8 +694,11 @@ zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
itx->itx_sync = (zp->z_sync_cnt != 0);
itx->itx_gen = gen;

itx->itx_callback = callback;
itx->itx_callback_data = callback_data;
if (resid == len) {
itx->itx_callback = callback;
itx->itx_callback_data = callback_data;
}

zil_itx_assign(zilog, itx, tx);

off += len;
Expand Down
Loading