diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 1a7a64e0777c3a0fb683ef80ed0b8b977ea1edfc..6747abe8bc08d3e439d54d14e1f89035786d27b0 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -184,7 +184,12 @@ struct vmalloc_info {
 };
 
 #ifdef CONFIG_MMU
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+extern unsigned long total_vmalloc_size;
+#define VMALLOC_TOTAL total_vmalloc_size
+#else
 #define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START)
+#endif
 extern void get_vmalloc_info(struct vmalloc_info *vmi);
 #else
 
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 0cc9adda252952d215f164df6891727c28214bb3..a123d58b70391d808c901270256397aceb07a913 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -290,6 +290,9 @@ static unsigned long vmap_area_pcpu_hole;
 #define VMALLOC_TO_BIT(addr)	((addr - PAGE_OFFSET) >> PAGE_SHIFT)
 #define BIT_TO_VMALLOC(i)	(PAGE_OFFSET + i * PAGE_SIZE)
 
+unsigned long total_vmalloc_size;
+unsigned long vmalloc_reserved;
+
 DECLARE_BITMAP(possible_areas, VMALLOC_BITMAP_SIZE);
 
 void mark_vmalloc_reserved_area(void *x, unsigned long size)
@@ -297,6 +300,7 @@ void mark_vmalloc_reserved_area(void *x, unsigned long size)
 	unsigned long addr = (unsigned long)x;
 
 	bitmap_set(possible_areas, VMALLOC_TO_BIT(addr), size >> PAGE_SHIFT);
+	vmalloc_reserved += size;
 }
 
 int is_vmalloc_addr(const void *x)
@@ -311,6 +315,12 @@ int is_vmalloc_addr(const void *x)
 
 	return 1;
 }
+
+static void calc_total_vmalloc_size(void)
+{
+	total_vmalloc_size = VMALLOC_END - POSSIBLE_VMALLOC_START -
+		vmalloc_reserved;
+}
 #else
 int is_vmalloc_addr(const void *x)
 {
@@ -318,6 +328,8 @@ int is_vmalloc_addr(const void *x)
 
 	return addr >= VMALLOC_START && addr < VMALLOC_END;
 }
+
+static void calc_total_vmalloc_size(void) { }
 #endif
 EXPORT_SYMBOL(is_vmalloc_addr);
 
@@ -1285,6 +1297,7 @@ void __init vmalloc_init(void)
 
 	vmap_area_pcpu_hole = VMALLOC_END;
 
+	calc_total_vmalloc_size();
 	vmap_initialized = true;
 }