From: Zhang Yi <yi.zhang@xxxxxxxxxx> dax_truncate_page() always assumes the block size of the truncating inode is i_blocksize(), this is not always true for some filesystems, e.g. XFS does extent size alignment for realtime inodes. Drop this assumption and pass the block size for zeroing into dax_truncate_page(), allow filesystems to indicate the correct block size. Suggested-by: Dave Chinner <david@xxxxxxxxxxxxx> Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx> --- fs/dax.c | 13 +++++++++---- fs/ext2/inode.c | 4 ++-- fs/xfs/xfs_iomap.c | 2 +- include/linux/dax.h | 4 ++-- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/fs/dax.c b/fs/dax.c index 423fc1607dfa..98419280d9ae 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -25,6 +25,7 @@ #include <linux/mmu_notifier.h> #include <linux/iomap.h> #include <linux/rmap.h> +#include <linux/math64.h> #include <asm/pgalloc.h> #define CREATE_TRACE_POINTS @@ -1403,11 +1404,15 @@ int dax_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero, } EXPORT_SYMBOL_GPL(dax_zero_range); -int dax_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, - const struct iomap_ops *ops) +int dax_truncate_page(struct inode *inode, loff_t pos, unsigned int blocksize, + bool *did_zero, const struct iomap_ops *ops) { - unsigned int blocksize = i_blocksize(inode); - unsigned int off = pos & (blocksize - 1); + unsigned int off; + + if (is_power_of_2(blocksize)) + off = pos & (blocksize - 1); + else + div_u64_rem(pos, blocksize, &off); /* Block boundary? Nothing to do */ if (!off) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index f3d570a9302b..fbbd479f3c4e 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1278,8 +1278,8 @@ static int ext2_setsize(struct inode *inode, loff_t newsize) inode_dio_wait(inode); if (IS_DAX(inode)) - error = dax_truncate_page(inode, newsize, NULL, - &ext2_iomap_ops); + error = dax_truncate_page(inode, newsize, i_blocksize(inode), + NULL, &ext2_iomap_ops); else error = block_truncate_page(inode->i_mapping, newsize, ext2_get_block); diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 31ac07bb8425..4958cc3337bc 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -1470,7 +1470,7 @@ xfs_truncate_page( unsigned int blocksize = i_blocksize(inode); if (IS_DAX(inode)) - return dax_truncate_page(inode, pos, did_zero, + return dax_truncate_page(inode, pos, blocksize, did_zero, &xfs_dax_write_iomap_ops); return iomap_truncate_page(inode, pos, blocksize, did_zero, &xfs_buffered_write_iomap_ops); diff --git a/include/linux/dax.h b/include/linux/dax.h index 9d3e3327af4c..4aa8ef7c8fd4 100644 --- a/include/linux/dax.h +++ b/include/linux/dax.h @@ -210,8 +210,8 @@ int dax_file_unshare(struct inode *inode, loff_t pos, loff_t len, const struct iomap_ops *ops); int dax_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero, const struct iomap_ops *ops); -int dax_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, - const struct iomap_ops *ops); +int dax_truncate_page(struct inode *inode, loff_t pos, unsigned int blocksize, + bool *did_zero, const struct iomap_ops *ops); #if IS_ENABLED(CONFIG_DAX) int dax_read_lock(void); -- 2.39.2