Message ID | 20211011185924.374213-2-tony.luck@intel.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Basic recovery for machine checks inside SGX | expand |
On Mon, Oct 11, 2021, Tony Luck wrote: > SGX EPC pages go through the following life cycle: > > DIRTY ---> FREE ---> IN-USE --\ > ^ | > \-----------------/ > > Recovery action for poison for a DIRTY or FREE page is simple. Just > make sure never to allocate the page. IN-USE pages need some extra > handling. > > Add a new flag bit SGX_EPC_PAGE_IN_USE that is set when a page > is allocated and cleared when the page is freed. > > Notes: > > 1) These transitions are made while holding the node->lock so that > future code that checks the flags while holding the node->lock > can be sure that if the SGX_EPC_PAGE_IN_USE bit is set, then the > page is on the free list. > > 2) Initially while the pages are on the dirty list the > SGX_EPC_PAGE_IN_USE bit is set. This needs to state _why_ pages are marked as IN_USE from the get-go. Ignoring the "Notes", the whole changelog clearly states the the DIRTY state does _not_ require special handling, but then "Add SGX infrastructure to recover from poison" goes and relies on it being set. Alternatively, why not invert it and have SGX_EPC_PAGE_FREE? That would have clear semantics, the poison recovery code wouldn't have to assume that !flags means "free", and the whole changelog becomes: Add a flag to explicitly track whether or not an EPC page is on a free list, memory failure recovery code needs to be able to detect if a poisoned page is free so that recovery can know if it's safe to "steal" the page.
diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c index 63d3de02bbcc..d18988a46c13 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -472,6 +472,7 @@ static struct sgx_epc_page *__sgx_alloc_epc_page_from_node(int nid) page = list_first_entry(&node->free_page_list, struct sgx_epc_page, list); list_del_init(&page->list); sgx_nr_free_pages--; + page->flags = SGX_EPC_PAGE_IN_USE; spin_unlock(&node->lock); @@ -626,6 +627,7 @@ void sgx_free_epc_page(struct sgx_epc_page *page) list_add_tail(&page->list, &node->free_page_list); sgx_nr_free_pages++; + page->flags = 0; spin_unlock(&node->lock); } @@ -651,7 +653,7 @@ static bool __init sgx_setup_epc_section(u64 phys_addr, u64 size, for (i = 0; i < nr_pages; i++) { section->pages[i].section = index; - section->pages[i].flags = 0; + section->pages[i].flags = SGX_EPC_PAGE_IN_USE; section->pages[i].owner = NULL; list_add_tail(§ion->pages[i].list, &sgx_dirty_page_list); } diff --git a/arch/x86/kernel/cpu/sgx/sgx.h b/arch/x86/kernel/cpu/sgx/sgx.h index 4628acec0009..f9202d3d6278 100644 --- a/arch/x86/kernel/cpu/sgx/sgx.h +++ b/arch/x86/kernel/cpu/sgx/sgx.h @@ -26,6 +26,9 @@ /* Pages, which are being tracked by the page reclaimer. */ #define SGX_EPC_PAGE_RECLAIMER_TRACKED BIT(0) +/* Allocated pages */ +#define SGX_EPC_PAGE_IN_USE BIT(1) + struct sgx_epc_page { unsigned int section; unsigned int flags;