All of lore.kernel.org
 help / color / mirror / Atom feed
From: Zhigang Wang <zhigang.x.wang@oracle.com>
To: Jim Fehlig <jfehlig@novell.com>
Cc: xen-devel@lists.xensource.com
Subject: Re: [PATCH] [RFC] Add lock on domain start
Date: Thu, 07 Aug 2008 10:23:59 +0800	[thread overview]
Message-ID: <489A5CBF.1040405@oracle.com> (raw)
In-Reply-To: <48993F48.9030705@novell.com>

[-- Attachment #1: Type: text/plain, Size: 1717 bytes --]

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@lists.xensource.com
> http://lists.xensource.com/xen-devel


[-- Attachment #2: xen-running-lock.patch --]
[-- Type: text/x-patch, Size: 5418 bytes --]

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
         """

[-- Attachment #3: file-lock.c --]
[-- Type: text/x-csrc, Size: 4649 bytes --]

/*
 * file-lock.c
 *
 * Copyright (C) 2008 Oracle Inc.
 * Copyright (C) 2008 Zhigang Wang <zhigang.x.wang@oracle.com>
 *
 * 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;
}


[-- Attachment #4: Type: text/plain, Size: 138 bytes --]

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

  reply	other threads:[~2008-08-07  2:23 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-06  6:06 [PATCH] [RFC] Add lock on domain start Jim Fehlig
2008-08-07  2:23 ` Zhigang Wang [this message]
2008-08-07  4:26   ` Zhigang Wang
2008-08-08 17:07     ` Jim Fehlig
2008-08-11  2:22       ` Zhigang Wang
2008-08-11 11:14 ` Ian Jackson
2008-08-11 16:45   ` Jim Fehlig
2009-08-05  7:41     ` Pasi Kärkkäinen
2009-08-05  8:39       ` Zhigang Wang
2009-08-05  9:33         ` Pasi Kärkkäinen
2009-08-05 16:30           ` Jia Ju Zhang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=489A5CBF.1040405@oracle.com \
    --to=zhigang.x.wang@oracle.com \
    --cc=jfehlig@novell.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.