diff --git a/drivers/platform/x86/intel_sgx.h b/drivers/platform/x86/intel_sgx.h
index fb5a75a..23cfd63 100644
--- a/drivers/platform/x86/intel_sgx.h
+++ b/drivers/platform/x86/intel_sgx.h
@@ -87,16 +87,6 @@ struct sgx_va_page {
 	struct list_head list;
 };
 
-static inline unsigned int sgx_alloc_va_slot(struct sgx_va_page *page)
-{
-	int slot = find_first_zero_bit(page->slots, SGX_VA_SLOT_COUNT);
-
-	if (slot < SGX_VA_SLOT_COUNT)
-		set_bit(slot, page->slots);
-
-	return slot << 3;
-}
-
 static inline void sgx_free_va_slot(struct sgx_va_page *page,
 				    unsigned int offset)
 {
@@ -136,6 +126,8 @@ enum sgx_encl_flags {
 struct sgx_encl {
 	unsigned int flags;
 	unsigned int secs_child_cnt;
+	unsigned int encl_page_cnt;
+	unsigned int va_page_cnt;
 	struct mutex lock;
 	struct task_struct *owner;
 	struct mm_struct *mm;
diff --git a/drivers/platform/x86/intel_sgx_ioctl.c b/drivers/platform/x86/intel_sgx_ioctl.c
index b78c552..a5849c6 100644
--- a/drivers/platform/x86/intel_sgx_ioctl.c
+++ b/drivers/platform/x86/intel_sgx_ioctl.c
@@ -385,65 +385,50 @@ static int sgx_validate_secs(const struct sgx_secs *secs)
 	return 0;
 }
 
-static int sgx_init_page(struct sgx_encl *encl,
-			 struct sgx_encl_page *entry,
-			 unsigned long addr)
+static int sgx_alloc_va_page(struct sgx_encl *encl)
 {
 	struct sgx_va_page *va_page;
 	struct sgx_epc_page *epc_page = NULL;
-	unsigned int va_offset = PAGE_SIZE;
 	void *vaddr;
 	int ret = 0;
 
-	list_for_each_entry(va_page, &encl->va_pages, list) {
-		va_offset = sgx_alloc_va_slot(va_page);
-		if (va_offset < PAGE_SIZE)
-			break;
-	}
-
-	if (va_offset == PAGE_SIZE) {
-		va_page = kzalloc(sizeof(*va_page), GFP_KERNEL);
-		if (!va_page)
-			return -ENOMEM;
-
-		epc_page = sgx_alloc_page(encl->tgid_ctx, 0);
-		if (IS_ERR(epc_page)) {
-			kfree(va_page);
-			return PTR_ERR(epc_page);
-		}
-
-		vaddr = sgx_get_epc_page(epc_page);
-		if (!vaddr) {
-			sgx_warn(encl, "kmap of a new VA page failed %d\n",
-				 ret);
-			sgx_free_page(epc_page, encl,
-					  SGX_FREE_SKIP_EREMOVE);
-			kfree(va_page);
-			return -EFAULT;
-		}
-
-		ret = __epa(vaddr);
-		sgx_put_epc_page(vaddr);
+	va_page = kzalloc(sizeof(*va_page), GFP_KERNEL);
+	if (!va_page)
+		return -ENOMEM;
 
-		if (ret) {
-			sgx_warn(encl, "EPA returned %d\n", ret);
-			sgx_free_page(epc_page, encl,
-					  SGX_FREE_SKIP_EREMOVE);
-			kfree(va_page);
-			return -EFAULT;
-		}
+	epc_page = sgx_alloc_page(encl->tgid_ctx, 0);
+	if (IS_ERR(epc_page)) {
+		kfree(va_page);
+		return PTR_ERR(epc_page);
+	}
+
+	vaddr = sgx_get_epc_page(epc_page);
+	if (!vaddr) {
+		sgx_warn(encl, "kmap of a new VA page failed %d\n",
+				ret);
+		sgx_free_page(epc_page, encl,
+					SGX_FREE_SKIP_EREMOVE);
+		kfree(va_page);
+		return -EFAULT;
+	}
 
-		va_page->epc_page = epc_page;
-		va_offset = sgx_alloc_va_slot(va_page);
+	ret = __epa(vaddr);
+	sgx_put_epc_page(vaddr);
 
-		mutex_lock(&encl->lock);
-		list_add(&va_page->list, &encl->va_pages);
-		mutex_unlock(&encl->lock);
+	if (ret) {
+		sgx_warn(encl, "EPA returned %d\n", ret);
+		sgx_free_page(epc_page, encl,
+					SGX_FREE_SKIP_EREMOVE);
+		kfree(va_page);
+		return -EFAULT;
 	}
 
-	entry->va_page = va_page;
-	entry->va_offset = va_offset;
-	entry->addr = addr;
+	va_page->epc_page = epc_page;
+
+	mutex_lock(&encl->lock);
+	encl->va_page_cnt++;
+	list_add(&va_page->list, &encl->va_pages);
+	mutex_unlock(&encl->lock);
 
 	return 0;
 }
@@ -537,8 +522,10 @@ static long sgx_ioc_enclave_create(struct file *filep, unsigned int cmd,
 	if (ret)
 		goto out;
 
-	ret = sgx_init_page(encl, &encl->secs_page,
-			    encl->base + encl->size);
+	encl->encl_page_cnt++;
+	encl->secs_page.addr = encl->base + encl->size;
+
+	ret = sgx_alloc_va_page(encl);
 	if (ret)
 		goto out;
 
@@ -677,14 +664,21 @@ static int __encl_add_page(struct sgx_encl *encl,
 		}
 	}
 
-	ret = sgx_init_page(encl, encl_page, addp->addr);
-	if (ret) {
-		__free_page(tmp_page);
-		return -EINVAL;
-	}
-
 	mutex_lock(&encl->lock);
 
+	encl_page->addr = addp->addr;
+	encl->encl_page_cnt++;
+
+	if (encl->encl_page_cnt > (encl->va_page_cnt * SGX_VA_SLOT_COUNT)) {
+		/* slow path, new VA page needed */
+		mutex_unlock(&encl->lock);
+		ret = sgx_alloc_va_page(encl);
+		mutex_lock(&encl->lock);
+		if (ret) {
+			goto out;
+		}
+	}
+
 	if (encl->flags & (SGX_ENCL_INITIALIZED | SGX_ENCL_DEAD)) {
 		ret = -EINVAL;
 		goto out;
@@ -739,8 +733,7 @@ static int __encl_add_page(struct sgx_encl *encl,
 
 	if (ret) {
 		kfree(req);
-		sgx_free_va_slot(encl_page->va_page,
-				 encl_page->va_offset);
+		encl->encl_page_cnt--;
 	}
 
 	mutex_unlock(&encl->lock);
diff --git a/drivers/platform/x86/intel_sgx_page_cache.c b/drivers/platform/x86/intel_sgx_page_cache.c
index 45964b4..e5965b3 100644
--- a/drivers/platform/x86/intel_sgx_page_cache.c
+++ b/drivers/platform/x86/intel_sgx_page_cache.c
@@ -232,6 +232,30 @@ static void sgx_etrack(struct sgx_epc_page *epc_page)
 	sgx_put_epc_page(epc);
 }
 
+/**
+ * sgx_alloc_va_slot() - allocate VA slot from a VA page
+ *
+ * @encl:        Enclave to allocate from
+ * @va_page:     Pointer to a VA page pointer
+ *
+ * Returns a free VA offset and sets va_page to the corresponding VA page.
+ * If there are no free slots, SGX_VA_SLOT_COUNT is returned.
+ */
+static inline unsigned int sgx_alloc_va_slot(struct sgx_encl *encl,
+					     struct sgx_va_page **va_page)
+{
+	unsigned int slot = SGX_VA_SLOT_COUNT;
+	list_for_each_entry((*va_page), &encl->va_pages, list) {
+		slot = find_first_zero_bit((*va_page)->slots, SGX_VA_SLOT_COUNT);
+		if (slot < SGX_VA_SLOT_COUNT) {
+			set_bit(slot, (*va_page)->slots);
+			break;
+		}
+	}
+
+	return (slot << 3);
+}
+
 static void sgx_free_encl_page(struct sgx_encl_page *encl_page,
 			       struct sgx_encl *encl,
 			       unsigned int flags)
@@ -245,9 +269,11 @@ static int __sgx_ewb(struct sgx_encl *encl,
 		     struct sgx_encl_page *encl_page)
 {
 	struct sgx_page_info pginfo;
+	struct sgx_va_page *va_page;
 	struct page *backing;
 	void *epc;
 	void *va;
+	unsigned int va_offset;
 	int ret;
 
 	backing = sgx_get_backing(encl, encl_page);
@@ -258,19 +284,33 @@ static int __sgx_ewb(struct sgx_encl *encl,
 		return ret;
 	}
 
+	va_offset = sgx_alloc_va_slot(encl, &va_page);
+	if (va_offset == PAGE_SIZE) {
+		sgx_put_backing(backing, true);
+		return -ENOMEM;
+	}
+
 	epc = sgx_get_epc_page(encl_page->epc_page);
-	va = sgx_get_epc_page(encl_page->va_page->epc_page);
+	va = sgx_get_epc_page(va_page->epc_page);
 
 	pginfo.srcpge = (unsigned long)kmap_atomic(backing);
 	pginfo.pcmd = (unsigned long)&encl_page->pcmd;
 	pginfo.linaddr = 0;
 	pginfo.secs = 0;
 	ret = __ewb(&pginfo, epc,
-		    (void *)((unsigned long)va + encl_page->va_offset));
+		    (void *)((unsigned long)va + va_offset));
 	kunmap_atomic((void *)(unsigned long)pginfo.srcpge);
 
 	sgx_put_epc_page(va);
 	sgx_put_epc_page(epc);
+
+	if (ret == SGX_SUCCESS) {
+		encl_page->va_page = va_page;
+		encl_page->va_offset = va_offset;
+	} else {
+		sgx_free_va_slot(va_page, va_offset);
+	}
+
 	sgx_put_backing(backing, true);
 
 	return ret;
diff --git a/drivers/platform/x86/intel_sgx_vma.c b/drivers/platform/x86/intel_sgx_vma.c
index db4cdcb..fd5536c 100644
--- a/drivers/platform/x86/intel_sgx_vma.c
+++ b/drivers/platform/x86/intel_sgx_vma.c
@@ -149,6 +149,10 @@ static int do_eldu(struct sgx_encl *encl,
 	if (ret)
 		return -EFAULT;
 
+	sgx_free_va_slot(encl_page->va_page, encl_page->va_offset);
+
+	encl_page->epc_page = epc_page;
+
 	return 0;
 }
 
@@ -229,8 +233,6 @@ static struct sgx_encl_page *sgx_vma_do_fault(struct vm_area_struct *vma,
 		if (rc)
 			goto out;
 
-		encl->secs_page.epc_page = secs_epc_page;
-
 		/* Do not free */
 		secs_epc_page = NULL;
 	}
@@ -256,8 +258,6 @@ static struct sgx_encl_page *sgx_vma_do_fault(struct vm_area_struct *vma,
 
 	encl->secs_child_cnt++;
 
-	entry->epc_page = epc_page;
-
 	if (reserve)
 		entry->flags |= SGX_ENCL_PAGE_RESERVED;
 
