diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 0242088d213f..642b9d6a71f7 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -77,7 +77,8 @@ static int fscrypt_zeroout_range_inlinecrypt(const struct inode *inode, lblk += blocks_this_page; pblk += blocks_this_page; len -= blocks_this_page; - } while (++i != BIO_MAX_PAGES && len != 0); + } while (++i != BIO_MAX_PAGES && len != 0 && + fscrypt_mergeable_bio(bio, inode, lblk)); err = submit_bio_wait(bio); if (err) diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 9b3a0c17c9b4..6504f053ae57 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -88,6 +88,19 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci, !sb->s_cop->inline_crypt_enabled(sb)) return 0; + /* + * When a page contains multiple logically contiguous filesystem blocks, + * some filesystem code only calls fscrypt_mergeable_bio() for the first + * block in the page. This is fine for most of fscrypt's IV generation + * strategies, where contiguous blocks imply contiguous IVs. But it + * doesn't work with IV_INO_LBLK_32. For now, simply exclude + * IV_INO_LBLK_32 with blocksize != PAGE_SIZE from inline encryption. + */ + if ((fscrypt_policy_flags(&ci->ci_policy) & + FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) && + sb->s_blocksize != PAGE_SIZE) + return 0; + /* * The needed encryption settings must be supported either by * blk-crypto-fallback, or by hardware on all the filesystem's devices. @@ -441,7 +454,6 @@ EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh); bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter) { const struct inode *inode = file_inode(iocb->ki_filp); - const struct fscrypt_info *ci = inode->i_crypt_info; const unsigned int blocksize = i_blocksize(inode); /* If the file is unencrypted, no veto from us. */ @@ -459,15 +471,6 @@ bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter) if (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), blocksize)) return false; - /* - * With IV_INO_LBLK_32 and sub-page blocks, the DUN can wrap around in - * the middle of a page. This isn't handled by the direct I/O code yet. - */ - if (blocksize != PAGE_SIZE && - (fscrypt_policy_flags(&ci->ci_policy) & - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) - return false; - return true; } EXPORT_SYMBOL_GPL(fscrypt_dio_supported); @@ -482,8 +485,6 @@ EXPORT_SYMBOL_GPL(fscrypt_dio_supported); * targeting @pos, in order to avoid crossing a data unit number (DUN) * discontinuity. This is only needed for certain IV generation methods. * - * This assumes block_size == PAGE_SIZE; see fscrypt_dio_supported(). - * * Return: the actual number of pages that can be submitted */ int fscrypt_limit_dio_pages(const struct inode *inode, loff_t pos, int nr_pages) @@ -501,6 +502,10 @@ int fscrypt_limit_dio_pages(const struct inode *inode, loff_t pos, int nr_pages) FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) return nr_pages; + /* + * fscrypt_select_encryption_impl() ensures that block_size == PAGE_SIZE + * when using FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32. + */ if (WARN_ON_ONCE(i_blocksize(inode) != PAGE_SIZE)) return 1;