All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/12] xenpaging changes for xen-unstable
@ 2011-01-10 16:43 Olaf Hering
  2011-01-10 16:43 ` [PATCH 01/12] xenpaging: remove domain_id and mfn from struct xenpaging_victim Olaf Hering
                   ` (12 more replies)
  0 siblings, 13 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel


Here are some changes for xenpaging in xen-unstable.

New to this series since my last post are patch 1 to 5.
They are likely non-controversial and could be applied.

Patches 6 and 7 are required to maintain the machine_to_phys_mapping[]
array properly. Unless there are objections to the deallocation part,
they could be applied.

Patch 8 could be applied as well.

All other changes are not ready yet for inclusion.

As it stands right now, a guest will hang hard with xenpaging once the
balloon driver is loaded in the guest. Its not clear what the issue is,
no memory_op hypercall has been issued yet. xm vcpu-list indicates the
guest makes no progress.  I will debug this further.


Olaf

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 01/12] xenpaging: remove domain_id and mfn from struct xenpaging_victim
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-10 16:43 ` [PATCH 02/12] xenpaging: specify policy mru_size at runtime Olaf Hering
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.no_domain_id.patch --]
[-- Type: text/plain, Size: 6856 bytes --]

Remove unused member 'mfn' from struct xenpaging_victim.

xenpaging operates on a single guest, so it needs only a single domain_id.
Remove domain_id from struct xenpaging_victim and use the one from
paging->mem_event where needed. Its not used in the policy.

This saves 4MB runtime data with a 1GB pagefile.

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
 tools/xenpaging/policy.h         |    7 +++----
 tools/xenpaging/policy_default.c |   10 +++-------
 tools/xenpaging/xenpaging.c      |   26 ++++++++++++--------------
 tools/xenpaging/xenpaging.h      |    4 ----
 4 files changed, 18 insertions(+), 29 deletions(-)

--- xen-unstable.hg-4.1.22694.orig/tools/xenpaging/policy.h
+++ xen-unstable.hg-4.1.22694/tools/xenpaging/policy.h
@@ -29,10 +29,9 @@
 
 
 int policy_init(xenpaging_t *paging);
-int policy_choose_victim(xenpaging_t *paging, domid_t domain_id,
-                         xenpaging_victim_t *victim);
-void policy_notify_paged_out(domid_t domain_id, unsigned long gfn);
-void policy_notify_paged_in(domid_t domain_id, unsigned long gfn);
+int policy_choose_victim(xenpaging_t *paging, xenpaging_victim_t *victim);
+void policy_notify_paged_out(unsigned long gfn);
+void policy_notify_paged_in(unsigned long gfn);
 
 #endif // __XEN_PAGING_POLICY_H__
 
--- xen-unstable.hg-4.1.22694.orig/tools/xenpaging/policy_default.c
+++ xen-unstable.hg-4.1.22694/tools/xenpaging/policy_default.c
@@ -67,16 +67,12 @@ int policy_init(xenpaging_t *paging)
     return rc;
 }
 
-int policy_choose_victim(xenpaging_t *paging, domid_t domain_id,
-                         xenpaging_victim_t *victim)
+int policy_choose_victim(xenpaging_t *paging, xenpaging_victim_t *victim)
 {
     xc_interface *xch = paging->xc_handle;
     unsigned long wrap = current_gfn;
     ASSERT(victim != NULL);
 
-    /* Domain to pick on */
-    victim->domain_id = domain_id;
-
     do
     {
         current_gfn++;
@@ -96,13 +92,13 @@ int policy_choose_victim(xenpaging_t *pa
     return 0;
 }
 
-void policy_notify_paged_out(domid_t domain_id, unsigned long gfn)
+void policy_notify_paged_out(unsigned long gfn)
 {
     set_bit(gfn, bitmap);
     clear_bit(gfn, unconsumed);
 }
 
-void policy_notify_paged_in(domid_t domain_id, unsigned long gfn)
+void policy_notify_paged_in(unsigned long gfn)
 {
     unsigned long old_gfn = mru[i_mru & (MRU_SIZE - 1)];
 
--- xen-unstable.hg-4.1.22694.orig/tools/xenpaging/xenpaging.c
+++ xen-unstable.hg-4.1.22694/tools/xenpaging/xenpaging.c
@@ -171,7 +171,7 @@ xenpaging_t *xenpaging_init(domid_t doma
         goto err;
     }
 
-    rc = xc_get_platform_info(xch, domain_id,
+    rc = xc_get_platform_info(xch, paging->mem_event.domain_id,
                               paging->platform_info);
     if ( rc != 1 )
     {
@@ -187,7 +187,7 @@ xenpaging_t *xenpaging_init(domid_t doma
         goto err;
     }
 
-    rc = xc_domain_getinfolist(xch, domain_id, 1,
+    rc = xc_domain_getinfolist(xch, paging->mem_event.domain_id, 1,
                                paging->domain_info);
     if ( rc != 1 )
     {
@@ -348,7 +348,7 @@ int xenpaging_evict_page(xenpaging_t *pa
     /* Map page */
     gfn = victim->gfn;
     ret = -EFAULT;
-    page = xc_map_foreign_pages(xch, victim->domain_id,
+    page = xc_map_foreign_pages(xch, paging->mem_event.domain_id,
                                 PROT_READ | PROT_WRITE, &gfn, 1);
     if ( page == NULL )
     {
@@ -380,7 +380,7 @@ int xenpaging_evict_page(xenpaging_t *pa
     }
 
     /* Notify policy of page being paged out */
-    policy_notify_paged_out(paging->mem_event.domain_id, victim->gfn);
+    policy_notify_paged_out(victim->gfn);
 
  out:
     return ret;
@@ -397,7 +397,7 @@ static int xenpaging_resume_page(xenpagi
 
     /* Notify policy of page being paged in */
     if ( notify_policy )
-        policy_notify_paged_in(paging->mem_event.domain_id, rsp->gfn);
+        policy_notify_paged_in(rsp->gfn);
 
     /* Tell Xen page is ready */
     ret = xc_mem_paging_resume(paging->xc_handle, paging->mem_event.domain_id,
@@ -464,7 +464,7 @@ static int xenpaging_populate_page(xenpa
     return ret;
 }
 
-static int evict_victim(xenpaging_t *paging, domid_t domain_id,
+static int evict_victim(xenpaging_t *paging,
                         xenpaging_victim_t *victim, int fd, int i)
 {
     xc_interface *xch = paging->xc_handle;
@@ -473,7 +473,7 @@ static int evict_victim(xenpaging_t *pag
 
     do
     {
-        ret = policy_choose_victim(paging, domain_id, victim);
+        ret = policy_choose_victim(paging, victim);
         if ( ret != 0 )
         {
             if ( ret != -ENOSPC )
@@ -486,14 +486,13 @@ static int evict_victim(xenpaging_t *pag
             ret = -EINTR;
             goto out;
         }
-        ret = xc_mem_paging_nominate(xch,
-                                     paging->mem_event.domain_id, victim->gfn);
+        ret = xc_mem_paging_nominate(xch, paging->mem_event.domain_id, victim->gfn);
         if ( ret == 0 )
             ret = xenpaging_evict_page(paging, victim, fd, i);
         else
         {
             if ( j++ % 1000 == 0 )
-                if ( xc_mem_paging_flush_ioemu_cache(domain_id) )
+                if ( xc_mem_paging_flush_ioemu_cache(paging->mem_event.domain_id) )
                     ERROR("Error flushing ioemu cache");
         }
     }
@@ -578,7 +577,7 @@ int main(int argc, char *argv[])
     memset(victims, 0, sizeof(xenpaging_victim_t) * num_pages);
     for ( i = 0; i < num_pages; i++ )
     {
-        rc = evict_victim(paging, domain_id, &victims[i], fd, i);
+        rc = evict_victim(paging, &victims[i], fd, i);
         if ( rc == -ENOSPC )
             break;
         if ( rc == -EINTR )
@@ -619,8 +618,7 @@ int main(int argc, char *argv[])
                 /* Find where in the paging file to read from */
                 for ( i = 0; i < num_pages; i++ )
                 {
-                    if ( (victims[i].domain_id == paging->mem_event.domain_id) &&
-                         (victims[i].gfn == req.gfn) )
+                    if ( victims[i].gfn == req.gfn )
                         break;
                 }
     
@@ -652,7 +650,7 @@ int main(int argc, char *argv[])
                 }
 
                 /* Evict a new page to replace the one we just paged in */
-                evict_victim(paging, domain_id, &victims[i], fd, i);
+                evict_victim(paging, &victims[i], fd, i);
             }
             else
             {
--- xen-unstable.hg-4.1.22694.orig/tools/xenpaging/xenpaging.h
+++ xen-unstable.hg-4.1.22694/tools/xenpaging/xenpaging.h
@@ -49,12 +49,8 @@ typedef struct xenpaging {
 
 
 typedef struct xenpaging_victim {
-    /* the domain to evict a page from */
-    domid_t domain_id;
     /* the gfn of the page to evict */
     unsigned long gfn;
-    /* the mfn of evicted page */
-    unsigned long mfn;
 } xenpaging_victim_t;

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 02/12] xenpaging: specify policy mru_size at runtime
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
  2011-01-10 16:43 ` [PATCH 01/12] xenpaging: remove domain_id and mfn from struct xenpaging_victim Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-10 16:43 ` [PATCH 03/12] xenpaging: mkdir /var/lib/xen/xenpaging during make install Olaf Hering
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.runtime_mru_size.patch --]
[-- Type: text/plain, Size: 3213 bytes --]

The environment variable XENPAGING_POLICY_MRU_SIZE will change the
mru_size in the policy at runtime.
Specifying the mru_size at runtime allows the admin to keep more pages in
memory so guests can make more progress.  Its also good for development to
reduce the value to put more pressure on the paging related code paths.  

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---

Note: some work is still required to actually get the value into the
      environment of the process. Maybe it will become an config option
      at some point.

 tools/xenpaging/policy_default.c |   23 ++++++++++++++++++-----
 tools/xenpaging/xenpaging.c      |    8 ++++++++
 tools/xenpaging/xenpaging.h      |    1 +
 3 files changed, 27 insertions(+), 5 deletions(-)

--- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/policy_default.c
+++ xen-unstable.hg-4.1.22571/tools/xenpaging/policy_default.c
@@ -26,11 +26,12 @@
 #include "policy.h"
 
 
-#define MRU_SIZE (1024 * 16)
+#define DEFAULT_MRU_SIZE (1024 * 16)
 
 
-static unsigned long mru[MRU_SIZE];
+static unsigned long *mru;
 static unsigned int i_mru;
+static unsigned int mru_size;
 static unsigned long *bitmap;
 static unsigned long *unconsumed;
 static unsigned long current_gfn;
@@ -57,7 +58,19 @@ int policy_init(xenpaging_t *paging)
     max_pages = paging->domain_info->max_pages;
 
     /* Initialise MRU list of paged in pages */
-    for ( i = 0; i < MRU_SIZE; i++ )
+    if ( paging->policy_mru_size > 0 )
+        mru_size = paging->policy_mru_size;
+    else
+        mru_size = DEFAULT_MRU_SIZE;
+
+    mru = malloc(sizeof(*mru) * mru_size);
+    if ( mru == NULL )
+    {
+        rc = -ENOMEM;
+        goto out;
+    }
+
+    for ( i = 0; i < mru_size; i++ )
         mru[i] = INVALID_MFN;
 
     /* Don't page out page 0 */
@@ -100,12 +113,12 @@ void policy_notify_paged_out(unsigned lo
 
 void policy_notify_paged_in(unsigned long gfn)
 {
-    unsigned long old_gfn = mru[i_mru & (MRU_SIZE - 1)];
+    unsigned long old_gfn = mru[i_mru & (mru_size - 1)];
 
     if ( old_gfn != INVALID_MFN )
         clear_bit(old_gfn, bitmap);
     
-    mru[i_mru & (MRU_SIZE - 1)] = gfn;
+    mru[i_mru & (mru_size - 1)] = gfn;
     i_mru++;
 }
 
--- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/xenpaging.c
+++ xen-unstable.hg-4.1.22571/tools/xenpaging/xenpaging.c
@@ -78,6 +78,7 @@ xenpaging_t *xenpaging_init(domid_t doma
     xenpaging_t *paging;
     xc_interface *xch;
     xentoollog_logger *dbg = NULL;
+    char *p;
     int rc;
 
     if ( getenv("XENPAGING_DEBUG") )
@@ -92,6 +93,13 @@ xenpaging_t *xenpaging_init(domid_t doma
     paging = malloc(sizeof(xenpaging_t));
     memset(paging, 0, sizeof(xenpaging_t));
 
+    p = getenv("XENPAGING_POLICY_MRU_SIZE");
+    if ( p && *p )
+    {
+         paging->policy_mru_size = atoi(p);
+         DPRINTF("Setting policy mru_size to %d\n", paging->policy_mru_size);
+    }
+
     /* Open connection to xen */
     paging->xc_handle = xch;
 
--- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/xenpaging.h
+++ xen-unstable.hg-4.1.22571/tools/xenpaging/xenpaging.h
@@ -45,6 +45,7 @@ typedef struct xenpaging {
     unsigned long *bitmap;
 
     mem_event_t mem_event;
+    int policy_mru_size;
 } xenpaging_t;

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 03/12] xenpaging: mkdir /var/lib/xen/xenpaging during make install
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
  2011-01-10 16:43 ` [PATCH 01/12] xenpaging: remove domain_id and mfn from struct xenpaging_victim Olaf Hering
  2011-01-10 16:43 ` [PATCH 02/12] xenpaging: specify policy mru_size at runtime Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-10 16:43 ` [PATCH 04/12] xenpaging: print page-in/page-out progress Olaf Hering
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.make_install.patch --]
[-- Type: text/plain, Size: 561 bytes --]

pagefiles go to /var/lib/xen/xenpaging directory,
create this directory during make install

Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
 tools/xenpaging/Makefile |    1 +
 1 file changed, 1 insertion(+)

--- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/Makefile
+++ xen-unstable.hg-4.1.22571/tools/xenpaging/Makefile
@@ -27,6 +27,7 @@ xenpaging: $(OBJS)
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
 
 install: all
+	$(INSTALL_DIR) $(DESTDIR)/var/lib/xen/xenpaging
 	$(INSTALL_DIR) $(DESTDIR)$(SBINDIR)
 	$(INSTALL_PROG) $(IBINS) $(DESTDIR)$(SBINDIR)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 04/12] xenpaging: print page-in/page-out progress
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
                   ` (2 preceding siblings ...)
  2011-01-10 16:43 ` [PATCH 03/12] xenpaging: mkdir /var/lib/xen/xenpaging during make install Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-10 16:43 ` [PATCH 05/12] xenpaging: make three functions static Olaf Hering
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.print-pageout-pagein-progress.patch --]
[-- Type: text/plain, Size: 978 bytes --]

Now that DPRINTF is triggered only when the environment variable
XENPAGING_DEBUG is found, make such a debug session actually useful by
printing the entire page-out/page-in process. The 'Got event from Xen'
message alone is not helpful.

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
 tools/xenpaging/xenpaging.c |    2 ++
 1 file changed, 2 insertions(+)

--- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/xenpaging.c
+++ xen-unstable.hg-4.1.22571/tools/xenpaging/xenpaging.c
@@ -387,6 +387,7 @@ int xenpaging_evict_page(xenpaging_t *pa
         goto out;
     }
 
+    DPRINTF("evict_page > gfn %lx pageslot %d\n", victim->gfn, i);
     /* Notify policy of page being paged out */
     policy_notify_paged_out(victim->gfn);
 
@@ -427,6 +428,7 @@ static int xenpaging_populate_page(xenpa
     unsigned char oom = 0;
 
     _gfn = *gfn;
+    DPRINTF("populate_page < gfn %lx pageslot %d\n", _gfn, i);
     do
     {
         /* Tell Xen to allocate a page for the domain */

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 05/12] xenpaging: make three functions static
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
                   ` (3 preceding siblings ...)
  2011-01-10 16:43 ` [PATCH 04/12] xenpaging: print page-in/page-out progress Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-11 18:36   ` Ian Jackson
  2011-01-10 16:43 ` [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation Olaf Hering
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.static_functions.patch --]
[-- Type: text/plain, Size: 1134 bytes --]

xenpaging_init(), xenpaging_teardown() and xenpaging_evict_page() are
only used in file scope, so they can be marked static.

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
 tools/xenpaging/xenpaging.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

--- xen-unstable.hg-4.1.22697.orig/tools/xenpaging/xenpaging.c
+++ xen-unstable.hg-4.1.22697/tools/xenpaging/xenpaging.c
@@ -73,7 +73,7 @@ static void *init_page(void)
     return NULL;
 }
 
-xenpaging_t *xenpaging_init(domid_t domain_id)
+static xenpaging_t *xenpaging_init(domid_t domain_id)
 {
     xenpaging_t *paging;
     xc_interface *xch;
@@ -251,7 +251,7 @@ xenpaging_t *xenpaging_init(domid_t doma
     return NULL;
 }
 
-int xenpaging_teardown(xenpaging_t *paging)
+static int xenpaging_teardown(xenpaging_t *paging)
 {
     int rc;
     xc_interface *xch;
@@ -343,7 +343,7 @@ static int put_response(mem_event_t *mem
     return 0;
 }
 
-int xenpaging_evict_page(xenpaging_t *paging,
+static int xenpaging_evict_page(xenpaging_t *paging,
                          xenpaging_victim_t *victim, int fd, int i)
 {
     xc_interface *xch = paging->xc_handle;

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
                   ` (4 preceding siblings ...)
  2011-01-10 16:43 ` [PATCH 05/12] xenpaging: make three functions static Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-11 10:37   ` Keir Fraser
  2011-01-10 16:43 ` [PATCH 07/12] xenpaging: update machine_to_phys_mapping[] during page-in Olaf Hering
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.machine_to_phys_mapping.free_domheap_pages.patch --]
[-- Type: text/plain, Size: 2029 bytes --]

The machine_to_phys_mapping[] array needs updating during page
deallocation.  If that page is allocated again, a call to
get_gpfn_from_mfn() will still return an old gfn from another guest.
This will cause trouble because this gfn number has no or different
meaning in the context of the current guest.

This happens when the entire guest ram is paged-out before
xen_vga_populate_vram() runs.  Then XENMEM_populate_physmap is called
with gfn 0xff000.  A new page is allocated with alloc_domheap_pages.
This new page does not have a gfn yet.  However, in
guest_physmap_add_entry() the passed mfn maps still to an old gfn
(perhaps from another old guest).  This old gfn is in paged-out state in
this guests context and has no mfn anymore.  As a result, the ASSERT()
triggers because p2m_is_ram() is true for p2m_ram_paging* types.
If the machine_to_phys_mapping[] array is updated properly, both loops
in guest_physmap_add_entry() turn into no-ops for the new page and the
mfn/gfn mapping will be done at the end of the function.

If XENMEM_add_to_physmap is used with XENMAPSPACE_gmfn,
get_gpfn_from_mfn() will return an appearently valid gfn.  As a result,
guest_physmap_remove_page() is called.  The ASSERT in p2m_remove_page
triggers because the passed mfn does not match the old mfn for the
passed gfn.


Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
 xen/common/page_alloc.c |    6 ++++++
 1 file changed, 6 insertions(+)

--- xen-unstable.hg-4.1.22571.orig/xen/common/page_alloc.c
+++ xen-unstable.hg-4.1.22571/xen/common/page_alloc.c
@@ -1200,9 +1200,15 @@ void free_domheap_pages(struct page_info
 {
     int            i, drop_dom_ref;
     struct domain *d = page_get_owner(pg);
+    unsigned long mfn;
 
     ASSERT(!in_irq());
 
+    /* this page is not a gfn anymore */
+    mfn = page_to_mfn(pg);
+    for ( i = 0; i < (1 << order); i++ )
+        set_gpfn_from_mfn(mfn + i, INVALID_M2P_ENTRY);
+
     if ( unlikely(is_xen_heap_page(pg)) )
     {
         /* NB. May recursively lock from relinquish_memory(). */

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 07/12] xenpaging: update machine_to_phys_mapping[] during page-in
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
                   ` (5 preceding siblings ...)
  2011-01-10 16:43 ` [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-10 16:43 ` [PATCH 08/12] xenpaging: drop paged pages in guest_remove_page Olaf Hering
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.machine_to_phys_mapping.patch --]
[-- Type: text/plain, Size: 663 bytes --]

Update the machine_to_phys_mapping[] array during page-in. The gfn is
now at a different page and the array has still INVALID_M2P_ENTRY in the
index.

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
 xen/arch/x86/mm/p2m.c |    1 +
 1 file changed, 1 insertion(+)

--- xen-unstable.hg-4.1.22694.orig/xen/arch/x86/mm/p2m.c
+++ xen-unstable.hg-4.1.22694/xen/arch/x86/mm/p2m.c
@@ -2850,6 +2850,7 @@ void p2m_mem_paging_resume(struct p2m_do
     mfn = gfn_to_mfn(p2m, rsp.gfn, &p2mt);
     p2m_lock(p2m);
     set_p2m_entry(p2m, rsp.gfn, mfn, 0, p2m_ram_rw, p2m->default_access);
+    set_gpfn_from_mfn(mfn_x(mfn), gfn);
     audit_p2m(p2m, 1);
     p2m_unlock(p2m);

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 08/12] xenpaging: drop paged pages in guest_remove_page
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
                   ` (6 preceding siblings ...)
  2011-01-10 16:43 ` [PATCH 07/12] xenpaging: update machine_to_phys_mapping[] during page-in Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-14 16:53   ` Olaf Hering
  2011-01-10 16:43 ` [PATCH 09/12] xenpaging: prevent page-out of gfn 0x80 Olaf Hering
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.guest_remove_page.patch --]
[-- Type: text/plain, Size: 7306 bytes --]

Simply drop paged-pages in guest_remove_page(), and notify xenpaging to
drop its reference to the gfn. If the ring is full, the page will
remain in paged-out state in xenpaging. This is not an issue, it just
means this gfn will not be nominated again.

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
v3:
 send one-way notification to pager to release page
 use new mem_event_check_ring() feature to not pause vcpu when ring is full
v2:
 resume dropped page to unpause vcpus

 tools/xenpaging/xenpaging.c    |   39 ++++++++++++++++++++------------
 xen/arch/x86/mm/p2m.c          |   49 ++++++++++++++++++++++++++++++-----------
 xen/common/memory.c            |    6 +++++
 xen/include/asm-x86/p2m.h      |    4 +++
 xen/include/public/mem_event.h |    1 
 5 files changed, 72 insertions(+), 27 deletions(-)

--- xen-unstable.hg-4.1.22694.orig/tools/xenpaging/xenpaging.c
+++ xen-unstable.hg-4.1.22694/tools/xenpaging/xenpaging.c
@@ -638,25 +638,34 @@ int main(int argc, char *argv[])
                     goto out;
                 }
                 
-                /* Populate the page */
-                rc = xenpaging_populate_page(paging, &req.gfn, fd, i);
-                if ( rc != 0 )
+                if ( req.flags & MEM_EVENT_FLAG_DROP_PAGE )
                 {
-                    ERROR("Error populating page");
-                    goto out;
+                    DPRINTF("drop_page ^ gfn %"PRIx64" pageslot %d\n", req.gfn, i);
+                    /* Notify policy of page being dropped */
+                    policy_notify_paged_in(req.gfn);
                 }
+                else
+                {
+                    /* Populate the page */
+                    rc = xenpaging_populate_page(paging, &req.gfn, fd, i);
+                    if ( rc != 0 )
+                    {
+                        ERROR("Error populating page");
+                        goto out;
+                    }
 
-                /* Prepare the response */
-                rsp.gfn = req.gfn;
-                rsp.p2mt = req.p2mt;
-                rsp.vcpu_id = req.vcpu_id;
-                rsp.flags = req.flags;
+                    /* Prepare the response */
+                    rsp.gfn = req.gfn;
+                    rsp.p2mt = req.p2mt;
+                    rsp.vcpu_id = req.vcpu_id;
+                    rsp.flags = req.flags;
 
-                rc = xenpaging_resume_page(paging, &rsp, 1);
-                if ( rc != 0 )
-                {
-                    ERROR("Error resuming page");
-                    goto out;
+                    rc = xenpaging_resume_page(paging, &rsp, 1);
+                    if ( rc != 0 )
+                    {
+                        ERROR("Error resuming page");
+                        goto out;
+                    }
                 }
 
                 /* Evict a new page to replace the one we just paged in */
--- xen-unstable.hg-4.1.22694.orig/xen/arch/x86/mm/p2m.c
+++ xen-unstable.hg-4.1.22694/xen/arch/x86/mm/p2m.c
@@ -2211,12 +2211,15 @@ p2m_remove_page(struct p2m_domain *p2m,
 
     P2M_DEBUG("removing gfn=%#lx mfn=%#lx\n", gfn, mfn);
 
-    for ( i = 0; i < (1UL << page_order); i++ )
+    if ( mfn_valid(_mfn(mfn)) )
     {
-        mfn_return = p2m->get_entry(p2m, gfn + i, &t, &a, p2m_query);
-        if ( !p2m_is_grant(t) )
-            set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY);
-        ASSERT( !p2m_is_valid(t) || mfn + i == mfn_x(mfn_return) );
+        for ( i = 0; i < (1UL << page_order); i++ )
+        {
+            mfn_return = p2m->get_entry(p2m, gfn + i, &t, &a, p2m_query);
+            if ( !p2m_is_grant(t) )
+                set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY);
+            ASSERT( !p2m_is_valid(t) || mfn + i == mfn_x(mfn_return) );
+        }
     }
     set_p2m_entry(p2m, gfn, _mfn(INVALID_MFN), page_order, p2m_invalid, p2m->default_access);
 }
@@ -2772,6 +2775,25 @@ int p2m_mem_paging_evict(struct p2m_doma
     return 0;
 }
 
+void p2m_mem_paging_drop_page(struct p2m_domain *p2m, unsigned long gfn)
+{
+    struct vcpu *v = current;
+    mem_event_request_t req;
+    struct domain *d = p2m->domain;
+
+    /* Check that there's space on the ring for this request */
+    if ( mem_event_check_ring(d) == 0)
+    {
+        /* Send release notification to pager */
+        memset(&req, 0, sizeof(req));
+        req.flags |= MEM_EVENT_FLAG_DROP_PAGE;
+        req.gfn = gfn;
+        req.vcpu_id = v->vcpu_id;
+
+        mem_event_put_request(d, &req);
+    }
+}
+
 void p2m_mem_paging_populate(struct p2m_domain *p2m, unsigned long gfn)
 {
     struct vcpu *v = current;
@@ -2846,13 +2868,16 @@ void p2m_mem_paging_resume(struct p2m_do
     /* Pull the response off the ring */
     mem_event_get_response(d, &rsp);
 
-    /* Fix p2m entry */
-    mfn = gfn_to_mfn(p2m, rsp.gfn, &p2mt);
-    p2m_lock(p2m);
-    set_p2m_entry(p2m, rsp.gfn, mfn, 0, p2m_ram_rw, p2m->default_access);
-    set_gpfn_from_mfn(mfn_x(mfn), gfn);
-    audit_p2m(p2m, 1);
-    p2m_unlock(p2m);
+    /* Fix p2m entry if the page was not dropped */
+    if ( !(rsp.flags & MEM_EVENT_FLAG_DROP_PAGE) )
+    {
+        mfn = gfn_to_mfn(p2m, rsp.gfn, &p2mt);
+        p2m_lock(p2m);
+        set_p2m_entry(p2m, rsp.gfn, mfn, 0, p2m_ram_rw, p2m->default_access);
+        set_gpfn_from_mfn(mfn_x(mfn), rsp.gfn);
+        audit_p2m(p2m, 1);
+        p2m_unlock(p2m);
+    }
 
     /* Unpause domain */
     if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED )
--- xen-unstable.hg-4.1.22694.orig/xen/common/memory.c
+++ xen-unstable.hg-4.1.22694/xen/common/memory.c
@@ -163,6 +163,12 @@ int guest_remove_page(struct domain *d,
 
 #ifdef CONFIG_X86
     mfn = mfn_x(gfn_to_mfn(p2m_get_hostp2m(d), gmfn, &p2mt)); 
+    if ( unlikely(p2m_is_paging(p2mt)) )
+    {
+        guest_physmap_remove_page(d, gmfn, mfn, 0);
+        p2m_mem_paging_drop_page(p2m_get_hostp2m(d), gmfn);
+        return 1;
+    }
 #else
     mfn = gmfn_to_mfn(d, gmfn);
 #endif
--- xen-unstable.hg-4.1.22694.orig/xen/include/asm-x86/p2m.h
+++ xen-unstable.hg-4.1.22694/xen/include/asm-x86/p2m.h
@@ -511,6 +511,8 @@ int set_shared_p2m_entry(struct p2m_doma
 int p2m_mem_paging_nominate(struct p2m_domain *p2m, unsigned long gfn);
 /* Evict a frame */
 int p2m_mem_paging_evict(struct p2m_domain *p2m, unsigned long gfn);
+/* Tell xenpaging to drop a paged out frame */
+void p2m_mem_paging_drop_page(struct p2m_domain *p2m, unsigned long gfn);
 /* Start populating a paged out frame */
 void p2m_mem_paging_populate(struct p2m_domain *p2m, unsigned long gfn);
 /* Prepare the p2m for paging a frame in */
@@ -518,6 +520,8 @@ int p2m_mem_paging_prep(struct p2m_domai
 /* Resume normal operation (in case a domain was paused) */
 void p2m_mem_paging_resume(struct p2m_domain *p2m);
 #else
+static inline void p2m_mem_paging_drop_page(struct p2m_domain *p2m, unsigned long gfn)
+{ }
 static inline void p2m_mem_paging_populate(struct p2m_domain *p2m, unsigned long gfn)
 { }
 #endif
--- xen-unstable.hg-4.1.22694.orig/xen/include/public/mem_event.h
+++ xen-unstable.hg-4.1.22694/xen/include/public/mem_event.h
@@ -33,6 +33,7 @@
 
 /* Memory event flags */
 #define MEM_EVENT_FLAG_VCPU_PAUSED  (1 << 0)
+#define MEM_EVENT_FLAG_DROP_PAGE    (1 << 1)
 
 /* Reasons for the memory event request */
 #define MEM_EVENT_REASON_UNKNOWN     0    /* typical reason */

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 09/12] xenpaging: prevent page-out of gfn 0x80
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
                   ` (7 preceding siblings ...)
  2011-01-10 16:43 ` [PATCH 08/12] xenpaging: drop paged pages in guest_remove_page Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-10 16:43 ` [PATCH 10/12] xenpaging: handle HVMCOPY_gfn_paged_out in copy_from/to_user Olaf Hering
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.realmode_gfn_0x80.patch --]
[-- Type: text/plain, Size: 1169 bytes --]

Add a workaround for missing handling of paged-out pages during BIOS startup.
For some reason, only gfn 0x80 is affected.

(XEN) HVM3: HVM Loader
(XEN) traps.c:649:d3 Bad GMFN 80 (MFN ffffffffff) to MSR 40000000
(XEN) HVM3: Detected Xen v4.1
(XEN) HVM3: HVMLoader bug at util.c:604
(XEN) hvm.c:1085:d3 Triple fault on VCPU0 - invoking HVM system reset.

(XEN) HVM4: HVM Loader
(XEN) traps.c:649:d4 Bad GMFN 80 (MFN ffffffffff) to MSR 40000000
(XEN) io.c:194:d4 MMIO emulation failed @ 0018:9ffff: 00 6a 10 80 c4 82
(XEN) hvm.c:1085:d4 Triple fault on VCPU0 - invoking HVM system reset.

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
Another part of the bugfix is the missing p2m_mem_paging_populate() call in
gfn_to_mfn()

 tools/xenpaging/policy_default.c |    3 +++
 1 file changed, 3 insertions(+)

--- xen-unstable.hg-4.1.22571.orig/tools/xenpaging/policy_default.c
+++ xen-unstable.hg-4.1.22571/tools/xenpaging/policy_default.c
@@ -76,6 +76,9 @@ int policy_init(xenpaging_t *paging)
     /* Don't page out page 0 */
     set_bit(0, bitmap);
 
+    /* this is the trap page, disabled for the time being */
+    set_bit(0x80, bitmap);
+
  out:
     return rc;
 }

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 10/12] xenpaging: handle HVMCOPY_gfn_paged_out in copy_from/to_user
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
                   ` (8 preceding siblings ...)
  2011-01-10 16:43 ` [PATCH 09/12] xenpaging: prevent page-out of gfn 0x80 Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-10 16:43 ` [PATCH 11/12] xenpaging: start xenpaging via config option Olaf Hering
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.HVMCOPY_gfn_paged_out.patch --]
[-- Type: text/plain, Size: 5000 bytes --]

copy_from_user_hvm can fail when __hvm_copy returns
HVMCOPY_gfn_paged_out for a referenced gfn, for example during guests
pagetable walk.  This has to be handled in some way.

For the time being, return -EAGAIN for the most common case (xen_balloon
driver crashing in guest) until the recently added waitqueues will be
used.

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
 xen/arch/x86/hvm/hvm.c |    4 ++++
 xen/common/memory.c    |   39 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 38 insertions(+), 5 deletions(-)

--- xen-unstable.hg-4.1.22697.orig/xen/arch/x86/hvm/hvm.c
+++ xen-unstable.hg-4.1.22697/xen/arch/x86/hvm/hvm.c
@@ -2154,6 +2154,8 @@ unsigned long copy_to_user_hvm(void *to,
 
     rc = hvm_copy_to_guest_virt_nofault((unsigned long)to, (void *)from,
                                         len, 0);
+    if ( unlikely(rc == HVMCOPY_gfn_paged_out) )
+        return -EAGAIN;
     return rc ? len : 0; /* fake a copy_to_user() return code */
 }
 
@@ -2171,6 +2173,8 @@ unsigned long copy_from_user_hvm(void *t
 #endif
 
     rc = hvm_copy_from_guest_virt_nofault(to, (unsigned long)from, len, 0);
+    if ( unlikely(rc == HVMCOPY_gfn_paged_out) )
+        return -EAGAIN;
     return rc ? len : 0; /* fake a copy_from_user() return code */
 }
 
--- xen-unstable.hg-4.1.22697.orig/xen/common/memory.c
+++ xen-unstable.hg-4.1.22697/xen/common/memory.c
@@ -48,6 +48,7 @@ static void increase_reservation(struct
 {
     struct page_info *page;
     unsigned long i;
+    unsigned long ctg_ret;
     xen_pfn_t mfn;
     struct domain *d = a->domain;
 
@@ -81,8 +82,13 @@ static void increase_reservation(struct
         if ( !guest_handle_is_null(a->extent_list) )
         {
             mfn = page_to_mfn(page);
-            if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) )
+            ctg_ret = __copy_to_guest_offset(a->extent_list, i, &mfn, 1);
+            if ( unlikely(ctg_ret) )
+            {
+                if ( (long)ctg_ret == -EAGAIN )
+                    a->preempted = 1;
                 goto out;
+            }
         }
     }
 
@@ -94,6 +100,7 @@ static void populate_physmap(struct memo
 {
     struct page_info *page;
     unsigned long i, j;
+    unsigned long cftg_ret;
     xen_pfn_t gpfn, mfn;
     struct domain *d = a->domain;
 
@@ -112,8 +119,13 @@ static void populate_physmap(struct memo
             goto out;
         }
 
-        if ( unlikely(__copy_from_guest_offset(&gpfn, a->extent_list, i, 1)) )
+        cftg_ret = __copy_from_guest_offset(&gpfn, a->extent_list, i, 1);
+        if ( unlikely(cftg_ret) )
+        {
+            if ( (long)cftg_ret == -EAGAIN )
+                a->preempted = 1;
             goto out;
+        }
 
         if ( a->memflags & MEMF_populate_on_demand )
         {
@@ -143,8 +155,13 @@ static void populate_physmap(struct memo
                     set_gpfn_from_mfn(mfn + j, gpfn + j);
 
                 /* Inform the domain of the new page's machine address. */ 
-                if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) )
+                cftg_ret = __copy_to_guest_offset(a->extent_list, i, &mfn, 1);
+                if ( unlikely(cftg_ret) )
+                {
+                    if ( (long)cftg_ret == -EAGAIN )
+                        a->preempted = 1;
                     goto out;
+                }
             }
         }
     }
@@ -213,6 +230,7 @@ int guest_remove_page(struct domain *d,
 static void decrease_reservation(struct memop_args *a)
 {
     unsigned long i, j;
+    unsigned long cfg_ret;
     xen_pfn_t gmfn;
 
     if ( !guest_handle_subrange_okay(a->extent_list, a->nr_done,
@@ -227,8 +245,13 @@ static void decrease_reservation(struct
             goto out;
         }
 
-        if ( unlikely(__copy_from_guest_offset(&gmfn, a->extent_list, i, 1)) )
+        cfg_ret = __copy_from_guest_offset(&gmfn, a->extent_list, i, 1);
+        if ( unlikely(cfg_ret) )
+        {
+            if ( (long)cfg_ret == -EAGAIN )
+                a->preempted = 1;
             goto out;
+        }
 
         if ( tb_init_done )
         {
@@ -509,6 +532,7 @@ long do_memory_op(unsigned long cmd, XEN
     int rc, op;
     unsigned int address_bits;
     unsigned long start_extent;
+    unsigned long cfg_ret;
     struct xen_memory_reservation reservation;
     struct memop_args args;
     domid_t domid;
@@ -522,8 +546,13 @@ long do_memory_op(unsigned long cmd, XEN
     case XENMEM_populate_physmap:
         start_extent = cmd >> MEMOP_EXTENT_SHIFT;
 
-        if ( copy_from_guest(&reservation, arg, 1) )
+	cfg_ret = copy_from_guest(&reservation, arg, 1);
+	if ( unlikely(cfg_ret) )
+        {
+            if ( (long)cfg_ret == -EAGAIN )
+                return hypercall_create_continuation(__HYPERVISOR_memory_op, "lh", cmd, arg);
             return start_extent;
+        }
 
         /* Is size too large for us to encode a continuation? */
         if ( reservation.nr_extents > (ULONG_MAX >> MEMOP_EXTENT_SHIFT) )

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 11/12] xenpaging: start xenpaging via config option
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
                   ` (9 preceding siblings ...)
  2011-01-10 16:43 ` [PATCH 10/12] xenpaging: handle HVMCOPY_gfn_paged_out in copy_from/to_user Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-10 16:43 ` [PATCH 12/12] xenpaging: document missing live migration Olaf Hering
  2011-01-11 17:20 ` [PATCH 00/12] xenpaging changes for xen-unstable Ian Jackson
  12 siblings, 0 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.autostart.patch --]
[-- Type: text/plain, Size: 9570 bytes --]

Start xenpaging via config option.

TODO: add config option for different pagefile directory
TODO: add libxl support
TODO: parse config values like 42K, 42M, 42G, 42%

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
v3:
  move debug for stopping xenpaging to destroyXenPaging
v2:
  unlink logfile instead of truncating it.
  allows hardlinking for further inspection

 tools/examples/xmexample.hvm            |    3 +
 tools/python/README.XendConfig          |    1 
 tools/python/README.sxpcfg              |    1 
 tools/python/xen/xend/XendConfig.py     |    3 +
 tools/python/xen/xend/XendDomainInfo.py |    5 +
 tools/python/xen/xend/image.py          |   87 ++++++++++++++++++++++++++++++++
 tools/python/xen/xm/create.py           |    5 +
 tools/python/xen/xm/xenapi_create.py    |    1 
 8 files changed, 106 insertions(+)

--- xen-unstable.hg-4.1.22571.orig/tools/examples/xmexample.hvm
+++ xen-unstable.hg-4.1.22571/tools/examples/xmexample.hvm
@@ -127,6 +127,9 @@ disk = [ 'file:/var/images/min-el3-i386.
 # Device Model to be used
 device_model = 'qemu-dm'
 
+# xenpaging, number of pages, or -1 for entire guest memory range
+xenpaging = 42
+
 #-----------------------------------------------------------------------------
 # boot on floppy (a), hard disk (c), Network (n) or CD-ROM (d) 
 # default: hard disk, cd-rom, floppy
--- xen-unstable.hg-4.1.22571.orig/tools/python/README.XendConfig
+++ xen-unstable.hg-4.1.22571/tools/python/README.XendConfig
@@ -120,6 +120,7 @@ otherConfig
                                 image.vncdisplay
                                 image.vncunused
                                 image.hvm.device_model
+                                image.hvm.xenpaging
                                 image.hvm.display
                                 image.hvm.xauthority
                                 image.hvm.vncconsole
--- xen-unstable.hg-4.1.22571.orig/tools/python/README.sxpcfg
+++ xen-unstable.hg-4.1.22571/tools/python/README.sxpcfg
@@ -51,6 +51,7 @@ image
   - vncunused
   (HVM)
   - device_model
+  - xenpaging
   - display
   - xauthority
   - vncconsole
--- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xend/XendConfig.py
+++ xen-unstable.hg-4.1.22571/tools/python/xen/xend/XendConfig.py
@@ -147,6 +147,7 @@ XENAPI_PLATFORM_CFG_TYPES = {
     'apic': int,
     'boot': str,
     'device_model': str,
+    'xenpaging': int,
     'loader': str,
     'display' : str,
     'fda': str,
@@ -508,6 +509,8 @@ class XendConfig(dict):
             self['platform']['nomigrate'] = 0
 
         if self.is_hvm():
+            if 'xenpaging' not in self['platform']:
+                self['platform']['xenpaging'] = None
             if 'timer_mode' not in self['platform']:
                 self['platform']['timer_mode'] = 1
             if 'viridian' not in self['platform']:
--- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xend/XendDomainInfo.py
+++ xen-unstable.hg-4.1.22571/tools/python/xen/xend/XendDomainInfo.py
@@ -2390,6 +2390,7 @@ class XendDomainInfo:
 
         if self.image:
             self.image.createDeviceModel()
+            self.image.createXenPaging()
 
         #if have pass-through devs, need the virtual pci slots info from qemu
         self.pci_device_configure_boot()
@@ -2402,6 +2403,10 @@ class XendDomainInfo:
                 self.image.destroyDeviceModel()
             except Exception, e:
                 log.exception("Device model destroy failed %s" % str(e))
+            try:
+                self.image.destroyXenPaging()
+            except Exception, e:
+                log.exception("stopping xenpaging failed %s" % str(e))
         else:
             log.debug("No device model")
 
--- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xend/image.py
+++ xen-unstable.hg-4.1.22571/tools/python/xen/xend/image.py
@@ -122,12 +122,16 @@ class ImageHandler:
         self.vm.permissionsVm("image/cmdline", { 'dom': self.vm.getDomid(), 'read': True } )
 
         self.device_model = vmConfig['platform'].get('device_model')
+        self.xenpaging = vmConfig['platform'].get('xenpaging')
+        if self.xenpaging == 0:
+            self.xenpaging = None
 
         self.display = vmConfig['platform'].get('display')
         self.xauthority = vmConfig['platform'].get('xauthority')
         self.vncconsole = int(vmConfig['platform'].get('vncconsole', 0))
         self.dmargs = self.parseDeviceModelArgs(vmConfig)
         self.pid = None
+        self.xenpaging_pid = None
         rtc_timeoffset = int(vmConfig['platform'].get('rtc_timeoffset', 0))
         if int(vmConfig['platform'].get('localtime', 0)):
             if time.localtime(time.time())[8]:
@@ -392,6 +396,89 @@ class ImageHandler:
         sentinel_fifos_inuse[sentinel_path_fifo] = 1
         self.sentinel_path_fifo = sentinel_path_fifo
 
+    def createXenPaging(self):
+        if self.xenpaging is None:
+            return
+        if self.xenpaging_pid:
+            return
+        xenpaging_bin = auxbin.pathTo("xenpaging")
+        args = [xenpaging_bin]
+        args = args + ([ "%d" % self.vm.getDomid()])
+        args = args + ([ "%s" % self.xenpaging])
+        env = dict(os.environ)
+        self.xenpaging_logfile = "/var/log/xen/xenpaging-%s.log" %  str(self.vm.info['name_label'])
+        logfile_mode = os.O_WRONLY|os.O_CREAT|os.O_APPEND|os.O_TRUNC
+        null = os.open("/dev/null", os.O_RDONLY)
+        try:
+            os.unlink(self.xenpaging_logfile)
+        except:
+            pass
+        logfd = os.open(self.xenpaging_logfile, logfile_mode, 0644)
+        sys.stderr.flush()
+        contract = osdep.prefork("%s:%d" % (self.vm.getName(), self.vm.getDomid()))
+        xenpaging_pid = os.fork()
+        if xenpaging_pid == 0: #child
+            try:
+                xenpaging_dir = "/var/lib/xen/xenpaging"
+                osdep.postfork(contract)
+                os.dup2(null, 0)
+                os.dup2(logfd, 1)
+                os.dup2(logfd, 2)
+                try:
+                    os.chdir(xenpaging_dir)
+                except:
+                    log.warn("chdir %s failed" % xenpaging_dir)
+                try:
+                    log.info("starting %s" % args)
+                    os.execve(xenpaging_bin, args, env)
+                except Exception, e:
+                    print >>sys.stderr, (
+                        'failed to execute xenpaging: %s: %s' %
+                        xenpaging_bin, utils.exception_string(e))
+                    os._exit(126)
+            except Exception, e:
+                log.warn("staring xenpaging in %s failed" % xenpaging_dir)
+                os._exit(127)
+        else:
+            osdep.postfork(contract, abandon=True)
+            self.xenpaging_pid = xenpaging_pid
+            os.close(null)
+            os.close(logfd)
+
+    def destroyXenPaging(self):
+        if self.xenpaging is None:
+            return
+        log.debug("stopping xenpaging")
+        if self.xenpaging_pid:
+            try:
+                os.kill(self.xenpaging_pid, signal.SIGHUP)
+            except OSError, exn:
+                log.exception(exn)
+            for i in xrange(100):
+                try:
+                    (p, rv) = os.waitpid(self.xenpaging_pid, os.WNOHANG)
+                    if p == self.xenpaging_pid:
+                        break
+                except OSError:
+                    # This is expected if Xend has been restarted within
+                    # the life of this domain.  In this case, we can kill
+                    # the process, but we can't wait for it because it's
+                    # not our child. We continue this loop, and after it is
+                    # terminated make really sure the process is going away
+                    # (SIGKILL).
+                    pass
+                time.sleep(0.1)
+            else:
+                log.warning("xenpaging %d took more than 10s "
+                            "to terminate: sending SIGKILL" % self.xenpaging_pid)
+                try:
+                    os.kill(self.xenpaging_pid, signal.SIGKILL)
+                    os.waitpid(self.xenpaging_pid, 0)
+                except OSError:
+                    # This happens if the process doesn't exist.
+                    pass
+        self.xenpaging_pid = None
+
     def createDeviceModel(self, restore = False):
         if self.device_model is None:
             return
--- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xm/create.py
+++ xen-unstable.hg-4.1.22571/tools/python/xen/xm/create.py
@@ -491,6 +491,10 @@ gopts.var('nfs_root', val="PATH",
           fn=set_value, default=None,
           use="Set the path of the root NFS directory.")
 
+gopts.var('xenpaging', val='NUM',
+          fn=set_int, default=None,
+          use="Number of pages to swap.")
+
 gopts.var('device_model', val='FILE',
           fn=set_value, default=None,
           use="Path to device model program.")
@@ -1076,6 +1080,7 @@ def configure_hvm(config_image, vals):
     args = [ 'acpi', 'apic',
              'boot',
              'cpuid', 'cpuid_check',
+             'xenpaging',
              'device_model', 'display',
              'fda', 'fdb',
              'gfx_passthru', 'guest_os_type',
--- xen-unstable.hg-4.1.22571.orig/tools/python/xen/xm/xenapi_create.py
+++ xen-unstable.hg-4.1.22571/tools/python/xen/xm/xenapi_create.py
@@ -1085,6 +1085,7 @@ class sxp2xml:
             'acpi',
             'apic',
             'boot',
+            'xenpaging',
             'device_model',
             'loader',
             'fda',

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 12/12] xenpaging: document missing live migration
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
                   ` (10 preceding siblings ...)
  2011-01-10 16:43 ` [PATCH 11/12] xenpaging: start xenpaging via config option Olaf Hering
@ 2011-01-10 16:43 ` Olaf Hering
  2011-01-11 17:20 ` [PATCH 00/12] xenpaging changes for xen-unstable Ian Jackson
  12 siblings, 0 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-10 16:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: xen-unstable.xenpaging.doc.patch --]
[-- Type: text/plain, Size: 429 bytes --]

live migration does not work yet

Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
 docs/misc/xenpaging.txt |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- xen-unstable.hg-4.1.22571.orig/docs/misc/xenpaging.txt
+++ xen-unstable.hg-4.1.22571/docs/misc/xenpaging.txt
@@ -42,7 +42,7 @@ changes.
 
 Todo:
 - implement stopping of xenpaging
-- implement/test live migration
+- implement live migration
 
 
 # vim: tw=72

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation
  2011-01-10 16:43 ` [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation Olaf Hering
@ 2011-01-11 10:37   ` Keir Fraser
  2011-01-11 11:00     ` Olaf Hering
  0 siblings, 1 reply; 19+ messages in thread
From: Keir Fraser @ 2011-01-11 10:37 UTC (permalink / raw)
  To: Olaf Hering, xen-devel

Could we do this in free_heap_pages() instead? That definitely catches
everything that gets placed in Xen's free pool.

 -- Keir

On 10/01/2011 16:43, "Olaf Hering" <olaf@aepfle.de> wrote:

> The machine_to_phys_mapping[] array needs updating during page
> deallocation.  If that page is allocated again, a call to
> get_gpfn_from_mfn() will still return an old gfn from another guest.
> This will cause trouble because this gfn number has no or different
> meaning in the context of the current guest.
> 
> This happens when the entire guest ram is paged-out before
> xen_vga_populate_vram() runs.  Then XENMEM_populate_physmap is called
> with gfn 0xff000.  A new page is allocated with alloc_domheap_pages.
> This new page does not have a gfn yet.  However, in
> guest_physmap_add_entry() the passed mfn maps still to an old gfn
> (perhaps from another old guest).  This old gfn is in paged-out state in
> this guests context and has no mfn anymore.  As a result, the ASSERT()
> triggers because p2m_is_ram() is true for p2m_ram_paging* types.
> If the machine_to_phys_mapping[] array is updated properly, both loops
> in guest_physmap_add_entry() turn into no-ops for the new page and the
> mfn/gfn mapping will be done at the end of the function.
> 
> If XENMEM_add_to_physmap is used with XENMAPSPACE_gmfn,
> get_gpfn_from_mfn() will return an appearently valid gfn.  As a result,
> guest_physmap_remove_page() is called.  The ASSERT in p2m_remove_page
> triggers because the passed mfn does not match the old mfn for the
> passed gfn.
> 
> 
> Signed-off-by: Olaf Hering <olaf@aepfle.de>
> 
> ---
>  xen/common/page_alloc.c |    6 ++++++
>  1 file changed, 6 insertions(+)
> 
> --- xen-unstable.hg-4.1.22571.orig/xen/common/page_alloc.c
> +++ xen-unstable.hg-4.1.22571/xen/common/page_alloc.c
> @@ -1200,9 +1200,15 @@ void free_domheap_pages(struct page_info
>  {
>      int            i, drop_dom_ref;
>      struct domain *d = page_get_owner(pg);
> +    unsigned long mfn;
>  
>      ASSERT(!in_irq());
>  
> +    /* this page is not a gfn anymore */
> +    mfn = page_to_mfn(pg);
> +    for ( i = 0; i < (1 << order); i++ )
> +        set_gpfn_from_mfn(mfn + i, INVALID_M2P_ENTRY);
> +
>      if ( unlikely(is_xen_heap_page(pg)) )
>      {
>          /* NB. May recursively lock from relinquish_memory(). */
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation
  2011-01-11 10:37   ` Keir Fraser
@ 2011-01-11 11:00     ` Olaf Hering
  2011-01-11 11:29       ` Keir Fraser
  0 siblings, 1 reply; 19+ messages in thread
From: Olaf Hering @ 2011-01-11 11:00 UTC (permalink / raw)
  To: Keir Fraser; +Cc: xen-devel

On Tue, Jan 11, Keir Fraser wrote:

> Could we do this in free_heap_pages() instead? That definitely catches
> everything that gets placed in Xen's free pool.

Yes, this is a compile-tested patch.


The machine_to_phys_mapping[] array needs updating during page
deallocation.  If that page is allocated again, a call to
get_gpfn_from_mfn() will still return an old gfn from another guest.
This will cause trouble because this gfn number has no or different
meaning in the context of the current guest.

This happens when the entire guest ram is paged-out before
xen_vga_populate_vram() runs.  Then XENMEM_populate_physmap is called
with gfn 0xff000.  A new page is allocated with alloc_domheap_pages.
This new page does not have a gfn yet.  However, in
guest_physmap_add_entry() the passed mfn maps still to an old gfn
(perhaps from another old guest).  This old gfn is in paged-out state in
this guests context and has no mfn anymore.  As a result, the ASSERT()
triggers because p2m_is_ram() is true for p2m_ram_paging* types.
If the machine_to_phys_mapping[] array is updated properly, both loops
in guest_physmap_add_entry() turn into no-ops for the new page and the
mfn/gfn mapping will be done at the end of the function.

If XENMEM_add_to_physmap is used with XENMAPSPACE_gmfn,
get_gpfn_from_mfn() will return an appearently valid gfn.  As a result,
guest_physmap_remove_page() is called.  The ASSERT in p2m_remove_page
triggers because the passed mfn does not match the old mfn for the
passed gfn.


Signed-off-by: Olaf Hering <olaf@aepfle.de>

---
v2:
    move from free_domheap_pages() to free_heap_pages() as suggested by Keir

 xen/common/page_alloc.c |    6 ++++++
 1 file changed, 6 insertions(+)

--- xen-unstable.hg-4.1.22697.orig/xen/common/page_alloc.c
+++ xen-unstable.hg-4.1.22697/xen/common/page_alloc.c
@@ -527,6 +527,7 @@ static int reserve_offlined_page(struct
 static void free_heap_pages(
     struct page_info *pg, unsigned int order)
 {
+    unsigned long mfn;
     unsigned long mask;
     unsigned int i, node = phys_to_nid(page_to_maddr(pg)), tainted = 0;
     unsigned int zone = page_to_zone(pg);
@@ -536,6 +537,11 @@ static void free_heap_pages(
 
     spin_lock(&heap_lock);
 
+    /* this page is not a gfn anymore */
+    mfn = page_to_mfn(pg);
+    for ( i = 0; i < (1 << order); i++ )
+        set_gpfn_from_mfn(mfn + i, INVALID_M2P_ENTRY);
+
     for ( i = 0; i < (1 << order); i++ )
     {
         /*

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation
  2011-01-11 11:00     ` Olaf Hering
@ 2011-01-11 11:29       ` Keir Fraser
  0 siblings, 0 replies; 19+ messages in thread
From: Keir Fraser @ 2011-01-11 11:29 UTC (permalink / raw)
  To: Olaf Hering; +Cc: xen-devel

On 11/01/2011 11:00, "Olaf Hering" <olaf@aepfle.de> wrote:

> On Tue, Jan 11, Keir Fraser wrote:
> 
>> Could we do this in free_heap_pages() instead? That definitely catches
>> everything that gets placed in Xen's free pool.
> 
> Yes, this is a compile-tested patch.

Thanks. I fixed a subtle bug (rather disgustingly, set_gpfn_from_mfn()
depends on page_get_owner(mfn_to_page(mfn))), and checked it in as c/s
22706.

 -- Keir

> 
> The machine_to_phys_mapping[] array needs updating during page
> deallocation.  If that page is allocated again, a call to
> get_gpfn_from_mfn() will still return an old gfn from another guest.
> This will cause trouble because this gfn number has no or different
> meaning in the context of the current guest.
> 
> This happens when the entire guest ram is paged-out before
> xen_vga_populate_vram() runs.  Then XENMEM_populate_physmap is called
> with gfn 0xff000.  A new page is allocated with alloc_domheap_pages.
> This new page does not have a gfn yet.  However, in
> guest_physmap_add_entry() the passed mfn maps still to an old gfn
> (perhaps from another old guest).  This old gfn is in paged-out state in
> this guests context and has no mfn anymore.  As a result, the ASSERT()
> triggers because p2m_is_ram() is true for p2m_ram_paging* types.
> If the machine_to_phys_mapping[] array is updated properly, both loops
> in guest_physmap_add_entry() turn into no-ops for the new page and the
> mfn/gfn mapping will be done at the end of the function.
> 
> If XENMEM_add_to_physmap is used with XENMAPSPACE_gmfn,
> get_gpfn_from_mfn() will return an appearently valid gfn.  As a result,
> guest_physmap_remove_page() is called.  The ASSERT in p2m_remove_page
> triggers because the passed mfn does not match the old mfn for the
> passed gfn.
> 
> 
> Signed-off-by: Olaf Hering <olaf@aepfle.de>
> 
> ---
> v2:
>     move from free_domheap_pages() to free_heap_pages() as suggested by Keir
> 
>  xen/common/page_alloc.c |    6 ++++++
>  1 file changed, 6 insertions(+)
> 
> --- xen-unstable.hg-4.1.22697.orig/xen/common/page_alloc.c
> +++ xen-unstable.hg-4.1.22697/xen/common/page_alloc.c
> @@ -527,6 +527,7 @@ static int reserve_offlined_page(struct
>  static void free_heap_pages(
>      struct page_info *pg, unsigned int order)
>  {
> +    unsigned long mfn;
>      unsigned long mask;
>      unsigned int i, node = phys_to_nid(page_to_maddr(pg)), tainted = 0;
>      unsigned int zone = page_to_zone(pg);
> @@ -536,6 +537,11 @@ static void free_heap_pages(
>  
>      spin_lock(&heap_lock);
>  
> +    /* this page is not a gfn anymore */
> +    mfn = page_to_mfn(pg);
> +    for ( i = 0; i < (1 << order); i++ )
> +        set_gpfn_from_mfn(mfn + i, INVALID_M2P_ENTRY);
> +
>      for ( i = 0; i < (1 << order); i++ )
>      {
>          /*

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 00/12] xenpaging changes for xen-unstable
  2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
                   ` (11 preceding siblings ...)
  2011-01-10 16:43 ` [PATCH 12/12] xenpaging: document missing live migration Olaf Hering
@ 2011-01-11 17:20 ` Ian Jackson
  12 siblings, 0 replies; 19+ messages in thread
From: Ian Jackson @ 2011-01-11 17:20 UTC (permalink / raw)
  To: Olaf Hering; +Cc: xen-devel

Olaf Hering writes ("[Xen-devel] [PATCH 00/12] xenpaging changes for xen-unstable"):
> Here are some changes for xenpaging in xen-unstable.

Thanks.

> New to this series since my last post are patch 1 to 5.
> They are likely non-controversial and could be applied.

Yes, I intend to apply 1-5 to xen-unstable.hg now unless someone
shouts to tell me not to.

> Patches 6 and 7 are required to maintain the machine_to_phys_mapping[]
> array properly. Unless there are objections to the deallocation part,
> they could be applied.
> 
> Patch 8 could be applied as well.

Does 8 depend on 6 and 7 ?

> As it stands right now, a guest will hang hard with xenpaging once the
> balloon driver is loaded in the guest. Its not clear what the issue is,
> no memory_op hypercall has been issued yet. xm vcpu-list indicates the
> guest makes no progress.  I will debug this further.

Thanks.  Bear in mind that we are in at the end of the release cycle
now and the tree is becoming more and more frozen.

Since xenpaging doesn't work properly without your patches they're
bugfixes but we do want to get all of them in sooner rather than
later.  It's possible that we'll have to release without all the
changes you might want to make :-/.

Thanks,
Ian.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 05/12] xenpaging: make three functions static
  2011-01-10 16:43 ` [PATCH 05/12] xenpaging: make three functions static Olaf Hering
@ 2011-01-11 18:36   ` Ian Jackson
  0 siblings, 0 replies; 19+ messages in thread
From: Ian Jackson @ 2011-01-11 18:36 UTC (permalink / raw)
  To: Olaf Hering; +Cc: xen-devel

Olaf Hering writes ("[Xen-devel] [PATCH 05/12] xenpaging: make three functions static"):
> xenpaging_init(), xenpaging_teardown() and xenpaging_evict_page() are
> only used in file scope, so they can be marked static.

I see Keir has applied 1-6.

Ian.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 08/12] xenpaging: drop paged pages in guest_remove_page
  2011-01-10 16:43 ` [PATCH 08/12] xenpaging: drop paged pages in guest_remove_page Olaf Hering
@ 2011-01-14 16:53   ` Olaf Hering
  0 siblings, 0 replies; 19+ messages in thread
From: Olaf Hering @ 2011-01-14 16:53 UTC (permalink / raw)
  To: xen-devel

On Mon, Jan 10, Olaf Hering wrote:

> Simply drop paged-pages in guest_remove_page(), and notify xenpaging to
> drop its reference to the gfn. If the ring is full, the page will
> remain in paged-out state in xenpaging. This is not an issue, it just
> means this gfn will not be nominated again.

>  send one-way notification to pager to release page

Here I need some help to make that a true one-way event.

The currently applied version of the patch just fills up the ring, with
the result that the guest can not proceed because there is no way to
tell the pager about required page-in requests.

How can the request which was just consumed with get_response() be freed
from the ring buffer? I tried a modified version of
mem_event_pause_vcpu() which does not call mem_event_pause_vcpu(), but
that does not change anything. It seems the stuck guest is a result of
incorrect mem_event_ring handling.

Olaf

> +void p2m_mem_paging_drop_page(struct p2m_domain *p2m, unsigned long gfn)
> +{
> +    struct vcpu *v = current;
> +    mem_event_request_t req;
> +    struct domain *d = p2m->domain;
> +
> +    /* Check that there's space on the ring for this request */
> +    if ( mem_event_check_ring(d) == 0)
> +    {
> +        /* Send release notification to pager */
> +        memset(&req, 0, sizeof(req));
> +        req.flags |= MEM_EVENT_FLAG_DROP_PAGE;
> +        req.gfn = gfn;
> +        req.vcpu_id = v->vcpu_id;
> +
> +        mem_event_put_request(d, &req);
> +    }
> +}
> +

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2011-01-14 16:53 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-10 16:43 [PATCH 00/12] xenpaging changes for xen-unstable Olaf Hering
2011-01-10 16:43 ` [PATCH 01/12] xenpaging: remove domain_id and mfn from struct xenpaging_victim Olaf Hering
2011-01-10 16:43 ` [PATCH 02/12] xenpaging: specify policy mru_size at runtime Olaf Hering
2011-01-10 16:43 ` [PATCH 03/12] xenpaging: mkdir /var/lib/xen/xenpaging during make install Olaf Hering
2011-01-10 16:43 ` [PATCH 04/12] xenpaging: print page-in/page-out progress Olaf Hering
2011-01-10 16:43 ` [PATCH 05/12] xenpaging: make three functions static Olaf Hering
2011-01-11 18:36   ` Ian Jackson
2011-01-10 16:43 ` [PATCH 06/12] xenpaging: update machine_to_phys_mapping[] during page deallocation Olaf Hering
2011-01-11 10:37   ` Keir Fraser
2011-01-11 11:00     ` Olaf Hering
2011-01-11 11:29       ` Keir Fraser
2011-01-10 16:43 ` [PATCH 07/12] xenpaging: update machine_to_phys_mapping[] during page-in Olaf Hering
2011-01-10 16:43 ` [PATCH 08/12] xenpaging: drop paged pages in guest_remove_page Olaf Hering
2011-01-14 16:53   ` Olaf Hering
2011-01-10 16:43 ` [PATCH 09/12] xenpaging: prevent page-out of gfn 0x80 Olaf Hering
2011-01-10 16:43 ` [PATCH 10/12] xenpaging: handle HVMCOPY_gfn_paged_out in copy_from/to_user Olaf Hering
2011-01-10 16:43 ` [PATCH 11/12] xenpaging: start xenpaging via config option Olaf Hering
2011-01-10 16:43 ` [PATCH 12/12] xenpaging: document missing live migration Olaf Hering
2011-01-11 17:20 ` [PATCH 00/12] xenpaging changes for xen-unstable Ian Jackson

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.