From 588e7c048d7d2bfcbe7776ee0888ee248adf01d1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 2 Mar 2026 06:18:09 -0800 Subject: ext4, fscrypt: merge fscrypt_mergeable_bio_bh into io_submit_need_new_bio ext4 already has the inode and folio and can't have a NULL folio->mapping in this path. Open code fscrypt_mergeable_bio_bh in io_submit_need_new_bio based on these simplifying assumptions. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20260302141922.370070-5-hch@lst.de Signed-off-by: Eric Biggers --- include/linux/fscrypt.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 516aba5b858b..6af3c1907adc 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -876,9 +876,6 @@ void fscrypt_set_bio_crypt_ctx_bh(struct bio *bio, bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, u64 next_lblk); -bool fscrypt_mergeable_bio_bh(struct bio *bio, - const struct buffer_head *next_bh); - bool fscrypt_dio_supported(struct inode *inode); u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks); @@ -906,12 +903,6 @@ static inline bool fscrypt_mergeable_bio(struct bio *bio, return true; } -static inline bool fscrypt_mergeable_bio_bh(struct bio *bio, - const struct buffer_head *next_bh) -{ - return true; -} - static inline bool fscrypt_dio_supported(struct inode *inode) { return !fscrypt_needs_contents_encryption(inode); -- cgit v1.2.3 From a18b1ab81654b06e7ff402e5d0b85249e9504bcb Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 2 Mar 2026 06:18:10 -0800 Subject: fscrypt: move fscrypt_set_bio_crypt_ctx_bh to buffer.c fscrypt_set_bio_crypt_ctx_bh is only used by submit_bh_wbc now. Move it there and merge bh_get_inode_and_lblk_num into it. Note that this does not add ifdefs for fscrypt as the compiler will optimize away the dead code if it is not built in. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20260302141922.370070-6-hch@lst.de Signed-off-by: Eric Biggers --- fs/buffer.c | 21 ++++++++++++++++++++- fs/crypto/inline_crypt.c | 45 --------------------------------------------- include/linux/fscrypt.h | 9 --------- 3 files changed, 20 insertions(+), 55 deletions(-) (limited to 'include/linux') diff --git a/fs/buffer.c b/fs/buffer.c index 22b43642ba57..b6504ec7fa4c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2774,6 +2774,24 @@ static void end_bio_bh_io_sync(struct bio *bio) bio_put(bio); } +static void buffer_set_crypto_ctx(struct bio *bio, const struct buffer_head *bh, + gfp_t gfp_mask) +{ + const struct address_space *mapping = folio_mapping(bh->b_folio); + const struct inode *inode; + u64 lblk; + + /* + * The ext4 journal (jbd2) can submit a buffer_head it directly created + * for a non-pagecache page. fscrypt doesn't care about these. + */ + if (!mapping) + return; + inode = mapping->host; + lblk = (folio_pos(bh->b_folio) + bh_offset(bh)) >> inode->i_blkbits; + fscrypt_set_bio_crypt_ctx(bio, inode, lblk, gfp_mask); +} + static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh, enum rw_hint write_hint, struct writeback_control *wbc) @@ -2800,7 +2818,8 @@ static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh, bio = bio_alloc(bh->b_bdev, 1, opf, GFP_NOIO); - fscrypt_set_bio_crypt_ctx_bh(bio, bh, GFP_NOIO); + if (IS_ENABLED(CONFIG_FS_ENCRYPTION)) + buffer_set_crypto_ctx(bio, bh, GFP_NOIO); bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_write_hint = write_hint; diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 0da53956a9b1..702d13d138aa 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -314,51 +314,6 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, } EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx); -/* Extract the inode and logical block number from a buffer_head. */ -static bool bh_get_inode_and_lblk_num(const struct buffer_head *bh, - const struct inode **inode_ret, - u64 *lblk_num_ret) -{ - struct folio *folio = bh->b_folio; - const struct address_space *mapping; - const struct inode *inode; - - /* - * The ext4 journal (jbd2) can submit a buffer_head it directly created - * for a non-pagecache page. fscrypt doesn't care about these. - */ - mapping = folio_mapping(folio); - if (!mapping) - return false; - inode = mapping->host; - - *inode_ret = inode; - *lblk_num_ret = (folio_pos(folio) + bh_offset(bh)) >> inode->i_blkbits; - return true; -} - -/** - * fscrypt_set_bio_crypt_ctx_bh() - prepare a file contents bio for inline - * crypto - * @bio: a bio which will eventually be submitted to the file - * @first_bh: the first buffer_head for which I/O will be submitted - * @gfp_mask: memory allocation flags - * - * Same as fscrypt_set_bio_crypt_ctx(), except this takes a buffer_head instead - * of an inode and block number directly. - */ -void fscrypt_set_bio_crypt_ctx_bh(struct bio *bio, - const struct buffer_head *first_bh, - gfp_t gfp_mask) -{ - const struct inode *inode; - u64 first_lblk; - - if (bh_get_inode_and_lblk_num(first_bh, &inode, &first_lblk)) - fscrypt_set_bio_crypt_ctx(bio, inode, first_lblk, gfp_mask); -} -EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx_bh); - /** * fscrypt_mergeable_bio() - test whether data can be added to a bio * @bio: the bio being built up diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 6af3c1907adc..26561b7994e0 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -869,10 +869,6 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, u64 first_lblk, gfp_t gfp_mask); -void fscrypt_set_bio_crypt_ctx_bh(struct bio *bio, - const struct buffer_head *first_bh, - gfp_t gfp_mask); - bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, u64 next_lblk); @@ -891,11 +887,6 @@ static inline void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, u64 first_lblk, gfp_t gfp_mask) { } -static inline void fscrypt_set_bio_crypt_ctx_bh( - struct bio *bio, - const struct buffer_head *first_bh, - gfp_t gfp_mask) { } - static inline bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, u64 next_lblk) -- cgit v1.2.3 From 22be86a23c5956254b752e4e98f0ef2799565a41 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 2 Mar 2026 06:18:12 -0800 Subject: fscrypt: pass a byte offset to fscrypt_mergeable_bio Logical offsets into an inode are usually expressed as bytes in the VFS. Switch fscrypt_mergeable_bio to that convention. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20260302141922.370070-8-hch@lst.de Signed-off-by: Eric Biggers --- fs/crypto/bio.c | 3 ++- fs/crypto/inline_crypt.c | 6 +++--- fs/ext4/page-io.c | 2 +- fs/ext4/readpage.c | 3 ++- fs/f2fs/data.c | 3 ++- include/linux/fscrypt.h | 4 ++-- 6 files changed, 12 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 6da683ea69dc..0a701d4a17ef 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -100,7 +100,8 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, len -= blocks_this_page; lblk += blocks_this_page; sector += (bytes_this_page >> SECTOR_SHIFT); - if (!len || !fscrypt_mergeable_bio(bio, inode, lblk)) + if (!len || !fscrypt_mergeable_bio(bio, inode, + (loff_t)lblk << blockbits)) break; } diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 5279565e9846..b0954d17904b 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -316,7 +316,7 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx); * fscrypt_mergeable_bio() - test whether data can be added to a bio * @bio: the bio being built up * @inode: the inode for the next part of the I/O - * @next_lblk: the next file logical block number in the I/O + * @pos: the next file position (in bytes) in the I/O * * When building a bio which may contain data which should undergo inline * encryption (or decryption) via fscrypt, filesystems should call this function @@ -334,7 +334,7 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx); * Return: true iff the I/O is mergeable */ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, - u64 next_lblk) + loff_t pos) { const struct bio_crypt_ctx *bc = bio->bi_crypt_context; const struct fscrypt_inode_info *ci; @@ -354,7 +354,7 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, if (bc->bc_key != ci->ci_enc_key.blk_key) return false; - fscrypt_generate_dun(ci, next_lblk << inode->i_blkbits, next_dun); + fscrypt_generate_dun(ci, pos, next_dun); return bio_crypt_dun_is_contiguous(bc, bio->bi_iter.bi_size, next_dun); } EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio); diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 293314d7f236..50f507bab82c 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -447,7 +447,7 @@ static bool io_submit_need_new_bio(struct ext4_io_submit *io, if (bh->b_blocknr != io->io_next_block) return true; if (!fscrypt_mergeable_bio(io->io_bio, inode, - (folio_pos(folio) + bh_offset(bh)) >> inode->i_blkbits)) + folio_pos(folio) + bh_offset(bh))) return true; return false; } diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index 830f3b8a321f..ba7cfddd6038 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -342,7 +342,8 @@ static int ext4_mpage_readpages(struct inode *inode, struct fsverity_info *vi, * BIO off first? */ if (bio && (last_block_in_bio != first_block - 1 || - !fscrypt_mergeable_bio(bio, inode, next_block))) { + !fscrypt_mergeable_bio(bio, inode, + (loff_t)next_block << blkbits))) { submit_and_realloc: blk_crypto_submit_bio(bio); bio = NULL; diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 338df7a2aea6..dca273fedfde 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -541,7 +541,8 @@ static bool f2fs_crypt_mergeable_bio(struct bio *bio, const struct inode *inode, if (fio && fio->encrypted_page) return !bio_has_crypt_ctx(bio); - return fscrypt_mergeable_bio(bio, inode, next_idx); + return fscrypt_mergeable_bio(bio, inode, + (loff_t)next_idx << inode->i_blkbits); } void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio, diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 26561b7994e0..98fb14660d40 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -870,7 +870,7 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, gfp_t gfp_mask); bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, - u64 next_lblk); + loff_t pos); bool fscrypt_dio_supported(struct inode *inode); @@ -889,7 +889,7 @@ static inline void fscrypt_set_bio_crypt_ctx(struct bio *bio, static inline bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, - u64 next_lblk) + loff_t pos) { return true; } -- cgit v1.2.3 From 3c7eaa775d8e008135646bd4b7aa7db7c5e40a0e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 2 Mar 2026 06:18:13 -0800 Subject: fscrypt: pass a byte offset to fscrypt_set_bio_crypt_ctx Logical offsets into an inode are usually expressed as bytes in the VFS. Switch fscrypt_set_bio_crypt_ctx to that convention. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20260302141922.370070-9-hch@lst.de Signed-off-by: Eric Biggers --- fs/buffer.c | 7 ++----- fs/crypto/bio.c | 8 ++++---- fs/crypto/inline_crypt.c | 6 +++--- fs/ext4/page-io.c | 5 ++--- fs/ext4/readpage.c | 4 ++-- fs/f2fs/data.c | 4 +++- fs/iomap/direct-io.c | 6 ++---- include/linux/fscrypt.h | 7 +++---- 8 files changed, 21 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/fs/buffer.c b/fs/buffer.c index b6504ec7fa4c..1c8ee5a59f88 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2778,8 +2778,6 @@ static void buffer_set_crypto_ctx(struct bio *bio, const struct buffer_head *bh, gfp_t gfp_mask) { const struct address_space *mapping = folio_mapping(bh->b_folio); - const struct inode *inode; - u64 lblk; /* * The ext4 journal (jbd2) can submit a buffer_head it directly created @@ -2787,9 +2785,8 @@ static void buffer_set_crypto_ctx(struct bio *bio, const struct buffer_head *bh, */ if (!mapping) return; - inode = mapping->host; - lblk = (folio_pos(bh->b_folio) + bh_offset(bh)) >> inode->i_blkbits; - fscrypt_set_bio_crypt_ctx(bio, inode, lblk, gfp_mask); + fscrypt_set_bio_crypt_ctx(bio, mapping->host, + folio_pos(bh->b_folio) + bh_offset(bh), gfp_mask); } static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh, diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 0a701d4a17ef..e7fb2fdd9728 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -75,6 +75,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, { const unsigned int blockbits = inode->i_blkbits; const unsigned int blocks_per_page = 1 << (PAGE_SHIFT - blockbits); + loff_t pos = (loff_t)lblk << blockbits; struct fscrypt_zero_done done = { .pending = ATOMIC_INIT(1), .done = COMPLETION_INITIALIZER_ONSTACK(done.done), @@ -89,7 +90,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, bio->bi_iter.bi_sector = sector; bio->bi_private = &done; bio->bi_end_io = fscrypt_zeroout_range_end_io; - fscrypt_set_bio_crypt_ctx(bio, inode, lblk, GFP_NOFS); + fscrypt_set_bio_crypt_ctx(bio, inode, pos, GFP_NOFS); for (n = 0; n < BIO_MAX_VECS; n++) { unsigned int blocks_this_page = @@ -98,10 +99,9 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, __bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0); len -= blocks_this_page; - lblk += blocks_this_page; + pos += bytes_this_page; sector += (bytes_this_page >> SECTOR_SHIFT); - if (!len || !fscrypt_mergeable_bio(bio, inode, - (loff_t)lblk << blockbits)) + if (!len || !fscrypt_mergeable_bio(bio, inode, pos)) break; } diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index b0954d17904b..37d42d357925 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -285,7 +285,7 @@ static void fscrypt_generate_dun(const struct fscrypt_inode_info *ci, * fscrypt_set_bio_crypt_ctx() - prepare a file contents bio for inline crypto * @bio: a bio which will eventually be submitted to the file * @inode: the file's inode - * @first_lblk: the first file logical block number in the I/O + * @pos: the first file position (in bytes) in the I/O * @gfp_mask: memory allocation flags - these must be a waiting mask so that * bio_crypt_set_ctx can't fail. * @@ -298,7 +298,7 @@ static void fscrypt_generate_dun(const struct fscrypt_inode_info *ci, * The encryption context will be freed automatically when the bio is freed. */ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, - u64 first_lblk, gfp_t gfp_mask) + loff_t pos, gfp_t gfp_mask) { const struct fscrypt_inode_info *ci; u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; @@ -307,7 +307,7 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, return; ci = fscrypt_get_inode_info_raw(inode); - fscrypt_generate_dun(ci, first_lblk << inode->i_blkbits, dun); + fscrypt_generate_dun(ci, pos, dun); bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask); } EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx); diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 50f507bab82c..181cda58d387 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -427,9 +427,8 @@ static void io_submit_init_bio(struct ext4_io_submit *io, * __GFP_DIRECT_RECLAIM is set, see comments for bio_alloc_bioset(). */ bio = bio_alloc(bh->b_bdev, BIO_MAX_VECS, REQ_OP_WRITE, GFP_NOIO); - fscrypt_set_bio_crypt_ctx(bio, inode, - (folio_pos(folio) + bh_offset(bh)) >> inode->i_blkbits, - GFP_NOIO); + fscrypt_set_bio_crypt_ctx(bio, inode, folio_pos(folio) + bh_offset(bh), + GFP_NOIO); bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_end_io = ext4_end_bio; bio->bi_private = ext4_get_io_end(io->io_end); diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index ba7cfddd6038..fbfa4d830d9a 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -355,8 +355,8 @@ static int ext4_mpage_readpages(struct inode *inode, struct fsverity_info *vi, */ bio = bio_alloc(bdev, bio_max_segs(nr_pages), REQ_OP_READ, GFP_KERNEL); - fscrypt_set_bio_crypt_ctx(bio, inode, next_block, - GFP_KERNEL); + fscrypt_set_bio_crypt_ctx(bio, inode, + (loff_t)next_block << blkbits, GFP_KERNEL); ext4_set_bio_post_read_ctx(bio, inode, vi); bio->bi_iter.bi_sector = first_block << (blkbits - 9); bio->bi_end_io = mpage_end_io; diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index dca273fedfde..07b4ed6bb0cc 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -527,7 +527,9 @@ static void f2fs_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, * read/write raw data without encryption. */ if (!fio || !fio->encrypted_page) - fscrypt_set_bio_crypt_ctx(bio, inode, first_idx, gfp_mask); + fscrypt_set_bio_crypt_ctx(bio, inode, + (loff_t)first_idx << inode->i_blkbits, + gfp_mask); } static bool f2fs_crypt_mergeable_bio(struct bio *bio, const struct inode *inode, diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c index e911daedff65..9da5d862ef9e 100644 --- a/fs/iomap/direct-io.c +++ b/fs/iomap/direct-io.c @@ -311,8 +311,7 @@ static int iomap_dio_zero(const struct iomap_iter *iter, struct iomap_dio *dio, bio = iomap_dio_alloc_bio(iter, dio, nr_vecs, REQ_OP_WRITE | REQ_SYNC | REQ_IDLE); - fscrypt_set_bio_crypt_ctx(bio, inode, pos >> inode->i_blkbits, - GFP_KERNEL); + fscrypt_set_bio_crypt_ctx(bio, inode, pos, GFP_KERNEL); bio->bi_iter.bi_sector = iomap_sector(&iter->iomap, pos); bio->bi_private = dio; bio->bi_end_io = iomap_dio_bio_end_io; @@ -342,8 +341,7 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter, nr_vecs = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_VECS); bio = iomap_dio_alloc_bio(iter, dio, nr_vecs, op); - fscrypt_set_bio_crypt_ctx(bio, iter->inode, - pos >> iter->inode->i_blkbits, GFP_KERNEL); + fscrypt_set_bio_crypt_ctx(bio, iter->inode, pos, GFP_KERNEL); bio->bi_iter.bi_sector = iomap_sector(&iter->iomap, pos); bio->bi_write_hint = iter->inode->i_write_hint; bio->bi_ioprio = dio->iocb->ki_ioprio; diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 98fb14660d40..90f75fe0e1c9 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -865,9 +865,8 @@ static inline void fscrypt_set_ops(struct super_block *sb, bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode); -void fscrypt_set_bio_crypt_ctx(struct bio *bio, - const struct inode *inode, u64 first_lblk, - gfp_t gfp_mask); +void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, + loff_t pos, gfp_t gfp_mask); bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, loff_t pos); @@ -885,7 +884,7 @@ static inline bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode) static inline void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, - u64 first_lblk, gfp_t gfp_mask) { } + loff_t pos, gfp_t gfp_mask) { } static inline bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, -- cgit v1.2.3 From cd7db2e7dfeef99c901156f58ab4a38256b0c3f1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 2 Mar 2026 06:18:16 -0800 Subject: fscrypt: pass a byte offset to fscrypt_zeroout_range Logical offsets into an inode are usually expressed as bytes in the VFS. Switch fscrypt_zeroout_range to that convention. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20260302141922.370070-12-hch@lst.de Signed-off-by: Eric Biggers --- fs/crypto/bio.c | 7 +++---- fs/ext4/inode.c | 3 ++- fs/f2fs/file.c | 4 +++- include/linux/fscrypt.h | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 303b5acc66a9..a07ac8dcf851 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -113,7 +113,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, /** * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file * @inode: the file's inode - * @lblk: the first file logical block to zero out + * @pos: the first file position (in bytes) to zero out * @pblk: the first filesystem physical block to zero out * @len: number of blocks to zero out * @@ -127,7 +127,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, * * Return: 0 on success; -errno on failure. */ -int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, +int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, sector_t pblk, unsigned int len) { const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode); @@ -135,9 +135,8 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, const unsigned int du_size = 1U << du_bits; const unsigned int du_per_page_bits = PAGE_SHIFT - du_bits; const unsigned int du_per_page = 1U << du_per_page_bits; - u64 du_index = (u64)lblk << (inode->i_blkbits - du_bits); + u64 du_index = pos >> du_bits; u64 du_remaining = (u64)len << (inode->i_blkbits - du_bits); - loff_t pos = (loff_t)lblk << inode->i_blkbits; sector_t sector = pblk << (inode->i_blkbits - SECTOR_SHIFT); struct page *pages[16]; /* write up to 16 pages at a time */ unsigned int nr_pages; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 396dc3a5d16b..945613c95ffa 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -405,7 +405,8 @@ int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk, KUNIT_STATIC_STUB_REDIRECT(ext4_issue_zeroout, inode, lblk, pblk, len); if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) - return fscrypt_zeroout_range(inode, lblk, pblk, len); + return fscrypt_zeroout_range(inode, + (loff_t)lblk << inode->i_blkbits, pblk, len); ret = sb_issue_zeroout(inode->i_sb, pblk, len, GFP_NOFS); if (ret > 0) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index c8a2f17a8f11..239c2666ceb5 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -4162,7 +4162,9 @@ static int f2fs_secure_erase(struct block_device *bdev, struct inode *inode, if (!ret && (flags & F2FS_TRIM_FILE_ZEROOUT)) { if (IS_ENCRYPTED(inode)) - ret = fscrypt_zeroout_range(inode, off, block, len); + ret = fscrypt_zeroout_range(inode, + (loff_t)off << inode->i_blkbits, block, + len); else ret = blkdev_issue_zeroout(bdev, sector, nr_sects, GFP_NOFS, 0); diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 90f75fe0e1c9..9fc15e1fbe57 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -450,7 +450,7 @@ u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name); /* bio.c */ bool fscrypt_decrypt_bio(struct bio *bio); -int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, +int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, sector_t pblk, unsigned int len); /* hooks.c */ @@ -755,7 +755,7 @@ static inline bool fscrypt_decrypt_bio(struct bio *bio) return true; } -static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, +static inline int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, sector_t pblk, unsigned int len) { return -EOPNOTSUPP; -- cgit v1.2.3 From fb87ab4ad3d0df2397648e5ce2384de26463c183 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 2 Mar 2026 06:18:17 -0800 Subject: fscrypt: pass a byte length to fscrypt_zeroout_range Range lengths are usually expressed as bytes in the VFS, switch fscrypt_zeroout_range to this convention. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20260302141922.370070-13-hch@lst.de Signed-off-by: Eric Biggers --- fs/crypto/bio.c | 11 ++++++----- fs/ext4/inode.c | 3 ++- fs/f2fs/file.c | 2 +- include/linux/fscrypt.h | 6 +++--- 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index a07ac8dcf851..9872408f4f52 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -115,12 +115,13 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, * @inode: the file's inode * @pos: the first file position (in bytes) to zero out * @pblk: the first filesystem physical block to zero out - * @len: number of blocks to zero out + * @len: bytes to zero out * * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write * ciphertext blocks which decrypt to the all-zeroes block. The blocks must be * both logically and physically contiguous. It's also assumed that the - * filesystem only uses a single block device, ->s_bdev. + * filesystem only uses a single block device, ->s_bdev. @len must be a + * multiple of the file system logical block size. * * Note that since each block uses a different IV, this involves writing a * different ciphertext to each block; we can't simply reuse the same one. @@ -128,7 +129,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, * Return: 0 on success; -errno on failure. */ int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, - sector_t pblk, unsigned int len) + sector_t pblk, u64 len) { const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode); const unsigned int du_bits = ci->ci_data_unit_bits; @@ -136,7 +137,7 @@ int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, const unsigned int du_per_page_bits = PAGE_SHIFT - du_bits; const unsigned int du_per_page = 1U << du_per_page_bits; u64 du_index = pos >> du_bits; - u64 du_remaining = (u64)len << (inode->i_blkbits - du_bits); + u64 du_remaining = len >> du_bits; sector_t sector = pblk << (inode->i_blkbits - SECTOR_SHIFT); struct page *pages[16]; /* write up to 16 pages at a time */ unsigned int nr_pages; @@ -150,7 +151,7 @@ int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, if (fscrypt_inode_uses_inline_crypto(inode)) return fscrypt_zeroout_range_inline_crypt(inode, pos, sector, - (u64)len << inode->i_blkbits); + len); BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_VECS); nr_pages = min_t(u64, ARRAY_SIZE(pages), diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 945613c95ffa..8ef61198e14c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -406,7 +406,8 @@ int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk, if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) return fscrypt_zeroout_range(inode, - (loff_t)lblk << inode->i_blkbits, pblk, len); + (loff_t)lblk << inode->i_blkbits, pblk, + (u64)len << inode->i_blkbits); ret = sb_issue_zeroout(inode->i_sb, pblk, len, GFP_NOFS); if (ret > 0) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 239c2666ceb5..8785f7c13657 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -4164,7 +4164,7 @@ static int f2fs_secure_erase(struct block_device *bdev, struct inode *inode, if (IS_ENCRYPTED(inode)) ret = fscrypt_zeroout_range(inode, (loff_t)off << inode->i_blkbits, block, - len); + (u64)len << inode->i_blkbits); else ret = blkdev_issue_zeroout(bdev, sector, nr_sects, GFP_NOFS, 0); diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 9fc15e1fbe57..90ac62fda926 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -450,8 +450,8 @@ u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name); /* bio.c */ bool fscrypt_decrypt_bio(struct bio *bio); -int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, - sector_t pblk, unsigned int len); +int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, sector_t pblk, + u64 len); /* hooks.c */ int fscrypt_file_open(struct inode *inode, struct file *filp); @@ -756,7 +756,7 @@ static inline bool fscrypt_decrypt_bio(struct bio *bio) } static inline int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, - sector_t pblk, unsigned int len) + sector_t pblk, u64 len) { return -EOPNOTSUPP; } -- cgit v1.2.3 From 5ca1a1f017ea0f0e0bcb6ec52064735f2ac1c393 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 2 Mar 2026 06:18:18 -0800 Subject: fscrypt: pass a real sector_t to fscrypt_zeroout_range While the pblk argument to fscrypt_zeroout_range is declared as a sector_t, it actually is interpreted as a logical block size unit, which is highly unusual. Switch to passing the 512 byte units that sector_t is defined for. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20260302141922.370070-14-hch@lst.de Signed-off-by: Eric Biggers --- fs/crypto/bio.c | 5 ++--- fs/ext4/inode.c | 3 ++- fs/f2fs/file.c | 2 +- include/linux/fscrypt.h | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 9872408f4f52..d07740680602 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -114,7 +114,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, * fscrypt_zeroout_range() - zero out a range of blocks in an encrypted file * @inode: the file's inode * @pos: the first file position (in bytes) to zero out - * @pblk: the first filesystem physical block to zero out + * @sector: the first sector to zero out * @len: bytes to zero out * * Zero out filesystem blocks in an encrypted regular file on-disk, i.e. write @@ -129,7 +129,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, * Return: 0 on success; -errno on failure. */ int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, - sector_t pblk, u64 len) + sector_t sector, u64 len) { const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode); const unsigned int du_bits = ci->ci_data_unit_bits; @@ -138,7 +138,6 @@ int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, const unsigned int du_per_page = 1U << du_per_page_bits; u64 du_index = pos >> du_bits; u64 du_remaining = len >> du_bits; - sector_t sector = pblk << (inode->i_blkbits - SECTOR_SHIFT); struct page *pages[16]; /* write up to 16 pages at a time */ unsigned int nr_pages; unsigned int i; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 8ef61198e14c..fe258ffd4840 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -406,7 +406,8 @@ int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk, if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) return fscrypt_zeroout_range(inode, - (loff_t)lblk << inode->i_blkbits, pblk, + (loff_t)lblk << inode->i_blkbits, + pblk << (inode->i_blkbits - SECTOR_SHIFT), (u64)len << inode->i_blkbits); ret = sb_issue_zeroout(inode->i_sb, pblk, len, GFP_NOFS); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 8785f7c13657..a264771cfbc2 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -4163,7 +4163,7 @@ static int f2fs_secure_erase(struct block_device *bdev, struct inode *inode, if (!ret && (flags & F2FS_TRIM_FILE_ZEROOUT)) { if (IS_ENCRYPTED(inode)) ret = fscrypt_zeroout_range(inode, - (loff_t)off << inode->i_blkbits, block, + (loff_t)off << inode->i_blkbits, sector, (u64)len << inode->i_blkbits); else ret = blkdev_issue_zeroout(bdev, sector, nr_sects, diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 90ac62fda926..54712ec61ffb 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -450,8 +450,8 @@ u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name); /* bio.c */ bool fscrypt_decrypt_bio(struct bio *bio); -int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, sector_t pblk, - u64 len); +int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, + sector_t sector, u64 len); /* hooks.c */ int fscrypt_file_open(struct inode *inode, struct file *filp); @@ -756,7 +756,7 @@ static inline bool fscrypt_decrypt_bio(struct bio *bio) } static inline int fscrypt_zeroout_range(const struct inode *inode, loff_t pos, - sector_t pblk, u64 len) + sector_t sector, u64 len) { return -EOPNOTSUPP; } -- cgit v1.2.3