mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
Move the suspend event channel function to libxc, it will use the
/var/lib/xen/suspend_evtchn_lock.d to protect the access. Signed-off-by: Jiang Yunhong <yunhong.jiang@intel.com>
This commit is contained in:
1 parent
760f973171
commit
cce99fb132
5 files changed
+161
-86
No files matched your search
@@ -744,7 +744,114 @@ static xen_pfn_t *map_and_save_p2m_table(int xc_handle,
|
||||
return success ? p2m : NULL;
|
||||
}
|
||||
|
||||
#define SUSPEND_LOCK_FILE "/var/lib/xen/suspend_evtchn_lock.d"
|
||||
static int lock_suspend_event(void)
|
||||
{
|
||||
int fd;
|
||||
mode_t mask;
|
||||
char buf[128];
|
||||
|
||||
mask = umask(022);
|
||||
fd = open(SUSPEND_LOCK_FILE, O_CREAT | O_EXCL | O_RDWR, 0666);
|
||||
if (fd < 0)
|
||||
{
|
||||
ERROR("Can't create lock file for suspend event channel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
umask(mask);
|
||||
snprintf(buf, sizeof(buf), "%10ld", (long)getpid());
|
||||
|
||||
write(fd, buf, strlen(buf));
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unlock_suspend_event(void)
|
||||
{
|
||||
int fd, pid, n;
|
||||
char buf[128];
|
||||
|
||||
fd = open(SUSPEND_LOCK_FILE, O_RDWR);
|
||||
|
||||
if (fd < 0)
|
||||
return -EINVAL;
|
||||
|
||||
n = read(fd, buf, 127);
|
||||
|
||||
close(fd);
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
sscanf(buf, "%d", &pid);
|
||||
/* We are the owner, so we can simply delete the file */
|
||||
if (pid == getpid())
|
||||
{
|
||||
unlink(SUSPEND_LOCK_FILE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
int xc_await_suspend(int xce, int suspend_evtchn)
|
||||
{
|
||||
int rc;
|
||||
|
||||
do {
|
||||
rc = xc_evtchn_pending(xce);
|
||||
if (rc < 0) {
|
||||
ERROR("error polling suspend notification channel: %d", rc);
|
||||
return -1;
|
||||
}
|
||||
} while (rc != suspend_evtchn);
|
||||
|
||||
/* harmless for one-off suspend */
|
||||
if (xc_evtchn_unmask(xce, suspend_evtchn) < 0)
|
||||
ERROR("failed to unmask suspend notification channel: %d", rc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xc_suspend_evtchn_release(int xce, int suspend_evtchn)
|
||||
{
|
||||
if (suspend_evtchn >= 0)
|
||||
xc_evtchn_unbind(xce, suspend_evtchn);
|
||||
|
||||
return unlock_suspend_event();
|
||||
}
|
||||
|
||||
int xc_suspend_evtchn_init(int xc, int xce, int domid, int port)
|
||||
{
|
||||
int rc, suspend_evtchn = -1;
|
||||
|
||||
if (lock_suspend_event())
|
||||
return -EINVAL;
|
||||
|
||||
suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port);
|
||||
if (suspend_evtchn < 0) {
|
||||
ERROR("failed to bind suspend event channel: %d", suspend_evtchn);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = xc_domain_subscribe_for_suspend(xc, domid, port);
|
||||
if (rc < 0) {
|
||||
ERROR("failed to subscribe to domain: %d", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* event channel is pending immediately after binding */
|
||||
xc_await_suspend(xce, suspend_evtchn);
|
||||
|
||||
return suspend_evtchn;
|
||||
|
||||
cleanup:
|
||||
if (suspend_evtchn > 0)
|
||||
xc_suspend_evtchn_release(xce, suspend_evtchn);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
uint32_t max_factor, uint32_t flags, int (*suspend)(void),
|
||||
|
||||
@@ -142,4 +142,10 @@ int xc_hvm_build_mem(int xc_handle,
|
||||
const char *image_buffer,
|
||||
unsigned long image_size);
|
||||
|
||||
int xc_suspend_evtchn_release(int xce, int suspend_evtchn);
|
||||
|
||||
int xc_suspend_evtchn_init(int xc, int xce, int domid, int port);
|
||||
|
||||
int xc_await_suspend(int xce, int suspend_evtchn);
|
||||
|
||||
#endif /* XENGUEST_H */
|
||||
+22
-86
@@ -46,83 +46,6 @@ static int compat_suspend(void)
|
||||
!strncmp(ans, "done\n", 5));
|
||||
}
|
||||
|
||||
static int suspend_evtchn_release(int xce, int suspend_evtchn)
|
||||
{
|
||||
if (suspend_evtchn >= 0)
|
||||
xc_evtchn_unbind(xce, suspend_evtchn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int await_suspend(int xce, int suspend_evtchn)
|
||||
{
|
||||
int rc;
|
||||
|
||||
do {
|
||||
rc = xc_evtchn_pending(xce);
|
||||
if (rc < 0) {
|
||||
warnx("error polling suspend notification channel: %d", rc);
|
||||
return -1;
|
||||
}
|
||||
} while (rc != suspend_evtchn);
|
||||
|
||||
/* harmless for one-off suspend */
|
||||
if (xc_evtchn_unmask(xce, suspend_evtchn) < 0)
|
||||
warnx("failed to unmask suspend notification channel: %d", rc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int suspend_evtchn_init(int xc, int xce, int domid)
|
||||
{
|
||||
struct xs_handle *xs;
|
||||
char path[128];
|
||||
char *portstr;
|
||||
unsigned int plen;
|
||||
int port;
|
||||
int rc, suspend_evtchn = -1;
|
||||
|
||||
xs = xs_daemon_open();
|
||||
if (!xs) {
|
||||
warnx("failed to get xenstore handle");
|
||||
return -1;
|
||||
}
|
||||
sprintf(path, "/local/domain/%d/device/suspend/event-channel", domid);
|
||||
portstr = xs_read(xs, XBT_NULL, path, &plen);
|
||||
xs_daemon_close(xs);
|
||||
|
||||
if (!portstr || !plen) {
|
||||
warnx("could not read suspend event channel");
|
||||
return -1;
|
||||
}
|
||||
|
||||
port = atoi(portstr);
|
||||
free(portstr);
|
||||
|
||||
suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port);
|
||||
if (suspend_evtchn < 0) {
|
||||
warnx("failed to bind suspend event channel: %d", si.suspend_evtchn);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = xc_domain_subscribe_for_suspend(xc, domid, port);
|
||||
if (rc < 0) {
|
||||
warnx("failed to subscribe to domain: %d", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* event channel is pending immediately after binding */
|
||||
await_suspend(xce, suspend_evtchn);
|
||||
|
||||
return suspend_evtchn;
|
||||
|
||||
cleanup:
|
||||
if (suspend_evtchn > 0)
|
||||
suspend_evtchn_release(xce, suspend_evtchn);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue a suspend request to a dedicated event channel in the guest, and
|
||||
* receive the acknowledgement from the subscribe event channel. */
|
||||
@@ -136,7 +59,7 @@ static int evtchn_suspend(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (await_suspend(si.xce, si.suspend_evtchn) < 0) {
|
||||
if (xc_await_suspend(si.xce, si.suspend_evtchn) < 0) {
|
||||
warnx("suspend failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -289,12 +212,11 @@ static void *init_qemu_maps(int domid, unsigned int bitmap_size)
|
||||
return seg;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
unsigned int maxit, max_f;
|
||||
int io_fd, ret;
|
||||
int io_fd, ret, port;
|
||||
|
||||
if (argc != 6)
|
||||
errx(1, "usage: %s iofd domid maxit maxf flags", argv[0]);
|
||||
@@ -309,23 +231,37 @@ main(int argc, char **argv)
|
||||
max_f = atoi(argv[4]);
|
||||
si.flags = atoi(argv[5]);
|
||||
|
||||
si.suspend_evtchn = si.xce = -1;
|
||||
|
||||
si.xce = xc_evtchn_open();
|
||||
if (si.xce < 0)
|
||||
errx(1, "failed to open event channel handle");
|
||||
warnx("failed to open event channel handle");
|
||||
|
||||
si.suspend_evtchn = suspend_evtchn_init(si.xc_fd, si.xce, si.domid);
|
||||
if (si.xce > 0)
|
||||
{
|
||||
port = xs_suspend_evtchn_port(si.domid);
|
||||
|
||||
if (si.suspend_evtchn < 0)
|
||||
warnx("suspend event channel initialization failed, using slow path");
|
||||
if (port < 0)
|
||||
warnx("faield to get the suspend evtchn port\n");
|
||||
else
|
||||
{
|
||||
si.suspend_evtchn =
|
||||
xc_suspend_evtchn_init(si.xc_fd, si.xce, si.domid, port);
|
||||
|
||||
if (si.suspend_evtchn < 0)
|
||||
warnx("suspend event channel initialization failed"
|
||||
"using slow path");
|
||||
}
|
||||
}
|
||||
ret = xc_domain_save(si.xc_fd, io_fd, si.domid, maxit, max_f, si.flags,
|
||||
&suspend, !!(si.flags & XCFLAGS_HVM),
|
||||
&init_qemu_maps, &qemu_flip_buffer);
|
||||
|
||||
suspend_evtchn_release(si.xce, si.suspend_evtchn);
|
||||
if (si.suspend_evtchn > 0)
|
||||
xc_suspend_evtchn_release(si.xce, si.suspend_evtchn);
|
||||
|
||||
xc_evtchn_close(si.xce);
|
||||
if (si.xce > 0)
|
||||
xc_evtchn_close(si.xce);
|
||||
|
||||
xc_interface_close(si.xc_fd);
|
||||
|
||||
|
||||
@@ -802,6 +802,31 @@ bool xs_is_domain_introduced(struct xs_handle *h, unsigned int domid)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int xs_suspend_evtchn_port(int domid)
|
||||
{
|
||||
char path[128];
|
||||
char *portstr;
|
||||
int port;
|
||||
unsigned int plen;
|
||||
struct xs_handle *xs;
|
||||
|
||||
xs = xs_daemon_open();
|
||||
if (!xs)
|
||||
return -1;
|
||||
|
||||
sprintf(path, "/local/domain/%d/device/suspend/event-channel", domid);
|
||||
portstr = xs_read(xs, XBT_NULL, path, &plen);
|
||||
xs_daemon_close(xs);
|
||||
|
||||
if (!portstr || !plen)
|
||||
return -1;
|
||||
|
||||
port = atoi(portstr);
|
||||
free(portstr);
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
/* Only useful for DEBUG versions */
|
||||
char *xs_debug_command(struct xs_handle *h, const char *cmd,
|
||||
void *data, unsigned int len)
|
||||
|
||||
@@ -163,6 +163,7 @@ bool xs_is_domain_introduced(struct xs_handle *h, unsigned int domid);
|
||||
char *xs_debug_command(struct xs_handle *h, const char *cmd,
|
||||
void *data, unsigned int len);
|
||||
|
||||
int xs_suspend_evtchn_port(int domid);
|
||||
#endif /* _XS_H */
|
||||
|
||||
/*
|
||||
|
||||