diff mbox series

[RFC,04/17] fscrypt: factor out fscrypt_set_inode_info()

Message ID fba20d354834b5b9f20c284b577381e5147692a0.1672547582.git.sweettea-kernel@dorminy.me (mailing list archive)
State New, archived
Headers show
Series fscrypt: add per-extent encryption keys | expand

Commit Message

Sweet Tea Dorminy Jan. 1, 2023, 5:06 a.m. UTC
As this function needs to be called in several different places to
short-circuit creating a new fscrypt_info for extent-based encryption,
it makes sense to pull it into its own function for easy calling.

Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
 fs/crypto/keysetup.c | 60 +++++++++++++++++++++++++++-----------------
 1 file changed, 37 insertions(+), 23 deletions(-)
diff mbox series

Patch

diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index 87f28d666602..4d7ff8244c55 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -515,6 +515,38 @@  static void put_crypt_info(struct fscrypt_info *ci)
 	kmem_cache_free(fscrypt_info_cachep, ci);
 }
 
+static bool fscrypt_set_inode_info(struct inode *inode,
+				   struct fscrypt_info *ci,
+				   struct fscrypt_master_key *mk)
+{
+	if (ci == NULL) {
+		inode->i_crypt_info = NULL;
+		return true;
+	}
+
+	/*
+	 * For existing inodes, multiple tasks may race to set ->i_crypt_info.
+	 * So use cmpxchg_release().  This pairs with the smp_load_acquire() in
+	 * fscrypt_get_info().  I.e., here we publish ->i_crypt_info with a
+	 * RELEASE barrier so that other tasks can ACQUIRE it.
+	 */
+	if (cmpxchg_release(&inode->i_crypt_info, NULL, ci) != NULL)
+		return false;
+
+	/*
+	 * We won the race and set ->i_crypt_info to our crypt_info.
+	 * Now link it into the master key's inode list.
+	 */
+	if (mk) {
+		ci->ci_master_key = mk;
+		refcount_inc(&mk->mk_active_refs);
+		spin_lock(&mk->mk_decrypted_inodes_lock);
+		list_add(&ci->ci_master_key_link, &mk->mk_decrypted_inodes);
+		spin_unlock(&mk->mk_decrypted_inodes_lock);
+	}
+	return true;
+}
+
 static int
 fscrypt_setup_encryption_info(struct inode *inode,
 			      const union fscrypt_policy *policy,
@@ -525,6 +557,7 @@  fscrypt_setup_encryption_info(struct inode *inode,
 	struct fscrypt_mode *mode;
 	struct fscrypt_master_key *mk = NULL;
 	int res;
+	bool set_succeeded;
 
 	res = fscrypt_initialize(inode->i_sb->s_cop->flags);
 	if (res)
@@ -550,34 +583,15 @@  fscrypt_setup_encryption_info(struct inode *inode,
 	if (res)
 		goto out;
 
-	/*
-	 * For existing inodes, multiple tasks may race to set ->i_crypt_info.
-	 * So use cmpxchg_release().  This pairs with the smp_load_acquire() in
-	 * fscrypt_get_info().  I.e., here we publish ->i_crypt_info with a
-	 * RELEASE barrier so that other tasks can ACQUIRE it.
-	 */
-	if (cmpxchg_release(&inode->i_crypt_info, NULL, crypt_info) == NULL) {
-		/*
-		 * We won the race and set ->i_crypt_info to our crypt_info.
-		 * Now link it into the master key's inode list.
-		 */
-		if (mk) {
-			crypt_info->ci_master_key = mk;
-			refcount_inc(&mk->mk_active_refs);
-			spin_lock(&mk->mk_decrypted_inodes_lock);
-			list_add(&crypt_info->ci_master_key_link,
-				 &mk->mk_decrypted_inodes);
-			spin_unlock(&mk->mk_decrypted_inodes_lock);
-		}
-		crypt_info = NULL;
-	}
+	set_succeeded = fscrypt_set_inode_info(inode, crypt_info, mk);
 	res = 0;
 out:
 	if (mk) {
 		up_read(&mk->mk_sem);
 		fscrypt_put_master_key(mk);
 	}
-	put_crypt_info(crypt_info);
+	if (!set_succeeded)
+		put_crypt_info(crypt_info);
 	return res;
 }
 
@@ -707,7 +721,7 @@  EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode);
 void fscrypt_put_encryption_info(struct inode *inode)
 {
 	put_crypt_info(fscrypt_get_inode_info(inode));
-	inode->i_crypt_info = NULL;
+	fscrypt_set_inode_info(inode, NULL, NULL);
 }
 EXPORT_SYMBOL(fscrypt_put_encryption_info);