[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] Fix qemu spawn for Solaris



# HG changeset patch
# User John Levon <john.levon@xxxxxxx>
# Date 1236822270 25200
# Node ID 93d25b0df1be0abc503ff721e291b6a1553f4da2
# Parent  403118d22a30b83b863609ae4e0a7f694e612e42
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@xxxxxxx>

diff --git a/tools/python/setup.py b/tools/python/setup.py
--- a/tools/python/setup.py
+++ b/tools/python/setup.py
@@ -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 @@ modules = [ xc, xs, ptsname, acm, flask 
 modules = [ xc, xs, ptsname, acm, flask ]
 if os.uname()[0] == 'SunOS':
     modules.append(scf)
+    modules.append(process)
 
 setup(name            = 'xen',
       version         = '3.0',
diff --git a/tools/python/xen/lowlevel/process/process.c 
b/tools/python/xen/lowlevel/process/process.c
new file mode 100644
--- /dev/null
+++ b/tools/python/xen/lowlevel/process/process.c
@@ -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);
+}
diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py
--- a/tools/python/xen/xend/image.py
+++ b/tools/python/xen/xend/image.py
@@ -40,6 +40,7 @@ from xen.xend import XendOptions
 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)
diff --git a/tools/python/xen/xend/osdep.py b/tools/python/xen/xend/osdep.py
--- a/tools/python/xen/xend/osdep.py
+++ b/tools/python/xen/xend/osdep.py
@@ -290,6 +290,32 @@ _boot_dev = {
     "SunOS": _solaris_boot_dev
 }
 
+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)
 
@@ -304,3 +330,5 @@ connection_allowed = _get(_connection_al
 connection_allowed = _get(_connection_allowed, _default_connection_allowed)
 get_boot_dev = _get(_boot_dev, _default_boot_dev)
 do_broadcast = _get(_do_broadcast)
+prefork = _get(_get_prefork, _default_prefork)
+postfork = _get(_get_postfork, _default_postfork)

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.