diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 4d5d50dca65c..6ccd5efb25b7 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -1047,8 +1047,8 @@ astute users may notice some differences in behavior: may be used to overwrite the source files but isn't guaranteed to be effective on all filesystems and storage devices. -- Direct I/O is not supported on encrypted files. Attempts to use - direct I/O on such files will fall back to buffered I/O. +- Direct I/O is supported on encrypted files only under some + circumstances. For details, see `Direct I/O support`_. - The fallocate operations FALLOC_FL_COLLAPSE_RANGE and FALLOC_FL_INSERT_RANGE are not supported on encrypted files and will @@ -1179,6 +1179,27 @@ Inline encryption doesn't affect the ciphertext or other aspects of the on-disk format, so users may freely switch back and forth between using "inlinecrypt" and not using "inlinecrypt". +Direct I/O support +================== + +For direct I/O on an encrypted file to work, the following conditions +must be met (in addition to the conditions for direct I/O on an +unencrypted file): + +* The file must be using inline encryption. Usually this means that + the filesystem must be mounted with ``-o inlinecrypt`` and inline + encryption hardware must be present. However, a software fallback + is also available. For details, see `Inline encryption support`_. + +* The I/O request must be fully aligned to the filesystem block size. + This means that the file position the I/O is targeting, the lengths + of all I/O segments, and the memory addresses of all I/O buffers + must be multiples of this value. Note that the filesystem block + size may be greater than the logical block size of the block device. + +If either of the above conditions is not met, then direct I/O on the +encrypted file will fall back to buffered I/O. + Implementation details ====================== diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index a6a47a7a7559..859f6400a919 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -380,6 +380,10 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx_bh); * * fscrypt_set_bio_crypt_ctx() must have already been called on the bio. * + * This function isn't required in cases where crypto-mergeability is ensured in + * another way, such as I/O targeting only a single file (and thus a single key) + * combined with fscrypt_limit_io_blocks() to ensure DUN contiguity. + * * This function also returns false if the next part of the I/O would need to * have a different value for the bi_skip_dm_default_key flag. * @@ -437,12 +441,15 @@ bool fscrypt_mergeable_bio_bh(struct bio *bio, EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh); /** - * fscrypt_dio_supported() - check whether a direct I/O request is unsupported - * due to encryption constraints + * fscrypt_dio_supported() - check whether a DIO (direct I/O) request is + * supported as far as encryption is concerned * @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 + * Return: %true if there are no encryption constraints that prevent DIO from + * being supported; %false if DIO is unsupported. (Note that in the + * %true case, the filesystem might have other, non-encryption-related + * constraints that prevent DIO from actually being supported.) */ bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter) { @@ -453,13 +460,22 @@ bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter) if (!fscrypt_needs_contents_encryption(inode)) return true; - /* We only support direct I/O with inline crypto, not fs-layer crypto */ + /* We only support DIO 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. + * Since the granularity of encryption is filesystem blocks, the file + * position and total I/O length must be aligned to the filesystem block + * size -- not just to the block device's logical block size as is + * traditionally the case for DIO on many filesystems. + * + * We require that the user-provided memory buffers be filesystem block + * aligned too. It is simpler to have a single alignment value required + * for all properties of the I/O, as is normally the case for DIO. + * Also, allowing less aligned buffers would imply that data units could + * cross bvecs, which would greatly complicate the I/O stack, which + * assumes that bios can be split at any bvec boundary. */ if (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), blocksize)) return false; @@ -472,24 +488,25 @@ EXPORT_SYMBOL_GPL(fscrypt_dio_supported); * fscrypt_limit_io_blocks() - limit I/O blocks to avoid discontiguous DUNs * @inode: the file on which I/O is being done * @lblk: the block at which the I/O is being started from - * @nr_blocks: the number of blocks we want to submit starting at @pos + * @nr_blocks: the number of blocks we want to submit starting at @lblk * - * Determine the limit to the number of blocks that can be submitted in the bio - * targeting @pos without causing a data unit number (DUN) discontinuity. + * Determine the limit to the number of blocks that can be submitted in a bio + * targeting @lblk without causing a data unit number (DUN) discontiguity. * * This is normally just @nr_blocks, as normally the DUNs just increment along * with the logical blocks. (Or the file is not encrypted.) * * In rare cases, fscrypt can be using an IV generation method that allows the - * DUN to wrap around within logically continuous blocks, and that wraparound + * DUN to wrap around within logically contiguous blocks, and that wraparound * will occur. If this happens, a value less than @nr_blocks will be returned - * so that the wraparound doesn't occur in the middle of the bio. + * so that the wraparound doesn't occur in the middle of a bio, which would + * cause encryption/decryption to produce wrong results. * * Return: the actual number of blocks that can be submitted */ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) { - const struct fscrypt_info *ci = inode->i_crypt_info; + const struct fscrypt_info *ci; u32 dun; if (!fscrypt_inode_uses_inline_crypto(inode)) @@ -498,6 +515,7 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) if (nr_blocks <= 1) return nr_blocks; + ci = inode->i_crypt_info; if (!(fscrypt_policy_flags(&ci->ci_policy) & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) return nr_blocks; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 27857b86ad7c..4cf55ef54193 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3409,10 +3409,9 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length, if (ret < 0) return ret; out: - /* * When inline encryption is enabled, sometimes I/O to an encrypted file - * has to be broken up to guarantee DUN contiguity. Handle this by + * has to be broken up to guarantee DUN contiguity. Handle this by * limiting the length of the mapping returned. */ map.m_len = fscrypt_limit_io_blocks(inode, map.m_lblk, map.m_len);