xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Julien Grall <julien.grall@citrix.com>
To: Ian Campbell <ian.campbell@citrix.com>, xen-devel@lists.xenproject.org
Cc: stefano.stabellini@eu.citrix.com
Subject: Re: [PATCH 4/4] xen/arm: p2m: Remove translation table when it's empty
Date: Mon, 30 Nov 2015 14:26:02 +0000	[thread overview]
Message-ID: <565C5C7A.3050100@citrix.com> (raw)
In-Reply-To: <1448455229.17688.105.camel@citrix.com>

Hi Ian,

On 25/11/15 12:40, Ian Campbell wrote:
> On Wed, 2015-11-18 at 15:49 +0000, Julien Grall wrote:
>> Currently, the translation table is left in place even if no entries is
>> inuse. Because of how the p2m code has been implemented, replacing a
>> translation table by a block (i.e superpage) is not supported. Therefore,
>> any mapping of a superpage size will be split in smaller chunks making
>> the translation less efficient.
>>
>> Replacing a table by a block when a new mapping is added would be too
>> complicated because it requires to check if all the upper levels are not
>> inuse and free them if necessary.
>>
>> Instead, we will remove the empty translation table when the mapping are
>> removed. To avoid going through all the table checking if no entry is
>> inuse, a counter representing the number of entry currently inuse is
>> kept per table translation and updated when an entry change state (i.e
>> valid <-> invalid).
>>
>> As Xen allocates a page for each translation table, it's possible to
>> store the counter in the struct page_info.The field type_info has been
>> choosen for this purpose as the p2m owns the page and nobody should used
> 
> "chosen"
> 
>> @@ -936,6 +938,16 @@ static int apply_one_level(struct domain *d,
>>      BUG(); /* Should never get here */
>>  }
>>  
>> +static void update_reference_mapping(struct page_info *page,
>> +                                     lpae_t old_entry,
>> +                                     lpae_t new_entry)
>> +{
>> +    if ( p2m_valid(old_entry) && !p2m_valid(new_entry) )
>> +        page->u.inuse.type_info--;
>> +    else if ( !p2m_valid(old_entry) && !p2m_valid(new_entry) )
>> +        page->u.inuse.type_info++;
>> +}
> 
> Is there some suitable locking in place for page here?
> 
> I think the argument is that this page is part of the p2m and therefore the
> p2m lock is the thing which protects it, and we certainly hold that
> everywhere around here.

Correct. I can add a comment in the code to explain that.

> type_info is not actually a bare integer, it has some flags at the top (see
> PGT_*) which are sometimes used (e.g. share_xen_page_with_guest).
> 
> I think for consistency we should probably add a PGT_p2m and use that (and
> perhaps audit some of the other PGT_* which don't all seem to be completely
> obviously not-x86).
> 
> Presumably we would then want {get,put}_page_type to actually do something
> and to use them.
> 
> If we don't want to do that (I'm leaning towards we should, but I might be
> convinceable otherwise) then I think we should avoid the use of type_info
> as a bare counter, which would imply using another member of the inuse
> union (p2m_refcount or some such).

I think using correctly the field type_count would require lots of faff
on ARM as we don't use it for now.

So I would go with introducing a new member of inuse union.

> 
>>              if ( ret != P2M_ONE_DESCEND ) break;
>> @@ -1099,6 +1118,45 @@ static int apply_p2m_changes(struct domain *d,
>>              }
>>              /* else: next level already valid */
>>          }
>> +
>> +        BUG_ON(level > 3);
>> +
>> +        if ( op == REMOVE )
>> +        {
>> +           for ( ; level > P2M_ROOT_LEVEL; level-- )
>> +            {
> 
> Something is up with the indentation here.

Hmmm will give a look.

> 
>> +                lpae_t old_entry;
>> +                lpae_t *entry;
>> +                unsigned int offset;
>> +
>> +                pg = pages[level];
>> +
>> +                /*
>> +                 * No need to try the previous level if the current one
>> +                 * still contains some mappings
>> +                 */
>> +                if ( pg->u.inuse.type_info )
>> +                    break;
>> +
>> +                offset = offsets[level - 1];
>> +                entry = &mappings[level - 1][offset];
>> +                old_entry = *entry;
>> +
>> +                page_list_del(pg, &p2m->pages);
>> +
>> +                p2m_remove_pte(entry, flush_pt);
> 
> This made me wonder how the existing pte clear path (which you refactored
> into this function) gets away without freeing the page, are we just leaking
> it onto the p2m->pages list?

Because the existing pte clear path is only called on the leaf of the
page tables.

The intermediate table will left linked and empty.

> p2m_put_l3_page (at the other call site) only takes care of foreign
> mappings, which aren't on that list.
> 
> Maybe there is a latent bug here? And if so perhaps the fix involves making
> p2m_remove_pte take care of various bits and bobs of the book keeping which
> is done here?
> 
>> +
>> +                p2m->stats.mappings[level - 1]--;
>> +                update_reference_mapping(pages[level - 1], old_entry, *entry);
>> +
>> +                /*
>> +                 * We can't free the page now because it may be present
>> +                 * in the guest TLB. Queue it and free it after the TLB
>> +                 * has been flushed.
>> +                 */
>> +                page_list_add(pg, &free_pages);
> 
> You could have used page_list_move instead of del+add, but I can't quite
> convince myself it matters.

Are you sure? AFAICT, page_list_move move the head of the list from one
variable to another. So all the list is moved.

Regards,

-- 
Julien Grall

  reply	other threads:[~2015-11-30 14:27 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-18 15:49 [PATCH 0/4] xen/arm: p2m: Add support to remove empty translation table Julien Grall
2015-11-18 15:49 ` [PATCH 1/4] xen/arm: p2m: Flush for every exit paths in apply_p2m_changes Julien Grall
2015-11-25 11:43   ` Ian Campbell
2015-11-18 15:49 ` [PATCH 2/4] xen/arm: p2m: Store the page for each mapping Julien Grall
2015-11-25 11:46   ` Ian Campbell
2015-11-18 15:49 ` [PATCH 3/4] xen/arm: p2m: Introduce an helper to remove an entry in the page table Julien Grall
2015-11-25 11:47   ` Ian Campbell
2015-11-18 15:49 ` [PATCH 4/4] xen/arm: p2m: Remove translation table when it's empty Julien Grall
2015-11-25 12:40   ` Ian Campbell
2015-11-30 14:26     ` Julien Grall [this message]
2015-11-30 14:32       ` Ian Campbell

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=565C5C7A.3050100@citrix.com \
    --to=julien.grall@citrix.com \
    --cc=ian.campbell@citrix.com \
    --cc=stefano.stabellini@eu.citrix.com \
    --cc=xen-devel@lists.xenproject.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).