From 4b166ca901dedd928cf61949b4268b490a06a564 Mon Sep 17 00:00:00 2001
From: Thirunarayanan Balathandayuthapani <thiru@mariadb.com>
Date: Thu, 25 Feb 2021 20:51:30 +0530
Subject: [PATCH] MDEV-24863 AHI entries mismatch with the index while
 reloading the evicted tables.

This is after-merge fix of f33e57a9e66f7e1790cb84b141381bb668e281a0.
In btr_search_drop_page_hash_index(), InnoDB should take
the exclusive lock on the AHI latch if index is already
freed to avoid the freed memory access during buf_pool_resize()
---
 storage/innobase/btr/btr0sea.cc | 35 +++++++++++++++++++++++----------
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index 5c8f97b7bcf..b00009820a8 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -1279,13 +1279,24 @@ retry:
 	auto part = btr_search_sys.get_part(index_id,
 					    block->page.id().space());
 
-	rw_lock_s_lock(&part->latch);
+	dict_index_t* index = block->index;
+	bool is_freed = index && index->freed();
+
+	if (is_freed) {
+		rw_lock_x_lock(&part->latch);
+	} else {
+		rw_lock_s_lock(&part->latch);
+	}
+
 	assert_block_ahi_valid(block);
 
-	dict_index_t* index = block->index;
 
 	if (!index || !btr_search_enabled) {
-		rw_lock_s_unlock(&part->latch);
+		if (is_freed) {
+			rw_lock_x_unlock(&part->latch);
+		} else {
+			rw_lock_s_unlock(&part->latch);
+		}
 		return;
 	}
 
@@ -1304,7 +1315,9 @@ retry:
 	/* NOTE: The AHI fields of block must not be accessed after
 	releasing search latch, as the index page might only be s-latched! */
 
-	rw_lock_s_unlock(&part->latch);
+	if (!is_freed) {
+		rw_lock_s_unlock(&part->latch);
+	}
 
 	ut_a(n_fields > 0 || n_bytes > 0);
 
@@ -1355,16 +1368,18 @@ next_rec:
 		mem_heap_free(heap);
 	}
 
-	rw_lock_x_lock(&part->latch);
+	if (!is_freed) {
+		rw_lock_x_lock(&part->latch);
 
-	if (UNIV_UNLIKELY(!block->index)) {
-		/* Someone else has meanwhile dropped the hash index */
+		if (UNIV_UNLIKELY(!block->index)) {
+			/* Someone else has meanwhile dropped the
+			hash index */
+			goto cleanup;
+		}
 
-		goto cleanup;
+		ut_a(block->index == index);
 	}
 
-	ut_a(block->index == index);
-
 	if (block->curr_n_fields != n_fields
 	    || block->curr_n_bytes != n_bytes) {