Loading fs/crypto/crypto.c +8 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,14 @@ void fscrypt_free_bounce_page(struct page *bounce_page) } EXPORT_SYMBOL(fscrypt_free_bounce_page); /* * Generate the IV for the given logical block number within the given file. * For filenames encryption, lblk_num == 0. * * Keep this in sync with fscrypt_limit_dio_pages(). fscrypt_limit_dio_pages() * needs to know about any IV generation methods where the low bits of IV don't * simply contain the lblk_num (e.g., IV_INO_LBLK_32). */ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, const struct fscrypt_info *ci) { Loading fs/crypto/inline_crypt.c +82 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/blkdev.h> #include <linux/buffer_head.h> #include <linux/keyslot-manager.h> #include <linux/uio.h> #include "fscrypt_private.h" Loading Loading @@ -428,3 +429,84 @@ bool fscrypt_mergeable_bio_bh(struct bio *bio, return fscrypt_mergeable_bio(bio, inode, next_lblk); } EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh); /** * fscrypt_dio_supported() - check whether a direct I/O request is unsupported * due to encryption constraints * @iocb: the file and position the I/O is targeting * @iter: the I/O data segment(s) * * Return: true if direct I/O is supported */ 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. */ if (!fscrypt_needs_contents_encryption(inode)) return true; /* We only support direct I/O with inline crypto, not fs-layer crypto */ if (!fscrypt_inode_uses_inline_crypto(inode)) return false; /* * Since the granularity of encryption is filesystem blocks, the I/O * must be block aligned -- not just disk sector aligned. */ 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); /** * fscrypt_limit_dio_pages() - limit I/O pages to avoid discontiguous DUNs * @inode: the file on which I/O is being done * @pos: the file position (in bytes) at which the I/O is being done * @nr_pages: the number of pages we want to submit starting at @pos * * For direct I/O: limit the number of pages that will be submitted in the bio * 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) { const struct fscrypt_info *ci = inode->i_crypt_info; u32 dun; if (!fscrypt_inode_uses_inline_crypto(inode)) return nr_pages; if (nr_pages <= 1) return nr_pages; if (!(fscrypt_policy_flags(&ci->ci_policy) & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) return nr_pages; if (WARN_ON_ONCE(i_blocksize(inode) != PAGE_SIZE)) return 1; /* With IV_INO_LBLK_32, the DUN can wrap around from U32_MAX to 0. */ dun = ci->ci_hashed_ino + (pos >> inode->i_blkbits); return min_t(u64, nr_pages, (u64)U32_MAX + 1 - dun); } fs/direct-io.c +9 −1 Original line number Diff line number Diff line Loading @@ -814,9 +814,17 @@ static inline int dio_send_cur_page(struct dio *dio, struct dio_submit *sdio, * current logical offset in the file does not equal what would * be the next logical offset in the bio, submit the bio we * have. * * When fscrypt inline encryption is used, data unit number * (DUN) contiguity is also required. Normally that's implied * by logical contiguity. However, certain IV generation * methods (e.g. IV_INO_LBLK_32) don't guarantee it. So, we * must explicitly check fscrypt_mergeable_bio() too. */ if (sdio->final_block_in_bio != sdio->cur_page_block || cur_offset != bio_next_offset) cur_offset != bio_next_offset || !fscrypt_mergeable_bio(sdio->bio, dio->inode, cur_offset >> dio->inode->i_blkbits)) dio_bio_submit(dio, sdio); } Loading fs/ext4/inode.c +3 −6 Original line number Diff line number Diff line Loading @@ -3919,12 +3919,9 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ssize_t ret; int rw = iov_iter_rw(iter); if (IS_ENABLED(CONFIG_FS_ENCRYPTION) && IS_ENCRYPTED(inode)) { if (!fscrypt_inode_uses_inline_crypto(inode) || !IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), i_blocksize(inode))) if (!fscrypt_dio_supported(iocb, iter)) return 0; } if (fsverity_active(inode)) return 0; Loading fs/f2fs/f2fs.h +2 −6 Original line number Diff line number Diff line Loading @@ -3971,12 +3971,8 @@ static inline bool f2fs_force_buffered_io(struct inode *inode, struct f2fs_sb_info *sbi = F2FS_I_SB(inode); int rw = iov_iter_rw(iter); if (IS_ENABLED(CONFIG_FS_ENCRYPTION) && f2fs_encrypted_file(inode)) { if (!fscrypt_inode_uses_inline_crypto(inode) || !IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), F2FS_BLKSIZE)) if (!fscrypt_dio_supported(iocb, iter)) return true; } if (fsverity_active(inode)) return true; if (f2fs_is_multi_device(sbi)) Loading Loading
fs/crypto/crypto.c +8 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,14 @@ void fscrypt_free_bounce_page(struct page *bounce_page) } EXPORT_SYMBOL(fscrypt_free_bounce_page); /* * Generate the IV for the given logical block number within the given file. * For filenames encryption, lblk_num == 0. * * Keep this in sync with fscrypt_limit_dio_pages(). fscrypt_limit_dio_pages() * needs to know about any IV generation methods where the low bits of IV don't * simply contain the lblk_num (e.g., IV_INO_LBLK_32). */ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, const struct fscrypt_info *ci) { Loading
fs/crypto/inline_crypt.c +82 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/blkdev.h> #include <linux/buffer_head.h> #include <linux/keyslot-manager.h> #include <linux/uio.h> #include "fscrypt_private.h" Loading Loading @@ -428,3 +429,84 @@ bool fscrypt_mergeable_bio_bh(struct bio *bio, return fscrypt_mergeable_bio(bio, inode, next_lblk); } EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh); /** * fscrypt_dio_supported() - check whether a direct I/O request is unsupported * due to encryption constraints * @iocb: the file and position the I/O is targeting * @iter: the I/O data segment(s) * * Return: true if direct I/O is supported */ 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. */ if (!fscrypt_needs_contents_encryption(inode)) return true; /* We only support direct I/O with inline crypto, not fs-layer crypto */ if (!fscrypt_inode_uses_inline_crypto(inode)) return false; /* * Since the granularity of encryption is filesystem blocks, the I/O * must be block aligned -- not just disk sector aligned. */ 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); /** * fscrypt_limit_dio_pages() - limit I/O pages to avoid discontiguous DUNs * @inode: the file on which I/O is being done * @pos: the file position (in bytes) at which the I/O is being done * @nr_pages: the number of pages we want to submit starting at @pos * * For direct I/O: limit the number of pages that will be submitted in the bio * 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) { const struct fscrypt_info *ci = inode->i_crypt_info; u32 dun; if (!fscrypt_inode_uses_inline_crypto(inode)) return nr_pages; if (nr_pages <= 1) return nr_pages; if (!(fscrypt_policy_flags(&ci->ci_policy) & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) return nr_pages; if (WARN_ON_ONCE(i_blocksize(inode) != PAGE_SIZE)) return 1; /* With IV_INO_LBLK_32, the DUN can wrap around from U32_MAX to 0. */ dun = ci->ci_hashed_ino + (pos >> inode->i_blkbits); return min_t(u64, nr_pages, (u64)U32_MAX + 1 - dun); }
fs/direct-io.c +9 −1 Original line number Diff line number Diff line Loading @@ -814,9 +814,17 @@ static inline int dio_send_cur_page(struct dio *dio, struct dio_submit *sdio, * current logical offset in the file does not equal what would * be the next logical offset in the bio, submit the bio we * have. * * When fscrypt inline encryption is used, data unit number * (DUN) contiguity is also required. Normally that's implied * by logical contiguity. However, certain IV generation * methods (e.g. IV_INO_LBLK_32) don't guarantee it. So, we * must explicitly check fscrypt_mergeable_bio() too. */ if (sdio->final_block_in_bio != sdio->cur_page_block || cur_offset != bio_next_offset) cur_offset != bio_next_offset || !fscrypt_mergeable_bio(sdio->bio, dio->inode, cur_offset >> dio->inode->i_blkbits)) dio_bio_submit(dio, sdio); } Loading
fs/ext4/inode.c +3 −6 Original line number Diff line number Diff line Loading @@ -3919,12 +3919,9 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ssize_t ret; int rw = iov_iter_rw(iter); if (IS_ENABLED(CONFIG_FS_ENCRYPTION) && IS_ENCRYPTED(inode)) { if (!fscrypt_inode_uses_inline_crypto(inode) || !IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), i_blocksize(inode))) if (!fscrypt_dio_supported(iocb, iter)) return 0; } if (fsverity_active(inode)) return 0; Loading
fs/f2fs/f2fs.h +2 −6 Original line number Diff line number Diff line Loading @@ -3971,12 +3971,8 @@ static inline bool f2fs_force_buffered_io(struct inode *inode, struct f2fs_sb_info *sbi = F2FS_I_SB(inode); int rw = iov_iter_rw(iter); if (IS_ENABLED(CONFIG_FS_ENCRYPTION) && f2fs_encrypted_file(inode)) { if (!fscrypt_inode_uses_inline_crypto(inode) || !IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), F2FS_BLKSIZE)) if (!fscrypt_dio_supported(iocb, iter)) return true; } if (fsverity_active(inode)) return true; if (f2fs_is_multi_device(sbi)) Loading