From: Jarkko Sakkinen <jarkko@kernel.org>
To: Dave Hansen <dave.hansen@intel.com>
Cc: linux-sgx@vger.kernel.org,
Dave Hansen <dave.hansen@linux.intel.com>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 3/5] x86/sgx: Replace section->init_laundry_list with a temp list
Date: Wed, 10 Mar 2021 16:50:32 +0200 [thread overview]
Message-ID: <YEjcuFRHqgF/nMg3@kernel.org> (raw)
In-Reply-To: <5f0c773f-4da1-7418-be42-e11427c2f137@intel.com>
On Wed, Mar 03, 2021 at 10:02:27AM -0800, Dave Hansen wrote:
> ...
> > -static void sgx_sanitize_section(struct sgx_epc_section *section)
> > +static void sgx_sanitize_section(struct list_head *laundry)
> > {
>
> Does this need a better function name now that it's not literally
> dealing with sections at *all*?
>
> sgx_sanitize_pages()
>
> perhaps.
Makes sense to me.
> > struct sgx_epc_page *page;
> > LIST_HEAD(dirty);
> > int ret;
> >
> > /* init_laundry_list is thread-local, no need for a lock: */
> > - while (!list_empty(§ion->init_laundry_list)) {
> > + while (!list_empty(laundry)) {
> > if (kthread_should_stop())
> > return;
> >
> > - /* needed for access to ->page_list: */
> > - spin_lock(§ion->lock);
> > -
> > - page = list_first_entry(§ion->init_laundry_list,
> > - struct sgx_epc_page, list);
> > + page = list_first_entry(laundry, struct sgx_epc_page, list);
> >
> > ret = __eremove(sgx_get_epc_virt_addr(page));
> > - if (!ret)
> > - list_move(&page->list, §ion->page_list);
> > - else
> > + if (!ret) {
> > + /* The page is clean - move to the free list. */
> > + list_del(&page->list);
> > + sgx_free_epc_page(page);
> > + } else {
> > + /* The page is not yet clean - move to the dirty list. */
> > list_move_tail(&page->list, &dirty);
> > -
> > - spin_unlock(§ion->lock);
> > + }
> >
> > cond_resched();
> > }
> >
> > - list_splice(&dirty, §ion->init_laundry_list);
> > + list_splice(&dirty, laundry);
> > }
> >
> > static bool sgx_reclaimer_age(struct sgx_epc_page *epc_page)
> > @@ -400,6 +398,7 @@ static bool sgx_should_reclaim(unsigned long watermark)
> >
> > static int ksgxd(void *p)
> > {
> > + struct list_head *laundry = p;
> > int i;
> >
> > set_freezable();
> > @@ -408,16 +407,13 @@ static int ksgxd(void *p)
> > * Sanitize pages in order to recover from kexec(). The 2nd pass is
> > * required for SECS pages, whose child pages blocked EREMOVE.
> > */
> > - for (i = 0; i < sgx_nr_epc_sections; i++)
> > - sgx_sanitize_section(&sgx_epc_sections[i]);
> > + sgx_sanitize_section(laundry);
> > + sgx_sanitize_section(laundry);
>
> Did you intend to call this twice?
Yes, see the inline comment above.
> > - for (i = 0; i < sgx_nr_epc_sections; i++) {
> > - sgx_sanitize_section(&sgx_epc_sections[i]);
> > + if (!list_empty(laundry))
> > + WARN(1, "EPC section %d has unsanitized pages.\n", i);
> >
> > - /* Should never happen. */
> > - if (!list_empty(&sgx_epc_sections[i].init_laundry_list))
> > - WARN(1, "EPC section %d has unsanitized pages.\n", i);
> > - }
> > + kfree(laundry);
>
> This is a bit unfortunate. 'laundry' is allocated up in another thread
> and the lifetime isn't obvious. It's just 32 bytes, but this is just
> asking to be leaked.
> > while (!kthread_should_stop()) {
> > if (try_to_freeze())
> > @@ -436,11 +432,11 @@ static int ksgxd(void *p)
> > return 0;
> > }
> >
> > -static bool __init sgx_page_reclaimer_init(void)
> > +static bool __init sgx_page_reclaimer_init(struct list_head *laundry)
> > {
> > struct task_struct *tsk;
> >
> > - tsk = kthread_run(ksgxd, NULL, "ksgxd");
> > + tsk = kthread_run(ksgxd, laundry, "ksgxd");
> > if (IS_ERR(tsk))
> > return false;
> >
> > @@ -614,7 +610,8 @@ void sgx_free_epc_page(struct sgx_epc_page *page)
> >
> > static bool __init sgx_setup_epc_section(u64 phys_addr, u64 size,
> > unsigned long index,
> > - struct sgx_epc_section *section)
> > + struct sgx_epc_section *section,
> > + struct list_head *laundry)
> > {
>
> I think this at least need a comment somewhere about what this function
> is doing with 'laundry'.
Ok.
> > unsigned long nr_pages = size >> PAGE_SHIFT;
> > unsigned long i;
> > @@ -632,13 +629,12 @@ static bool __init sgx_setup_epc_section(u64 phys_addr, u64 size,
> > section->phys_addr = phys_addr;
> > spin_lock_init(§ion->lock);
> > INIT_LIST_HEAD(§ion->page_list);
> > - INIT_LIST_HEAD(§ion->init_laundry_list);
> >
> > for (i = 0; i < nr_pages; i++) {
> > section->pages[i].section = index;
> > section->pages[i].flags = 0;
> > section->pages[i].owner = NULL;
> > - list_add_tail(§ion->pages[i].list, §ion->init_laundry_list);
> > + list_add_tail(§ion->pages[i].list, laundry);
> > }
> >
> > section->free_cnt = nr_pages;
> > @@ -656,7 +652,7 @@ static inline u64 __init sgx_calc_section_metric(u64 low, u64 high)
> > ((high & GENMASK_ULL(19, 0)) << 32);
> > }
> >
> > -static bool __init sgx_page_cache_init(void)
> > +static bool __init sgx_page_cache_init(struct list_head *laundry)
> > {
> > u32 eax, ebx, ecx, edx, type;
> > u64 pa, size;
> > @@ -679,7 +675,7 @@ static bool __init sgx_page_cache_init(void)
> >
> > pr_info("EPC section 0x%llx-0x%llx\n", pa, pa + size - 1);
> >
> > - if (!sgx_setup_epc_section(pa, size, i, &sgx_epc_sections[i])) {
> > + if (!sgx_setup_epc_section(pa, size, i, &sgx_epc_sections[i], laundry)) {
> > pr_err("No free memory for an EPC section\n");
> > break;
> > }
>
> This is a great place for a comment about what is coming back on 'laundry'.
>
> > @@ -697,18 +693,25 @@ static bool __init sgx_page_cache_init(void)
> >
> > static int __init sgx_init(void)
> > {
> > + struct list_head *laundry;
> > int ret;
> > int i;
> >
> > if (!cpu_feature_enabled(X86_FEATURE_SGX))
> > return -ENODEV;
> >
> > - if (!sgx_page_cache_init()) {
> > + laundry = kzalloc(sizeof(*laundry), GFP_KERNEL);
> > + if (!laundry)
> > + return -ENOMEM;
> > +
> > + INIT_LIST_HEAD(laundry);
> > +
> > + if (!sgx_page_cache_init(laundry)) {
> > ret = -ENOMEM;
> > goto err_page_cache;
> > }
> >
> > - if (!sgx_page_reclaimer_init()) {
> > + if (!sgx_page_reclaimer_init(laundry)) {
> > ret = -ENOMEM;
> > goto err_page_cache;
> > }
>
> I really don't like this being dynamically allocated, especially since
> it's freed in another task in a non-obvious place.
>
> Wouldn't this all just be a lot simpler if we had a global list_head?
> That will eat a whopping 16 bytes of space.
Yeah, why not. It's just then one global instead of per-struct field, which
is quite ugly.
/Jarkko
next prev parent reply other threads:[~2021-03-10 14:51 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-03-03 15:03 [PATCH v3 0/5] x86/sgx: NUMA Jarkko Sakkinen
2021-03-03 15:03 ` [PATCH v3 1/5] x86/sgx: Fix a resource leak in sgx_init() Jarkko Sakkinen
2021-03-03 16:56 ` Dave Hansen
2021-03-10 15:00 ` Jarkko Sakkinen
2021-03-10 15:49 ` Sean Christopherson
2021-03-10 21:52 ` Jarkko Sakkinen
2021-03-03 15:03 ` [PATCH v3 2/5] x86/sgx: Use sgx_free_epc_page() in sgx_reclaim_pages() Jarkko Sakkinen
2021-03-03 16:59 ` Dave Hansen
2021-03-10 15:11 ` Jarkko Sakkinen
2021-03-10 15:55 ` Dave Hansen
2021-03-10 21:56 ` Jarkko Sakkinen
2021-03-10 20:36 ` Kai Huang
2021-03-10 22:10 ` Jarkko Sakkinen
2021-03-10 22:12 ` Jarkko Sakkinen
2021-03-10 22:35 ` Jarkko Sakkinen
2021-03-10 22:43 ` Kai Huang
2021-03-10 22:52 ` Kai Huang
2021-03-03 15:03 ` [PATCH v3 3/5] x86/sgx: Replace section->init_laundry_list with a temp list Jarkko Sakkinen
2021-03-03 18:02 ` Dave Hansen
2021-03-10 14:50 ` Jarkko Sakkinen [this message]
2021-03-03 15:03 ` [PATCH v3 4/5] x86/sgx: Replace section->page_list with a global free page list Jarkko Sakkinen
2021-03-03 23:48 ` Dave Hansen
2021-03-10 10:54 ` Jarkko Sakkinen
2021-03-03 15:03 ` [PATCH v3 5/5] x86/sgx: Add a basic NUMA allocation scheme to sgx_alloc_epc_page() Jarkko Sakkinen
2021-03-04 0:20 ` Dave Hansen
2021-03-10 11:30 ` Jarkko Sakkinen
2021-03-10 15:44 ` Dave Hansen
2021-03-10 21:48 ` Jarkko Sakkinen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YEjcuFRHqgF/nMg3@kernel.org \
--to=jarkko@kernel.org \
--cc=bp@alien8.de \
--cc=dave.hansen@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sgx@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.