* [PATCH 01/11] fscrypt: pass a real sector_t to fscrypt_zeroout_range_inline_crypt
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
2025-11-18 6:21 ` [PATCH 02/11] fscrypt: keep multiple bios in flight in fscrypt_zeroout_range_inline_crypt Christoph Hellwig
` (9 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
While the pblk argument to fscrypt_zeroout_range_inline_crypt 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 <hch@lst.de>
Reviewed-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/bio.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 5f5599020e94..68b0424d879a 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -48,7 +48,7 @@ bool fscrypt_decrypt_bio(struct bio *bio)
EXPORT_SYMBOL(fscrypt_decrypt_bio);
static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
- pgoff_t lblk, sector_t pblk,
+ pgoff_t lblk, sector_t sector,
unsigned int len)
{
const unsigned int blockbits = inode->i_blkbits;
@@ -67,8 +67,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
if (num_pages == 0) {
fscrypt_set_bio_crypt_ctx(bio, inode, lblk, GFP_NOFS);
- bio->bi_iter.bi_sector =
- pblk << (blockbits - SECTOR_SHIFT);
+ bio->bi_iter.bi_sector = sector;
}
ret = bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0);
if (WARN_ON_ONCE(ret != bytes_this_page)) {
@@ -78,7 +77,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
num_pages++;
len -= blocks_this_page;
lblk += blocks_this_page;
- pblk += blocks_this_page;
+ sector += (bytes_this_page >> SECTOR_SHIFT);
if (num_pages == BIO_MAX_VECS || !len ||
!fscrypt_mergeable_bio(bio, inode, lblk)) {
err = submit_bio_wait(bio);
@@ -132,7 +131,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
return 0;
if (fscrypt_inode_uses_inline_crypto(inode))
- return fscrypt_zeroout_range_inline_crypt(inode, lblk, pblk,
+ return fscrypt_zeroout_range_inline_crypt(inode, lblk, sector,
len);
BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_VECS);
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 02/11] fscrypt: keep multiple bios in flight in fscrypt_zeroout_range_inline_crypt
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
2025-11-18 6:21 ` [PATCH 01/11] fscrypt: pass a real sector_t to fscrypt_zeroout_range_inline_crypt Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
2025-11-18 6:21 ` [PATCH 03/11] fscrypt: pass a byte offset to fscrypt_generate_dun Christoph Hellwig
` (8 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
This should slightly improve performance for large zeroing operations,
but more importantly prepares for blk-crypto refactoring that requires
all fscrypt users to call submit_bio directly.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Eric Biggers <ebiggers@kernel.org>
---
fs/crypto/bio.c | 86 +++++++++++++++++++++++++++++++------------------
1 file changed, 54 insertions(+), 32 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 68b0424d879a..c2b3ca100f8d 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -47,49 +47,71 @@ bool fscrypt_decrypt_bio(struct bio *bio)
}
EXPORT_SYMBOL(fscrypt_decrypt_bio);
+struct fscrypt_zero_done {
+ atomic_t pending;
+ blk_status_t status;
+ struct completion done;
+};
+
+static void fscrypt_zeroout_range_done(struct fscrypt_zero_done *done)
+{
+ if (atomic_dec_and_test(&done->pending))
+ complete(&done->done);
+}
+
+static void fscrypt_zeroout_range_end_io(struct bio *bio)
+{
+ struct fscrypt_zero_done *done = bio->bi_private;
+
+ if (bio->bi_status)
+ cmpxchg(&done->status, 0, bio->bi_status);
+ fscrypt_zeroout_range_done(done);
+ bio_put(bio);
+}
+
static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
pgoff_t lblk, sector_t sector,
unsigned int len)
{
const unsigned int blockbits = inode->i_blkbits;
const unsigned int blocks_per_page = 1 << (PAGE_SHIFT - blockbits);
- struct bio *bio;
- int ret, err = 0;
- int num_pages = 0;
-
- /* This always succeeds since __GFP_DIRECT_RECLAIM is set. */
- bio = bio_alloc(inode->i_sb->s_bdev, BIO_MAX_VECS, REQ_OP_WRITE,
- GFP_NOFS);
+ struct fscrypt_zero_done done = {
+ .pending = ATOMIC_INIT(1),
+ .done = COMPLETION_INITIALIZER_ONSTACK(done.done),
+ };
while (len) {
- unsigned int blocks_this_page = min(len, blocks_per_page);
- unsigned int bytes_this_page = blocks_this_page << blockbits;
+ struct bio *bio;
+ unsigned int n;
- if (num_pages == 0) {
- fscrypt_set_bio_crypt_ctx(bio, inode, lblk, GFP_NOFS);
- bio->bi_iter.bi_sector = sector;
- }
- ret = bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0);
- if (WARN_ON_ONCE(ret != bytes_this_page)) {
- err = -EIO;
- goto out;
- }
- num_pages++;
- len -= blocks_this_page;
- lblk += blocks_this_page;
- sector += (bytes_this_page >> SECTOR_SHIFT);
- if (num_pages == BIO_MAX_VECS || !len ||
- !fscrypt_mergeable_bio(bio, inode, lblk)) {
- err = submit_bio_wait(bio);
- if (err)
- goto out;
- bio_reset(bio, inode->i_sb->s_bdev, REQ_OP_WRITE);
- num_pages = 0;
+ bio = bio_alloc(inode->i_sb->s_bdev, BIO_MAX_VECS, REQ_OP_WRITE,
+ GFP_NOFS);
+ 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);
+
+ for (n = 0; n < BIO_MAX_VECS; n++) {
+ unsigned int blocks_this_page =
+ min(len, blocks_per_page);
+ unsigned int bytes_this_page = blocks_this_page << blockbits;
+
+ __bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0);
+ len -= blocks_this_page;
+ lblk += blocks_this_page;
+ sector += (bytes_this_page >> SECTOR_SHIFT);
+ if (!len || !fscrypt_mergeable_bio(bio, inode, lblk))
+ break;
}
+
+ atomic_inc(&done.pending);
+ submit_bio(bio);
}
-out:
- bio_put(bio);
- return err;
+
+ fscrypt_zeroout_range_done(&done);
+
+ wait_for_completion(&done.done);
+ return blk_status_to_errno(done.status);
}
/**
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 03/11] fscrypt: pass a byte offset to fscrypt_generate_dun
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
2025-11-18 6:21 ` [PATCH 01/11] fscrypt: pass a real sector_t to fscrypt_zeroout_range_inline_crypt Christoph Hellwig
2025-11-18 6:21 ` [PATCH 02/11] fscrypt: keep multiple bios in flight in fscrypt_zeroout_range_inline_crypt Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
2025-11-18 6:21 ` [PATCH 04/11] fscrypt: pass a byte offset to fscrypt_mergeable_bio Christoph Hellwig
` (7 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
Logical offsets into an inode are usually expresssed as bytes in the VFS.
Switch fscrypt_generate_dun to that convention and remove the
ci_data_units_per_block_bits member in struct fscrypt_inode_info that
was only used to cache the DUN shift based on the logical block size
granularity.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/crypto/fscrypt_private.h | 3 ---
fs/crypto/inline_crypt.c | 10 ++++------
fs/crypto/keysetup.c | 2 --
3 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 4e8e82a9ccf9..8d3c278a7591 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -278,9 +278,6 @@ struct fscrypt_inode_info {
*/
u8 ci_data_unit_bits;
- /* Cached value: log2 of number of data units per FS block */
- u8 ci_data_units_per_block_bits;
-
/* Hashed inode number. Only set for IV_INO_LBLK_32 */
u32 ci_hashed_ino;
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index ed6e926226b5..1773dd7ea7cf 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -268,14 +268,12 @@ bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode)
EXPORT_SYMBOL_GPL(__fscrypt_inode_uses_inline_crypto);
static void fscrypt_generate_dun(const struct fscrypt_inode_info *ci,
- u64 lblk_num,
- u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE])
+ loff_t pos, u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE])
{
- u64 index = lblk_num << ci->ci_data_units_per_block_bits;
union fscrypt_iv iv;
int i;
- fscrypt_generate_iv(&iv, index, ci);
+ fscrypt_generate_iv(&iv, pos >> ci->ci_data_unit_bits, ci);
BUILD_BUG_ON(FSCRYPT_MAX_IV_SIZE > BLK_CRYPTO_MAX_IV_SIZE);
memset(dun, 0, BLK_CRYPTO_MAX_IV_SIZE);
@@ -309,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, dun);
+ fscrypt_generate_dun(ci, first_lblk << inode->i_blkbits, dun);
bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask);
}
EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx);
@@ -401,7 +399,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, next_dun);
+ fscrypt_generate_dun(ci, next_lblk << inode->i_blkbits, 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/crypto/keysetup.c b/fs/crypto/keysetup.c
index 4bd3918f50e3..f8a96d729dfc 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -609,8 +609,6 @@ fscrypt_setup_encryption_info(struct inode *inode,
crypt_info->ci_data_unit_bits =
fscrypt_policy_du_bits(&crypt_info->ci_policy, inode);
- crypt_info->ci_data_units_per_block_bits =
- inode->i_blkbits - crypt_info->ci_data_unit_bits;
res = setup_file_encryption_key(crypt_info, need_dirhash_key, &mk);
if (res)
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 04/11] fscrypt: pass a byte offset to fscrypt_mergeable_bio
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
` (2 preceding siblings ...)
2025-11-18 6:21 ` [PATCH 03/11] fscrypt: pass a byte offset to fscrypt_generate_dun Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
2025-11-22 18:17 ` Eric Biggers
2025-11-18 6:21 ` [PATCH 05/11] fscrypt: pass a byte offset to fscrypt_set_bio_crypt_ctx Christoph Hellwig
` (6 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
Logical offsets into an inode are usually expresssed as bytes in the VFS.
Switch fscrypt_mergeable_bio to that convention.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/crypto/bio.c | 3 ++-
fs/crypto/inline_crypt.c | 9 +++++----
fs/ext4/readpage.c | 3 ++-
fs/f2fs/data.c | 3 ++-
include/linux/fscrypt.h | 4 ++--
5 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index c2b3ca100f8d..fce401c9df98 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 1773dd7ea7cf..aba830e0827d 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -361,7 +361,7 @@ 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
* @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 logical offset (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
@@ -379,7 +379,7 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx_bh);
* 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;
@@ -399,7 +399,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);
@@ -423,7 +423,8 @@ bool fscrypt_mergeable_bio_bh(struct bio *bio,
if (!bh_get_inode_and_lblk_num(next_bh, &inode, &next_lblk))
return !bio->bi_crypt_context;
- return fscrypt_mergeable_bio(bio, inode, next_lblk);
+ return fscrypt_mergeable_bio(bio, inode,
+ (loff_t)next_lblk << inode->i_blkbits);
}
EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh);
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index f329daf6e5c7..371f34a14084 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -346,7 +346,8 @@ int ext4_mpage_readpages(struct inode *inode,
* 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:
submit_bio(bio);
bio = NULL;
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 775aa4f63aa3..dd3c98fbe6b5 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -503,7 +503,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 516aba5b858b..5f2e02a61401 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -874,7 +874,7 @@ void fscrypt_set_bio_crypt_ctx_bh(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_mergeable_bio_bh(struct bio *bio,
const struct buffer_head *next_bh);
@@ -901,7 +901,7 @@ static inline void fscrypt_set_bio_crypt_ctx_bh(
static inline bool fscrypt_mergeable_bio(struct bio *bio,
const struct inode *inode,
- u64 next_lblk)
+ loff_t pos)
{
return true;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 04/11] fscrypt: pass a byte offset to fscrypt_mergeable_bio
2025-11-18 6:21 ` [PATCH 04/11] fscrypt: pass a byte offset to fscrypt_mergeable_bio Christoph Hellwig
@ 2025-11-22 18:17 ` Eric Biggers
2025-11-24 14:16 ` Christoph Hellwig
0 siblings, 1 reply; 17+ messages in thread
From: Eric Biggers @ 2025-11-22 18:17 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
On Tue, Nov 18, 2025 at 07:21:47AM +0100, Christoph Hellwig wrote:
> diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
> index 1773dd7ea7cf..aba830e0827d 100644
> --- a/fs/crypto/inline_crypt.c
> +++ b/fs/crypto/inline_crypt.c
> @@ -361,7 +361,7 @@ 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
> * @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 logical offset (in bytes) in the I/O
In comments, maybe call it a "file position" instead of "file logical
offset" to match the variable name?
- Eric
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 04/11] fscrypt: pass a byte offset to fscrypt_mergeable_bio
2025-11-22 18:17 ` Eric Biggers
@ 2025-11-24 14:16 ` Christoph Hellwig
0 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-24 14:16 UTC (permalink / raw)
To: Eric Biggers
Cc: Christoph Hellwig, Theodore Y. Ts'o, Jaegeuk Kim,
Andreas Dilger, Chao Yu, Christian Brauner, Darrick J. Wong,
linux-fscrypt, linux-ext4, linux-f2fs-devel, linux-fsdevel
On Sat, Nov 22, 2025 at 10:17:17AM -0800, Eric Biggers wrote:
> On Tue, Nov 18, 2025 at 07:21:47AM +0100, Christoph Hellwig wrote:
> > diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
> > index 1773dd7ea7cf..aba830e0827d 100644
> > --- a/fs/crypto/inline_crypt.c
> > +++ b/fs/crypto/inline_crypt.c
> > @@ -361,7 +361,7 @@ 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
> > * @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 logical offset (in bytes) in the I/O
>
> In comments, maybe call it a "file position" instead of "file logical
> offset" to match the variable name?
Doing a quick grep, "file offset" seems to be a bit more than twice
as common as "file position" in the kernel. Logical offset, even
without file is barely used. So I think "file offset' might be best
here, but if you prefer "file position" I can switch to that as well.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 05/11] fscrypt: pass a byte offset to fscrypt_set_bio_crypt_ctx
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
` (3 preceding siblings ...)
2025-11-18 6:21 ` [PATCH 04/11] fscrypt: pass a byte offset to fscrypt_mergeable_bio Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
2025-11-18 6:21 ` [PATCH 06/11] fscrypt: pass a byte offset to fscrypt_zeroout_range_inline_crypt Christoph Hellwig
` (5 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
Logical offsets into an inode are usually expresssed as bytes in the VFS.
Switch fscrypt_set_bio_crypt_ctx to that convention.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/crypto/bio.c | 8 ++++----
fs/crypto/inline_crypt.c | 9 +++++----
fs/ext4/readpage.c | 4 ++--
fs/f2fs/data.c | 4 +++-
fs/iomap/direct-io.c | 6 ++----
include/linux/fscrypt.h | 7 +++----
6 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index fce401c9df98..3a7e3b37ac02 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 aba830e0827d..c069958c4819 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 logical offset (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);
@@ -353,7 +353,8 @@ void fscrypt_set_bio_crypt_ctx_bh(struct bio *bio,
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);
+ fscrypt_set_bio_crypt_ctx(bio, inode,
+ first_lblk << inode->i_blkbits, gfp_mask);
}
EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx_bh);
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index 371f34a14084..ac3965040f85 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -359,8 +359,8 @@ int ext4_mpage_readpages(struct inode *inode,
*/
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, folio->index);
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 dd3c98fbe6b5..270770c611cf 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -489,7 +489,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 5d5d63efbd57..01b4a8c44cc2 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -295,8 +295,7 @@ static int iomap_dio_zero(const struct iomap_iter *iter, struct iomap_dio *dio,
return -EINVAL;
bio = iomap_dio_alloc_bio(iter, dio, 1, 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;
@@ -425,8 +424,7 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
}
bio = iomap_dio_alloc_bio(iter, dio, nr_pages, bio_opf);
- 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(iomap, pos);
bio->bi_write_hint = inode->i_write_hint;
bio->bi_ioprio = dio->iocb->ki_ioprio;
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 5f2e02a61401..5b86d7d0d367 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);
void fscrypt_set_bio_crypt_ctx_bh(struct bio *bio,
const struct buffer_head *first_bh,
@@ -892,7 +891,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 void fscrypt_set_bio_crypt_ctx_bh(
struct bio *bio,
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 06/11] fscrypt: pass a byte offset to fscrypt_zeroout_range_inline_crypt
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
` (4 preceding siblings ...)
2025-11-18 6:21 ` [PATCH 05/11] fscrypt: pass a byte offset to fscrypt_set_bio_crypt_ctx Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
2025-11-18 6:21 ` [PATCH 07/11] fscrypt: pass a byte length " Christoph Hellwig
` (4 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
Logical offsets into an inode are usually expresssed as bytes in the VFS.
Switch fscrypt_zeroout_range_inline_crypt to that convention.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/crypto/bio.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 3a7e3b37ac02..07d757d2777e 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -70,12 +70,11 @@ static void fscrypt_zeroout_range_end_io(struct bio *bio)
}
static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
- pgoff_t lblk, sector_t sector,
+ loff_t pos, sector_t sector,
unsigned int len)
{
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),
@@ -142,6 +141,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
const unsigned int du_per_page = 1U << du_per_page_bits;
u64 du_index = (u64)lblk << (inode->i_blkbits - 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;
@@ -154,7 +154,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
return 0;
if (fscrypt_inode_uses_inline_crypto(inode))
- return fscrypt_zeroout_range_inline_crypt(inode, lblk, sector,
+ return fscrypt_zeroout_range_inline_crypt(inode, pos, sector,
len);
BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_VECS);
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 07/11] fscrypt: pass a byte length to fscrypt_zeroout_range_inline_crypt
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
` (5 preceding siblings ...)
2025-11-18 6:21 ` [PATCH 06/11] fscrypt: pass a byte offset to fscrypt_zeroout_range_inline_crypt Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
2025-11-18 6:21 ` [PATCH 08/11] fscrypt: return a byte offset from bh_get_inode_and_lblk_num Christoph Hellwig
` (3 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
Range lengths are usually expressed as bytes in the VFS, switch
fscrypt_zeroout_range_inline_crypt to this convention.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/crypto/bio.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 07d757d2777e..be751bcd2976 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -73,8 +73,6 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
loff_t pos, sector_t sector,
unsigned int len)
{
- const unsigned int blockbits = inode->i_blkbits;
- const unsigned int blocks_per_page = 1 << (PAGE_SHIFT - blockbits);
struct fscrypt_zero_done done = {
.pending = ATOMIC_INIT(1),
.done = COMPLETION_INITIALIZER_ONSTACK(done.done),
@@ -92,12 +90,10 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
fscrypt_set_bio_crypt_ctx(bio, inode, pos, GFP_NOFS);
for (n = 0; n < BIO_MAX_VECS; n++) {
- unsigned int blocks_this_page =
- min(len, blocks_per_page);
- unsigned int bytes_this_page = blocks_this_page << blockbits;
+ unsigned int bytes_this_page = min(len, PAGE_SIZE);
__bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0);
- len -= blocks_this_page;
+ len -= bytes_this_page;
pos += bytes_this_page;
sector += (bytes_this_page >> SECTOR_SHIFT);
if (!len || !fscrypt_mergeable_bio(bio, inode, pos))
@@ -155,7 +151,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
if (fscrypt_inode_uses_inline_crypto(inode))
return fscrypt_zeroout_range_inline_crypt(inode, pos, sector,
- len);
+ len << inode->i_blkbits);
BUILD_BUG_ON(ARRAY_SIZE(pages) > BIO_MAX_VECS);
nr_pages = min_t(u64, ARRAY_SIZE(pages),
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 08/11] fscrypt: return a byte offset from bh_get_inode_and_lblk_num
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
` (6 preceding siblings ...)
2025-11-18 6:21 ` [PATCH 07/11] fscrypt: pass a byte length " Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
2025-11-22 18:19 ` Eric Biggers
2025-11-18 6:21 ` [PATCH 09/11] fscrypt: pass a byte offset to fscrypt_zeroout_range Christoph Hellwig
` (2 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
All the callers now want a byte offset into the inode, so return
that from bh_get_inode_and_lblk_num.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/crypto/inline_crypt.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index c069958c4819..128268adf960 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -315,7 +315,7 @@ 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)
+ loff_t *pos_ret)
{
struct folio *folio = bh->b_folio;
const struct address_space *mapping;
@@ -331,7 +331,7 @@ static bool bh_get_inode_and_lblk_num(const struct buffer_head *bh,
inode = mapping->host;
*inode_ret = inode;
- *lblk_num_ret = (folio_pos(folio) + bh_offset(bh)) >> inode->i_blkbits;
+ *pos_ret = folio_pos(folio) + bh_offset(bh);
return true;
}
@@ -350,11 +350,10 @@ void fscrypt_set_bio_crypt_ctx_bh(struct bio *bio,
gfp_t gfp_mask)
{
const struct inode *inode;
- u64 first_lblk;
+ loff_t pos;
- if (bh_get_inode_and_lblk_num(first_bh, &inode, &first_lblk))
- fscrypt_set_bio_crypt_ctx(bio, inode,
- first_lblk << inode->i_blkbits, gfp_mask);
+ if (bh_get_inode_and_lblk_num(first_bh, &inode, &pos))
+ fscrypt_set_bio_crypt_ctx(bio, inode, pos, gfp_mask);
}
EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx_bh);
@@ -419,13 +418,12 @@ bool fscrypt_mergeable_bio_bh(struct bio *bio,
const struct buffer_head *next_bh)
{
const struct inode *inode;
- u64 next_lblk;
+ loff_t pos;
- if (!bh_get_inode_and_lblk_num(next_bh, &inode, &next_lblk))
+ if (!bh_get_inode_and_lblk_num(next_bh, &inode, &pos))
return !bio->bi_crypt_context;
- return fscrypt_mergeable_bio(bio, inode,
- (loff_t)next_lblk << inode->i_blkbits);
+ return fscrypt_mergeable_bio(bio, inode, pos);
}
EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh);
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 08/11] fscrypt: return a byte offset from bh_get_inode_and_lblk_num
2025-11-18 6:21 ` [PATCH 08/11] fscrypt: return a byte offset from bh_get_inode_and_lblk_num Christoph Hellwig
@ 2025-11-22 18:19 ` Eric Biggers
0 siblings, 0 replies; 17+ messages in thread
From: Eric Biggers @ 2025-11-22 18:19 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
On Tue, Nov 18, 2025 at 07:21:51AM +0100, Christoph Hellwig wrote:
> All the callers now want a byte offset into the inode, so return
> that from bh_get_inode_and_lblk_num.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/crypto/inline_crypt.c | 18 ++++++++----------
> 1 file changed, 8 insertions(+), 10 deletions(-)
>
> diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
> index c069958c4819..128268adf960 100644
> --- a/fs/crypto/inline_crypt.c
> +++ b/fs/crypto/inline_crypt.c
> @@ -315,7 +315,7 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx);
> /* Extract the inode and logical block number from a buffer_head. */
inode and file position
> static bool bh_get_inode_and_lblk_num(const struct buffer_head *bh,
> const struct inode **inode_ret,
> - u64 *lblk_num_ret)
> + loff_t *pos_ret)
Rename to bh_get_inode_and_pos()
> * 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)
inode and file position
> * Same as fscrypt_mergeable_bio(), except this takes a buffer_head instead of
> * an inode and block number directly.
> *
> * Return: true iff the I/O is mergeable
> */
> bool fscrypt_mergeable_bio_bh(struct bio *bio,
> const struct buffer_head *next_bh)
inode and file position
- Eric
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 09/11] fscrypt: pass a byte offset to fscrypt_zeroout_range
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
` (7 preceding siblings ...)
2025-11-18 6:21 ` [PATCH 08/11] fscrypt: return a byte offset from bh_get_inode_and_lblk_num Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
2025-11-18 6:21 ` [PATCH 10/11] fscrypt: pass a byte length " Christoph Hellwig
2025-11-18 6:21 ` [PATCH 11/11] fscrypt: pass a real sector_t " Christoph Hellwig
10 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
Logical offsets into an inode are usually expresssed as bytes in the VFS.
Switch fscrypt_zeroout_range to that convention.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/crypto/bio.c | 6 +++---
fs/ext4/inode.c | 3 ++-
fs/f2fs/file.c | 4 +++-
include/linux/fscrypt.h | 4 ++--
4 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index be751bcd2976..235dd1c3d443 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 logical offset (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,7 +135,7 @@ 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);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index e99306a8f47c..209d326b8be9 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -402,7 +402,8 @@ int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk,
int ret;
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 ffa045b39c01..150c3eb15f51 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -4142,7 +4142,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 5b86d7d0d367..065f909ebda2 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;
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 10/11] fscrypt: pass a byte length to fscrypt_zeroout_range
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
` (8 preceding siblings ...)
2025-11-18 6:21 ` [PATCH 09/11] fscrypt: pass a byte offset to fscrypt_zeroout_range Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
2025-11-22 18:29 ` Eric Biggers
2025-11-18 6:21 ` [PATCH 11/11] fscrypt: pass a real sector_t " Christoph Hellwig
10 siblings, 1 reply; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
Range lengths are usually expressed as bytes in the VFS, switch
fscrypt_zeroout_range to this convention.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
fs/crypto/bio.c | 6 +++---
fs/ext4/inode.c | 3 ++-
fs/f2fs/file.c | 2 +-
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 235dd1c3d443..4e9893664c0f 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -115,7 +115,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
* @inode: the file's inode
* @pos: the first file logical offset (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
@@ -136,7 +136,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;
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 */
@@ -151,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,
- 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 209d326b8be9..3743260b70d4 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -403,7 +403,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,
+ 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 150c3eb15f51..45ec6f83fcda 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -4144,7 +4144,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);
+ len << inode->i_blkbits);
else
ret = blkdev_issue_zeroout(bdev, sector, nr_sects,
GFP_NOFS, 0);
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 10/11] fscrypt: pass a byte length to fscrypt_zeroout_range
2025-11-18 6:21 ` [PATCH 10/11] fscrypt: pass a byte length " Christoph Hellwig
@ 2025-11-22 18:29 ` Eric Biggers
2025-11-24 14:17 ` Christoph Hellwig
0 siblings, 1 reply; 17+ messages in thread
From: Eric Biggers @ 2025-11-22 18:29 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
On Tue, Nov 18, 2025 at 07:21:53AM +0100, Christoph Hellwig wrote:
> Range lengths are usually expressed as bytes in the VFS, switch
> fscrypt_zeroout_range to this convention.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
> fs/crypto/bio.c | 6 +++---
> fs/ext4/inode.c | 3 ++-
> fs/f2fs/file.c | 2 +-
> 3 files changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
> index 235dd1c3d443..4e9893664c0f 100644
> --- a/fs/crypto/bio.c
> +++ b/fs/crypto/bio.c
> @@ -115,7 +115,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode,
> * @inode: the file's inode
> * @pos: the first file logical offset (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
[...]
> int fscrypt_zeroout_range(const struct inode *inode, loff_t pos,
> sector_t sector, unsigned int len)
The type of 'len' is still unsigned int, so this reduces the maximum
length accepted by fscrypt_zeroout_range() from UINT32_MAX blocks to
UINT32_MAX bytes. Is that really okay?
Both ext4 and f2fs call this from functions where they have the length
as a u32 number of logical blocks. And of course both filesystems
support files longer than UINT32_MAX bytes. So it's not clear to me.
ext4 extents have a smaller size limit, so maybe at least ext4 is okay.
But different extents can be contiguous and operated on together. So
we'd have to check the callers of the callers, etc.
It would be safer to change the type to u64 and have the callers do
(u64)len_in_blocks << blockbits.
- Eric
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 10/11] fscrypt: pass a byte length to fscrypt_zeroout_range
2025-11-22 18:29 ` Eric Biggers
@ 2025-11-24 14:17 ` Christoph Hellwig
0 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-24 14:17 UTC (permalink / raw)
To: Eric Biggers
Cc: Christoph Hellwig, Theodore Y. Ts'o, Jaegeuk Kim,
Andreas Dilger, Chao Yu, Christian Brauner, Darrick J. Wong,
linux-fscrypt, linux-ext4, linux-f2fs-devel, linux-fsdevel
On Sat, Nov 22, 2025 at 10:29:26AM -0800, Eric Biggers wrote:
> The type of 'len' is still unsigned int, so this reduces the maximum
> length accepted by fscrypt_zeroout_range() from UINT32_MAX blocks to
> UINT32_MAX bytes. Is that really okay?
Linus has limited Linux's read/write I/O sizes to a signed integer,
even if size_t/ssize_t could be larger. We have internal support
to do a few things larger, so there would be precedence to support a
64-bit value and I'd be happy siwtch over to that.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 11/11] fscrypt: pass a real sector_t to fscrypt_zeroout_range
2025-11-18 6:21 fscrypt API cleanups Christoph Hellwig
` (9 preceding siblings ...)
2025-11-18 6:21 ` [PATCH 10/11] fscrypt: pass a byte length " Christoph Hellwig
@ 2025-11-18 6:21 ` Christoph Hellwig
10 siblings, 0 replies; 17+ messages in thread
From: Christoph Hellwig @ 2025-11-18 6:21 UTC (permalink / raw)
To: Eric Biggers
Cc: Theodore Y. Ts'o, Jaegeuk Kim, Andreas Dilger, Chao Yu,
Christian Brauner, Darrick J. Wong, linux-fscrypt, linux-ext4,
linux-f2fs-devel, linux-fsdevel
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 <hch@lst.de>
---
fs/crypto/bio.c | 6 ++----
fs/ext4/inode.c | 3 ++-
fs/f2fs/file.c | 2 +-
include/linux/fscrypt.h | 4 ++--
4 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 4e9893664c0f..63bb53aeac4a 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 logical offset (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
@@ -128,7 +128,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 sector, unsigned int len)
{
const struct fscrypt_inode_info *ci = fscrypt_get_inode_info_raw(inode);
const unsigned int du_bits = ci->ci_data_unit_bits;
@@ -137,8 +137,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;
- 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;
unsigned int i;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 3743260b70d4..d8a845da2881 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -403,7 +403,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),
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 45ec6f83fcda..315816ac07be 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -4143,7 +4143,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,
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 065f909ebda2..11464bf0a241 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -451,7 +451,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, loff_t pos,
- sector_t pblk, unsigned int len);
+ sector_t sector, unsigned int 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 sector, unsigned int len)
{
return -EOPNOTSUPP;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread