Fix qemu spawn for Solaris

On Solaris, xend runs in a 'process contract' such that all children
are killed when the service is restarted.  Spawn qemu processes in a
new contract to avoid this.

Signed-off-by: John Levon <john.levon@sun.com>
This commit is contained in:
Keir Fraser committed 2009-03-12 11:07:00 +00:00
1 parent eb10d0f954
commit 43a12c170e
4 files changed
+205

No files matched your search

+8
View File
@@ -38,6 +38,13 @@ scf = Extension("scf",
libraries = libraries,
sources = [ "xen/lowlevel/scf/scf.c" ])
process = Extension("process",
extra_compile_args = extra_compile_args,
include_dirs = include_dirs + [ "xen/lowlevel/process" ],
library_dirs = library_dirs,
libraries = libraries + [ "contract" ],
sources = [ "xen/lowlevel/process/process.c" ])
acm = Extension("acm",
extra_compile_args = extra_compile_args,
include_dirs = include_dirs + [ "xen/lowlevel/acm" ],
@@ -63,6 +70,7 @@ ptsname = Extension("ptsname",
modules = [ xc, xs, ptsname, acm, flask ]
if os.uname()[0] == 'SunOS':
modules.append(scf)
modules.append(process)
setup(name = 'xen',
version = '3.0',
+164
View File
@@ -0,0 +1,164 @@
/*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <Python.h>
#include <libcontract.h>
#include <sys/contract/process.h>
#include <fcntl.h>
#include <stdio.h>
/*
* On Solaris, xend runs under a contract as an smf(5) service. As a
* result, when spawning long-running children such as a domain's
* qemu-dm instantiation, we have to make sure it's in a separate
* contract. Before we fork, we must activate a separate process
* contract template to place the child processes in a new contract.
*/
static PyObject *
pyprocess_activate(PyObject *o, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "name", NULL };
char *name = NULL;
int flags;
int cfd;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwlist, &name))
return (NULL);
cfd = open64("/system/contract/process/template", O_RDWR);
if (cfd == -1)
goto err;
if ((flags = fcntl(cfd, F_GETFD, 0)) == -1)
goto err;
if (fcntl(cfd, F_SETFD, flags | FD_CLOEXEC) == -1)
goto err;
if (name != NULL)
ct_pr_tmpl_set_svc_aux(cfd, name);
if (ct_tmpl_activate(cfd))
goto err;
return (PyInt_FromLong((long)cfd));
err:
if (cfd != -1)
close(cfd);
PyErr_SetFromErrno(PyExc_OSError);
return (NULL);
}
static PyObject *
pyprocess_clear(PyObject *o, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "contract", NULL };
int cfd;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &cfd))
return (NULL);
if (ct_tmpl_clear(cfd) != 0) {
PyErr_SetFromErrno(PyExc_OSError);
return (NULL);
}
close(cfd);
Py_INCREF(Py_None);
return (Py_None);
}
static PyObject *
pyprocess_abandon_latest(PyObject *o, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { NULL };
static char path[PATH_MAX];
ct_stathdl_t st;
ctid_t latest;
int cfd;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist))
return (NULL);
cfd = open64("/system/contract/process/latest", O_RDONLY);
if (cfd == -1)
goto err;
ct_status_read(cfd, CTD_COMMON, &st);
latest = ct_status_get_id(st);
ct_status_free(st);
close(cfd);
snprintf(path, PATH_MAX, "/system/contract/process/%ld/ctl",
(long)latest);
if ((cfd = open64(path, O_WRONLY)) < 0)
goto err;
if (ct_ctl_abandon(cfd))
goto err;
close(cfd);
Py_INCREF(Py_None);
return (Py_None);
err:
PyErr_SetFromErrno(PyExc_OSError);
return (NULL);
}
PyDoc_STRVAR(pyprocess_activate__doc__,
"activate(name)\n"
"\n"
"Activate a new process contract template. If name is given,\n"
"it is used as the template's auxiliary value.\n"
"Returns the new contract template.\n");
PyDoc_STRVAR(pyprocess_clear__doc__,
"clear(contract)\n"
"\n"
"Clear and close the given contract template.\n");
PyDoc_STRVAR(pyprocess_abandon_latest__doc__,
"abandon_latest()\n"
"\n"
"Abandon the latest contract created by this thread.\n");
static struct PyMethodDef pyprocess_module_methods[] = {
{ "activate", (PyCFunction) pyprocess_activate,
METH_VARARGS|METH_KEYWORDS, pyprocess_activate__doc__ },
{ "clear", (PyCFunction) pyprocess_clear,
METH_VARARGS|METH_KEYWORDS, pyprocess_clear__doc__ },
{ "abandon_latest", (PyCFunction) pyprocess_abandon_latest,
METH_VARARGS|METH_KEYWORDS, pyprocess_abandon_latest__doc__ },
{ NULL, NULL, 0, NULL }
};
PyMODINIT_FUNC
initprocess(void)
{
Py_InitModule("process", pyprocess_module_methods);
}
+5
View File
@@ -40,6 +40,7 @@ from xen.xend import arch
from xen.xend import XendOptions
from xen.util import oshelp
from xen.util import utils
from xen.xend import osdep
xc = xen.lowlevel.xc.xc()
@@ -407,9 +408,12 @@ class ImageHandler:
logfd = os.open(self.logfile, logfile_mode)
sys.stderr.flush()
contract = osdep.prefork("%s:%d" %
(self.vm.getName(), self.vm.getDomid()))
pid = os.fork()
if pid == 0: #child
try:
osdep.postfork(contract)
os.dup2(null, 0)
os.dup2(logfd, 1)
os.dup2(logfd, 2)
@@ -426,6 +430,7 @@ class ImageHandler:
except:
os._exit(127)
else:
osdep.postfork(contract, abandon=True)
self.pid = pid
os.close(null)
os.close(logfd)
+28
View File
@@ -192,6 +192,32 @@ _get_cpuinfo = {
"SunOS": _solaris_get_cpuinfo
}
def _default_prefork(name):
pass
def _default_postfork(ct, abandon=False):
pass
# call this for long-running processes that should survive a xend
# restart
def _solaris_prefork(name):
from xen.lowlevel import process
return process.activate(name)
def _solaris_postfork(ct, abandon=False):
from xen.lowlevel import process
process.clear(ct)
if abandon:
process.abandon_latest()
_get_prefork = {
"SunOS": _solaris_prefork
}
_get_postfork = {
"SunOS": _solaris_postfork
}
def _get(var, default=None):
return var.get(os.uname()[0], default)
@@ -201,3 +227,5 @@ pygrub_path = _get(_pygrub_path, "/usr/bin/pygrub")
vif_script = _get(_vif_script, "vif-bridge")
lookup_balloon_stat = _get(_balloon_stat, _linux_balloon_stat)
get_cpuinfo = _get(_get_cpuinfo, _linux_get_cpuinfo)
prefork = _get(_get_prefork, _default_prefork)
postfork = _get(_get_postfork, _default_postfork)
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.