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

Re: [Xen-devel] [PATCH] [RFC] Add lock on domain start



Jim Fehlig wrote:
> This patch adds a simple lock mechanism when starting domains by placing 
> a lock file in xend-domains-path/<dom_uuid>.  The lock file is removed 
> when domain is stopped.  The motivation for such a mechanism is to 
> prevent starting the same domain from multiple hosts.
> 
> If xend-domains-path is set to shared mount point, a domain will fail to 
> start on host B if it is already running on host A.  I've added an 
> option to XendOptions to control the behavior with default of no lock.
> 
> The patch certainly needs some testing (and probably adjustment) to 
> ensure the lock is handled properly on save, restore, migrate, domain 
> crash, etc. but wanted to get folks' thought on this approach before 
> continuing this endeavor.  Some simple improvements could include adding 
> info (domain name/id, start time, vmm hostname) to the lock file, 
> allowing such messages as "domain foo seems to be already running on 
> host bar" and  a --force option to create/start to override the lock.  A 
> per-domain config option could also be added to allow more fine-grained 
> control.
> 
> Comments, suggestions, alternative approaches, ... are welcome and 
> appreciated :-).
> 

this patch xen-running-lock.patch add a external lock facility to get the same
result. file-lock.c is a simple implement of the external lock utility.

the external locking facility can leverage the dlm if you are in a cluster
environment.

cheers,

zhigang

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

diff -Nura xen-unstable.orig/tools/examples/xend-config.sxp 
xen-unstable/tools/examples/xend-config.sxp
--- xen-unstable.orig/tools/examples/xend-config.sxp    2008-08-06 
17:26:37.000000000 +0800
+++ xen-unstable/tools/examples/xend-config.sxp 2008-08-06 17:28:45.000000000 
+0800
@@ -63,6 +63,12 @@
 
 #(xend-unix-path /var/lib/xend/xend-socket)
 
+# External locking utility for get/release domain running lock. By default,
+# no utility is specified. Thus there will be no lock as VM running.
+# The locking utility should accept:
+# <--lock | --unlock> --name <name> --uuid <uuid>
+# command line options, and returns zero on success, others on error.
+#(xend-domains-lock-path '')
 
 # Address and port xend should use for the legacy TCP XMLRPC interface, 
 # if xend-tcp-xmlrpc-server is set.
diff -Nura xen-unstable.orig/tools/python/xen/xend/XendDomainInfo.py 
xen-unstable/tools/python/xen/xend/XendDomainInfo.py
--- xen-unstable.orig/tools/python/xen/xend/XendDomainInfo.py   2008-08-06 
17:26:39.000000000 +0800
+++ xen-unstable/tools/python/xen/xend/XendDomainInfo.py        2008-08-06 
17:31:27.000000000 +0800
@@ -328,6 +328,8 @@
     @type state_updated: threading.Condition
     @ivar refresh_shutdown_lock: lock for polling shutdown state
     @type refresh_shutdown_lock: threading.Condition
+    @ivar running_lock: lock for running VM
+    @type running_lock: bool or None
     @ivar _deviceControllers: device controller cache for this domain
     @type _deviceControllers: dict 'string' to DevControllers
     """
@@ -395,6 +397,8 @@
         self.refresh_shutdown_lock = threading.Condition()
         self._stateSet(DOM_STATE_HALTED)
 
+        self.running_lock = None
+
         self._deviceControllers = {}
 
         for state in DOM_STATES_OLD:
@@ -421,6 +425,7 @@
 
         if self._stateGet() in (XEN_API_VM_POWER_STATE_HALTED, 
XEN_API_VM_POWER_STATE_SUSPENDED, XEN_API_VM_POWER_STATE_CRASHED):
             try:
+                self.acquire_running_lock();
                 XendTask.log_progress(0, 30, self._constructDomain)
                 XendTask.log_progress(31, 60, self._initDomain)
                 
@@ -453,6 +458,7 @@
         state = self._stateGet()
         if state in (DOM_STATE_SUSPENDED, DOM_STATE_HALTED):
             try:
+                self.acquire_running_lock();
                 self._constructDomain()
                 self._storeVmDetails()
                 self._createDevices()
@@ -2292,6 +2298,11 @@
 
             self._stateSet(DOM_STATE_HALTED)
             self.domid = None  # Do not push into _stateSet()!
+      
+            try:
+                self.release_running_lock()
+            except:
+                log.exception("Release running lock failed: %s" % status)
         finally:
             self.refresh_shutdown_lock.release()
 
@@ -3520,6 +3531,28 @@
     def has_device(self, dev_class, dev_uuid):
         return (dev_uuid in self.info['%s_refs' % dev_class.lower()])
 
+    def acquire_running_lock(self):
+        if not self.running_lock:
+            lock_path = xoptions.get_xend_domains_lock_path()
+            if lock_path:
+                status = os.system('%s --lock --name %s --uuid %s' % \
+                                   (lock_path, self.info['name_label'], 
self.info['uuid']))
+                if status == 0:
+                    self.running_lock = True
+                else:
+                    raise XendError('Acquire running lock failed: %s' % status)
+
+    def release_running_lock(self):
+        if self.running_lock:
+            lock_path = xoptions.get_xend_domains_lock_path()
+            if lock_path:
+                status = os.system('%s --unlock --name %s --uuid %s' % \
+                                   (lock_path, self.info['name_label'], 
self.info['uuid']))
+                if status == 0:
+                    self.running_lock = False
+                else:
+                    raise XendError('Release running lock failed: %s' % status)
+
     def __str__(self):
         return '<domain id=%s name=%s memory=%s state=%s>' % \
                (str(self.domid), self.info['name_label'],
diff -Nura xen-unstable.orig/tools/python/xen/xend/XendDomain.py 
xen-unstable/tools/python/xen/xend/XendDomain.py
--- xen-unstable.orig/tools/python/xen/xend/XendDomain.py       2008-08-06 
17:26:39.000000000 +0800
+++ xen-unstable/tools/python/xen/xend/XendDomain.py    2008-08-06 
17:30:23.000000000 +0800
@@ -1295,6 +1295,7 @@
                              POWER_STATE_NAMES[dominfo._stateGet()])
 
         """ The following call may raise a XendError exception """
+        dominfo.release_running_lock();
         dominfo.testMigrateDevices(True, dst)
 
         if live:
diff -Nura xen-unstable.orig/tools/python/xen/xend/XendOptions.py 
xen-unstable/tools/python/xen/xend/XendOptions.py
--- xen-unstable.orig/tools/python/xen/xend/XendOptions.py      2008-08-06 
17:26:39.000000000 +0800
+++ xen-unstable/tools/python/xen/xend/XendOptions.py   2008-08-06 
17:28:45.000000000 +0800
@@ -271,6 +271,11 @@
         """
         return self.get_config_string("xend-domains-path", 
self.xend_domains_path_default)
 
+    def get_xend_domains_lock_path(self):
+        """ Get the path of the lock utility for running domains.
+        """
+        return self.get_config_string("xend-domains-lock-path")
+
     def get_xend_state_path(self):
         """ Get the path for persistent domain configuration storage
         """
/*
 * file-lock.c
 *
 * Copyright (C) 2008 Oracle Inc.
 * Copyright (C) 2008 Zhigang Wang <zhigang.x.wang@xxxxxxxxxx>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <getopt.h>

const char version[] = "0.0.1";
static char short_opts[] = "lup:d:n:hvV";
static struct option long_opts[] = {
        { "lock",       no_argument,            NULL,   'l' },
        { "unlock",     no_argument,            NULL,   'u' },
        { "path",       required_argument,      NULL,   'p' },
        { "name",       required_argument,      NULL,   'n' },
        { "uuid",       required_argument,      NULL,   'd' },
        { "help",       no_argument,            NULL,   'h' },
        { "verbose",    no_argument,            NULL,   'v' },
        { "version",    no_argument,            NULL,   'V' },
        {  NULL,        0,                      NULL,    0  }
};

static void usage(char *prog, FILE *fp, int n) {
        fprintf(fp, "usage: %s [options]\n", prog);
        fprintf(fp, "\n");
        fprintf(fp, "options:\n");
        fprintf(fp, " -l, --lock       Acquire the lock.\n");
        fprintf(fp, " -u, --unlock     Release the lock.\n");
        fprintf(fp, " -p, --path       Set the path for the locks.\n");
        fprintf(fp, " -n, --name       Set the name of the VM.\n");
        fprintf(fp, " -d, --uuid       Set the uuid of the VM.\n");
        fprintf(fp, " -v, --verbose    Show more infomation.\n");
        fprintf(fp, " -V, --version    Show version number and exit.\n");
        fprintf(fp, " -h, --help       Show this help information.\n");
        fprintf(fp, "\n");
        exit(n);
}

static int do_lock(char *path, char *name, char *uuid)
{
        char *fn;
        int fd;

        if (asprintf(&fn, "%s/%s-%s.lock", path, name, uuid) == -1)
                return -1;

        fd = open(fn, O_CREAT|O_RDWR|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
        if (fd == -1) {
                free(fn);
                return errno;
        }

        free(fn);
        close(fd);
        return 0;
}

static int do_unlock(char *path, char *name, char *uuid)
{
        char *fn;

        if (asprintf(&fn, "%s/%s-%s.lock", path, name, uuid) == -1)
                return -1;

        if (unlink(fn) == -1) {
                free(fn);
                return errno;
        }

        free(fn);
        return 0;
}

int main(int argc, char *argv[])
{
        char *prog, *p;
        char *name = NULL;
        char *uuid = NULL;
        char *path = ".";       /* create lock file on current working 
directory by default*/
        int verbose = 0;        /* turn off verbose output by default */
        int status = 0;         /* returned value */
        int lock = 0, unlock = 0;
        int c;

        prog = argv[0];
        p = strrchr(prog, '/');
        if (p)
                prog = p+1;

        while ((c = getopt_long(argc, argv, short_opts,
                                 long_opts, NULL)) != -1) {
                switch (c) {
                case 'l':               /* acquire the lock */
                        lock = 1;
                        break;
                case 'u':               /* release the lock */
                        unlock = 1;
                        break;
                case 'p':               /* path for lock file */
                        path = optarg;
                        break;
                case 'n':               /* name of vm  */
                        name = optarg;
                        break;
                case 'd':               /* uuid of vm  */
                        uuid = optarg;
                        break;
                case 'h':               /* help */
                        usage(prog, stdout, 0);
                        break;
                case 'v':               /* be chatty */
                        ++verbose;
                        break;
                case 'V':               /* version */
                        fprintf(stdout, "%s: %s\n", prog, version);
                        exit(0);
                case 0:
                        break;
                case '?':
                default:
                        usage(prog, stderr, 1);
                }
        }

        if (optind < argc)
                usage(prog, stderr, 1);

        if (name==NULL || uuid==NULL) {
                fprintf(stderr, "you should specify the name and uuid of 
vm.\n\n");
                usage(prog, stderr, 1);
        }

        if (lock && unlock) {
                fprintf(stderr, "cannot execute lock and unlock at the same 
time.\n\n");
                usage(prog, stderr, 1);
        }

        if (lock) {
                if (verbose)
                        fprintf(stdout, "creating lock file %s/%s-%s.lock\n", 
path, name, uuid);

                status = do_lock(path, name, uuid);

                if (verbose)
                        if (status == 0)
                                fprintf(stdout, "lock sucess.\n");
                        else
                                fprintf(stdout, "lock failed.\n");
        } else if (unlock) {
                if (verbose)
                        fprintf(stdout, "removing lock file %s/%s-%s.lock\n", 
path, name, uuid);

                status = do_unlock(path, name, uuid);

                if (verbose)
                        if (status == 0)
                                fprintf(stdout, "unlock sucess.\n");
                        else
                                fprintf(stdout, "unlock failed.\n");
        } else {
                fprintf(stderr, "you should specify lock or unlock.\n\n");
                usage(prog, stderr, 1);
        }

        return status;
}

_______________________________________________
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®.