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
|