From: Darrick J. Wong <djwong@xxxxxxxxxx> Make it so that filesystems can pass an explicit blocksize to the remap prep function. This enables filesystems whose fundamental allocation units are /not/ the same as the blocksize to ensure that the remapping checks are aligned properly. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- fs/dax.c | 5 ++++- fs/remap_range.c | 30 ++++++++++++++++++------------ include/linux/fs.h | 3 ++- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/fs/dax.c b/fs/dax.c index 21b47402b3dca4..c7ea298b4214a5 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -2076,7 +2076,10 @@ int dax_remap_file_range_prep(struct file *file_in, loff_t pos_in, loff_t *len, unsigned int remap_flags, const struct iomap_ops *ops) { + unsigned int blocksize = file_inode(file_out)->i_sb->s_blocksize; + return __generic_remap_file_range_prep(file_in, pos_in, file_out, - pos_out, len, remap_flags, ops); + pos_out, len, remap_flags, ops, + blocksize); } EXPORT_SYMBOL_GPL(dax_remap_file_range_prep); diff --git a/fs/remap_range.c b/fs/remap_range.c index 26afbbbfb10c2e..d3c6c6b05eb191 100644 --- a/fs/remap_range.c +++ b/fs/remap_range.c @@ -30,18 +30,18 @@ */ static int generic_remap_checks(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, - loff_t *req_count, unsigned int remap_flags) + loff_t *req_count, unsigned int remap_flags, + unsigned int blocksize) { struct inode *inode_in = file_in->f_mapping->host; struct inode *inode_out = file_out->f_mapping->host; uint64_t count = *req_count; uint64_t bcount; loff_t size_in, size_out; - loff_t bs = inode_out->i_sb->s_blocksize; int ret; /* The start of both ranges must be aligned to an fs block. */ - if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_out, bs)) + if (!IS_ALIGNED(pos_in, blocksize) || !IS_ALIGNED(pos_out, blocksize)) return -EINVAL; /* Ensure offsets don't wrap. */ @@ -75,10 +75,10 @@ static int generic_remap_checks(struct file *file_in, loff_t pos_in, */ if (pos_in + count == size_in && (!(remap_flags & REMAP_FILE_DEDUP) || pos_out + count == size_out)) { - bcount = ALIGN(size_in, bs) - pos_in; + bcount = ALIGN(size_in, blocksize) - pos_in; } else { - if (!IS_ALIGNED(count, bs)) - count = ALIGN_DOWN(count, bs); + if (!IS_ALIGNED(count, blocksize)) + count = ALIGN_DOWN(count, blocksize); bcount = count; } @@ -134,9 +134,10 @@ static int generic_remap_check_len(struct inode *inode_in, struct inode *inode_out, loff_t pos_out, loff_t *len, - unsigned int remap_flags) + unsigned int remap_flags, + unsigned int blocksize) { - u64 blkmask = i_blocksize(inode_in) - 1; + u64 blkmask = blocksize - 1; loff_t new_len = *len; if ((*len & blkmask) == 0) @@ -277,7 +278,8 @@ int __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t *len, unsigned int remap_flags, - const struct iomap_ops *dax_read_ops) + const struct iomap_ops *dax_read_ops, + unsigned int blocksize) { struct inode *inode_in = file_inode(file_in); struct inode *inode_out = file_inode(file_out); @@ -312,7 +314,7 @@ __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, /* Check that we don't violate system file offset limits. */ ret = generic_remap_checks(file_in, pos_in, file_out, pos_out, len, - remap_flags); + remap_flags, blocksize); if (ret || *len == 0) return ret; @@ -353,7 +355,7 @@ __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, } ret = generic_remap_check_len(inode_in, inode_out, pos_out, len, - remap_flags); + remap_flags, blocksize); if (ret || *len == 0) return ret; @@ -363,13 +365,17 @@ __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, return ret; } +EXPORT_SYMBOL(__generic_remap_file_range_prep); int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t *len, unsigned int remap_flags) { + unsigned int blocksize = file_inode(file_out)->i_sb->s_blocksize; + return __generic_remap_file_range_prep(file_in, pos_in, file_out, - pos_out, len, remap_flags, NULL); + pos_out, len, remap_flags, NULL, + blocksize); } EXPORT_SYMBOL(generic_remap_file_range_prep); diff --git a/include/linux/fs.h b/include/linux/fs.h index 7e29433c5ecce2..b638fb1bcbc96f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2191,7 +2191,8 @@ int remap_verify_area(struct file *file, loff_t pos, loff_t len, bool write); int __generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t *len, unsigned int remap_flags, - const struct iomap_ops *dax_read_ops); + const struct iomap_ops *dax_read_ops, + unsigned int block_size); int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, loff_t *count, unsigned int remap_flags);