From f5b732d44d3b1aba3a14f18cee955a750e1609ed Mon Sep 17 00:00:00 2001 From: Pavel Snajdr Date: Fri, 29 Nov 2024 23:11:44 +0100 Subject: [PATCH 1/2] Linux: syncfs(2) should sync all cached files While debugging problem with data not being synced on umount, we've noticed that even syncfs(2) doesn't help to get the data written out. It is because it doesn't actually sync any of the live znodes. Signed-off-by: Pavel Snajdr --- module/os/linux/zfs/zpl_super.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/module/os/linux/zfs/zpl_super.c b/module/os/linux/zfs/zpl_super.c index b97b701b7460..a3337cd64356 100644 --- a/module/os/linux/zfs/zpl_super.c +++ b/module/os/linux/zfs/zpl_super.c @@ -109,11 +109,23 @@ zpl_sync_fs(struct super_block *sb, int wait) { fstrans_cookie_t cookie; cred_t *cr = CRED(); + znode_t *zp; + zfsvfs_t *zfsvfs = sb->s_fs_info; int error; crhold(cr); cookie = spl_fstrans_mark(); - error = -zfs_sync(sb, wait, cr); + mutex_enter(&zfsvfs->z_znodes_lock); + for (zp = list_head(&zfsvfs->z_all_znodes); zp; + zp = list_next(&zfsvfs->z_all_znodes, zp)) { + if (zp->z_sa_hdl) + error = filemap_write_and_wait(ZTOI(zp)->i_mapping); + if (error != 0) + break; + } + mutex_exit(&zfsvfs->z_znodes_lock); + if (error == 0) + error = -zfs_sync(sb, wait, cr); spl_fstrans_unmark(cookie); crfree(cr); ASSERT3S(error, <=, 0); From 1a7214ee8cd10826a5ab5a1b316aa402695840b7 Mon Sep 17 00:00:00 2001 From: Pavel Snajdr Date: Sat, 30 Nov 2024 00:38:44 +0100 Subject: [PATCH 2/2] wip: do custom zpl_writepages on syncfs(2) Signed-off-by: Pavel Snajdr --- include/os/linux/zfs/sys/zpl.h | 2 ++ module/os/linux/zfs/zpl_file.c | 2 +- module/os/linux/zfs/zpl_super.c | 8 +++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h index c6e235c48ef3..dd35c343036f 100644 --- a/include/os/linux/zfs/sys/zpl.h +++ b/include/os/linux/zfs/sys/zpl.h @@ -49,6 +49,8 @@ extern const struct inode_operations zpl_special_inode_operations; extern const struct address_space_operations zpl_address_space_operations; extern const struct file_operations zpl_file_operations; extern const struct file_operations zpl_dir_file_operations; +extern int zpl_writepages(struct address_space *mapping, + struct writeback_control *wbc); /* zpl_super.c */ extern void zpl_prune_sb(uint64_t nr_to_scan, void *arg); diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c index f6e014327717..1ebdd83b1d68 100644 --- a/module/os/linux/zfs/zpl_file.c +++ b/module/os/linux/zfs/zpl_file.c @@ -546,7 +546,7 @@ zpl_write_cache_pages(struct address_space *mapping, return (result); } -static int +int zpl_writepages(struct address_space *mapping, struct writeback_control *wbc) { znode_t *zp = ITOZ(mapping->host); diff --git a/module/os/linux/zfs/zpl_super.c b/module/os/linux/zfs/zpl_super.c index a3337cd64356..c952c89c718f 100644 --- a/module/os/linux/zfs/zpl_super.c +++ b/module/os/linux/zfs/zpl_super.c @@ -111,6 +111,12 @@ zpl_sync_fs(struct super_block *sb, int wait) cred_t *cr = CRED(); znode_t *zp; zfsvfs_t *zfsvfs = sb->s_fs_info; + struct writeback_control wbc = { + .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_NONE, + .nr_to_write = LONG_MAX, + .range_start = 0, + .range_end = LLONG_MAX, + }; int error; crhold(cr); @@ -119,7 +125,7 @@ zpl_sync_fs(struct super_block *sb, int wait) for (zp = list_head(&zfsvfs->z_all_znodes); zp; zp = list_next(&zfsvfs->z_all_znodes, zp)) { if (zp->z_sa_hdl) - error = filemap_write_and_wait(ZTOI(zp)->i_mapping); + error = zpl_writepages(ZTOI(zp)->i_mapping, &wbc); if (error != 0) break; }