From c7100fc32c35f90d1155d5d4eab3157ae240c856 Mon Sep 17 00:00:00 2001 From: Robert Evans Date: Tue, 19 Mar 2024 19:48:38 -0400 Subject: [PATCH] Retry zn_flush_cached_data on ERESTART `zfs_putpage` sometimes fails on `dmu_tx_assign`, and looping prevents writeback flush from missing any pages needed to detect dirty records. Also fix zn_has_cached_data bounds. Signed-off-by: Robert Evans --- module/os/linux/zfs/zpl_file.c | 8 ++++---- module/zfs/zfs_vnops.c | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c index 3caa0fc6c214..9dec52215c7c 100644 --- a/module/os/linux/zfs/zpl_file.c +++ b/module/os/linux/zfs/zpl_file.c @@ -720,23 +720,23 @@ zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data) { boolean_t *for_sync = data; fstrans_cookie_t cookie; + int ret; ASSERT(PageLocked(pp)); ASSERT(!PageWriteback(pp)); cookie = spl_fstrans_mark(); - (void) zfs_putpage(pp->mapping->host, pp, wbc, *for_sync); + ret = zfs_putpage(pp->mapping->host, pp, wbc, *for_sync); spl_fstrans_unmark(cookie); - return (0); + return (ret); } #ifdef HAVE_WRITEPAGE_T_FOLIO static int zpl_putfolio(struct folio *pp, struct writeback_control *wbc, void *data) { - (void) zpl_putpage(&pp->page, wbc, data); - return (0); + return (zpl_putpage(&pp->page, wbc, data)); } #endif diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index d50beb804da4..e7171660f53e 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -122,8 +122,13 @@ zfs_holey_common(znode_t *zp, ulong_t cmd, loff_t *off) hole = B_FALSE; /* Flush any mmap()'d data to disk */ - if (zn_has_cached_data(zp, 0, file_sz - 1)) - zn_flush_cached_data(zp, B_FALSE); + if (zn_has_cached_data(zp, 0, file_sz - 1)) { + do { + error = zn_flush_cached_data(zp, B_TRUE); + } while (error == ERESTART); + if (error != 0) + return (error); + } lr = zfs_rangelock_enter(&zp->z_rangelock, 0, UINT64_MAX, RL_READER); error = dmu_offset_next(ZTOZSB(zp)->z_os, zp->z_id, hole, &noff); @@ -1190,9 +1195,15 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp, /* * Flush mmap'ed pages to disk before cloning. */ - if (zn_has_cached_data(inzp, inoff, len)) { + if (zn_has_cached_data(inzp, inoff, inoff + len - 1)) { // FIXME: flush only the cloned range - zn_flush_cached_data(inzp, B_FALSE); + do { + error = zn_flush_cached_data(inzp, B_TRUE); + } while (error == ERESTART); + if (error != 0) { + zfs_exit_two(inzfsvfs, outzfsvfs, FTAG); + return (error); + } } /*