ia64/xen-unstable

view tools/libxc/xc_suspend.c @ 19691:f44438bc79ac

libxc: Exchange a page for PV guest

This patch support exchange a page for a suspended PV guest from user
space.

The basic idea to offline a page is:
1) mark a page offline pending
2) If the page is owned by a HVM domain, user have to live migrate it.
In future, with stub-domain support, we can also exchange the page
without migration.
3) If the page is owned by a PV domain, we will try to exchange the
offline pending page to a new one and free the old page.

This patch achieves item 3.

The method to exchange the offline pending page for PV domain is:

1) Suspend the guest.
2) If the page is being granted out, return with offline pending.
3) Get a copy for the content
4) Scan all page table page to see if any reference to the offending
page, if yes, make the entry to be non-present to reduce the reference
count.
5) After update all page tables, user space tools will try to exchange
the old page. If the new mfn has no reference anymore (i.e.
count_info & count_mask =3D 1), the exchange will allocate a new page,
update the m2p and return success, otherwise it will return fail.
6) If step 5 is success, user space tools will update the content of
the new page change the p2m table, and change all entries scaned in
step 4 to point to new entry.
if step failed, it will try to undo step 4 to revert page table.
7) Resume the guest.

Please refer to thread in
http://www.mailinglistarchive.com/xen-devel@lists.xensource.com/msg63084.html
for more information.

Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jun 01 14:15:48 2009 +0100 (2009-06-01)
parents 0b13d9787622
children
line source
1 /*
2 * This file is subject to the terms and conditions of the GNU General
3 * Public License. See the file "COPYING" in the main directory of
4 * this archive for more details.
5 */
7 #include "xc_private.h"
8 #include "xenguest.h"
10 #define SUSPEND_LOCK_FILE "/var/lib/xen/suspend_evtchn_lock.d"
11 static int lock_suspend_event(void)
12 {
13 int fd, rc;
14 mode_t mask;
15 char buf[128];
17 mask = umask(022);
18 fd = open(SUSPEND_LOCK_FILE, O_CREAT | O_EXCL | O_RDWR, 0666);
19 if (fd < 0)
20 {
21 ERROR("Can't create lock file for suspend event channel\n");
22 return -EINVAL;
23 }
24 umask(mask);
25 snprintf(buf, sizeof(buf), "%10ld", (long)getpid());
27 rc = write_exact(fd, buf, strlen(buf));
28 close(fd);
30 return rc;
31 }
33 static int unlock_suspend_event(void)
34 {
35 int fd, pid, n;
36 char buf[128];
38 fd = open(SUSPEND_LOCK_FILE, O_RDWR);
40 if (fd < 0)
41 return -EINVAL;
43 n = read(fd, buf, 127);
45 close(fd);
47 if (n > 0)
48 {
49 sscanf(buf, "%d", &pid);
50 /* We are the owner, so we can simply delete the file */
51 if (pid == getpid())
52 {
53 unlink(SUSPEND_LOCK_FILE);
54 return 0;
55 }
56 }
58 return -EPERM;
59 }
61 int xc_await_suspend(int xce, int suspend_evtchn)
62 {
63 int rc;
65 do {
66 rc = xc_evtchn_pending(xce);
67 if (rc < 0) {
68 ERROR("error polling suspend notification channel: %d", rc);
69 return -1;
70 }
71 } while (rc != suspend_evtchn);
73 /* harmless for one-off suspend */
74 if (xc_evtchn_unmask(xce, suspend_evtchn) < 0)
75 ERROR("failed to unmask suspend notification channel: %d", rc);
77 return 0;
78 }
80 int xc_suspend_evtchn_release(int xce, int suspend_evtchn)
81 {
82 if (suspend_evtchn >= 0)
83 xc_evtchn_unbind(xce, suspend_evtchn);
85 return unlock_suspend_event();
86 }
88 int xc_suspend_evtchn_init(int xc, int xce, int domid, int port)
89 {
90 int rc, suspend_evtchn = -1;
92 if (lock_suspend_event())
93 return -EINVAL;
95 suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port);
96 if (suspend_evtchn < 0) {
97 ERROR("failed to bind suspend event channel: %d", suspend_evtchn);
98 goto cleanup;
99 }
101 rc = xc_domain_subscribe_for_suspend(xc, domid, port);
102 if (rc < 0) {
103 ERROR("failed to subscribe to domain: %d", rc);
104 goto cleanup;
105 }
107 /* event channel is pending immediately after binding */
108 xc_await_suspend(xce, suspend_evtchn);
110 return suspend_evtchn;
112 cleanup:
113 if (suspend_evtchn != -1)
114 xc_suspend_evtchn_release(xce, suspend_evtchn);
116 return -1;
117 }