@@ -307,6 +307,11 @@ struct fscrypt_info {
*/
struct fscrypt_extent_info {
struct fscrypt_common_info info;
+
+ /* Reference count. Normally 1, unless a extent info is shared by
+ * several virtual extents.
+ */
+ refcount_t refs;
};
typedef enum {
@@ -919,6 +919,21 @@ int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
}
EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode);
+/**
+ * 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_extent_info *info)
+{
+ if (info)
+ refcount_inc(&info->refs);
+}
+
/**
* fscrypt_put_encryption_info() - free most of an inode's fscrypt data
* @inode: an inode being evicted
@@ -997,7 +1012,7 @@ EXPORT_SYMBOL_GPL(fscrypt_drop_inode);
static void put_crypt_extent_info(struct fscrypt_extent_info *ci)
{
- if (!ci)
+ if (!ci || !refcount_dec_and_test(&ci->refs))
return;
free_prepared_key(&ci->info);
@@ -1042,6 +1057,8 @@ fscrypt_setup_extent_info(struct inode *inode,
if (res)
goto out;
+ refcount_set(&crypt_extent_info->refs, 1);
+
*info_ptr = crypt_extent_info;
add_info_to_mk_decrypted_list(crypt_info, mk);
@@ -362,7 +362,7 @@ int fscrypt_prepare_new_extent(struct inode *inode,
void fscrypt_free_extent_info(struct fscrypt_extent_info **info_ptr);
int fscrypt_load_extent_info(struct inode *inode, void *buf, size_t len,
struct fscrypt_extent_info **info_ptr);
-
+void fscrypt_get_extent_info_ref(struct fscrypt_extent_info *info);
/* fname.c */
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
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@dorminy.me> --- fs/crypto/fscrypt_private.h | 5 +++++ fs/crypto/keysetup.c | 19 ++++++++++++++++++- include/linux/fscrypt.h | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-)