x86/sgx: Free up EPC pages directly to support large page ranges
authorReinette Chatre <reinette.chatre@intel.com>
Tue, 10 May 2022 18:08:56 +0000 (11:08 -0700)
committerDave Hansen <dave.hansen@linux.intel.com>
Thu, 7 Jul 2022 17:13:03 +0000 (10:13 -0700)
The page reclaimer ensures availability of EPC pages across all
enclaves. In support of this it runs independently from the
individual enclaves in order to take locks from the different
enclaves as it writes pages to swap.

When needing to load a page from swap an EPC page needs to be
available for its contents to be loaded into. Loading an existing
enclave page from swap does not reclaim EPC pages directly if
none are available, instead the reclaimer is woken when the
available EPC pages are found to be below a watermark.

When iterating over a large number of pages in an oversubscribed
environment there is a race between the reclaimer woken up and
EPC pages reclaimed fast enough for the page operations to proceed.

Ensure there are EPC pages available before attempting to load
a page that may potentially be pulled from swap into an available
EPC page.

Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Acked-by: Jarkko Sakkinen <jarkko@kernel.org>
Link: https://lkml.kernel.org/r/a0d8f037c4a075d56bf79f432438412985f7ff7a.1652137848.git.reinette.chatre@intel.com
arch/x86/kernel/cpu/sgx/ioctl.c
arch/x86/kernel/cpu/sgx/main.c
arch/x86/kernel/cpu/sgx/sgx.h

index 1a2595f261d3ee15624a9b8cc4cc4d0e23b6f930..ebe79d60619f2f161c7a564aed3144572201b5ea 100644 (file)
@@ -745,6 +745,8 @@ sgx_enclave_restrict_permissions(struct sgx_encl *encl,
        for (c = 0 ; c < modp->length; c += PAGE_SIZE) {
                addr = encl->base + modp->offset + c;
 
+               sgx_reclaim_direct();
+
                mutex_lock(&encl->lock);
 
                entry = sgx_encl_load_page(encl, addr);
@@ -910,6 +912,8 @@ static long sgx_enclave_modify_types(struct sgx_encl *encl,
        for (c = 0 ; c < modt->length; c += PAGE_SIZE) {
                addr = encl->base + modt->offset + c;
 
+               sgx_reclaim_direct();
+
                mutex_lock(&encl->lock);
 
                entry = sgx_encl_load_page(encl, addr);
@@ -1096,6 +1100,8 @@ static long sgx_encl_remove_pages(struct sgx_encl *encl,
        for (c = 0 ; c < params->length; c += PAGE_SIZE) {
                addr = encl->base + params->offset + c;
 
+               sgx_reclaim_direct();
+
                mutex_lock(&encl->lock);
 
                entry = sgx_encl_load_page(encl, addr);
index 180ad840b2266fea541d05beb2852f6b2f159b88..5acd4c54d904c13ae18caa41c8d71cb73af1ab77 100644 (file)
@@ -375,6 +375,17 @@ static bool sgx_should_reclaim(unsigned long watermark)
               !list_empty(&sgx_active_page_list);
 }
 
+/*
+ * sgx_reclaim_direct() should be called (without enclave's mutex held)
+ * in locations where SGX memory resources might be low and might be
+ * needed in order to make forward progress.
+ */
+void sgx_reclaim_direct(void)
+{
+       if (sgx_should_reclaim(SGX_NR_LOW_PAGES))
+               sgx_reclaim_pages();
+}
+
 static int ksgxd(void *p)
 {
        set_freezable();
index b30cee4de90302b2f9dcec65cf9413b8d8106a33..0f2020653fba05544f1477ba5871c18a991e924e 100644 (file)
@@ -86,6 +86,7 @@ static inline void *sgx_get_epc_virt_addr(struct sgx_epc_page *page)
 struct sgx_epc_page *__sgx_alloc_epc_page(void);
 void sgx_free_epc_page(struct sgx_epc_page *page);
 
+void sgx_reclaim_direct(void);
 void sgx_mark_page_reclaimable(struct sgx_epc_page *page);
 int sgx_unmark_page_reclaimable(struct sgx_epc_page *page);
 struct sgx_epc_page *sgx_alloc_epc_page(void *owner, bool reclaim);