Skip to content

Commit deb7a84

Browse files
rrevansbehlendorf
authored andcommitted
Fix corruption caused by mmap flushing problems
1) Make mmap flushes synchronous. Linux may skip flushing dirty pages already in writeback unless data-integrity sync is requested. 2) Change zfs_putpage to use TXG_WAIT. Otherwise dirty pages may be skipped due to DMU pushing back on TX assign. 3) Add missing mmap flush when doing block cloning. 4) While here, pass errors from putpage to writepage/writepages. This change fixes corruption edge cases, but unfortunately adds synchronous ZIL flushes for dirty mmap pages to llseek and bclone operations. It may be possible to avoid these sync writes later but would need more tricky refactoring of the writeback code. Reviewed-by: Alexander Motin <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Robert Evans <[email protected]> Closes #15933 Closes #16019
1 parent eebf00b commit deb7a84

File tree

3 files changed

+10
-9
lines changed

3 files changed

+10
-9
lines changed

module/os/linux/zfs/zfs_vnops_os.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3792,11 +3792,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc,
37923792
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
37933793
zfs_sa_upgrade_txholds(tx, zp);
37943794

3795-
err = dmu_tx_assign(tx, TXG_NOWAIT);
3795+
err = dmu_tx_assign(tx, TXG_WAIT);
37963796
if (err != 0) {
3797-
if (err == ERESTART)
3798-
dmu_tx_wait(tx);
3799-
38003797
dmu_tx_abort(tx);
38013798
#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO
38023799
filemap_dirty_folio(page_mapping(pp), page_folio(pp));

module/os/linux/zfs/zpl_file.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -720,23 +720,23 @@ zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data)
720720
{
721721
boolean_t *for_sync = data;
722722
fstrans_cookie_t cookie;
723+
int ret;
723724

724725
ASSERT(PageLocked(pp));
725726
ASSERT(!PageWriteback(pp));
726727

727728
cookie = spl_fstrans_mark();
728-
(void) zfs_putpage(pp->mapping->host, pp, wbc, *for_sync);
729+
ret = zfs_putpage(pp->mapping->host, pp, wbc, *for_sync);
729730
spl_fstrans_unmark(cookie);
730731

731-
return (0);
732+
return (ret);
732733
}
733734

734735
#ifdef HAVE_WRITEPAGE_T_FOLIO
735736
static int
736737
zpl_putfolio(struct folio *pp, struct writeback_control *wbc, void *data)
737738
{
738-
(void) zpl_putpage(&pp->page, wbc, data);
739-
return (0);
739+
return (zpl_putpage(&pp->page, wbc, data));
740740
}
741741
#endif
742742

module/zfs/zfs_vnops.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ zfs_holey_common(znode_t *zp, ulong_t cmd, loff_t *off)
130130

131131
/* Flush any mmap()'d data to disk */
132132
if (zn_has_cached_data(zp, 0, file_sz - 1))
133-
zn_flush_cached_data(zp, B_FALSE);
133+
zn_flush_cached_data(zp, B_TRUE);
134134

135135
lr = zfs_rangelock_enter(&zp->z_rangelock, 0, UINT64_MAX, RL_READER);
136136
error = dmu_offset_next(ZTOZSB(zp)->z_os, zp->z_id, hole, &noff);
@@ -1193,6 +1193,10 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
11931193
}
11941194
}
11951195

1196+
/* Flush any mmap()'d data to disk */
1197+
if (zn_has_cached_data(inzp, inoff, inoff + len - 1))
1198+
zn_flush_cached_data(inzp, B_TRUE);
1199+
11961200
/*
11971201
* Maintain predictable lock order.
11981202
*/

0 commit comments

Comments
 (0)