diff --git a/arch/s390/include/asm/kasan.h b/arch/s390/include/asm/kasan.h
index 892f4585c663f7fc5462db0a12358932aa79d118..8b9ae18430ad18928183c990b511c9ce880bf52d 100644
--- a/arch/s390/include/asm/kasan.h
+++ b/arch/s390/include/asm/kasan.h
@@ -15,9 +15,11 @@
 
 extern void kasan_early_init(void);
 extern void kasan_copy_shadow(pgd_t *dst);
+extern void kasan_free_early_identity(void);
 #else
 static inline void kasan_early_init(void) { }
 static inline void kasan_copy_shadow(pgd_t *dst) { }
+static inline void kasan_free_early_identity(void) { }
 #endif
 
 #endif
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 50ebda9b3d0caf98657f4a95bfdc17767682eac3..92d7a153e72a0fe8bad784552d7a142a9d03ba69 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -109,6 +109,7 @@ void __init paging_init(void)
 	psw_bits(psw).dat = 1;
 	psw_bits(psw).as = PSW_BITS_AS_HOME;
 	__load_psw_mask(psw.mask);
+	kasan_free_early_identity();
 
 	sparse_memory_present_with_active_regions(MAX_NUMNODES);
 	sparse_init();
diff --git a/arch/s390/mm/kasan_init.c b/arch/s390/mm/kasan_init.c
index e4697900e884da1317e0af497b8037418fdba647..40748afc43fa5e234915676496667563151d8bee 100644
--- a/arch/s390/mm/kasan_init.c
+++ b/arch/s390/mm/kasan_init.c
@@ -15,6 +15,7 @@ static unsigned long segment_pos __initdata;
 static unsigned long segment_low __initdata;
 static unsigned long pgalloc_pos __initdata;
 static unsigned long pgalloc_low __initdata;
+static unsigned long pgalloc_freeable __initdata;
 static bool has_edat __initdata;
 static bool has_nx __initdata;
 
@@ -298,14 +299,16 @@ void __init kasan_early_init(void)
 	 * | 2Gb	     |	\|	unmapped  | allocated per module
 	 * +-----------------+	 +- shadow end ---+
 	 */
-	/* populate identity mapping */
-	kasan_early_vmemmap_populate(0, memsize, POPULATE_ONE2ONE);
 	/* populate kasan shadow (for identity mapping and zero page mapping) */
 	kasan_early_vmemmap_populate(__sha(0), __sha(memsize), POPULATE_MAP);
 	if (IS_ENABLED(CONFIG_MODULES))
 		untracked_mem_end = vmax - MODULES_LEN;
 	kasan_early_vmemmap_populate(__sha(memsize), __sha(untracked_mem_end),
 				     POPULATE_ZERO_SHADOW);
+	/* memory allocated for identity mapping structs will be freed later */
+	pgalloc_freeable = pgalloc_pos;
+	/* populate identity mapping */
+	kasan_early_vmemmap_populate(0, memsize, POPULATE_ONE2ONE);
 	kasan_set_pgd(early_pg_dir, asce_type);
 	kasan_enable_dat();
 	/* enable kasan */
@@ -345,3 +348,8 @@ void __init kasan_copy_shadow(pgd_t *pg_dir)
 	memcpy(pu_dir_dst, pu_dir_src,
 	       (KASAN_SHADOW_SIZE >> PUD_SHIFT) * sizeof(pud_t));
 }
+
+void __init kasan_free_early_identity(void)
+{
+	memblock_free(pgalloc_pos, pgalloc_freeable - pgalloc_pos);
+}