[PATCH 01/11] vfs: explicitly pass the block size to the remap prep function

Darrick J. Wong
2024-12-13T01:21:44Z

From: Darrick J. Wong <djwong@kernel.org>

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@kernel.org>
---
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);