Sweet Tea Dorminy <sweettea-kernel@xxxxxxxxxx> writes: > btrfs occasionally splits in-memory extents while holding a mutex. This > means we can't just copy the info, since setting up a new inlinecrypt > key requires taking a semaphore. Thus adding a mechanism to split > extents and merely take a new reference on the info is necessary. > > Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@xxxxxxxxxx> > --- > fs/crypto/fscrypt_private.h | 5 +++++ > fs/crypto/keysetup.c | 18 +++++++++++++++++- > include/linux/fscrypt.h | 2 ++ > 3 files changed, 24 insertions(+), 1 deletion(-) > > diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h > index cd29c71b4349..03be2c136c0e 100644 > --- a/fs/crypto/fscrypt_private.h > +++ b/fs/crypto/fscrypt_private.h > @@ -287,6 +287,11 @@ struct fscrypt_info { > > /* Hashed inode number. Only set for IV_INO_LBLK_32 */ > u32 ci_hashed_ino; > + > + /* Reference count. Normally 1, unless a extent info is shared by > + * several virtual extents. > + */ > + refcount_t refs; > }; > > typedef enum { > diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c > index 8d50716bdf11..12c3851b7cd6 100644 > --- a/fs/crypto/keysetup.c > +++ b/fs/crypto/keysetup.c > @@ -598,7 +598,7 @@ static void put_crypt_info(struct fscrypt_info *ci) > { > struct fscrypt_master_key *mk; > > - if (!ci) > + if (!ci || !refcount_dec_and_test(&ci->refs)) > return; > > if (ci->ci_enc_key) { > @@ -686,6 +686,7 @@ fscrypt_setup_encryption_info(struct inode *inode, > crypt_info->ci_inode = inode; > crypt_info->ci_sb = inode->i_sb; > crypt_info->ci_policy = *policy; > + refcount_set(&crypt_info->refs, 1); > memcpy(crypt_info->ci_nonce, nonce, FSCRYPT_FILE_NONCE_SIZE); > > mode = select_encryption_mode(&crypt_info->ci_policy, inode); > @@ -1046,6 +1047,21 @@ int fscrypt_load_extent_info(struct inode *inode, void *buf, size_t len, > } > EXPORT_SYMBOL_GPL(fscrypt_load_extent_info); > > +/** > + * fscrypt_get_extent_info_ref() - mark a second extent using the same info > + * @info: the info to be used by another extent > + * > + * Sometimes, an existing extent must be split into multiple extents in memory. > + * In such a case, this function allows multiple extents to use the same extent > + * info without allocating or taking any lock, which is necessary in certain IO > + * paths. > + */ > +void fscrypt_get_extent_info_ref(struct fscrypt_info *info) > +{ > + if (info) > + refcount_inc(&info->refs); > +} > + There's an EXPORT_SYMBOL_GPL() missing here, right? Cheers, -- Luís > > /** > * fscrypt_put_encryption_info() - free most of an inode's fscrypt data > * @inode: an inode being evicted > diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h > index 4ba624beea91..b67054a2c965 100644 > --- a/include/linux/fscrypt.h > +++ b/include/linux/fscrypt.h > @@ -370,6 +370,8 @@ void fscrypt_free_extent_info(struct fscrypt_info **info_ptr); > int fscrypt_load_extent_info(struct inode *inode, void *buf, size_t len, > struct fscrypt_info **info_ptr); > > +void fscrypt_get_extent_info_ref(struct fscrypt_info *info); > + > /* fname.c */ > int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, > u8 *out, unsigned int olen); > -- > > 2.41.0 >