diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index edbc2d6962be..ec146270d94b 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -17,6 +17,7 @@
 
 #include <linux/rculist.h>
 #include <linux/slab.h>
+#include <linux/async.h>
 #include "ima.h"
 
 #define AUDIT_CAUSE_LEN_MAX 32
@@ -44,6 +45,21 @@ struct ima_h_table ima_htable = {
  */
 static DEFINE_MUTEX(ima_extend_list_mutex);
 
+/* list for pcr extned asynchronous */
+static LIST_HEAD(ima_pcr_extend_list);
+
+struct ima_pcr_extend_async_ctx {
+	struct list_head list;
+	struct ima_template_entry *entry;
+	int violation;
+	const char *op;
+	struct inode *inode;
+	const unsigned char *filename;
+	const char *audit_cause;
+	int audit_info;
+	int result;
+};
+
 /* lookup up the digest value in the hash table, and return the entry */
 static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
 						       int pcr)
@@ -150,6 +166,48 @@ static int ima_pcr_extend(const u8 *hash, int pcr)
 	return result;
 }
 
+static void ima_pcr_extend_async(void *data, async_cookie_t cookie)
+{
+	struct ima_pcr_extend_async_ctx *ctx;
+	u8 digest[TPM_DIGEST_SIZE];
+	char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX];
+	int empty;
+	int result;
+
+retry:
+	mutex_lock(&ima_extend_list_mutex);
+	empty = list_empty(&ima_pcr_extend_list);
+	if (!empty) {
+		ctx = list_first_entry(&ima_pcr_extend_list,
+				struct ima_pcr_extend_async_ctx, list);
+		list_del(&ctx->list);
+	}
+	mutex_unlock(&ima_extend_list_mutex);
+
+	/* no more pending pcr_extend, return */
+	if (empty)
+		return;
+
+	if (ctx->violation)		/* invalidate pcr */
+		memset(digest, 0xff, sizeof(digest));
+	else
+		memcpy(digest, ctx->entry->digest, sizeof(digest));
+
+	result = ima_pcr_extend(digest, ctx->entry->pcr);
+	if (result != 0) {
+		snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
+			 result);
+		ctx->audit_cause = tpm_audit_cause;
+		ctx->audit_info = 0;
+	}
+	integrity_audit_msg(AUDIT_INTEGRITY_PCR, ctx->inode, ctx->filename,
+			    ctx->op, ctx->audit_cause,
+			    ctx->result, ctx->audit_info);
+
+	kfree(ctx);
+	goto retry;
+}
+
 /*
  * Add template entry to the measurement list and hash table, and
  * extend the pcr.
@@ -162,20 +220,16 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 			   const char *op, struct inode *inode,
 			   const unsigned char *filename)
 {
-	u8 digest[TPM_DIGEST_SIZE];
 	const char *audit_cause = "hash_added";
-	char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX];
 	int audit_info = 1;
-	int result = 0, tpmresult = 0;
+	int result = 0;
+	struct ima_pcr_extend_async_ctx *ctx;
 
 	mutex_lock(&ima_extend_list_mutex);
-	if (!violation) {
-		memcpy(digest, entry->digest, sizeof(digest));
-		if (ima_lookup_digest_entry(digest, entry->pcr)) {
-			audit_cause = "hash_exists";
-			result = -EEXIST;
-			goto out;
-		}
+	if (!violation && ima_lookup_digest_entry(entry->digest, entry->pcr)) {
+		audit_cause = "hash_exists";
+		result = -EEXIST;
+		goto out;
 	}
 
 	result = ima_add_digest_entry(entry, 1);
@@ -185,20 +239,26 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 		goto out;
 	}
 
-	if (violation)		/* invalidate pcr */
-		memset(digest, 0xff, sizeof(digest));
-
-	tpmresult = ima_pcr_extend(digest, entry->pcr);
-	if (tpmresult != 0) {
-		snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
-			 tpmresult);
-		audit_cause = tpm_audit_cause;
-		audit_info = 0;
+	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		audit_cause = "ENOMEM";
+		result = -ENOMEM;
+		goto out;
 	}
+
+	ctx->entry = entry;
+	ctx->violation = violation;
+	ctx->op = op;
+	ctx->inode = inode;
+	ctx->filename = filename;
+	ctx->audit_cause = audit_cause;
+	ctx->audit_info = audit_info;
+	ctx->result = result;
+	list_add_tail(&ctx->list, &ima_pcr_extend_list);
+	async_schedule(ima_pcr_extend_async, NULL);
+
 out:
 	mutex_unlock(&ima_extend_list_mutex);
-	integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
-			    op, audit_cause, result, audit_info);
 	return result;
 }
 
