From 01921f8046e2a93bb1990c56e9f65a59c24a89c8 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Sun, 9 Oct 2005 11:52:24 +0100 Subject: [PATCH 01/42] Change xenbus callbacks to match new signature of xenbus_watch. Signed-off-by: Ewan Mellor --- linux-2.6-xen-sparse/arch/xen/kernel/reboot.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c index fddc705c7e..b83f136f70 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @@ -270,7 +270,8 @@ static void __shutdown_handler(void *unused) } } -static void shutdown_handler(struct xenbus_watch *watch, const char *node) +static void shutdown_handler(struct xenbus_watch *watch, + const char **vec, unsigned int len) { static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL); char *str; @@ -315,7 +316,8 @@ static void shutdown_handler(struct xenbus_watch *watch, const char *node) } #ifdef CONFIG_MAGIC_SYSRQ -static void sysrq_handler(struct xenbus_watch *watch, const char *node) +static void sysrq_handler(struct xenbus_watch *watch, const char **vec, + unsigned int len) { char sysrq_key = '\0'; int err; @@ -411,4 +413,3 @@ subsys_initcall(setup_shutdown_event); * tab-width: 8 * End: */ -# From e92ad65f027316849b66d2986027701060a6a15e Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Sun, 9 Oct 2005 11:53:34 +0100 Subject: [PATCH 02/42] Append a newline to error messages, so that they are parsed by XendCheckpoint.py correctly. Signed-off-by: Ewan Mellor --- tools/libxc/xc_linux_save.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/libxc/xc_linux_save.c b/tools/libxc/xc_linux_save.c index 4720e4076a..ba3aff36a6 100644 --- a/tools/libxc/xc_linux_save.c +++ b/tools/libxc/xc_linux_save.c @@ -35,7 +35,7 @@ #define DEBUG 0 #if 1 -#define ERR(_f, _a...) do { fprintf(stderr, _f , ## _a); fflush(stderr); } while (0) +#define ERR(_f, _a...) do { fprintf(stderr, _f "\n" , ## _a); fflush(stderr); } while (0) #else #define ERR(_f, _a...) ((void)0) #endif From 9c04557e2d6601750d3a54bdee74ac3e2973d4de Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Sun, 9 Oct 2005 11:57:24 +0100 Subject: [PATCH 03/42] Remove code seeding RNG from /dev/urandom. The random module's default RNG is already seeded from the clock, so this is unnecessary, non-portable, and expensive. This should improve start-up time of Xend. Replace twisty maze of code with something sensible. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/uuid.py | 60 +++++++++++------------------------ 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/tools/python/xen/xend/uuid.py b/tools/python/xen/xend/uuid.py index 6c923feccf..b37cb17a39 100644 --- a/tools/python/xen/xend/uuid.py +++ b/tools/python/xen/xend/uuid.py @@ -13,14 +13,19 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2005 Mike Wray +# Copyright (C) 2005 XenSource Ltd #============================================================================ + """Universal(ly) Unique Identifiers (UUIDs). """ + + import commands import random -def uuidgen(random=True): + +def getUuidUuidgen(random = True): """Generate a UUID using the command uuidgen. If random is true (default) generates a random uuid. @@ -33,50 +38,21 @@ def uuidgen(random=True): cmd += " -t" return commands.getoutput(cmd) -class UuidFactoryUuidgen: - """A uuid factory using uuidgen.""" +def getUuidRandom(): + """Generate a random UUID.""" + + bytes = [ random.randint(0, 255) for i in range(0, 16) ] + # Encode the variant. + bytes[6] = (bytes[6] & 0x0f) | 0x40 + bytes[8] = (bytes[8] & 0x3f) | 0x80 + f = "%02x" + return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(bytes) ) - def __init__(self): - pass - def getUuid(self): - return uuidgen() +#uuidFactory = getUuidUuidgen +uuidFactory = getUuidRandom -class UuidFactoryRandom: - - """A random uuid factory.""" - - def __init__(self): - f = file("/dev/urandom", "r") - seed = f.read(16) - f.close() - self.rand = random.Random(seed) - - def randBytes(self, n): - return [ self.rand.randint(0, 255) for i in range(0, n) ] - - def getUuid(self): - bytes = self.randBytes(16) - # Encode the variant. - bytes[6] = (bytes[6] & 0x0f) | 0x40 - bytes[8] = (bytes[8] & 0x3f) | 0x80 - f = "%02x" - return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(bytes) ) - -def getFactory(): - """Get the factory to use for creating uuids. - This is so it's easy to change the uuid factory. - For example, for testing we might want repeatable uuids - rather than the random ones we normally use. - """ - global uuidFactory - try: - uuidFactory - except: - #uuidFactory = UuidFactoryUuidgen() - uuidFactory = UuidFactoryRandom() - return uuidFactory def getUuid(): - return getFactory().getUuid() + return uuidFactory() From e156cce3a42ee327882a1dc2792b53d6cd1fd0ae Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Sun, 9 Oct 2005 11:59:37 +0100 Subject: [PATCH 04/42] Remove cruft. Signed-off-by: Ewan Mellor --- tools/python/xen/xm/sysrq.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/python/xen/xm/sysrq.py b/tools/python/xen/xm/sysrq.py index 12b2da22fe..9a5b8fced5 100644 --- a/tools/python/xen/xm/sysrq.py +++ b/tools/python/xen/xm/sysrq.py @@ -1,17 +1,12 @@ # (C) Matthew Bloch 2004 +# Copyright (C) 2005 XenSource Ltd -"""Domain shutdown. +"""Domain sysrq. """ -import string -import sys -import time from xen.xend.XendClient import server from xen.xm.opts import * -DOM0_NAME = 'Domain-0' -DOM0_ID = '0' - gopts = Opts(use="""[DOM] [letter] Sends a Linux sysrq to a domain. From 9d12287d147a2cefffbcf8694661131c4e6030d5 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Sun, 9 Oct 2005 12:14:46 +0100 Subject: [PATCH 05/42] /home/emellor/log2 --- tools/python/xen/util/asserts.py | 22 +++++ tools/python/xen/xend/XendClient.py | 3 + tools/python/xen/xend/XendDomain.py | 83 ----------------- tools/python/xen/xend/XendDomainInfo.py | 17 ++-- tools/python/xen/xend/server/SrvDomain.py | 95 ++++++++------------ tools/python/xen/xend/server/SrvDomainDir.py | 26 ++++-- tools/python/xen/xm/main.py | 27 +++--- 7 files changed, 108 insertions(+), 165 deletions(-) create mode 100644 tools/python/xen/util/asserts.py diff --git a/tools/python/xen/util/asserts.py b/tools/python/xen/util/asserts.py new file mode 100644 index 0000000000..78f4c1b4a8 --- /dev/null +++ b/tools/python/xen/util/asserts.py @@ -0,0 +1,22 @@ +#=========================================================================== +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2005 XenSource Ltd +#============================================================================ + + +def isCharConvertible(c): + assert (isinstance(c, int) or + (isinstance(c, str) and + len(c) == 1)), "%s is not convertible to a character" % c diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 5f198ac9f7..39c57dc8b8 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -196,6 +196,9 @@ class Xend: def xend_domains(self): return self.xendGet(self.domainurl()) + def xend_list_domains(self): + return self.xendGet(self.domainurl(), {'detail': '1'}) + def xend_domain_create(self, conf): return self.xendPost(self.domainurl(), {'op' : 'create', diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 56e967dfb7..7809c80fd9 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -359,20 +359,6 @@ class XendDomain: raise XendError(str(ex)) - def domain_shutdown(self, domid, reason = 'poweroff'): - """Shutdown domain (nicely). - - @param reason: shutdown reason: poweroff, reboot, suspend, halt - """ - self.callInfo(domid, XendDomainInfo.XendDomainInfo.shutdown, reason) - - - def domain_sysrq(self, domid, key): - """Send a SysRq to the specified domain.""" - return self.callInfo(domid, XendDomainInfo.XendDomainInfo.send_sysrq, - key) - - def domain_destroy(self, domid): """Terminate domain immediately.""" @@ -475,37 +461,6 @@ class XendDomain: raise XendError(str(ex)) - def domain_device_create(self, domid, devconfig): - """Create a new device for the specified domain. - """ - return self.callInfo(domid, - XendDomainInfo.XendDomainInfo.device_create, - devconfig) - - - def domain_device_configure(self, domid, devconfig, devid): - """Configure an existing device in the specified domain. - @return: updated device configuration - """ - return self.callInfo(domid, - XendDomainInfo.XendDomainInfo.device_configure, - devconfig, devid) - - - def domain_device_destroy(self, domid, devtype, devid): - """Destroy a device.""" - return self.callInfo(domid, - XendDomainInfo.XendDomainInfo.destroyDevice, - devtype, devid) - - - def domain_devtype_ls(self, domid, devtype): - """Get list of device sxprs for the specified domain.""" - return self.callInfo(domid, - XendDomainInfo.XendDomainInfo.getDeviceSxprs, - devtype) - - def domain_vif_limit_set(self, domid, vif, credit, period): """Limit the vif's transmission rate """ @@ -537,44 +492,6 @@ class XendDomain: except Exception, ex: raise XendError(str(ex)) - def domain_mem_target_set(self, domid, mem): - """Set the memory target for a domain. - - @param mem: memory target (in MiB) - """ - self.callInfo(domid, XendDomainInfo.XendDomainInfo.setMemoryTarget, - mem << 10) - - - def domain_vcpu_hotplug(self, domid, vcpu, state): - """Enable or disable specified VCPU in specified domain - - @param vcpu: target VCPU in domain - @param state: which state VCPU will become - """ - self.callInfo(domid, XendDomainInfo.XendDomainInfo.vcpu_hotplug, vcpu, - state) - - - def domain_dumpcore(self, domid): - """Save a core dump for a crashed domain.""" - self.callInfo(domid, XendDomainInfo.XendDomainInfo.dumpCore) - - - ## private: - - def callInfo(self, domid, fn, *args, **kwargs): - try: - self.refresh() - dominfo = self.domains.get(domid) - if dominfo: - return fn(dominfo, *args, **kwargs) - except XendError: - raise - except Exception, exn: - log.exception("") - raise XendError(str(exn)) - def instance(): """Singleton constructor. Use this instead of the class constructor. diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 2b3bf06667..e8ed2c2995 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -30,6 +30,7 @@ import threading import errno import xen.lowlevel.xc +from xen.util import asserts from xen.util.blkif import blkdev_uname_to_file from xen.xend import image @@ -41,7 +42,8 @@ from xen.xend.XendLogging import log from xen.xend.XendError import XendError, VmError from xen.xend.XendRoot import get_component -from xen.xend.uuid import getUuid +from uuid import getUuid + from xen.xend.xenstore.xstransact import xstransact from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain @@ -793,10 +795,12 @@ class XendDomainInfo: def setMemoryTarget(self, target): """Set the memory target of this domain. - @param target In KiB. + @param target In MiB. """ - self.info['memory_KiB'] = target - self.storeDom("memory/target", target) + # Internally we use KiB, but the command interface uses MiB. + t = target << 10 + self.info['memory_KiB'] = t + self.storeDom("memory/target", t) def update(self, info = None): @@ -1366,7 +1370,10 @@ class XendDomainInfo: self.storeVm('vcpu_avail', self.info['vcpu_avail']) self.storeDom("cpu/%d/availability" % vcpu, availability) - def send_sysrq(self, key=0): + + def send_sysrq(self, key): + asserts.isCharConvertible(key) + self.storeDom("control/sysrq", '%c' % key) diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 8c70bfe27d..7dd7d16da4 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -51,40 +51,28 @@ class SrvDomain(SrvDir): val = self.xd.domain_pause(self.dom.domid) return val - def op_shutdown(self, op, req): - fn = FormFn(self.xd.domain_shutdown, - [['dom', 'int'], - ['reason', 'str']]) - val = fn(req.args, {'dom': self.dom.domid}) + def acceptCommand(self, req): req.setResponseCode(http.ACCEPTED) req.setHeader("Location", "%s/.." % req.prePathURL()) - return val + + def op_shutdown(self, op, req): + self.acceptCommand(req) + return self.dom.shutdown(req.args['reason'][0]) def op_sysrq(self, op, req): - fn = FormFn(self.xd.domain_sysrq, - [['dom', 'int'], - ['key', 'int']]) - val = fn(req.args, {'dom' : self.dom.domid}) - req.setResponseCode(http.ACCEPTED) - req.setHeader("Location", "%s/.." % req.prePathURL()) - return val + self.acceptCommand(req) + return self.dom.send_sysrq(int(req.args['key'][0])) def op_destroy(self, op, req): - fn = FormFn(self.xd.domain_destroy, - [['dom', 'int']]) - val = fn(req.args, {'dom': self.dom.domid}) - req.setHeader("Location", "%s/.." % req.prePathURL()) - return val + self.acceptCommand(req) + return self.xd.domain_destroy(self.dom.domid) def op_save(self, op, req): + self.acceptCommand(req) return req.threadRequest(self.do_save, op, req) def do_save(self, op, req): - fn = FormFn(self.xd.domain_save, - [['dom', 'int'], - ['file', 'str']]) - val = fn(req.args, {'dom': self.dom.domid}) - return 0 + return self.xd.domain_save(self.dom.domid, req.args['file'][0]) def op_migrate(self, op, req): return req.threadRequest(self.do_migrate, op, req) @@ -134,43 +122,39 @@ class SrvDomain(SrvDir): ['memory', 'int']]) val = fn(req.args, {'dom': self.dom.domid}) return val + + def call(self, fn, args, req): + return FormFn(fn, args)(req.args) + + def op_mem_target_set(self, op, req): - fn = FormFn(self.xd.domain_mem_target_set, - [['dom', 'int'], - ['target', 'int']]) - val = fn(req.args, {'dom': self.dom.domid}) - return val + return self.call(self.dom.setMemoryTarget + [['target', 'int']], + req) def op_devices(self, op, req): - fn = FormFn(self.xd.domain_devtype_ls, - [['dom', 'int'], - ['type', 'str']]) - val = fn(req.args, {'dom': self.dom.domid}) - return val + return self.call(self.dom.getDeviceSxprs, + [['deviceClass', 'str']], + req) def op_device_create(self, op, req): - fn = FormFn(self.xd.domain_device_create, - [['dom', 'int'], - ['config', 'sxpr']]) - val = fn(req.args, {'dom': self.dom.domid}) - return val + return self.call(self.dom.device_create, + [['dev_config', 'sxpr']], + req) def op_device_destroy(self, op, req): - fn = FormFn(self.xd.domain_device_destroy, - [['dom', 'int'], - ['type', 'str'], - ['dev', 'str']]) - val = fn(req.args, {'dom': self.dom.domid}) - return val + return self.call(self.dom.destroyDevice, + [['deviceClass', 'str'], + ['devid', 'int']], + req) def op_device_configure(self, op, req): - fn = FormFn(self.xd.domain_device_configure, - [['dom', 'int'], - ['config', 'sxpr'], - ['dev', 'str']]) - val = fn(req.args, {'dom': self.dom.domid}) - return val + return self.call(self.dom.device_configure, + [['dev_config', 'sxpr'], + ['devid', 'int']], + req) + def op_vif_limit_set(self, op, req): fn = FormFn(self.xd.domain_vif_limit_set, @@ -182,12 +166,10 @@ class SrvDomain(SrvDir): return val def op_vcpu_hotplug(self, op, req): - fn = FormFn(self.xd.domain_vcpu_hotplug, - [['dom', 'int'], - ['vcpu', 'int'], - ['state', 'int']]) - val = fn(req.args, {'dom': self.dom.domid}) - return val + return self.call(self.dom.vcpu_hotplug, + [['vcpu', 'int'], + ['state', 'int']], + req) def render_POST(self, req): return self.perform(req) @@ -201,7 +183,6 @@ class SrvDomain(SrvDir): # # if op and op[0] in ['vifs', 'vif', 'vbds', 'vbd', 'mem_target_set']: # return self.perform(req) - self.dom.update() if self.use_sxp(req): req.setHeader("Content-Type", sxp.mime_type) sxp.show(self.dom.sxpr(), out=req) diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index 0bbcd8e607..b410174fac 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -22,6 +22,7 @@ from xen.web import http from xen.xend import sxp from xen.xend import XendDomain +from xen.xend.XendDomainInfo import XendDomainInfo from xen.xend.Args import FormFn from xen.xend.XendError import XendError from xen.xend.XendLogging import log @@ -29,6 +30,7 @@ from xen.xend.XendLogging import log from xen.web.SrvDir import SrvDir from SrvDomain import SrvDomain + class SrvDomainDir(SrvDir): """Service that manages the domain directory. """ @@ -124,28 +126,41 @@ class SrvDomainDir(SrvDir): out.close() return val + + def op_list(self, _, req): + """List the details for this domain.""" + self._list(req, True) + + def render_POST(self, req): return self.perform(req) def render_GET(self, req): + self._list(req, 'detail' in req.args and req.args['detail'] == ['1']) + + + def _list(self, req, detail): if self.use_sxp(req): req.setHeader("Content-Type", sxp.mime_type) - self.ls_domain(req, 1) + self.ls_domain(req, detail, True) else: req.write("") self.print_path(req) self.ls(req) - self.ls_domain(req) + self.ls_domain(req, detail, False) self.form(req) req.write("") - def ls_domain(self, req, use_sxp=0): + + def ls_domain(self, req, detail, use_sxp): url = req.prePathURL() if not url.endswith('/'): url += '/' if use_sxp: - domains = self.xd.list_names() - sxp.show(domains, out=req) + if detail: + sxp.show(map(XendDomainInfo.sxpr, self.xd.list()), out=req) + else: + sxp.show(self.xd.list_names(), out=req) else: domains = self.xd.list_sorted() req.write('
    ') @@ -158,6 +173,7 @@ class SrvDomainDir(SrvDir): req.write('') req.write('
') + def form(self, req): """Generate the form(s) for domain dir operations. """ diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 8433d819da..615ef4ef60 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -225,25 +225,22 @@ def xm_list(args): if k in ['-v', '--vcpus']: show_vcpus = 1 - domsinfo = [] from xen.xend.XendClient import server if n == 0: - doms = server.xend_domains() - doms.sort() + doms = server.xend_list_domains() else: - doms = params - for dom in doms: - info = server.xend_domain(dom) - domsinfo.append(parse_doms_info(info)) + doms = map(server.xend_domain, params) if use_long: for dom in doms: - info = server.xend_domain(dom) - PrettyPrint.prettyprint(info) - elif show_vcpus: - xm_show_vcpus(domsinfo) + PrettyPrint.prettyprint(doms) else: - xm_brief_list(domsinfo) + domsinfo = map(parse_doms_info, doms) + + if show_vcpus: + xm_show_vcpus(domsinfo) + else: + xm_brief_list(domsinfo) def parse_doms_info(info): dominfo = {} @@ -279,12 +276,12 @@ def parse_doms_info(info): return dominfo def xm_brief_list(domsinfo): - print 'Name Id Mem(MB) CPU VCPU(s) State Time(s)' + print 'Name ID Mem(MiB) CPU VCPUs State Time(s)' for dominfo in domsinfo: if dominfo.has_key("ssidref1"): - print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo) + print ("%(name)-16s %(dom)3d %(mem)8d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo) else: - print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f" % dominfo) + print ("%(name)-16s %(dom)3d %(mem)8d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f" % dominfo) def xm_show_vcpus(domsinfo): print 'Name Id VCPU CPU CPUMAP' From 94f779dfb18251455b1176fcba2d7f7d6fa9d1b4 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Sun, 9 Oct 2005 12:16:23 +0100 Subject: [PATCH 06/42] Remove unnecessary extraction of ssidref from config inside restore -- this is now handled by the construct call, which restore has recently started using. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomainInfo.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index e8ed2c2995..3b73e572c9 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -219,17 +219,12 @@ def recreate(xeninfo): def restore(config): """Create a domain and a VM object to do a restore. - @param config: domain configuration + @param config: domain configuration """ log.debug("XendDomainInfo.restore(%s)", config) - try: - uuid = sxp.child_value(config, 'uuid') - ssidref = int(sxp.child_value(config, 'ssidref')) - except TypeError, exn: - raise VmError('Invalid ssidref in config: %s' % exn) - + uuid = sxp.child_value(config, 'uuid') vm = XendDomainInfo(uuid, parseConfig(config)) try: vm.construct() From a513eb7d8844b7397a555215d5bc70ab0ea2e47f Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Sun, 9 Oct 2005 12:20:12 +0100 Subject: [PATCH 07/42] Alter logging statements to move the interpolation inside the logging function, meaning that it will only occur if the message is to be logged. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomainInfo.py | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 3b73e572c9..c9711808a8 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -254,7 +254,7 @@ def parseConfig(config): return val - log.debug("parseConfig: config is %s" % str(config)) + log.debug("parseConfig: config is %s", config) result = {} @@ -312,7 +312,7 @@ def parseConfig(config): log.warn("Ignoring malformed and deprecated config option " "restart = %s", restart) - log.debug("parseConfig: result is %s" % str(result)) + log.debug("parseConfig: result is %s", result) return result @@ -526,7 +526,7 @@ class XendDomainInfo: except KeyError, exn: log.exception(exn) - raise VmError('Unspecified domain detail: %s' % str(exn)) + raise VmError('Unspecified domain detail: %s' % exn) def readVm(self, *args): @@ -576,7 +576,7 @@ class XendDomainInfo: if self.infoIsSet(k): to_store[k] = str(self.info[k]) - log.debug("Storing VM details: %s" % str(to_store)) + log.debug("Storing VM details: %s", to_store) self.writeVm(to_store) @@ -602,7 +602,7 @@ class XendDomainInfo: for v in range(0, self.info['vcpus']): to_store["cpu/%d/availability" % v] = availability(v) - log.debug("Storing domain details: %s" % str(to_store)) + log.debug("Storing domain details: %s", to_store) self.writeDom(to_store) @@ -743,7 +743,7 @@ class XendDomainInfo: def shutdown(self, reason): if not reason in shutdown_reasons.values(): - raise XendError('invalid reason:' + reason) + raise XendError('Invalid reason: %s' % reason) self.storeDom("control/shutdown", reason) if reason != 'suspend': self.storeDom('xend/shutdown_start_time', time.time()) @@ -985,8 +985,8 @@ class XendDomainInfo: """ log.debug('XendDomainInfo.construct: %s %s', - str(self.domid), - str(self.info['ssidref'])) + self.domid, + self.info['ssidref']) self.domid = xc.domain_create(dom = 0, ssidref = self.info['ssidref']) @@ -1003,9 +1003,9 @@ class XendDomainInfo: def initDomain(self): log.debug('XendDomainInfo.initDomain: %s %s %s', - str(self.domid), - str(self.info['memory_KiB']), - str(self.info['cpu_weight'])) + self.domid, + self.info['memory_KiB'], + self.info['cpu_weight']) if not self.infoIsSet('image'): raise VmError('Missing image in configuration') @@ -1084,14 +1084,14 @@ class XendDomainInfo: def destroy(self): """Cleanup VM and destroy domain. Nothrow guarantee.""" - log.debug("XendDomainInfo.destroy: domid=%s", str(self.domid)) + log.debug("XendDomainInfo.destroy: domid=%s", self.domid) self.cleanupVm() self.destroyDomain() def destroyDomain(self): - log.debug("XendDomainInfo.destroyDomain(%s)", str(self.domid)) + log.debug("XendDomainInfo.destroyDomain(%s)", self.domid) try: if self.domid is not None: @@ -1390,18 +1390,18 @@ class XendDomainInfo: dom = 0 # get max number of vcpus to use for dom0 from config target = int(xroot.get_dom0_vcpus()) - log.debug("number of vcpus to use is %d" % (target)) + log.debug("number of vcpus to use is %d", target) # target = 0 means use all processors if target > 0: # count the number of online vcpus (cpu values in v2c map >= 0) vcpu_to_cpu = dom_get(dom)['vcpu_to_cpu'] vcpus_online = len(filter(lambda x: x >= 0, vcpu_to_cpu)) - log.debug("found %d vcpus online" % (vcpus_online)) + log.debug("found %d vcpus online", vcpus_online) # disable any extra vcpus that are online over the requested target for vcpu in range(target, vcpus_online): - log.info("enforcement is disabling DOM%d VCPU%d" % (dom, vcpu)) + log.info("enforcement is disabling DOM%d VCPU%d", dom, vcpu) self.vcpu_hotplug(vcpu, 0) From 211e84b39af8ebe4834f6c4d8b046f4248f14f71 Mon Sep 17 00:00:00 2001 From: "smh22@firebug.cl.cam.ac.uk" Date: Sun, 9 Oct 2005 16:26:08 +0100 Subject: [PATCH 08/42] Fix cpu hotplug issue with SMP guests (including save/restore). Was a nasty one - worth ensuring we cast to u64 whenever playing with Xen time values. Signed-off-by: Steven Hand --- linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c | 2 +- linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c index 2a9213decb..79d5b93d46 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -1578,7 +1578,7 @@ void smp_suspend(void) void smp_resume(void) { smp_intr_init(); - local_setup_timer_irq(); + local_setup_timer(); } void vcpu_prepare(int vcpu) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c index 4642ddd1ad..ea09ebbb95 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c @@ -122,7 +122,7 @@ static u32 shadow_tv_version; static u64 processed_system_time; /* System time (ns) at last processing. */ static DEFINE_PER_CPU(u64, processed_system_time); -#define NS_PER_TICK (1000000000L/HZ) +#define NS_PER_TICK (1000000000ULL/HZ) static inline void __normalize_time(time_t *sec, s64 *nsec) { @@ -800,9 +800,9 @@ static inline u64 jiffies_to_st(unsigned long j) delta = j - jiffies; /* NB. The next check can trigger in some wrap-around cases, * but that's ok: we'll just end up with a shorter timeout. */ - if (delta < 1) + if (delta < 1) delta = 1; - st = processed_system_time + (delta * NS_PER_TICK); + st = processed_system_time + ((u64)delta * NS_PER_TICK); } while (read_seqretry(&xtime_lock, seq)); return st; @@ -816,7 +816,7 @@ void stop_hz_timer(void) { unsigned int cpu = smp_processor_id(); unsigned long j; - + /* s390 does this /before/ checking rcu_pending(). We copy them. */ cpu_set(cpu, nohz_cpu_mask); From b1f64c5b903b3b99972e9d76e00159b4c5fcd02e Mon Sep 17 00:00:00 2001 From: "vh249@kneesaa.uk.xensource.com" Date: Sun, 9 Oct 2005 12:29:24 -0400 Subject: [PATCH 09/42] Don't increment mi->usage is alloc_major_info return NULL Signed-off-by: Vincent Hanquez --- linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c b/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c index 01b62e695d..49a6ab4882 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c @@ -160,7 +160,8 @@ xlbd_get_major_info(int vdevice) mi = ((major_info[index] != NULL) ? major_info[index] : xlbd_alloc_major_info(major, minor, index)); - mi->usage++; + if (mi) + mi->usage++; return mi; } From 4657d174aba23168b14408dc59a3ec181154b833 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sun, 9 Oct 2005 18:52:54 +0100 Subject: [PATCH 10/42] Refactor xenbus to break up the xenbus_lock and permit watches to fire concurrently with request/reply pairs. Remove watch_ack message: no longer needed. Signed-off-by: Keir Fraser --- .../arch/xen/i386/kernel/smpboot.c | 8 +- linux-2.6-xen-sparse/arch/xen/kernel/reboot.c | 5 - .../drivers/xen/balloon/balloon.c | 5 - .../drivers/xen/xenbus/xenbus_comms.c | 22 +- .../drivers/xen/xenbus/xenbus_dev.c | 150 +++--- .../drivers/xen/xenbus/xenbus_probe.c | 7 +- .../drivers/xen/xenbus/xenbus_xs.c | 452 +++++++++++++----- linux-2.6-xen-sparse/include/asm-xen/xenbus.h | 14 +- tools/blktap/xenbus.c | 4 - tools/console/daemon/io.c | 1 - tools/python/xen/lowlevel/xs/xs.c | 42 -- tools/python/xen/xend/xenstore/xswatch.py | 9 +- tools/xenstore/testsuite/07watch.test | 21 - tools/xenstore/testsuite/08transaction.test | 4 - .../xenstore/testsuite/10domain-homedir.test | 1 - tools/xenstore/testsuite/11domain-watch.test | 2 - tools/xenstore/testsuite/12readonly.test | 1 - tools/xenstore/testsuite/13watch-ack.test | 1 - tools/xenstore/xenstored_core.c | 11 - tools/xenstore/xenstored_core.h | 3 - tools/xenstore/xenstored_watch.c | 56 +-- tools/xenstore/xs.c | 49 +- tools/xenstore/xs.h | 6 - tools/xenstore/xs_test.c | 11 - xen/include/public/io/xs_wire.h | 2 - 25 files changed, 499 insertions(+), 388 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c index 79d5b93d46..c4bfaeacbd 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -1327,18 +1327,14 @@ static struct xenbus_watch cpu_watch = { .callback = handle_vcpu_hotplug_event }; -/* NB: Assumes xenbus_lock is held! */ static int setup_cpu_watcher(struct notifier_block *notifier, unsigned long event, void *data) { - int err = 0; + int err; - BUG_ON(down_trylock(&xenbus_lock) == 0); err = register_xenbus_watch(&cpu_watch); - - if (err) { + if (err) printk("Failed to register watch on /cpu\n"); - } return NOTIFY_DONE; } diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c index b83f136f70..6094573a82 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @@ -360,9 +360,6 @@ static struct xenbus_watch sysrq_watch = { static struct notifier_block xenstore_notifier; -/* Setup our watcher - NB: Assumes xenbus_lock is held! -*/ static int setup_shutdown_watcher(struct notifier_block *notifier, unsigned long event, void *data) @@ -372,8 +369,6 @@ static int setup_shutdown_watcher(struct notifier_block *notifier, int err2 = 0; #endif - BUG_ON(down_trylock(&xenbus_lock) == 0); - err1 = register_xenbus_watch(&shutdown_watch); #ifdef CONFIG_MAGIC_SYSRQ err2 = register_xenbus_watch(&sysrq_watch); diff --git a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c index 119315c5e4..36c6286cd3 100644 --- a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c +++ b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c @@ -370,17 +370,12 @@ static void watch_target(struct xenbus_watch *watch, } -/* Setup our watcher - NB: Assumes xenbus_lock is held! -*/ int balloon_init_watcher(struct notifier_block *notifier, unsigned long event, void *data) { int err; - BUG_ON(down_trylock(&xenbus_lock) == 0); - err = register_xenbus_watch(&target_watch); if (err) printk(KERN_ERR "Failed to set balloon watcher\n"); diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c index 7d0ef111bc..aa2e90b7cb 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c @@ -130,15 +130,10 @@ int xb_write(const void *data, unsigned len) wait_event(xb_waitq, output_avail(out)); - /* Read, then check: not that we don't trust store. - * Hell, some of my best friends are daemons. But, - * in this post-911 world... */ - h = *out; mb(); - if (!check_buffer(&h)) { - set_current_state(TASK_RUNNING); - return -EIO; /* ETERRORIST! */ - } + h = *out; + if (!check_buffer(&h)) + return -EIO; dst = get_output_chunk(&h, out->buf, &avail); if (avail > len) @@ -173,12 +168,11 @@ int xb_read(void *data, unsigned len) const char *src; wait_event(xb_waitq, xs_input_avail()); - h = *in; + mb(); - if (!check_buffer(&h)) { - set_current_state(TASK_RUNNING); + h = *in; + if (!check_buffer(&h)) return -EIO; - } src = get_input_chunk(&h, in->buf, &avail); if (avail > len) @@ -195,10 +189,6 @@ int xb_read(void *data, unsigned len) notify_remote_via_evtchn(xen_start_info->store_evtchn); } - /* If we left something, wake watch thread to deal with it. */ - if (xs_input_avail()) - wake_up(&xb_waitq); - return 0; } diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c index a1d24be2b4..f4c0d35c3c 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c @@ -46,85 +46,113 @@ #include struct xenbus_dev_data { - /* Are there bytes left to be read in this message? */ - int bytes_left; - /* Are we still waiting for the reply to a message we wrote? */ - int awaiting_reply; - /* Buffer for outgoing messages. */ + int in_transaction; + + /* Partial request. */ unsigned int len; union { struct xsd_sockmsg msg; char buffer[PAGE_SIZE]; } u; + + /* Response queue. */ +#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1)) + char read_buffer[PAGE_SIZE]; + unsigned int read_cons, read_prod; + wait_queue_head_t read_waitq; }; static struct proc_dir_entry *xenbus_dev_intf; -/* Reply can be long (dir, getperm): don't buffer, just examine - * headers so we can discard rest if they die. */ static ssize_t xenbus_dev_read(struct file *filp, char __user *ubuf, size_t len, loff_t *ppos) { - struct xenbus_dev_data *data = filp->private_data; - struct xsd_sockmsg msg; - int err; + struct xenbus_dev_data *u = filp->private_data; + int i; - /* Refill empty buffer? */ - if (data->bytes_left == 0) { - if (len < sizeof(msg)) - return -EINVAL; + if (wait_event_interruptible(u->read_waitq, + u->read_prod != u->read_cons)) + return -EINTR; - err = xb_read(&msg, sizeof(msg)); - if (err) - return err; - data->bytes_left = msg.len; - if (ubuf && copy_to_user(ubuf, &msg, sizeof(msg)) != 0) - return -EFAULT; - /* We can receive spurious XS_WATCH_EVENT messages. */ - if (msg.type != XS_WATCH_EVENT) - data->awaiting_reply = 0; - return sizeof(msg); + for (i = 0; i < len; i++) { + if (u->read_cons == u->read_prod) + break; + put_user(u->read_buffer[MASK_READ_IDX(u->read_cons)], ubuf+i); + u->read_cons++; } - /* Don't read over next header, or over temporary buffer. */ - if (len > sizeof(data->u.buffer)) - len = sizeof(data->u.buffer); - if (len > data->bytes_left) - len = data->bytes_left; - - err = xb_read(data->u.buffer, len); - if (err) - return err; - - data->bytes_left -= len; - if (ubuf && copy_to_user(ubuf, data->u.buffer, len) != 0) - return -EFAULT; - return len; + return i; +} + +static void queue_reply(struct xenbus_dev_data *u, + char *data, unsigned int len) +{ + int i; + + for (i = 0; i < len; i++, u->read_prod++) + u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; + + BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer)); + + wake_up(&u->read_waitq); } -/* We do v. basic sanity checking so they don't screw up kernel later. */ static ssize_t xenbus_dev_write(struct file *filp, const char __user *ubuf, size_t len, loff_t *ppos) { - struct xenbus_dev_data *data = filp->private_data; - int err; + struct xenbus_dev_data *u = filp->private_data; + void *reply; + int err = 0; - /* We gather data in buffer until we're ready to send it. */ - if (len > data->len + sizeof(data->u)) + if ((len + u->len) > sizeof(u->u.buffer)) return -EINVAL; - if (copy_from_user(data->u.buffer + data->len, ubuf, len) != 0) + + if (copy_from_user(u->u.buffer + u->len, ubuf, len) != 0) return -EFAULT; - data->len += len; - if (data->len >= sizeof(data->u.msg) + data->u.msg.len) { - err = xb_write(data->u.buffer, data->len); - if (err) - return err; - data->len = 0; - data->awaiting_reply = 1; + + u->len += len; + if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) + return len; + + switch (u->u.msg.type) { + case XS_TRANSACTION_START: + case XS_TRANSACTION_END: + case XS_DIRECTORY: + case XS_READ: + case XS_GET_PERMS: + case XS_RELEASE: + case XS_GET_DOMAIN_PATH: + case XS_WRITE: + case XS_MKDIR: + case XS_RM: + case XS_SET_PERMS: + reply = xenbus_dev_request_and_reply(&u->u.msg); + if (IS_ERR(reply)) + err = PTR_ERR(reply); + else { + if (u->u.msg.type == XS_TRANSACTION_START) + u->in_transaction = 1; + if (u->u.msg.type == XS_TRANSACTION_END) + u->in_transaction = 0; + queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); + queue_reply(u, (char *)reply, u->u.msg.len); + kfree(reply); + } + break; + + default: + err = -EINVAL; + break; } - return len; + + if (err == 0) { + u->len = 0; + err = len; + } + + return err; } static int xenbus_dev_open(struct inode *inode, struct file *filp) @@ -134,7 +162,6 @@ static int xenbus_dev_open(struct inode *inode, struct file *filp) if (xen_start_info->store_evtchn == 0) return -ENOENT; - /* Don't try seeking. */ nonseekable_open(inode, filp); u = kmalloc(sizeof(*u), GFP_KERNEL); @@ -142,28 +169,21 @@ static int xenbus_dev_open(struct inode *inode, struct file *filp) return -ENOMEM; memset(u, 0, sizeof(*u)); + init_waitqueue_head(&u->read_waitq); filp->private_data = u; - down(&xenbus_lock); - return 0; } static int xenbus_dev_release(struct inode *inode, struct file *filp) { - struct xenbus_dev_data *data = filp->private_data; + struct xenbus_dev_data *u = filp->private_data; - /* Discard any unread replies. */ - while (data->bytes_left || data->awaiting_reply) - xenbus_dev_read(filp, NULL, sizeof(data->u.buffer), NULL); + if (u->in_transaction) + xenbus_transaction_end(1); - /* Harmless if no transaction in progress. */ - xenbus_transaction_end(1); - - up(&xenbus_lock); - - kfree(data); + kfree(u); return 0; } diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index e872df679c..a320bf36ae 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -43,6 +43,9 @@ static struct notifier_block *xenstore_chain; +/* Now used to protect xenbus probes against save/restore. */ +static DECLARE_MUTEX(xenbus_lock); + /* If something in array of ids matches this device, return it. */ static const struct xenbus_device_id * match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) @@ -625,12 +628,13 @@ void xenbus_suspend(void) down(&xenbus_lock); bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev); bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev); + xs_suspend(); } void xenbus_resume(void) { xb_init_comms(); - reregister_xenbus_watches(); + xs_resume(); bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev); bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev); up(&xenbus_lock); @@ -685,6 +689,7 @@ int do_xenbus_probe(void *unused) /* Notify others that xenstore is up */ notifier_call_chain(&xenstore_chain, 0, 0); up(&xenbus_lock); + return 0; } diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c index 744576c02f..8e52045853 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @@ -42,11 +42,67 @@ #define streq(a, b) (strcmp((a), (b)) == 0) -static char printf_buffer[4096]; -static LIST_HEAD(watches); +struct xs_stored_msg { + struct xsd_sockmsg hdr; -DECLARE_MUTEX(xenbus_lock); -EXPORT_SYMBOL(xenbus_lock); + union { + /* Stored replies. */ + struct { + struct list_head list; + char *body; + } reply; + + /* Queued watch callbacks. */ + struct { + struct work_struct work; + struct xenbus_watch *handle; + char **vec; + unsigned int vec_size; + } watch; + } u; +}; + +struct xs_handle { + /* A list of replies. Currently only one will ever be outstanding. */ + struct list_head reply_list; + spinlock_t reply_lock; + wait_queue_head_t reply_waitq; + + /* One request at a time. */ + struct semaphore request_mutex; + + /* One transaction at a time. */ + struct semaphore transaction_mutex; + int transaction_pid; +}; + +static struct xs_handle xs_state; + +static LIST_HEAD(watches); +static DEFINE_SPINLOCK(watches_lock); + +/* Can wait on !xs_resuming for suspend/resume cycle to complete. */ +static int xs_resuming; +static DECLARE_WAIT_QUEUE_HEAD(xs_resuming_waitq); + +static void request_mutex_acquire(void) +{ + /* + * We can't distinguish non-transactional from transactional + * requests right now. So temporarily acquire the transaction mutex + * if this task is outside transaction context. + */ + if (xs_state.transaction_pid != current->pid) + down(&xs_state.transaction_mutex); + down(&xs_state.request_mutex); +} + +static void request_mutex_release(void) +{ + up(&xs_state.request_mutex); + if (xs_state.transaction_pid != current->pid) + up(&xs_state.transaction_mutex); +} static int get_error(const char *errorstring) { @@ -65,29 +121,32 @@ static int get_error(const char *errorstring) static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) { - struct xsd_sockmsg msg; - void *ret; - int err; + struct xs_stored_msg *msg; + char *body; - err = xb_read(&msg, sizeof(msg)); - if (err) - return ERR_PTR(err); + spin_lock(&xs_state.reply_lock); - ret = kmalloc(msg.len + 1, GFP_KERNEL); - if (!ret) - return ERR_PTR(-ENOMEM); - - err = xb_read(ret, msg.len); - if (err) { - kfree(ret); - return ERR_PTR(err); + while (list_empty(&xs_state.reply_list)) { + spin_unlock(&xs_state.reply_lock); + wait_event(xs_state.reply_waitq, + !list_empty(&xs_state.reply_list)); + spin_lock(&xs_state.reply_lock); } - ((char*)ret)[msg.len] = '\0'; - *type = msg.type; + msg = list_entry(xs_state.reply_list.next, + struct xs_stored_msg, u.reply.list); + list_del(&msg->u.reply.list); + + spin_unlock(&xs_state.reply_lock); + + *type = msg->hdr.type; if (len) - *len = msg.len; - return ret; + *len = msg->hdr.len; + body = msg->u.reply.body; + + kfree(msg); + + return body; } /* Emergency write. */ @@ -98,10 +157,45 @@ void xenbus_debug_write(const char *str, unsigned int count) msg.type = XS_DEBUG; msg.len = sizeof("print") + count + 1; + request_mutex_acquire(); xb_write(&msg, sizeof(msg)); xb_write("print", sizeof("print")); xb_write(str, count); xb_write("", 1); + request_mutex_release(); +} + +void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) +{ + void *ret; + struct xsd_sockmsg req_msg = *msg; + int err; + + if (req_msg.type == XS_TRANSACTION_START) { + down(&xs_state.transaction_mutex); + xs_state.transaction_pid = current->pid; + } + + request_mutex_acquire(); + + err = xb_write(msg, sizeof(*msg) + msg->len); + if (err) { + msg->type = XS_ERROR; + ret = ERR_PTR(err); + } else { + ret = read_reply(&msg->type, &msg->len); + } + + request_mutex_release(); + + if ((msg->type == XS_TRANSACTION_END) || + ((req_msg.type == XS_TRANSACTION_START) && + (msg->type == XS_ERROR))) { + xs_state.transaction_pid = -1; + up(&xs_state.transaction_mutex); + } + + return ret; } /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ @@ -115,31 +209,33 @@ static void *xs_talkv(enum xsd_sockmsg_type type, unsigned int i; int err; - WARN_ON(down_trylock(&xenbus_lock) == 0); - msg.type = type; msg.len = 0; for (i = 0; i < num_vecs; i++) msg.len += iovec[i].iov_len; + request_mutex_acquire(); + err = xb_write(&msg, sizeof(msg)); - if (err) + if (err) { + up(&xs_state.request_mutex); return ERR_PTR(err); + } for (i = 0; i < num_vecs; i++) { err = xb_write(iovec[i].iov_base, iovec[i].iov_len);; - if (err) + if (err) { + request_mutex_release(); return ERR_PTR(err); + } } - /* Watches can have fired before reply comes: daemon detects - * and re-transmits, so we can ignore this. */ - do { - kfree(ret); - ret = read_reply(&msg.type, len); - if (IS_ERR(ret)) - return ret; - } while (msg.type == XS_WATCH_EVENT); + ret = read_reply(&msg.type, len); + + request_mutex_release(); + + if (IS_ERR(ret)) + return ret; if (msg.type == XS_ERROR) { err = get_error(ret); @@ -187,8 +283,6 @@ static char *join(const char *dir, const char *name) { static char buffer[4096]; - BUG_ON(down_trylock(&xenbus_lock) == 0); - /* XXX FIXME: might not be correct if name == "" */ BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer)); strcpy(buffer, dir); @@ -207,7 +301,7 @@ static char **split(char *strings, unsigned int len, unsigned int *num) *num = count_strings(strings, len); /* Transfer to one big alloc for easy freeing. */ - ret = kmalloc(*num * sizeof(char *) + len, GFP_ATOMIC); + ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL); if (!ret) { kfree(strings); return ERR_PTR(-ENOMEM); @@ -298,7 +392,18 @@ EXPORT_SYMBOL(xenbus_rm); */ int xenbus_transaction_start(void) { - return xs_error(xs_single(XS_TRANSACTION_START, "", NULL)); + int err; + + down(&xs_state.transaction_mutex); + xs_state.transaction_pid = current->pid; + + err = xs_error(xs_single(XS_TRANSACTION_START, "", NULL)); + if (err) { + xs_state.transaction_pid = -1; + up(&xs_state.transaction_mutex); + } + + return err; } EXPORT_SYMBOL(xenbus_transaction_start); @@ -308,12 +413,19 @@ EXPORT_SYMBOL(xenbus_transaction_start); int xenbus_transaction_end(int abort) { char abortstr[2]; + int err; if (abort) strcpy(abortstr, "F"); else strcpy(abortstr, "T"); - return xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL)); + + err = xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL)); + + xs_state.transaction_pid = -1; + up(&xs_state.transaction_mutex); + + return err; } EXPORT_SYMBOL(xenbus_transaction_end); @@ -344,14 +456,23 @@ int xenbus_printf(const char *dir, const char *node, const char *fmt, ...) { va_list ap; int ret; +#define PRINTF_BUFFER_SIZE 4096 + char *printf_buffer; + + printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); + if (printf_buffer == NULL) + return -ENOMEM; - BUG_ON(down_trylock(&xenbus_lock) == 0); va_start(ap, fmt); - ret = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, ap); + ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); va_end(ap); - BUG_ON(ret > sizeof(printf_buffer)-1); - return xenbus_write(dir, node, printf_buffer); + BUG_ON(ret > PRINTF_BUFFER_SIZE-1); + ret = xenbus_write(dir, node, printf_buffer); + + kfree(printf_buffer); + + return ret; } EXPORT_SYMBOL(xenbus_printf); @@ -361,19 +482,28 @@ void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...) va_list ap; int ret; unsigned int len; + char *printf_buffer; - BUG_ON(down_trylock(&xenbus_lock) == 0); + printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); + if (printf_buffer == NULL) + goto fail; len = sprintf(printf_buffer, "%i ", -err); va_start(ap, fmt); - ret = vsnprintf(printf_buffer+len, sizeof(printf_buffer)-len, fmt, ap); + ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap); va_end(ap); - BUG_ON(len + ret > sizeof(printf_buffer)-1); + BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1); dev->has_error = 1; if (xenbus_write(dev->nodename, "error", printf_buffer) != 0) - printk("xenbus: failed to write error node for %s (%s)\n", - dev->nodename, printf_buffer); + goto fail; + + kfree(printf_buffer); + return; + + fail: + printk("xenbus: failed to write error node for %s (%s)\n", + dev->nodename, printf_buffer); } EXPORT_SYMBOL(xenbus_dev_error); @@ -432,26 +562,6 @@ static int xs_watch(const char *path, const char *token) return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL)); } -static char **xs_read_watch(unsigned int *num) -{ - enum xsd_sockmsg_type type; - char *strings; - unsigned int len; - - strings = read_reply(&type, &len); - if (IS_ERR(strings)) - return (char **)strings; - - BUG_ON(type != XS_WATCH_EVENT); - - return split(strings, len, num); -} - -static int xs_acknowledge_watch(const char *token) -{ - return xs_error(xs_single(XS_WATCH_ACK, token, NULL)); -} - static int xs_unwatch(const char *path, const char *token) { struct kvec iov[2]; @@ -464,7 +574,6 @@ static int xs_unwatch(const char *path, const char *token) return xs_error(xs_talkv(XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL)); } -/* A little paranoia: we don't just trust token. */ static struct xenbus_watch *find_watch(const char *token) { struct xenbus_watch *i, *cmp; @@ -474,6 +583,7 @@ static struct xenbus_watch *find_watch(const char *token) list_for_each_entry(i, &watches, list) if (i == cmp) return i; + return NULL; } @@ -485,11 +595,20 @@ int register_xenbus_watch(struct xenbus_watch *watch) int err; sprintf(token, "%lX", (long)watch); + + spin_lock(&watches_lock); BUG_ON(find_watch(token)); + spin_unlock(&watches_lock); err = xs_watch(watch->node, token); - if (!err) + + /* Ignore errors due to multiple registration. */ + if ((err == 0) || (err == -EEXIST)) { + spin_lock(&watches_lock); list_add(&watch->list, &watches); + spin_unlock(&watches_lock); + } + return err; } EXPORT_SYMBOL(register_xenbus_watch); @@ -500,77 +619,188 @@ void unregister_xenbus_watch(struct xenbus_watch *watch) int err; sprintf(token, "%lX", (long)watch); + + spin_lock(&watches_lock); BUG_ON(!find_watch(token)); + list_del(&watch->list); + spin_unlock(&watches_lock); + + /* Ensure xs_resume() is not in progress (see comments there). */ + wait_event(xs_resuming_waitq, !xs_resuming); err = xs_unwatch(watch->node, token); - list_del(&watch->list); - if (err) printk(KERN_WARNING "XENBUS Failed to release watch %s: %i\n", watch->node, err); + + /* Make sure watch is not in use. */ + flush_scheduled_work(); } EXPORT_SYMBOL(unregister_xenbus_watch); -/* Re-register callbacks to all watches. */ -void reregister_xenbus_watches(void) +void xs_suspend(void) { + down(&xs_state.transaction_mutex); + down(&xs_state.request_mutex); +} + +void xs_resume(void) +{ + struct list_head *ent, *prev_ent = &watches; struct xenbus_watch *watch; char token[sizeof(watch) * 2 + 1]; - list_for_each_entry(watch, &watches, list) { - sprintf(token, "%lX", (long)watch); - xs_watch(watch->node, token); + /* Protect against concurrent unregistration and freeing of watches. */ + BUG_ON(xs_resuming); + xs_resuming = 1; + + up(&xs_state.request_mutex); + up(&xs_state.transaction_mutex); + + /* + * Iterate over the watch list re-registering each node. We must + * be careful about concurrent registrations and unregistrations. + * We search for the node immediately following the previously + * re-registered node. If we get no match then either we are done + * (previous node is last in list) or the node was unregistered, in + * which case we restart from the beginning of the list. + * register_xenbus_watch() + unregister_xenbus_watch() is safe because + * it will only ever move a watch node earlier in the list, so it + * cannot cause us to skip nodes. + */ + for (;;) { + spin_lock(&watches_lock); + list_for_each(ent, &watches) + if (ent->prev == prev_ent) + break; + spin_unlock(&watches_lock); + + /* No match because prev_ent is at the end of the list? */ + if ((ent == &watches) && (watches.prev == prev_ent)) + break; /* We're done! */ + + if ((prev_ent = ent) != &watches) { + /* + * Safe even with watch_lock not held. We are saved by + * (xs_resumed==1) check in unregister_xenbus_watch. + */ + watch = list_entry(ent, struct xenbus_watch, list); + sprintf(token, "%lX", (long)watch); + xs_watch(watch->node, token); + } } + + xs_resuming = 0; + wake_up(&xs_resuming_waitq); } -static int watch_thread(void *unused) +static void xenbus_fire_watch(void *arg) { + struct xs_stored_msg *msg = arg; + + msg->u.watch.handle->callback(msg->u.watch.handle, + (const char **)msg->u.watch.vec, + msg->u.watch.vec_size); + + kfree(msg->u.watch.vec); + kfree(msg); +} + +static int process_msg(void) +{ + struct xs_stored_msg *msg; + char *body; + int err; + + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (msg == NULL) + return -ENOMEM; + + err = xb_read(&msg->hdr, sizeof(msg->hdr)); + if (err) { + kfree(msg); + return err; + } + + body = kmalloc(msg->hdr.len + 1, GFP_KERNEL); + if (body == NULL) { + kfree(msg); + return -ENOMEM; + } + + err = xb_read(body, msg->hdr.len); + if (err) { + kfree(body); + kfree(msg); + return err; + } + body[msg->hdr.len] = '\0'; + + if (msg->hdr.type == XS_WATCH_EVENT) { + INIT_WORK(&msg->u.watch.work, xenbus_fire_watch, msg); + + msg->u.watch.vec = split(body, msg->hdr.len, + &msg->u.watch.vec_size); + if (IS_ERR(msg->u.watch.vec)) { + kfree(msg); + return PTR_ERR(msg->u.watch.vec); + } + + spin_lock(&watches_lock); + msg->u.watch.handle = find_watch( + msg->u.watch.vec[XS_WATCH_TOKEN]); + if (msg->u.watch.handle != NULL) { + schedule_work(&msg->u.watch.work); + } else { + kfree(msg->u.watch.vec); + kfree(msg); + } + spin_unlock(&watches_lock); + } else { + msg->u.reply.body = body; + spin_lock(&xs_state.reply_lock); + list_add_tail(&msg->u.reply.list, &xs_state.reply_list); + spin_unlock(&xs_state.reply_lock); + wake_up(&xs_state.reply_waitq); + } + + return 0; +} + +static int read_thread(void *unused) +{ + int err; + for (;;) { - char **vec = NULL; - unsigned int num; - - wait_event(xb_waitq, xs_input_avail()); - - /* If this is a spurious wakeup caused by someone - * doing an op, they'll hold the lock and the buffer - * will be empty by the time we get there. - */ - down(&xenbus_lock); - if (xs_input_avail()) - vec = xs_read_watch(&num); - - if (vec && !IS_ERR(vec)) { - struct xenbus_watch *w; - int err; - - err = xs_acknowledge_watch(vec[XS_WATCH_TOKEN]); - if (err) - printk(KERN_WARNING "XENBUS ack %s fail %i\n", - vec[XS_WATCH_TOKEN], err); - w = find_watch(vec[XS_WATCH_TOKEN]); - BUG_ON(!w); - w->callback(w, (const char **)vec, num); - kfree(vec); - } else if (vec) - printk(KERN_WARNING "XENBUS xs_read_watch: %li\n", - PTR_ERR(vec)); - up(&xenbus_lock); + err = process_msg(); + if (err) + printk(KERN_WARNING "XENBUS error %d while reading " + "message\n", err); } } int xs_init(void) { int err; - struct task_struct *watcher; + struct task_struct *reader; + + INIT_LIST_HEAD(&xs_state.reply_list); + spin_lock_init(&xs_state.reply_lock); + init_waitqueue_head(&xs_state.reply_waitq); + + init_MUTEX(&xs_state.request_mutex); + init_MUTEX(&xs_state.transaction_mutex); + xs_state.transaction_pid = -1; err = xb_init_comms(); if (err) return err; - watcher = kthread_run(watch_thread, NULL, "kxbwatch"); - if (IS_ERR(watcher)) - return PTR_ERR(watcher); + reader = kthread_run(read_thread, NULL, "xenbusd"); + if (IS_ERR(reader)) + return PTR_ERR(reader); + return 0; } diff --git a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h index 219cc96b4f..3db3254d96 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h +++ b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h @@ -78,10 +78,6 @@ int xenbus_register_driver(struct xenbus_driver *drv); int xenbus_register_backend(struct xenbus_driver *drv); void xenbus_unregister_driver(struct xenbus_driver *drv); -/* Caller must hold this lock to call these functions: it's also held - * across watch callbacks. */ -extern struct semaphore xenbus_lock; - char **xenbus_directory(const char *dir, const char *node, unsigned int *num); void *xenbus_read(const char *dir, const char *node, unsigned int *len); int xenbus_write(const char *dir, const char *node, const char *string); @@ -113,7 +109,11 @@ void xenbus_dev_ok(struct xenbus_device *dev); struct xenbus_watch { struct list_head list; + + /* Path being watched. */ char *node; + + /* Callback (executed in a process context with no locks held). */ void (*callback)(struct xenbus_watch *, const char **vec, unsigned int len); }; @@ -124,7 +124,11 @@ void unregister_xenstore_notifier(struct notifier_block *nb); int register_xenbus_watch(struct xenbus_watch *watch); void unregister_xenbus_watch(struct xenbus_watch *watch); -void reregister_xenbus_watches(void); +void xs_suspend(void); +void xs_resume(void); + +/* Used by xenbus_dev to borrow kernel's store connection. */ +void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg); /* Called from xen core code. */ void xenbus_suspend(void); diff --git a/tools/blktap/xenbus.c b/tools/blktap/xenbus.c index c9cbea5fb3..99ba9ea49e 100644 --- a/tools/blktap/xenbus.c +++ b/tools/blktap/xenbus.c @@ -260,10 +260,6 @@ int xs_fire_next_watch(struct xs_handle *h) node = res[XS_WATCH_PATH]; token = res[XS_WATCH_TOKEN]; - er = xs_acknowledge_watch(h, token); - if (er == 0) - warn("Couldn't acknowledge watch (%s)", token); - w = find_watch(token); if (!w) { diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c index 24afe0b513..d533bd9b5c 100644 --- a/tools/console/daemon/io.c +++ b/tools/console/daemon/io.c @@ -505,7 +505,6 @@ static void handle_xs(int fd) domain_create_ring(dom); } - xs_acknowledge_watch(xs, vec[1]); free(vec); } diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c index 7389ea20ff..9c244d195a 100644 --- a/tools/python/xen/lowlevel/xs/xs.c +++ b/tools/python/xen/lowlevel/xs/xs.c @@ -442,9 +442,6 @@ static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds) #define xspy_read_watch_doc "\n" \ "Read a watch notification.\n" \ - "The notification must be acknowledged by passing\n" \ - "the token to acknowledge_watch().\n" \ - " path [string]: xenstore path.\n" \ "\n" \ "Returns: [tuple] (path, token).\n" \ "Raises RuntimeError on error.\n" \ @@ -495,44 +492,6 @@ static PyObject *xspy_read_watch(PyObject *self, PyObject *args, return val; } -#define xspy_acknowledge_watch_doc "\n" \ - "Acknowledge a watch notification that has been read.\n" \ - " token [string] : from the watch notification\n" \ - "\n" \ - "Returns None on success.\n" \ - "Raises RuntimeError on error.\n" \ - "\n" - -static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args, - PyObject *kwds) -{ - static char *kwd_spec[] = { "token", NULL }; - static char *arg_spec = "O"; - PyObject *token; - char token_str[MAX_STRLEN(unsigned long) + 1]; - - struct xs_handle *xh = xshandle(self); - PyObject *val = NULL; - int xsval = 0; - - if (!xh) - goto exit; - if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &token)) - goto exit; - sprintf(token_str, "%li", (unsigned long)token); - Py_BEGIN_ALLOW_THREADS - xsval = xs_acknowledge_watch(xh, token_str); - Py_END_ALLOW_THREADS - if (!xsval) { - PyErr_SetFromErrno(PyExc_RuntimeError); - goto exit; - } - Py_INCREF(Py_None); - val = Py_None; - exit: - return val; -} - #define xspy_unwatch_doc "\n" \ "Stop watching a path.\n" \ " path [string] : xenstore path.\n" \ @@ -833,7 +792,6 @@ static PyMethodDef xshandle_methods[] = { XSPY_METH(set_permissions), XSPY_METH(watch), XSPY_METH(read_watch), - XSPY_METH(acknowledge_watch), XSPY_METH(unwatch), XSPY_METH(transaction_start), XSPY_METH(transaction_end), diff --git a/tools/python/xen/xend/xenstore/xswatch.py b/tools/python/xen/xend/xenstore/xswatch.py index 8baf36e430..8a2da8d12c 100644 --- a/tools/python/xen/xend/xenstore/xswatch.py +++ b/tools/python/xen/xend/xenstore/xswatch.py @@ -8,6 +8,7 @@ import select import threading from xen.lowlevel import xs +from xen.xend.xenstore.xsutil import xshandle class xswatch: @@ -27,10 +28,7 @@ class xswatch: if cls.watchThread: cls.xslock.release() return - # XXX: When we fix xenstored to have better watch semantics, - # this can change to shared xshandle(). Currently that would result - # in duplicate watch firings, thus failed extra xs.acknowledge_watch. - cls.xs = xs.open() + cls.xs = xshandle() cls.watchThread = threading.Thread(name="Watcher", target=cls.watchMain) cls.watchThread.setDaemon(True) @@ -43,11 +41,10 @@ class xswatch: while True: try: we = cls.xs.read_watch() - watch = we[1] - cls.xs.acknowledge_watch(watch) except RuntimeError, ex: print ex raise + watch = we[1] watch.fn(*watch.args, **watch.kwargs) watchMain = classmethod(watchMain) diff --git a/tools/xenstore/testsuite/07watch.test b/tools/xenstore/testsuite/07watch.test index 5ae025765e..b4a44adebc 100644 --- a/tools/xenstore/testsuite/07watch.test +++ b/tools/xenstore/testsuite/07watch.test @@ -5,7 +5,6 @@ write /test contents 2 write /test contents2 expect 1:/test:token 1 waitwatch -1 ackwatch token 1 close # Check that reads don't set it off. @@ -22,15 +21,12 @@ mkdir /dir 2 mkdir /dir/newdir expect 1:/dir/newdir:token 1 waitwatch -1 ackwatch token 2 setperm /dir/newdir 0 READ expect 1:/dir/newdir:token 1 waitwatch -1 ackwatch token 2 rm /dir/newdir expect 1:/dir/newdir:token 1 waitwatch -1 ackwatch token 1 close 2 close @@ -49,7 +45,6 @@ expect contents read /dir/test expect /dir/test:token waitwatch -ackwatch token close # watch priority test: all simultaneous @@ -59,13 +54,10 @@ close write /dir/test contents expect 3:/dir/test:token3 3 waitwatch -3 ackwatch token3 expect 2:/dir/test:token2 2 waitwatch -2 ackwatch token2 expect 1:/dir/test:token1 1 waitwatch -1 ackwatch token1 1 close 2 close 3 close @@ -79,7 +71,6 @@ expect 2:/dir/test:token2 2 close expect 1:/dir/test:token1 1 waitwatch -1 ackwatch token1 1 close # If one dies (without reading at all), the other should still get ack. @@ -89,7 +80,6 @@ write /dir/test contents 2 close expect 1:/dir/test:token1 1 waitwatch -1 ackwatch token1 1 close 2 close @@ -111,7 +101,6 @@ write /dir/test contents 2 unwatch /dir token2 expect 1:/dir/test:token1 1 waitwatch -1 ackwatch token1 1 close 2 close @@ -123,14 +112,12 @@ write /dir/test contents write /dir/test contents2 expect 1:/dir/test:token2 1 waitwatch -1 ackwatch token2 # check we only get notified once. 1 watch /test token 2 write /test contents2 expect 1:/test:token 1 waitwatch -1 ackwatch token expect 1: waitwatch failed: Connection timed out 1 waitwatch 1 close @@ -142,13 +129,10 @@ expect 1: waitwatch failed: Connection timed out 2 write /test3 contents expect 1:/test1:token 1 waitwatch -1 ackwatch token expect 1:/test2:token 1 waitwatch -1 ackwatch token expect 1:/test3:token 1 waitwatch -1 ackwatch token 1 close # Creation of subpaths should be covered correctly. @@ -157,10 +141,8 @@ expect 1:/test3:token 2 write /test/subnode/subnode contents2 expect 1:/test/subnode:token 1 waitwatch -1 ackwatch token expect 1:/test/subnode/subnode:token 1 waitwatch -1 ackwatch token expect 1: waitwatch failed: Connection timed out 1 waitwatch 1 close @@ -171,7 +153,6 @@ expect 1: waitwatch failed: Connection timed out 1 watchnoack / token2 0 expect 1:/test/subnode:token 1 waitwatch -1 ackwatch token expect 1:/:token2 1 waitwatch expect 1: waitwatch failed: Connection timed out @@ -183,7 +164,6 @@ expect 1: waitwatch failed: Connection timed out 2 rm /test expect 1:/test/subnode:token 1 waitwatch -1 ackwatch token # Watch should not double-send after we ack, even if we did something in between. 1 watch /test2 token @@ -192,6 +172,5 @@ expect 1:/test2/foo:token 1 waitwatch expect 1:contents2 1 read /test2/foo -1 ackwatch token expect 1: waitwatch failed: Connection timed out 1 waitwatch diff --git a/tools/xenstore/testsuite/08transaction.test b/tools/xenstore/testsuite/08transaction.test index 558e06b9bc..c65fb647fa 100644 --- a/tools/xenstore/testsuite/08transaction.test +++ b/tools/xenstore/testsuite/08transaction.test @@ -68,7 +68,6 @@ expect 1: waitwatch failed: Connection timed out 2 commit expect 1:/test/dir/sub:token 1 waitwatch -1 ackwatch token 1 close # Rm inside transaction works like rm outside: children get notified. @@ -78,7 +77,6 @@ expect 1:/test/dir/sub:token 2 commit expect 1:/test/dir/sub:token 1 waitwatch -1 ackwatch token 1 close # Multiple events from single transaction don't trigger assert @@ -89,8 +87,6 @@ expect 1:/test/dir/sub:token 2 commit expect 1:/test/1:token 1 waitwatch -1 ackwatch token expect 1:/test/2:token 1 waitwatch -1 ackwatch token 1 close diff --git a/tools/xenstore/testsuite/10domain-homedir.test b/tools/xenstore/testsuite/10domain-homedir.test index 077606c0a5..88e4672909 100644 --- a/tools/xenstore/testsuite/10domain-homedir.test +++ b/tools/xenstore/testsuite/10domain-homedir.test @@ -16,4 +16,3 @@ dir /home write /home/foo/bar contents expect 1:foo/bar:token 1 waitwatch -1 ackwatch token diff --git a/tools/xenstore/testsuite/11domain-watch.test b/tools/xenstore/testsuite/11domain-watch.test index 159a85402e..3b28ee3094 100644 --- a/tools/xenstore/testsuite/11domain-watch.test +++ b/tools/xenstore/testsuite/11domain-watch.test @@ -10,7 +10,6 @@ introduce 1 100 7 /my/home write /test contents2 expect 1:/test:token 1 waitwatch -1 ackwatch token 1 unwatch /test token release 1 1 close @@ -25,7 +24,6 @@ write /dir/test contents 1 write /dir/test4 contents4 expect 1:/dir/test:token 1 waitwatch -1 ackwatch token release 1 1 close diff --git a/tools/xenstore/testsuite/12readonly.test b/tools/xenstore/testsuite/12readonly.test index 04331fab9d..14878e7dc1 100644 --- a/tools/xenstore/testsuite/12readonly.test +++ b/tools/xenstore/testsuite/12readonly.test @@ -36,4 +36,3 @@ watch / token 1 write /test contents expect /test:token waitwatch -ackwatch token diff --git a/tools/xenstore/testsuite/13watch-ack.test b/tools/xenstore/testsuite/13watch-ack.test index 41f2443aa0..e15f2b85e3 100644 --- a/tools/xenstore/testsuite/13watch-ack.test +++ b/tools/xenstore/testsuite/13watch-ack.test @@ -18,5 +18,4 @@ expect 1:/test/2:token2 1 waitwatch 3 write /test/1 contents1 4 write /test/3 contents3 -1 ackwatch token2 1 close diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 2061721547..25c9b03bb8 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -154,7 +154,6 @@ static char *sockmsg_string(enum xsd_sockmsg_type type) case XS_READ: return "READ"; case XS_GET_PERMS: return "GET_PERMS"; case XS_WATCH: return "WATCH"; - case XS_WATCH_ACK: return "WATCH_ACK"; case XS_UNWATCH: return "UNWATCH"; case XS_TRANSACTION_START: return "TRANSACTION_START"; case XS_TRANSACTION_END: return "TRANSACTION_END"; @@ -1103,10 +1102,6 @@ static void process_message(struct connection *conn, struct buffered_data *in) do_watch(conn, in); break; - case XS_WATCH_ACK: - do_watch_ack(conn, onearg(in)); - break; - case XS_UNWATCH: do_unwatch(conn, in); break; @@ -1168,11 +1163,6 @@ static void consider_message(struct connection *conn) xprintf("Got message %s len %i from %p\n", sockmsg_string(type), conn->in->hdr.msg.len, conn); - /* We might get a command while waiting for an ack: this means - * the other end discarded it: we will re-transmit. */ - if (type != XS_WATCH_ACK) - conn->waiting_for_ack = NULL; - /* Careful: process_message may free connection. We detach * "in" beforehand and allocate the new buffer to avoid * touching conn after process_message. @@ -1266,7 +1256,6 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) new->state = OK; new->out = new->waiting_reply = NULL; - new->waiting_for_ack = NULL; new->fd = -1; new->id = 0; new->domain = NULL; diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index e0e4d58886..e017bddf42 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -71,9 +71,6 @@ struct connection /* Is this a read-only connection? */ bool can_write; - /* Are we waiting for a watch event ack? */ - struct watch *waiting_for_ack; - /* Buffered incoming data. */ struct buffered_data *in; diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c index 0f8bc6fbdf..dfb0cd1a3e 100644 --- a/tools/xenstore/xenstored_watch.c +++ b/tools/xenstore/xenstored_watch.c @@ -69,18 +69,14 @@ void queue_next_event(struct connection *conn) if (conn->waiting_reply) { conn->out = conn->waiting_reply; conn->waiting_reply = NULL; - conn->waiting_for_ack = NULL; return; } - /* If we're already waiting for ack, don't queue more. */ - if (conn->waiting_for_ack) - return; - list_for_each_entry(watch, &conn->watches, list) { event = list_top(&watch->events, struct watch_event, list); if (event) { - conn->waiting_for_ack = watch; + list_del(&event->list); + talloc_free(event); send_reply(conn,XS_WATCH_EVENT,event->data,event->len); break; } @@ -181,6 +177,15 @@ void do_watch(struct connection *conn, struct buffered_data *in) } } + /* Check for duplicates. */ + list_for_each_entry(watch, &conn->watches, list) { + if (streq(watch->node, vec[0]) && + streq(watch->token, vec[1])) { + send_error(conn, EEXIST); + return; + } + } + watch = talloc(conn, struct watch); watch->node = talloc_strdup(watch, vec[0]); watch->token = talloc_strdup(watch, vec[1]); @@ -200,37 +205,6 @@ void do_watch(struct connection *conn, struct buffered_data *in) add_event(conn, watch, watch->node); } -void do_watch_ack(struct connection *conn, const char *token) -{ - struct watch_event *event; - - if (!token) { - send_error(conn, EINVAL); - return; - } - - if (!conn->waiting_for_ack) { - send_error(conn, ENOENT); - return; - } - - if (!streq(conn->waiting_for_ack->token, token)) { - /* They're confused: this will cause us to send event again */ - conn->waiting_for_ack = NULL; - send_error(conn, EINVAL); - return; - } - - /* Remove event: after ack sent, core will call queue_next_event */ - event = list_top(&conn->waiting_for_ack->events, struct watch_event, - list); - list_del(&event->list); - talloc_free(event); - - conn->waiting_for_ack = NULL; - send_ack(conn, XS_WATCH_ACK); -} - void do_unwatch(struct connection *conn, struct buffered_data *in) { struct watch *watch; @@ -241,9 +215,6 @@ void do_unwatch(struct connection *conn, struct buffered_data *in) return; } - /* We don't need to worry if we're waiting for an ack for the - * watch we're deleting: conn->waiting_for_ack was reset by - * this command in consider_message anyway. */ node = canonicalize(conn, vec[0]); list_for_each_entry(watch, &conn->watches, list) { if (streq(watch->node, node) && streq(watch->token, vec[1])) { @@ -262,11 +233,6 @@ void dump_watches(struct connection *conn) struct watch *watch; struct watch_event *event; - if (conn->waiting_for_ack) - printf(" waiting_for_ack for watch on %s token %s\n", - conn->waiting_for_ack->node, - conn->waiting_for_ack->token); - list_for_each_entry(watch, &conn->watches, list) { printf(" watch on %s token %s\n", watch->node, watch->token); diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c index 6dc4c4532c..1b648d2578 100644 --- a/tools/xenstore/xs.c +++ b/tools/xenstore/xs.c @@ -78,10 +78,30 @@ struct xs_handle { /* One transaction at a time. */ pthread_mutex_t transaction_mutex; + pthread_t transaction_pthread; }; static void *read_thread(void *arg); +static void request_mutex_acquire(struct xs_handle *h) +{ + /* + * We can't distinguish non-transactional from transactional + * requests right now. So temporarily acquire the transaction mutex + * if this task is outside transaction context. + */ + if (h->transaction_pthread != pthread_self()) + pthread_mutex_lock(&h->transaction_mutex); + pthread_mutex_lock(&h->request_mutex); +} + +static void request_mutex_release(struct xs_handle *h) +{ + pthread_mutex_unlock(&h->request_mutex); + if (h->transaction_pthread != pthread_self()) + pthread_mutex_unlock(&h->transaction_mutex); +} + int xs_fileno(struct xs_handle *h) { char c = 0; @@ -163,6 +183,7 @@ static struct xs_handle *get_handle(const char *connect_to) pthread_mutex_init(&h->request_mutex, NULL); pthread_mutex_init(&h->transaction_mutex, NULL); + h->transaction_pthread = -1; if (pthread_create(&h->read_thr, NULL, read_thread, h) != 0) goto error; @@ -316,7 +337,7 @@ static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type, ignorepipe.sa_flags = 0; sigaction(SIGPIPE, &ignorepipe, &oldact); - pthread_mutex_lock(&h->request_mutex); + request_mutex_acquire(h); if (!xs_write_all(h->fd, &msg, sizeof(msg))) goto fail; @@ -329,7 +350,7 @@ static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type, if (!ret) goto fail; - pthread_mutex_unlock(&h->request_mutex); + request_mutex_release(h); sigaction(SIGPIPE, &oldact, NULL); if (msg.type == XS_ERROR) { @@ -350,7 +371,7 @@ static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type, fail: /* We're in a bad state, so close fd. */ saved_errno = errno; - pthread_mutex_unlock(&h->request_mutex); + request_mutex_release(h); sigaction(SIGPIPE, &oldact, NULL); close_fd: close(h->fd); @@ -593,15 +614,6 @@ char **xs_read_watch(struct xs_handle *h, unsigned int *num) return ret; } -/* Acknowledge watch on node. Watches must be acknowledged before - * any other watches can be read. - * Returns false on failure. - */ -bool xs_acknowledge_watch(struct xs_handle *h, const char *token) -{ - return xs_bool(xs_single(h, XS_WATCH_ACK, token, NULL)); -} - /* Remove a watch on a node. * Returns false on failure (no watch on that node). */ @@ -624,8 +636,18 @@ bool xs_unwatch(struct xs_handle *h, const char *path, const char *token) */ bool xs_transaction_start(struct xs_handle *h) { + bool rc; + pthread_mutex_lock(&h->transaction_mutex); - return xs_bool(xs_single(h, XS_TRANSACTION_START, "", NULL)); + h->transaction_pthread = pthread_self(); + + rc = xs_bool(xs_single(h, XS_TRANSACTION_START, "", NULL)); + if (!rc) { + h->transaction_pthread = -1; + pthread_mutex_unlock(&h->transaction_mutex); + } + + return rc; } /* End a transaction. @@ -645,6 +667,7 @@ bool xs_transaction_end(struct xs_handle *h, bool abort) rc = xs_bool(xs_single(h, XS_TRANSACTION_END, abortstr, NULL)); + h->transaction_pthread = -1; pthread_mutex_unlock(&h->transaction_mutex); return rc; diff --git a/tools/xenstore/xs.h b/tools/xenstore/xs.h index b027a360dd..59dd96d5da 100644 --- a/tools/xenstore/xs.h +++ b/tools/xenstore/xs.h @@ -96,12 +96,6 @@ int xs_fileno(struct xs_handle *h); */ char **xs_read_watch(struct xs_handle *h, unsigned int *num); -/* Acknowledge watch on node. Watches must be acknowledged before - * any other watches can be read. - * Returns false on failure. - */ -bool xs_acknowledge_watch(struct xs_handle *h, const char *token); - /* Remove a watch on a node: implicitly acks any outstanding watch. * Returns false on failure (no watch on that node). */ diff --git a/tools/xenstore/xs_test.c b/tools/xenstore/xs_test.c index 2517ac1560..45b9085153 100644 --- a/tools/xenstore/xs_test.c +++ b/tools/xenstore/xs_test.c @@ -201,7 +201,6 @@ static void __attribute__((noreturn)) usage(void) " watch \n" " watchnoack \n" " waitwatch\n" - " ackwatch \n" " unwatch \n" " close\n" " start \n" @@ -455,8 +454,6 @@ static void do_watch(unsigned int handle, const char *node, const char *token, !streq(vec[XS_WATCH_PATH], node) || !streq(vec[XS_WATCH_TOKEN], token)) failed(handle); - if (!xs_acknowledge_watch(handles[handle], token)) - failed(handle); } } @@ -515,12 +512,6 @@ static void do_waitwatch(unsigned int handle) free(vec); } -static void do_ackwatch(unsigned int handle, const char *token) -{ - if (!xs_acknowledge_watch(handles[handle], token)) - failed(handle); -} - static void do_unwatch(unsigned int handle, const char *node, const char *token) { if (!xs_unwatch(handles[handle], node, token)) @@ -746,8 +737,6 @@ static void do_command(unsigned int default_handle, char *line) do_watch(handle, arg(line, 1), arg(line, 2), false); else if (streq(command, "waitwatch")) do_waitwatch(handle); - else if (streq(command, "ackwatch")) - do_ackwatch(handle, arg(line, 1)); else if (streq(command, "unwatch")) do_unwatch(handle, arg(line, 1), arg(line, 2)); else if (streq(command, "close")) { diff --git a/xen/include/public/io/xs_wire.h b/xen/include/public/io/xs_wire.h index 066c709e30..3c26cc0d80 100644 --- a/xen/include/public/io/xs_wire.h +++ b/xen/include/public/io/xs_wire.h @@ -35,11 +35,9 @@ enum xsd_sockmsg_type XS_READ, XS_GET_PERMS, XS_WATCH, - XS_WATCH_ACK, XS_UNWATCH, XS_TRANSACTION_START, XS_TRANSACTION_END, - XS_OP_READ_ONLY = XS_TRANSACTION_END, XS_INTRODUCE, XS_RELEASE, XS_GET_DOMAIN_PATH, From f2b39d8ae1082e6d2f364e5dab146d2396094cac Mon Sep 17 00:00:00 2001 From: "smh22@firebug.cl.cam.ac.uk" Date: Sun, 9 Oct 2005 20:55:53 +0100 Subject: [PATCH 11/42] Added some clarifying comments regarding xenbus/xenstore kernel startup. Signed-off-by: Steven Hand --- linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c | 5 ++++- .../drivers/xen/xenbus/xenbus_probe.c | 12 ++++++++++-- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c | 4 ++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c index f3103092f1..6ed338bab1 100644 --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @@ -246,7 +246,10 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, PAGE_SHIFT); ret = xen_start_info->store_mfn; - /* We'll return then this will wait for daemon to answer */ + /* + ** Complete initialization of xenbus (viz. set up the + ** connection to xenstored now that it has started). + */ kthread_run(do_xenbus_probe, NULL, "xenbus_probe"); } break; diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index a320bf36ae..5db856fe44 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -666,12 +666,16 @@ void unregister_xenstore_notifier(struct notifier_block *nb) } EXPORT_SYMBOL(unregister_xenstore_notifier); -/* called from a thread in privcmd/privcmd.c */ +/* +** Called either from below xenbus_probe_init() initcall (for domUs) +** or, for dom0, from a thread created in privcmd/privcmd.c (after +** the user-space tools have invoked initDomainStore()) +*/ int do_xenbus_probe(void *unused) { int err = 0; - /* Initialize xenstore comms unless already done. */ + /* Initialize the interface to xenstore. */ err = xs_init(); if (err) { printk("XENBUS: Error initializing xenstore comms:" @@ -703,6 +707,10 @@ static int __init xenbus_probe_init(void) device_register(&xenbus_frontend.dev); device_register(&xenbus_backend.dev); + /* + ** Domain0 doesn't have a store_evtchn yet - this will + ** be set up later by xend invoking initDomainStore() + */ if (!xen_start_info->store_evtchn) return 0; diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c index 8e52045853..ea0ead1596 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @@ -780,6 +780,9 @@ static int read_thread(void *unused) } } +/* +** Initialize the interface to xenstore. +*/ int xs_init(void) { int err; @@ -793,6 +796,7 @@ int xs_init(void) init_MUTEX(&xs_state.transaction_mutex); xs_state.transaction_pid = -1; + /* Initialize the shared memory rings to talk to xenstored */ err = xb_init_comms(); if (err) return err; From 25517fd2f2a26162a466a0933cb56c49373fbae7 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sun, 9 Oct 2005 21:29:10 +0100 Subject: [PATCH 12/42] Extend xenbus/xenstore client interface to include a transaction handle on appropriate operations. Next step is to plug this through to the store daemon and get rid of the nasty serialisation mutex for transactions. Signed-off-by: Keir Fraser --- .../arch/xen/i386/kernel/smpboot.c | 2 +- linux-2.6-xen-sparse/arch/xen/kernel/reboot.c | 26 ++-- .../drivers/xen/balloon/balloon.c | 2 +- .../drivers/xen/blkback/xenbus.c | 43 +++--- .../drivers/xen/blkfront/blkfront.c | 22 +-- .../drivers/xen/netback/xenbus.c | 17 +-- .../drivers/xen/netfront/netfront.c | 22 +-- .../drivers/xen/tpmback/xenbus.c | 23 +-- .../drivers/xen/tpmfront/tpmfront.c | 20 +-- .../drivers/xen/xenbus/xenbus_dev.c | 2 +- .../drivers/xen/xenbus/xenbus_probe.c | 12 +- .../drivers/xen/xenbus/xenbus_xs.c | 46 +++--- linux-2.6-xen-sparse/include/asm-xen/xenbus.h | 35 +++-- tools/console/client/main.c | 4 +- tools/console/daemon/io.c | 6 +- tools/python/xen/lowlevel/xs/xs.c | 133 +++++++++++++----- tools/python/xen/xend/xenstore/xstransact.py | 33 +++-- tools/xenstore/Makefile | 2 +- tools/xenstore/xenstore_client.c | 17 +-- tools/xenstore/xs.c | 37 +++-- tools/xenstore/xs.h | 40 ++++-- tools/xenstore/xs_test.c | 43 ++++-- 22 files changed, 364 insertions(+), 223 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c index c4bfaeacbd..6152c349c4 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -1364,7 +1364,7 @@ static void handle_vcpu_hotplug_event(struct xenbus_watch *watch, const char *no return; /* get the state value */ - err = xenbus_scanf(dir, "availability", "%s", state); + err = xenbus_scanf(NULL, dir, "availability", "%s", state); if (err != 1) { printk(KERN_ERR diff --git a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c index 6094573a82..ced2d54582 100644 --- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c +++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @@ -275,22 +275,23 @@ static void shutdown_handler(struct xenbus_watch *watch, { static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL); char *str; + struct xenbus_transaction *xbt; int err; again: - err = xenbus_transaction_start(); - if (err) + xbt = xenbus_transaction_start(); + if (IS_ERR(xbt)) return; - str = (char *)xenbus_read("control", "shutdown", NULL); + str = (char *)xenbus_read(xbt, "control", "shutdown", NULL); /* Ignore read errors and empty reads. */ if (XENBUS_IS_ERR_READ(str)) { - xenbus_transaction_end(1); + xenbus_transaction_end(xbt, 1); return; } - xenbus_write("control", "shutdown", ""); + xenbus_write(xbt, "control", "shutdown", ""); - err = xenbus_transaction_end(0); + err = xenbus_transaction_end(xbt, 0); if (err == -EAGAIN) { kfree(str); goto again; @@ -320,23 +321,24 @@ static void sysrq_handler(struct xenbus_watch *watch, const char **vec, unsigned int len) { char sysrq_key = '\0'; + struct xenbus_transaction *xbt; int err; again: - err = xenbus_transaction_start(); - if (err) + xbt = xenbus_transaction_start(); + if (IS_ERR(xbt)) return; - if (!xenbus_scanf("control", "sysrq", "%c", &sysrq_key)) { + if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) { printk(KERN_ERR "Unable to read sysrq code in " "control/sysrq\n"); - xenbus_transaction_end(1); + xenbus_transaction_end(xbt, 1); return; } if (sysrq_key != '\0') - xenbus_printf("control", "sysrq", "%c", '\0'); + xenbus_printf(xbt, "control", "sysrq", "%c", '\0'); - err = xenbus_transaction_end(0); + err = xenbus_transaction_end(xbt, 0); if (err == -EAGAIN) goto again; diff --git a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c index 36c6286cd3..984e6f9ad9 100644 --- a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c +++ b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c @@ -357,7 +357,7 @@ static void watch_target(struct xenbus_watch *watch, unsigned long long new_target; int err; - err = xenbus_scanf("memory", "target", "%llu", &new_target); + err = xenbus_scanf(NULL, "memory", "target", "%llu", &new_target); if (err != 1) { printk(KERN_ERR "Unable to read memory/target\n"); return; diff --git a/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c index 187bec8121..1e40eb1947 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c @@ -61,18 +61,19 @@ static void frontend_changed(struct xenbus_watch *watch, unsigned long ring_ref; unsigned int evtchn; int err; + struct xenbus_transaction *xbt; struct backend_info *be = container_of(watch, struct backend_info, watch); /* If other end is gone, delete ourself. */ - if (vec && !xenbus_exists(be->frontpath, "")) { + if (vec && !xenbus_exists(NULL, be->frontpath, "")) { device_unregister(&be->dev->dev); return; } if (be->blkif == NULL || be->blkif->status == CONNECTED) return; - err = xenbus_gather(be->frontpath, "ring-ref", "%lu", &ring_ref, + err = xenbus_gather(NULL, be->frontpath, "ring-ref", "%lu", &ring_ref, "event-channel", "%u", &evtchn, NULL); if (err) { xenbus_dev_error(be->dev, err, @@ -84,7 +85,8 @@ static void frontend_changed(struct xenbus_watch *watch, /* Map the shared frame, irq etc. */ err = blkif_map(be->blkif, ring_ref, evtchn); if (err) { - xenbus_dev_error(be->dev, err, "mapping ring-ref %lu port %u", + xenbus_dev_error(be->dev, err, + "mapping ring-ref %lu port %u", ring_ref, evtchn); return; } @@ -92,13 +94,13 @@ static void frontend_changed(struct xenbus_watch *watch, again: /* Supply the information about the device the frontend needs */ - err = xenbus_transaction_start(); - if (err) { + xbt = xenbus_transaction_start(); + if (IS_ERR(xbt)) { xenbus_dev_error(be->dev, err, "starting transaction"); return; } - err = xenbus_printf(be->dev->nodename, "sectors", "%lu", + err = xenbus_printf(xbt, be->dev->nodename, "sectors", "%lu", vbd_size(&be->blkif->vbd)); if (err) { xenbus_dev_error(be->dev, err, "writing %s/sectors", @@ -107,14 +109,14 @@ again: } /* FIXME: use a typename instead */ - err = xenbus_printf(be->dev->nodename, "info", "%u", + err = xenbus_printf(xbt, be->dev->nodename, "info", "%u", vbd_info(&be->blkif->vbd)); if (err) { xenbus_dev_error(be->dev, err, "writing %s/info", be->dev->nodename); goto abort; } - err = xenbus_printf(be->dev->nodename, "sector-size", "%lu", + err = xenbus_printf(xbt, be->dev->nodename, "sector-size", "%lu", vbd_secsize(&be->blkif->vbd)); if (err) { xenbus_dev_error(be->dev, err, "writing %s/sector-size", @@ -122,7 +124,7 @@ again: goto abort; } - err = xenbus_transaction_end(0); + err = xenbus_transaction_end(xbt, 0); if (err == -EAGAIN) goto again; if (err) { @@ -136,7 +138,7 @@ again: return; abort: - xenbus_transaction_end(1); + xenbus_transaction_end(xbt, 1); } /* @@ -154,7 +156,8 @@ static void backend_changed(struct xenbus_watch *watch, = container_of(watch, struct backend_info, backend_watch); struct xenbus_device *dev = be->dev; - err = xenbus_scanf(dev->nodename, "physical-device", "%li", &pdev); + err = xenbus_scanf(NULL, dev->nodename, + "physical-device", "%li", &pdev); if (XENBUS_EXIST_ERR(err)) return; if (err < 0) { @@ -169,7 +172,7 @@ static void backend_changed(struct xenbus_watch *watch, be->pdev = pdev; /* If there's a read-only node, we're read only. */ - p = xenbus_read(dev->nodename, "read-only", NULL); + p = xenbus_read(NULL, dev->nodename, "read-only", NULL); if (!IS_ERR(p)) { be->readonly = 1; kfree(p); @@ -184,7 +187,8 @@ static void backend_changed(struct xenbus_watch *watch, if (IS_ERR(be->blkif)) { err = PTR_ERR(be->blkif); be->blkif = NULL; - xenbus_dev_error(dev, err, "creating block interface"); + xenbus_dev_error(dev, err, + "creating block interface"); return; } @@ -192,7 +196,8 @@ static void backend_changed(struct xenbus_watch *watch, if (err) { blkif_put(be->blkif); be->blkif = NULL; - xenbus_dev_error(dev, err, "creating vbd structure"); + xenbus_dev_error(dev, err, + "creating vbd structure"); return; } @@ -210,13 +215,14 @@ static int blkback_probe(struct xenbus_device *dev, be = kmalloc(sizeof(*be), GFP_KERNEL); if (!be) { - xenbus_dev_error(dev, -ENOMEM, "allocating backend structure"); + xenbus_dev_error(dev, -ENOMEM, + "allocating backend structure"); return -ENOMEM; } memset(be, 0, sizeof(*be)); frontend = NULL; - err = xenbus_gather(dev->nodename, + err = xenbus_gather(NULL, dev->nodename, "frontend-id", "%li", &be->frontend_id, "frontend", NULL, &frontend, NULL); @@ -228,7 +234,7 @@ static int blkback_probe(struct xenbus_device *dev, dev->nodename); goto free_be; } - if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) { + if (strlen(frontend) == 0 || !xenbus_exists(NULL, frontend, "")) { /* If we can't get a frontend path and a frontend-id, * then our bus-id is no longer valid and we need to * destroy the backend device. @@ -244,7 +250,8 @@ static int blkback_probe(struct xenbus_device *dev, err = register_xenbus_watch(&be->backend_watch); if (err) { be->backend_watch.node = NULL; - xenbus_dev_error(dev, err, "adding backend watch on %s", + xenbus_dev_error(dev, err, + "adding backend watch on %s", dev->nodename); goto free_be; } diff --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c index 8d6e071fef..edb5360cd7 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c @@ -460,7 +460,7 @@ static void watch_for_status(struct xenbus_watch *watch, if (info->connected == BLKIF_STATE_CONNECTED) return; - err = xenbus_gather(watch->node, + err = xenbus_gather(NULL, watch->node, "sectors", "%lu", §ors, "info", "%u", &binfo, "sector-size", "%lu", §or_size, @@ -532,10 +532,11 @@ static int talk_to_backend(struct xenbus_device *dev, { char *backend; const char *message; + struct xenbus_transaction *xbt; int err; backend = NULL; - err = xenbus_gather(dev->nodename, + err = xenbus_gather(NULL, dev->nodename, "backend-id", "%i", &info->backend_id, "backend", NULL, &backend, NULL); @@ -559,25 +560,26 @@ static int talk_to_backend(struct xenbus_device *dev, } again: - err = xenbus_transaction_start(); - if (err) { + xbt = xenbus_transaction_start(); + if (IS_ERR(xbt)) { xenbus_dev_error(dev, err, "starting transaction"); goto destroy_blkring; } - err = xenbus_printf(dev->nodename, "ring-ref","%u", info->ring_ref); + err = xenbus_printf(xbt, dev->nodename, + "ring-ref","%u", info->ring_ref); if (err) { message = "writing ring-ref"; goto abort_transaction; } - err = xenbus_printf(dev->nodename, + err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", info->evtchn); if (err) { message = "writing event-channel"; goto abort_transaction; } - err = xenbus_transaction_end(0); + err = xenbus_transaction_end(xbt, 0); if (err) { if (err == -EAGAIN) goto again; @@ -598,8 +600,7 @@ again: return 0; abort_transaction: - xenbus_transaction_end(1); - /* Have to do this *outside* transaction. */ + xenbus_transaction_end(xbt, 1); xenbus_dev_error(dev, err, "%s", message); destroy_blkring: blkif_free(info); @@ -620,7 +621,8 @@ static int blkfront_probe(struct xenbus_device *dev, struct blkfront_info *info; /* FIXME: Use dynamic device id if this is not set. */ - err = xenbus_scanf(dev->nodename, "virtual-device", "%i", &vdevice); + err = xenbus_scanf(NULL, dev->nodename, + "virtual-device", "%i", &vdevice); if (XENBUS_EXIST_ERR(err)) return err; if (err < 0) { diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c index c452d7e29f..905ca8b801 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c @@ -69,15 +69,15 @@ static void frontend_changed(struct xenbus_watch *watch, int i; /* If other end is gone, delete ourself. */ - if (vec && !xenbus_exists(be->frontpath, "")) { - xenbus_rm(be->dev->nodename, ""); + if (vec && !xenbus_exists(NULL, be->frontpath, "")) { + xenbus_rm(NULL, be->dev->nodename, ""); device_unregister(&be->dev->dev); return; } if (be->netif == NULL || be->netif->status == CONNECTED) return; - mac = xenbus_read(be->frontpath, "mac", NULL); + mac = xenbus_read(NULL, be->frontpath, "mac", NULL); if (IS_ERR(mac)) { err = PTR_ERR(mac); xenbus_dev_error(be->dev, err, "reading %s/mac", @@ -98,7 +98,8 @@ static void frontend_changed(struct xenbus_watch *watch, } kfree(mac); - err = xenbus_gather(be->frontpath, "tx-ring-ref", "%lu", &tx_ring_ref, + err = xenbus_gather(NULL, be->frontpath, + "tx-ring-ref", "%lu", &tx_ring_ref, "rx-ring-ref", "%lu", &rx_ring_ref, "event-channel", "%u", &evtchn, NULL); if (err) { @@ -137,7 +138,7 @@ static void backend_changed(struct xenbus_watch *watch, struct xenbus_device *dev = be->dev; u8 be_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; - err = xenbus_scanf(dev->nodename, "handle", "%li", &handle); + err = xenbus_scanf(NULL, dev->nodename, "handle", "%li", &handle); if (XENBUS_EXIST_ERR(err)) return; if (err < 0) { @@ -188,7 +189,7 @@ static int netback_hotplug(struct xenbus_device *xdev, char **envp, key = env_vars; while (*key != NULL) { - val = xenbus_read(xdev->nodename, *key, NULL); + val = xenbus_read(NULL, xdev->nodename, *key, NULL); if (!IS_ERR(val)) { char buf[strlen(*key) + 4]; sprintf(buf, "%s=%%s", *key); @@ -220,7 +221,7 @@ static int netback_probe(struct xenbus_device *dev, memset(be, 0, sizeof(*be)); frontend = NULL; - err = xenbus_gather(dev->nodename, + err = xenbus_gather(NULL, dev->nodename, "frontend-id", "%li", &be->frontend_id, "frontend", NULL, &frontend, NULL); @@ -232,7 +233,7 @@ static int netback_probe(struct xenbus_device *dev, dev->nodename); goto free_be; } - if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) { + if (strlen(frontend) == 0 || !xenbus_exists(NULL, frontend, "")) { /* If we can't get a frontend path and a frontend-id, * then our bus-id is no longer valid and we need to * destroy the backend device. diff --git a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c index 9a2969f5a0..1b43e5ed38 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c @@ -1083,10 +1083,11 @@ static int talk_to_backend(struct xenbus_device *dev, { char *backend, *mac, *e, *s; const char *message; + struct xenbus_transaction *xbt; int err, i; backend = NULL; - err = xenbus_gather(dev->nodename, + err = xenbus_gather(NULL, dev->nodename, "backend-id", "%i", &info->backend_id, "backend", NULL, &backend, NULL); @@ -1102,7 +1103,7 @@ static int talk_to_backend(struct xenbus_device *dev, goto out; } - mac = xenbus_read(dev->nodename, "mac", NULL); + mac = xenbus_read(NULL, dev->nodename, "mac", NULL); if (IS_ERR(mac)) { err = PTR_ERR(mac); xenbus_dev_error(dev, err, "reading %s/mac", @@ -1131,32 +1132,32 @@ static int talk_to_backend(struct xenbus_device *dev, } again: - err = xenbus_transaction_start(); - if (err) { + xbt = xenbus_transaction_start(); + if (IS_ERR(xbt)) { xenbus_dev_error(dev, err, "starting transaction"); goto destroy_ring; } - err = xenbus_printf(dev->nodename, "tx-ring-ref","%u", + err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u", info->tx_ring_ref); if (err) { message = "writing tx ring-ref"; goto abort_transaction; } - err = xenbus_printf(dev->nodename, "rx-ring-ref","%u", + err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u", info->rx_ring_ref); if (err) { message = "writing rx ring-ref"; goto abort_transaction; } - err = xenbus_printf(dev->nodename, + err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", info->evtchn); if (err) { message = "writing event-channel"; goto abort_transaction; } - err = xenbus_transaction_end(0); + err = xenbus_transaction_end(xbt, 0); if (err) { if (err == -EAGAIN) goto again; @@ -1177,8 +1178,7 @@ again: return 0; abort_transaction: - xenbus_transaction_end(1); - /* Have to do this *outside* transaction. */ + xenbus_transaction_end(xbt, 1); xenbus_dev_error(dev, err, "%s", message); destroy_ring: shutdown_device(info); @@ -1201,7 +1201,7 @@ static int netfront_probe(struct xenbus_device *dev, struct netfront_info *info; unsigned int handle; - err = xenbus_scanf(dev->nodename, "handle", "%u", &handle); + err = xenbus_scanf(NULL, dev->nodename, "handle", "%u", &handle); if (XENBUS_EXIST_ERR(err)) return err; if (err < 0) { diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c index ac31843a2c..954330d0de 100644 --- a/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c @@ -66,12 +66,13 @@ static void frontend_changed(struct xenbus_watch *watch, unsigned int evtchn; unsigned long ready = 1; int err; + struct xenbus_transaction *xbt; struct backend_info *be = container_of(watch, struct backend_info, watch); /* If other end is gone, delete ourself. */ - if (vec && !xenbus_exists(be->frontpath, "")) { - xenbus_rm(be->dev->nodename, ""); + if (vec && !xenbus_exists(NULL, be->frontpath, "")) { + xenbus_rm(NULL, be->dev->nodename, ""); device_unregister(&be->dev->dev); return; } @@ -79,7 +80,7 @@ static void frontend_changed(struct xenbus_watch *watch, if (be->tpmif == NULL || be->tpmif->status == CONNECTED) return; - err = xenbus_gather(be->frontpath, + err = xenbus_gather(NULL, be->frontpath, "ring-ref", "%lu", &ringref, "event-channel", "%u", &evtchn, NULL); if (err) { @@ -115,20 +116,20 @@ static void frontend_changed(struct xenbus_watch *watch, * unless something bad happens */ again: - err = xenbus_transaction_start(); - if (err) { + xbt = xenbus_transaction_start(); + if (IS_ERR(xbt)) { xenbus_dev_error(be->dev, err, "starting transaction"); return; } - err = xenbus_printf(be->dev->nodename, + err = xenbus_printf(xbt, be->dev->nodename, "ready", "%lu", ready); if (err) { xenbus_dev_error(be->dev, err, "writing 'ready'"); goto abort; } - err = xenbus_transaction_end(0); + err = xenbus_transaction_end(xbt, 0); if (err == -EAGAIN) goto again; if (err) { @@ -139,7 +140,7 @@ again: xenbus_dev_ok(be->dev); return; abort: - xenbus_transaction_end(1); + xenbus_transaction_end(xbt, 1); } @@ -152,7 +153,7 @@ static void backend_changed(struct xenbus_watch *watch, = container_of(watch, struct backend_info, backend_watch); struct xenbus_device *dev = be->dev; - err = xenbus_scanf(dev->nodename, "instance", "%li", &instance); + err = xenbus_scanf(NULL, dev->nodename, "instance", "%li", &instance); if (XENBUS_EXIST_ERR(err)) return; if (err < 0) { @@ -205,7 +206,7 @@ static int tpmback_probe(struct xenbus_device *dev, memset(be, 0, sizeof(*be)); frontend = NULL; - err = xenbus_gather(dev->nodename, + err = xenbus_gather(NULL, dev->nodename, "frontend-id", "%li", &be->frontend_id, "frontend", NULL, &frontend, NULL); @@ -217,7 +218,7 @@ static int tpmback_probe(struct xenbus_device *dev, dev->nodename); goto free_be; } - if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) { + if (strlen(frontend) == 0 || !xenbus_exists(NULL, frontend, "")) { /* If we can't get a frontend path and a frontend-id, * then our bus-id is no longer valid and we need to * destroy the backend device. diff --git a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c index c6401a1a4a..09ffb02002 100644 --- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c @@ -226,7 +226,7 @@ static void watch_for_status(struct xenbus_watch *watch, if (tp->connected) return; - err = xenbus_gather(watch->node, + err = xenbus_gather(NULL, watch->node, "ready", "%lu", &ready, NULL); if (err) { @@ -311,9 +311,10 @@ static int talk_to_backend(struct xenbus_device *dev, const char *message; int err; int backend_id; + struct xenbus_transaction *xbt; backend = NULL; - err = xenbus_gather(dev->nodename, + err = xenbus_gather(NULL, dev->nodename, "backend-id", "%i", &backend_id, "backend", NULL, &backend, NULL); @@ -339,27 +340,27 @@ static int talk_to_backend(struct xenbus_device *dev, } again: - err = xenbus_transaction_start(); - if (err) { + xbt = xenbus_transaction_start(); + if (IS_ERR(xbt)) { xenbus_dev_error(dev, err, "starting transaction"); goto destroy_tpmring; } - err = xenbus_printf(dev->nodename, + err = xenbus_printf(xbt, dev->nodename, "ring-ref","%u", info->ring_ref); if (err) { message = "writing ring-ref"; goto abort_transaction; } - err = xenbus_printf(dev->nodename, + err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", my_private.evtchn); if (err) { message = "writing event-channel"; goto abort_transaction; } - err = xenbus_transaction_end(0); + err = xenbus_transaction_end(xbt, 0); if (err == -EAGAIN) goto again; if (err) { @@ -380,8 +381,7 @@ again: return 0; abort_transaction: - xenbus_transaction_end(1); - /* Have to do this *outside* transaction. */ + xenbus_transaction_end(xbt, 1); xenbus_dev_error(dev, err, "%s", message); destroy_tpmring: destroy_tpmring(info, &my_private); @@ -399,7 +399,7 @@ static int tpmfront_probe(struct xenbus_device *dev, struct tpmfront_info *info; int handle; - err = xenbus_scanf(dev->nodename, + err = xenbus_scanf(NULL, dev->nodename, "handle", "%i", &handle); if (XENBUS_EXIST_ERR(err)) return err; diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c index f4c0d35c3c..cd577451ce 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c @@ -181,7 +181,7 @@ static int xenbus_dev_release(struct inode *inode, struct file *filp) struct xenbus_dev_data *u = filp->private_data; if (u->in_transaction) - xenbus_transaction_end(1); + xenbus_transaction_end((struct xenbus_transaction *)1, 1); kfree(u); diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index 5db856fe44..77a9c1bbc1 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -128,7 +128,7 @@ static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) devid = strrchr(nodename, '/') + 1; - err = xenbus_gather(nodename, "frontend-id", "%i", &domid, + err = xenbus_gather(NULL, nodename, "frontend-id", "%i", &domid, "frontend", NULL, &frontend, NULL); if (err) @@ -136,7 +136,7 @@ static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) if (strlen(frontend) == 0) err = -ERANGE; - if (!err && !xenbus_exists(frontend, "")) + if (!err && !xenbus_exists(NULL, frontend, "")) err = -ENOENT; if (err) { @@ -450,7 +450,7 @@ static int xenbus_probe_backend(const char *type, const char *domid) if (!nodename) return -ENOMEM; - dir = xenbus_directory(nodename, "", &dir_n); + dir = xenbus_directory(NULL, nodename, "", &dir_n); if (IS_ERR(dir)) { kfree(nodename); return PTR_ERR(dir); @@ -473,7 +473,7 @@ static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type) unsigned int dir_n = 0; int i; - dir = xenbus_directory(bus->root, type, &dir_n); + dir = xenbus_directory(NULL, bus->root, type, &dir_n); if (IS_ERR(dir)) return PTR_ERR(dir); @@ -492,7 +492,7 @@ static int xenbus_probe_devices(struct xen_bus_type *bus) char **dir; unsigned int i, dir_n; - dir = xenbus_directory(bus->root, "", &dir_n); + dir = xenbus_directory(NULL, bus->root, "", &dir_n); if (IS_ERR(dir)) return PTR_ERR(dir); @@ -538,7 +538,7 @@ static void dev_changed(const char *node, struct xen_bus_type *bus) if (char_count(node, '/') < 2) return; - exists = xenbus_exists(node, ""); + exists = xenbus_exists(NULL, node, ""); if (!exists) { xenbus_cleanup_devices(node, &bus->bus); return; diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c index ea0ead1596..2df33487ea 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @@ -316,7 +316,8 @@ static char **split(char *strings, unsigned int len, unsigned int *num) return ret; } -char **xenbus_directory(const char *dir, const char *node, unsigned int *num) +char **xenbus_directory(struct xenbus_transaction *t, + const char *dir, const char *node, unsigned int *num) { char *strings; unsigned int len; @@ -330,12 +331,13 @@ char **xenbus_directory(const char *dir, const char *node, unsigned int *num) EXPORT_SYMBOL(xenbus_directory); /* Check if a path exists. Return 1 if it does. */ -int xenbus_exists(const char *dir, const char *node) +int xenbus_exists(struct xenbus_transaction *t, + const char *dir, const char *node) { char **d; int dir_n; - d = xenbus_directory(dir, node, &dir_n); + d = xenbus_directory(t, dir, node, &dir_n); if (IS_ERR(d)) return 0; kfree(d); @@ -347,7 +349,8 @@ EXPORT_SYMBOL(xenbus_exists); * Returns a kmalloced value: call free() on it after use. * len indicates length in bytes. */ -void *xenbus_read(const char *dir, const char *node, unsigned int *len) +void *xenbus_read(struct xenbus_transaction *t, + const char *dir, const char *node, unsigned int *len) { return xs_single(XS_READ, join(dir, node), len); } @@ -356,7 +359,8 @@ EXPORT_SYMBOL(xenbus_read); /* Write the value of a single file. * Returns -err on failure. */ -int xenbus_write(const char *dir, const char *node, const char *string) +int xenbus_write(struct xenbus_transaction *t, + const char *dir, const char *node, const char *string) { const char *path; struct kvec iovec[2]; @@ -373,14 +377,15 @@ int xenbus_write(const char *dir, const char *node, const char *string) EXPORT_SYMBOL(xenbus_write); /* Create a new directory. */ -int xenbus_mkdir(const char *dir, const char *node) +int xenbus_mkdir(struct xenbus_transaction *t, + const char *dir, const char *node) { return xs_error(xs_single(XS_MKDIR, join(dir, node), NULL)); } EXPORT_SYMBOL(xenbus_mkdir); /* Destroy a file or directory (directories must be empty). */ -int xenbus_rm(const char *dir, const char *node) +int xenbus_rm(struct xenbus_transaction *t, const char *dir, const char *node) { return xs_error(xs_single(XS_RM, join(dir, node), NULL)); } @@ -388,9 +393,8 @@ EXPORT_SYMBOL(xenbus_rm); /* Start a transaction: changes by others will not be seen during this * transaction, and changes will not be visible to others until end. - * You can only have one transaction at any time. */ -int xenbus_transaction_start(void) +struct xenbus_transaction *xenbus_transaction_start(void) { int err; @@ -403,18 +407,20 @@ int xenbus_transaction_start(void) up(&xs_state.transaction_mutex); } - return err; + return err ? ERR_PTR(err) : (struct xenbus_transaction *)1; } EXPORT_SYMBOL(xenbus_transaction_start); /* End a transaction. * If abandon is true, transaction is discarded instead of committed. */ -int xenbus_transaction_end(int abort) +int xenbus_transaction_end(struct xenbus_transaction *t, int abort) { char abortstr[2]; int err; + BUG_ON(t == NULL); + if (abort) strcpy(abortstr, "F"); else @@ -430,13 +436,14 @@ int xenbus_transaction_end(int abort) EXPORT_SYMBOL(xenbus_transaction_end); /* Single read and scanf: returns -errno or num scanned. */ -int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...) +int xenbus_scanf(struct xenbus_transaction *t, + const char *dir, const char *node, const char *fmt, ...) { va_list ap; int ret; char *val; - val = xenbus_read(dir, node, NULL); + val = xenbus_read(t, dir, node, NULL); if (IS_ERR(val)) return PTR_ERR(val); @@ -452,7 +459,8 @@ int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...) EXPORT_SYMBOL(xenbus_scanf); /* Single printf and write: returns -errno or 0. */ -int xenbus_printf(const char *dir, const char *node, const char *fmt, ...) +int xenbus_printf(struct xenbus_transaction *t, + const char *dir, const char *node, const char *fmt, ...) { va_list ap; int ret; @@ -468,7 +476,7 @@ int xenbus_printf(const char *dir, const char *node, const char *fmt, ...) va_end(ap); BUG_ON(ret > PRINTF_BUFFER_SIZE-1); - ret = xenbus_write(dir, node, printf_buffer); + ret = xenbus_write(t, dir, node, printf_buffer); kfree(printf_buffer); @@ -495,7 +503,7 @@ void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...) BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1); dev->has_error = 1; - if (xenbus_write(dev->nodename, "error", printf_buffer) != 0) + if (xenbus_write(NULL, dev->nodename, "error", printf_buffer) != 0) goto fail; kfree(printf_buffer); @@ -511,7 +519,7 @@ EXPORT_SYMBOL(xenbus_dev_error); void xenbus_dev_ok(struct xenbus_device *dev) { if (dev->has_error) { - if (xenbus_rm(dev->nodename, "error") != 0) + if (xenbus_rm(NULL, dev->nodename, "error") != 0) printk("xenbus: failed to clear error node for %s\n", dev->nodename); else @@ -521,7 +529,7 @@ void xenbus_dev_ok(struct xenbus_device *dev) EXPORT_SYMBOL(xenbus_dev_ok); /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ -int xenbus_gather(const char *dir, ...) +int xenbus_gather(struct xenbus_transaction *t, const char *dir, ...) { va_list ap; const char *name; @@ -533,7 +541,7 @@ int xenbus_gather(const char *dir, ...) void *result = va_arg(ap, void *); char *p; - p = xenbus_read(dir, name, NULL); + p = xenbus_read(t, dir, name, NULL); if (IS_ERR(p)) { ret = PTR_ERR(p); break; diff --git a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h index 3db3254d96..8717e4201e 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h +++ b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h @@ -78,26 +78,35 @@ int xenbus_register_driver(struct xenbus_driver *drv); int xenbus_register_backend(struct xenbus_driver *drv); void xenbus_unregister_driver(struct xenbus_driver *drv); -char **xenbus_directory(const char *dir, const char *node, unsigned int *num); -void *xenbus_read(const char *dir, const char *node, unsigned int *len); -int xenbus_write(const char *dir, const char *node, const char *string); -int xenbus_mkdir(const char *dir, const char *node); -int xenbus_exists(const char *dir, const char *node); -int xenbus_rm(const char *dir, const char *node); -int xenbus_transaction_start(void); -int xenbus_transaction_end(int abort); +struct xenbus_transaction; + +char **xenbus_directory(struct xenbus_transaction *t, + const char *dir, const char *node, unsigned int *num); +void *xenbus_read(struct xenbus_transaction *t, + const char *dir, const char *node, unsigned int *len); +int xenbus_write(struct xenbus_transaction *t, + const char *dir, const char *node, const char *string); +int xenbus_mkdir(struct xenbus_transaction *t, + const char *dir, const char *node); +int xenbus_exists(struct xenbus_transaction *t, + const char *dir, const char *node); +int xenbus_rm(struct xenbus_transaction *t, const char *dir, const char *node); +struct xenbus_transaction *xenbus_transaction_start(void); +int xenbus_transaction_end(struct xenbus_transaction *t, int abort); /* Single read and scanf: returns -errno or num scanned if > 0. */ -int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...) - __attribute__((format(scanf, 3, 4))); +int xenbus_scanf(struct xenbus_transaction *t, + const char *dir, const char *node, const char *fmt, ...) + __attribute__((format(scanf, 4, 5))); /* Single printf and write: returns -errno or 0. */ -int xenbus_printf(const char *dir, const char *node, const char *fmt, ...) - __attribute__((format(printf, 3, 4))); +int xenbus_printf(struct xenbus_transaction *t, + const char *dir, const char *node, const char *fmt, ...) + __attribute__((format(printf, 4, 5))); /* Generic read function: NULL-terminated triples of name, * sprintf-style type string, and pointer. Returns 0 or errno.*/ -int xenbus_gather(const char *dir, ...); +int xenbus_gather(struct xenbus_transaction *t, const char *dir, ...); /* Report a (negative) errno into the store, with explanation. */ void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,...); diff --git a/tools/console/client/main.c b/tools/console/client/main.c index 4c7b2710b8..0760f0cb9c 100644 --- a/tools/console/client/main.c +++ b/tools/console/client/main.c @@ -220,7 +220,7 @@ int main(int argc, char **argv) if (path == NULL) err(ENOMEM, "realloc"); strcat(path, "/console/tty"); - str_pty = xs_read(xs, path, &len); + str_pty = xs_read(xs, NULL, path, &len); /* FIXME consoled currently does not assume domain-0 doesn't have a console which is good when we break domain-0 up. To keep us @@ -245,7 +245,7 @@ int main(int argc, char **argv) struct timeval tv = { 0, 500 }; select(0, NULL, NULL, NULL, &tv); /* pause briefly */ - str_pty = xs_read(xs, path, &len); + str_pty = xs_read(xs, NULL, path, &len); } if (str_pty == NULL) { diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c index d533bd9b5c..01fb0730fc 100644 --- a/tools/console/daemon/io.c +++ b/tools/console/daemon/io.c @@ -179,7 +179,7 @@ static int domain_create_tty(struct domain *dom) success = asprintf(&path, "%s/tty", dom->conspath) != -1; if (!success) goto out; - success = xs_write(xs, path, slave, strlen(slave)); + success = xs_write(xs, NULL, path, slave, strlen(slave)); free(path); if (!success) goto out; @@ -187,7 +187,7 @@ static int domain_create_tty(struct domain *dom) success = asprintf(&path, "%s/limit", dom->conspath) != -1; if (!success) goto out; - data = xs_read(xs, path, &len); + data = xs_read(xs, NULL, path, &len); if (data) { dom->buffer.max_capacity = strtoul(data, 0, 0); free(data); @@ -216,7 +216,7 @@ int xs_gather(struct xs_handle *xs, const char *dir, ...) char *p; asprintf(&path, "%s/%s", dir, name); - p = xs_read(xs, path, NULL); + p = xs_read(xs, NULL, path, NULL); free(path); if (p == NULL) { ret = ENOENT; diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c index 9c244d195a..be3e0ad4c2 100644 --- a/tools/python/xen/lowlevel/xs/xs.c +++ b/tools/python/xen/lowlevel/xs/xs.c @@ -80,8 +80,8 @@ static inline PyObject *pyvalue_str(char *val) { static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "path", NULL }; - static char *arg_spec = "s|"; + static char *kwd_spec[] = { "transaction", "path", NULL }; + static char *arg_spec = "ss"; char *path = NULL; struct xs_handle *xh = xshandle(self); @@ -89,13 +89,19 @@ static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds) unsigned int xsval_n = 0; PyObject *val = NULL; + struct xs_transaction_handle *th; + char *thstr; + if (!xh) goto exit; if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, - &path)) + &thstr, &path)) goto exit; + + th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16); + Py_BEGIN_ALLOW_THREADS - xsval = xs_read(xh, path, &xsval_n); + xsval = xs_read(xh, th, path, &xsval_n); Py_END_ALLOW_THREADS if (!xsval) { if (errno == ENOENT) { @@ -123,8 +129,8 @@ static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds) static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "path", "data", NULL }; - static char *arg_spec = "ss#"; + static char *kwd_spec[] = { "transaction", "path", "data", NULL }; + static char *arg_spec = "sss#"; char *path = NULL; char *data = NULL; int data_n = 0; @@ -133,13 +139,19 @@ static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds) PyObject *val = NULL; int xsval = 0; + struct xs_transaction_handle *th; + char *thstr; + if (!xh) goto exit; if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, - &path, &data, &data_n)) + &thstr, &path, &data, &data_n)) goto exit; + + th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16); + Py_BEGIN_ALLOW_THREADS - xsval = xs_write(xh, path, data, data_n); + xsval = xs_write(xh, th, path, data, data_n); Py_END_ALLOW_THREADS if (!xsval) { PyErr_SetFromErrno(PyExc_RuntimeError); @@ -162,8 +174,8 @@ static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds) static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "path", NULL }; - static char *arg_spec = "s|"; + static char *kwd_spec[] = { "transaction", "path", NULL }; + static char *arg_spec = "ss"; char *path = NULL; struct xs_handle *xh = xshandle(self); @@ -172,12 +184,20 @@ static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds) unsigned int xsval_n = 0; int i; + struct xs_transaction_handle *th; + char *thstr; + if (!xh) goto exit; - if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, + &thstr, &path)) goto exit; + + + th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16); + Py_BEGIN_ALLOW_THREADS - xsval = xs_directory(xh, path, &xsval_n); + xsval = xs_directory(xh, th, path, &xsval_n); Py_END_ALLOW_THREADS if (!xsval) { if (errno == ENOENT) { @@ -205,20 +225,27 @@ static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds) static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "path", NULL }; - static char *arg_spec = "s|"; + static char *kwd_spec[] = { "transaction", "path", NULL }; + static char *arg_spec = "ss"; char *path = NULL; struct xs_handle *xh = xshandle(self); PyObject *val = NULL; int xsval = 0; + struct xs_transaction_handle *th; + char *thstr; + if (!xh) goto exit; - if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, + &thstr, &path)) goto exit; + + th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16); + Py_BEGIN_ALLOW_THREADS - xsval = xs_mkdir(xh, path); + xsval = xs_mkdir(xh, th, path); Py_END_ALLOW_THREADS if (!xsval) { PyErr_SetFromErrno(PyExc_RuntimeError); @@ -240,20 +267,27 @@ static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds) static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "path", NULL }; - static char *arg_spec = "s|"; + static char *kwd_spec[] = { "transaction", "path", NULL }; + static char *arg_spec = "ss"; char *path = NULL; struct xs_handle *xh = xshandle(self); PyObject *val = NULL; int xsval = 0; + struct xs_transaction_handle *th; + char *thstr; + if (!xh) goto exit; - if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, + &thstr, &path)) goto exit; + + th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16); + Py_BEGIN_ALLOW_THREADS - xsval = xs_rm(xh, path); + xsval = xs_rm(xh, th, path); Py_END_ALLOW_THREADS if (!xsval && errno != ENOENT) { PyErr_SetFromErrno(PyExc_RuntimeError); @@ -276,8 +310,8 @@ static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds) static PyObject *xspy_get_permissions(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "path", NULL }; - static char *arg_spec = "s|"; + static char *kwd_spec[] = { "transaction", "path", NULL }; + static char *arg_spec = "ss"; char *path = NULL; struct xs_handle *xh = xshandle(self); @@ -286,12 +320,19 @@ static PyObject *xspy_get_permissions(PyObject *self, PyObject *args, unsigned int perms_n = 0; int i; + struct xs_transaction_handle *th; + char *thstr; + if (!xh) goto exit; - if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, + &thstr, &path)) goto exit; + + th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16); + Py_BEGIN_ALLOW_THREADS - perms = xs_get_permissions(xh, path, &perms_n); + perms = xs_get_permissions(xh, th, path, &perms_n); Py_END_ALLOW_THREADS if (!perms) { PyErr_SetFromErrno(PyExc_RuntimeError); @@ -321,8 +362,8 @@ static PyObject *xspy_get_permissions(PyObject *self, PyObject *args, static PyObject *xspy_set_permissions(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "path", "perms", NULL }; - static char *arg_spec = "sO"; + static char *kwd_spec[] = { "transaction", "path", "perms", NULL }; + static char *arg_spec = "ssO"; char *path = NULL; PyObject *perms = NULL; static char *perm_names[] = { "dom", "read", "write", NULL }; @@ -335,11 +376,17 @@ static PyObject *xspy_set_permissions(PyObject *self, PyObject *args, PyObject *tuple0 = NULL; PyObject *val = NULL; + struct xs_transaction_handle *th; + char *thstr; + if (!xh) goto exit; if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, - &path, &perms)) + &thstr, &path, &perms)) goto exit; + + th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16); + if (!PyList_Check(perms)) { PyErr_SetString(PyExc_RuntimeError, "perms must be a list"); goto exit; @@ -369,7 +416,7 @@ static PyObject *xspy_set_permissions(PyObject *self, PyObject *args, xsperms[i].perms |= XS_PERM_WRITE; } Py_BEGIN_ALLOW_THREADS - xsval = xs_set_permissions(xh, path, xsperms, xsperms_n); + xsval = xs_set_permissions(xh, th, path, xsperms, xsperms_n); Py_END_ALLOW_THREADS if (!xsval) { PyErr_SetFromErrno(PyExc_RuntimeError); @@ -543,9 +590,8 @@ static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds) #define xspy_transaction_start_doc "\n" \ "Start a transaction.\n" \ - "Only one transaction can be active at a time.\n" \ "\n" \ - "Returns None on success.\n" \ + "Returns transaction handle on success.\n" \ "Raises RuntimeError on error.\n" \ "\n" @@ -558,21 +604,23 @@ static PyObject *xspy_transaction_start(PyObject *self, PyObject *args, struct xs_handle *xh = xshandle(self); PyObject *val = NULL; - int xsval = 0; + struct xs_transaction_handle *th; + char thstr[20]; if (!xh) goto exit; if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) goto exit; Py_BEGIN_ALLOW_THREADS - xsval = xs_transaction_start(xh); + th = xs_transaction_start(xh); Py_END_ALLOW_THREADS - if (!xsval) { + if (th == NULL) { PyErr_SetFromErrno(PyExc_RuntimeError); goto exit; } - Py_INCREF(Py_None); - val = Py_None; + + sprintf(thstr, "%lX", (unsigned long)th); + val = PyString_FromString(thstr); exit: return val; } @@ -589,20 +637,27 @@ static PyObject *xspy_transaction_start(PyObject *self, PyObject *args, static PyObject *xspy_transaction_end(PyObject *self, PyObject *args, PyObject *kwds) { - static char *kwd_spec[] = { "abort", NULL }; - static char *arg_spec = "|i"; + static char *kwd_spec[] = { "transaction", "abort", NULL }; + static char *arg_spec = "s|i"; int abort = 0; struct xs_handle *xh = xshandle(self); PyObject *val = NULL; int xsval = 0; + struct xs_transaction_handle *th; + char *thstr; + if (!xh) goto exit; - if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &abort)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, + &thstr, &abort)) goto exit; + + th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16); + Py_BEGIN_ALLOW_THREADS - xsval = xs_transaction_end(xh, abort); + xsval = xs_transaction_end(xh, th, abort); Py_END_ALLOW_THREADS if (!xsval) { if (errno == EAGAIN) { diff --git a/tools/python/xen/xend/xenstore/xstransact.py b/tools/python/xen/xend/xenstore/xstransact.py index 8554b2ad8c..d33b209e8e 100644 --- a/tools/python/xen/xend/xenstore/xstransact.py +++ b/tools/python/xen/xend/xenstore/xstransact.py @@ -14,29 +14,34 @@ from xen.xend.xenstore.xsutil import xshandle class xstransact: def __init__(self, path): - self.in_transaction = False self.path = path.rstrip("/") - xshandle().transaction_start() + self.transaction = xshandle().transaction_start() self.in_transaction = True def __del__(self): if self.in_transaction: - xshandle().transaction_end(True) + xshandle().transaction_end(self.transaction, True) def commit(self): if not self.in_transaction: raise RuntimeError self.in_transaction = False - return xshandle().transaction_end(False) + rc = xshandle().transaction_end(self.transaction, False) + self.transaction = "0" + return rc def abort(self): + if not self.in_transaction: + return True self.in_transaction = False - return xshandle().transaction_end(True) + rc = xshandle().transaction_end(self.transaction, True) + self.transaction = "0" + return rc def _read(self, key): path = "%s/%s" % (self.path, key) try: - return xshandle().read(path) + return xshandle().read(self.transaction, path) except RuntimeError, ex: raise RuntimeError(ex.args[0], '%s, while reading %s' % (ex.args[1], path)) @@ -50,7 +55,7 @@ class xstransact: instead. """ if len(args) == 0: - return xshandle().read(self.path) + return xshandle().read(self.transaction, self.path) if len(args) == 1: return self._read(args[0]) ret = [] @@ -61,7 +66,7 @@ class xstransact: def _write(self, key, data): path = "%s/%s" % (self.path, key) try: - xshandle().write(path, data) + xshandle().write(self.transaction, path, data) except RuntimeError, ex: raise RuntimeError(ex.args[0], ('%s, while writing %s : %s' % @@ -93,7 +98,7 @@ class xstransact: def _remove(self, key): path = "%s/%s" % (self.path, key) - return xshandle().rm(path) + return xshandle().rm(self.transaction, path) def remove(self, *args): """If no arguments are given, remove this transaction's path. @@ -101,14 +106,14 @@ class xstransact: path, and remove each of those instead. """ if len(args) == 0: - xshandle().rm(self.path) + xshandle().rm(self.transaction, self.path) else: for key in args: self._remove(key) def _list(self, key): path = "%s/%s" % (self.path, key) - l = xshandle().ls(path) + l = xshandle().ls(self.transaction, path) if l: return map(lambda x: key + "/" + x, l) return [] @@ -120,7 +125,7 @@ class xstransact: path, and return the cumulative listing of each of those instead. """ if len(args) == 0: - ret = xshandle().ls(self.path) + ret = xshandle().ls(self.transaction, self.path) if ret is None: return [] else: @@ -136,11 +141,11 @@ class xstransact: ret = [] for key in keys: new_subdir = subdir + "/" + key - l = xshandle().ls(new_subdir) + l = xshandle().ls(self.transaction, new_subdir) if l: ret.append([key, self.list_recursive_(new_subdir, l)]) else: - ret.append([key, xshandle().read(new_subdir)]) + ret.append([key, xshandle().read(self.transaction, new_subdir)]) return ret diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index d72c0c4973..212ae13e4a 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -8,7 +8,7 @@ INSTALL_PROG = $(INSTALL) -m0755 INSTALL_DIR = $(INSTALL) -d -m0755 PROFILE=#-pg -BASECFLAGS=-Wall -W -g -Werror +BASECFLAGS=-Wall -g -Werror # Make gcc generate dependencies. BASECFLAGS += -Wp,-MD,.$(@F).d PROG_DEP = .*.d diff --git a/tools/xenstore/xenstore_client.c b/tools/xenstore/xenstore_client.c index ef428f9acb..5370d43e99 100644 --- a/tools/xenstore/xenstore_client.c +++ b/tools/xenstore/xenstore_client.c @@ -32,6 +32,7 @@ int main(int argc, char **argv) { struct xs_handle *xsh; + struct xs_transaction_handle *xth; bool success; int ret = 0; #if defined(CLIENT_read) || defined(CLIENT_list) @@ -84,13 +85,13 @@ main(int argc, char **argv) #endif again: - success = xs_transaction_start(xsh); - if (!success) + xth = xs_transaction_start(xsh); + if (xth == NULL) errx(1, "couldn't start transaction"); while (optind < argc) { #if defined(CLIENT_read) - char *val = xs_read(xsh, argv[optind], NULL); + char *val = xs_read(xsh, xth, argv[optind], NULL); if (val == NULL) { warnx("couldn't read path %s", argv[optind]); ret = 1; @@ -102,7 +103,7 @@ main(int argc, char **argv) free(val); optind++; #elif defined(CLIENT_write) - success = xs_write(xsh, argv[optind], argv[optind + 1], + success = xs_write(xsh, xth, argv[optind], argv[optind + 1], strlen(argv[optind + 1])); if (!success) { warnx("could not write path %s", argv[optind]); @@ -111,7 +112,7 @@ main(int argc, char **argv) } optind += 2; #elif defined(CLIENT_rm) - success = xs_rm(xsh, argv[optind]); + success = xs_rm(xsh, xth, argv[optind]); if (!success) { warnx("could not remove path %s", argv[optind]); ret = 1; @@ -119,7 +120,7 @@ main(int argc, char **argv) } optind++; #elif defined(CLIENT_exists) - char *val = xs_read(xsh, argv[optind], NULL); + char *val = xs_read(xsh, xth, argv[optind], NULL); if (val == NULL) { ret = 1; goto out; @@ -128,7 +129,7 @@ main(int argc, char **argv) optind++; #elif defined(CLIENT_list) unsigned int i, num; - char **list = xs_directory(xsh, argv[optind], &num); + char **list = xs_directory(xsh, xth, argv[optind], &num); if (list == NULL) { warnx("could not list path %s", argv[optind]); ret = 1; @@ -145,7 +146,7 @@ main(int argc, char **argv) } out: - success = xs_transaction_end(xsh, ret ? true : false); + success = xs_transaction_end(xsh, xth, ret ? true : false); if (!success) { if (ret == 0 && errno == EAGAIN) goto again; diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c index 1b648d2578..89b42ba734 100644 --- a/tools/xenstore/xs.c +++ b/tools/xenstore/xs.c @@ -81,6 +81,10 @@ struct xs_handle { pthread_t transaction_pthread; }; +struct xs_transaction_handle { + int id; +}; + static void *read_thread(void *arg); static void request_mutex_acquire(struct xs_handle *h) @@ -407,7 +411,8 @@ static bool xs_bool(char *reply) return true; } -char **xs_directory(struct xs_handle *h, const char *path, unsigned int *num) +char **xs_directory(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path, unsigned int *num) { char *strings, *p, **ret; unsigned int len; @@ -438,7 +443,8 @@ char **xs_directory(struct xs_handle *h, const char *path, unsigned int *num) * Returns a malloced value: call free() on it after use. * len indicates length in bytes, not including the nul. */ -void *xs_read(struct xs_handle *h, const char *path, unsigned int *len) +void *xs_read(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path, unsigned int *len) { return xs_single(h, XS_READ, path, len); } @@ -446,8 +452,8 @@ void *xs_read(struct xs_handle *h, const char *path, unsigned int *len) /* Write the value of a single file. * Returns false on failure. */ -bool xs_write(struct xs_handle *h, const char *path, - const void *data, unsigned int len) +bool xs_write(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path, const void *data, unsigned int len) { struct iovec iovec[2]; @@ -462,7 +468,8 @@ bool xs_write(struct xs_handle *h, const char *path, /* Create a new directory. * Returns false on failure, or success if it already exists. */ -bool xs_mkdir(struct xs_handle *h, const char *path) +bool xs_mkdir(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path) { return xs_bool(xs_single(h, XS_MKDIR, path, NULL)); } @@ -470,7 +477,8 @@ bool xs_mkdir(struct xs_handle *h, const char *path) /* Destroy a file or directory (directories must be empty). * Returns false on failure, or success if it doesn't exist. */ -bool xs_rm(struct xs_handle *h, const char *path) +bool xs_rm(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path) { return xs_bool(xs_single(h, XS_RM, path, NULL)); } @@ -479,6 +487,7 @@ bool xs_rm(struct xs_handle *h, const char *path) * Returns malloced array, or NULL: call free() after use. */ struct xs_permissions *xs_get_permissions(struct xs_handle *h, + struct xs_transaction_handle *t, const char *path, unsigned int *num) { char *strings; @@ -511,7 +520,9 @@ struct xs_permissions *xs_get_permissions(struct xs_handle *h, /* Set permissions of node (must be owner). * Returns false on failure. */ -bool xs_set_permissions(struct xs_handle *h, const char *path, +bool xs_set_permissions(struct xs_handle *h, + struct xs_transaction_handle *t, + const char *path, struct xs_permissions *perms, unsigned int num_perms) { @@ -632,9 +643,9 @@ bool xs_unwatch(struct xs_handle *h, const char *path, const char *token) /* Start a transaction: changes by others will not be seen during this * transaction, and changes will not be visible to others until end. * You can only have one transaction at any time. - * Returns false on failure. + * Returns NULL on failure. */ -bool xs_transaction_start(struct xs_handle *h) +struct xs_transaction_handle *xs_transaction_start(struct xs_handle *h) { bool rc; @@ -647,7 +658,7 @@ bool xs_transaction_start(struct xs_handle *h) pthread_mutex_unlock(&h->transaction_mutex); } - return rc; + return (struct xs_transaction_handle *)rc; } /* End a transaction. @@ -655,11 +666,15 @@ bool xs_transaction_start(struct xs_handle *h) * Returns false on failure, which indicates an error: transactions will * not fail spuriously. */ -bool xs_transaction_end(struct xs_handle *h, bool abort) +bool xs_transaction_end(struct xs_handle *h, struct xs_transaction_handle *t, + bool abort) { char abortstr[2]; bool rc; + if (t == NULL) + return -EINVAL; + if (abort) strcpy(abortstr, "F"); else diff --git a/tools/xenstore/xs.h b/tools/xenstore/xs.h index 59dd96d5da..133884ad52 100644 --- a/tools/xenstore/xs.h +++ b/tools/xenstore/xs.h @@ -23,6 +23,7 @@ #include struct xs_handle; +struct xs_transaction_handle; /* On failure, these routines set errno. */ @@ -44,41 +45,47 @@ void xs_daemon_close(struct xs_handle *); * Returns a malloced array: call free() on it after use. * Num indicates size. */ -char **xs_directory(struct xs_handle *h, const char *path, unsigned int *num); +char **xs_directory(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path, unsigned int *num); /* Get the value of a single file, nul terminated. * Returns a malloced value: call free() on it after use. * len indicates length in bytes, not including terminator. */ -void *xs_read(struct xs_handle *h, const char *path, unsigned int *len); +void *xs_read(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path, unsigned int *len); /* Write the value of a single file. * Returns false on failure. */ -bool xs_write(struct xs_handle *h, const char *path, const void *data, - unsigned int len); +bool xs_write(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path, const void *data, unsigned int len); /* Create a new directory. * Returns false on failure, or success if it already exists. */ -bool xs_mkdir(struct xs_handle *h, const char *path); +bool xs_mkdir(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path); /* Destroy a file or directory (and children). * Returns false on failure, or success if it doesn't exist. */ -bool xs_rm(struct xs_handle *h, const char *path); +bool xs_rm(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path); /* Get permissions of node (first element is owner, first perms is "other"). * Returns malloced array, or NULL: call free() after use. */ struct xs_permissions *xs_get_permissions(struct xs_handle *h, + struct xs_transaction_handle *t, const char *path, unsigned int *num); /* Set permissions of node (must be owner). * Returns false on failure. */ -bool xs_set_permissions(struct xs_handle *h, const char *path, - struct xs_permissions *perms, unsigned int num_perms); +bool xs_set_permissions(struct xs_handle *h, struct xs_transaction_handle *t, + const char *path, struct xs_permissions *perms, + unsigned int num_perms); /* Watch a node for changes (poll on fd to detect, or call read_watch()). * When the node (or any child) changes, fd will become readable. @@ -104,16 +111,17 @@ bool xs_unwatch(struct xs_handle *h, const char *path, const char *token); /* Start a transaction: changes by others will not be seen during this * transaction, and changes will not be visible to others until end. * You can only have one transaction at any time. - * Returns false on failure. + * Returns NULL on failure. */ -bool xs_transaction_start(struct xs_handle *h); +struct xs_transaction_handle *xs_transaction_start(struct xs_handle *h); /* End a transaction. * If abandon is true, transaction is discarded instead of committed. * Returns false on failure: if errno == EAGAIN, you have to restart * transaction. */ -bool xs_transaction_end(struct xs_handle *h, bool abort); +bool xs_transaction_end(struct xs_handle *h, struct xs_transaction_handle *t, + bool abort); /* Introduce a new domain. * This tells the store daemon about a shared memory page, event channel @@ -136,3 +144,13 @@ char *xs_debug_command(struct xs_handle *h, const char *cmd, void *data, unsigned int len); #endif /* _XS_H */ + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/tools/xenstore/xs_test.c b/tools/xenstore/xs_test.c index 45b9085153..9e49bdfb87 100644 --- a/tools/xenstore/xs_test.c +++ b/tools/xenstore/xs_test.c @@ -42,6 +42,7 @@ #define XSTEST static struct xs_handle *handles[10] = { NULL }; +static struct xs_transaction_handle *txh[10] = { NULL }; static unsigned int timeout_ms = 500; static bool timeout_suppressed = true; @@ -312,7 +313,7 @@ static void do_dir(unsigned int handle, char *path) char **entries; unsigned int i, num; - entries = xs_directory(handles[handle], path, &num); + entries = xs_directory(handles[handle], txh[handle], path, &num); if (!entries) { failed(handle); return; @@ -331,7 +332,7 @@ static void do_read(unsigned int handle, char *path) char *value; unsigned int len; - value = xs_read(handles[handle], path, &len); + value = xs_read(handles[handle], txh[handle], path, &len); if (!value) { failed(handle); return; @@ -347,7 +348,7 @@ static void do_read(unsigned int handle, char *path) static void do_write(unsigned int handle, char *path, char *data) { - if (!xs_write(handles[handle], path, data, strlen(data))) + if (!xs_write(handles[handle], txh[handle], path, data, strlen(data))) failed(handle); } @@ -360,13 +361,13 @@ static void do_setid(unsigned int handle, char *id) static void do_mkdir(unsigned int handle, char *path) { - if (!xs_mkdir(handles[handle], path)) + if (!xs_mkdir(handles[handle], txh[handle], path)) failed(handle); } static void do_rm(unsigned int handle, char *path) { - if (!xs_rm(handles[handle], path)) + if (!xs_rm(handles[handle], txh[handle], path)) failed(handle); } @@ -375,7 +376,7 @@ static void do_getperm(unsigned int handle, char *path) unsigned int i, num; struct xs_permissions *perms; - perms = xs_get_permissions(handles[handle], path, &num); + perms = xs_get_permissions(handles[handle], txh[handle], path, &num); if (!perms) { failed(handle); return; @@ -436,7 +437,7 @@ static void do_setperm(unsigned int handle, char *path, char *line) barf("bad flags %s\n", arg); } - if (!xs_set_permissions(handles[handle], path, perms, i)) + if (!xs_set_permissions(handles[handle], txh[handle], path, perms, i)) failed(handle); } @@ -520,14 +521,16 @@ static void do_unwatch(unsigned int handle, const char *node, const char *token) static void do_start(unsigned int handle) { - if (!xs_transaction_start(handles[handle])) + txh[handle] = xs_transaction_start(handles[handle]); + if (txh[handle] == NULL) failed(handle); } static void do_end(unsigned int handle, bool abort) { - if (!xs_transaction_end(handles[handle], abort)) + if (!xs_transaction_end(handles[handle], txh[handle], abort)) failed(handle); + txh[handle] = NULL; } static void do_introduce(unsigned int handle, @@ -617,7 +620,8 @@ static void dump_dir(unsigned int handle, sprintf(subnode, "%s/%s", node, dir[i]); - perms = xs_get_permissions(handles[handle], subnode,&numperms); + perms = xs_get_permissions(handles[handle], txh[handle], + subnode,&numperms); if (!perms) { failed(handle); return; @@ -634,7 +638,8 @@ static void dump_dir(unsigned int handle, output("\n"); /* Even directories can have contents. */ - contents = xs_read(handles[handle], subnode, &len); + contents = xs_read(handles[handle], txh[handle], + subnode, &len); if (!contents) { if (errno != EISDIR) failed(handle); @@ -644,7 +649,8 @@ static void dump_dir(unsigned int handle, } /* Every node is a directory. */ - subdirs = xs_directory(handles[handle], subnode, &subnum); + subdirs = xs_directory(handles[handle], txh[handle], + subnode, &subnum); if (!subdirs) { failed(handle); return; @@ -659,7 +665,7 @@ static void dump(int handle) char **subdirs; unsigned int subnum; - subdirs = xs_directory(handles[handle], "/", &subnum); + subdirs = xs_directory(handles[handle], txh[handle], "/", &subnum); if (!subdirs) { failed(handle); return; @@ -742,6 +748,7 @@ static void do_command(unsigned int default_handle, char *line) else if (streq(command, "close")) { xs_daemon_close(handles[handle]); handles[handle] = NULL; + txh[handle] = NULL; } else if (streq(command, "start")) do_start(handle); else if (streq(command, "commit")) @@ -825,3 +832,13 @@ int main(int argc, char *argv[]) return 0; } + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ From 5fec4cf7660cbcd50a016750b5de37394c6a65b1 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sun, 9 Oct 2005 23:53:03 +0100 Subject: [PATCH 13/42] Simplify reply logic in xenstored. Maintain a linked list of pending replies that are sent out in order. Currently we only read new requests when the reply list is empty. In fact there is no good reason for this restriction. Another interesting point is that (on my test machine) hotplug blk setup fails if xenstored_client connects to xenstored via the unix domain socket rather than through the kernel --- this points to some user/kernel races that are 'fixed' by the extra serialisation of the in-kernel mutexes. It definitely needs looking into. Signed-off-by: Keir Fraser --- tools/xenstore/xenstored_core.c | 115 ++++++++++++++---------------- tools/xenstore/xenstored_core.h | 33 ++++----- tools/xenstore/xenstored_domain.c | 6 +- tools/xenstore/xenstored_watch.c | 87 ++++++---------------- tools/xenstore/xenstored_watch.h | 10 +-- xen/include/public/io/xs_wire.h | 78 ++++++++++---------- 6 files changed, 135 insertions(+), 194 deletions(-) diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 25c9b03bb8..4c998bea70 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -235,52 +235,50 @@ void trace(const char *fmt, ...) talloc_free(str); } -static bool write_message(struct connection *conn) +static bool write_messages(struct connection *conn) { int ret; - struct buffered_data *out = conn->out; + struct buffered_data *out, *tmp; + + list_for_each_entry_safe(out, tmp, &conn->out_list, list) { + if (out->inhdr) { + if (verbose) + xprintf("Writing msg %s (%s) out to %p\n", + sockmsg_string(out->hdr.msg.type), + out->buffer, conn); + ret = conn->write(conn, out->hdr.raw + out->used, + sizeof(out->hdr) - out->used); + if (ret < 0) + return false; + + out->used += ret; + if (out->used < sizeof(out->hdr)) + return true; + + out->inhdr = false; + out->used = 0; + + /* Second write might block if non-zero. */ + if (out->hdr.msg.len && !conn->domain) + return true; + } + + ret = conn->write(conn, out->buffer + out->used, + out->hdr.msg.len - out->used); - if (out->inhdr) { - if (verbose) - xprintf("Writing msg %s (%s) out to %p\n", - sockmsg_string(out->hdr.msg.type), - out->buffer, conn); - ret = conn->write(conn, out->hdr.raw + out->used, - sizeof(out->hdr) - out->used); if (ret < 0) return false; out->used += ret; - if (out->used < sizeof(out->hdr)) + if (out->used != out->hdr.msg.len) return true; - out->inhdr = false; - out->used = 0; + trace_io(conn, "OUT", out); - /* Second write might block if non-zero. */ - if (out->hdr.msg.len && !conn->domain) - return true; + list_del(&out->list); + talloc_free(out); } - ret = conn->write(conn, out->buffer + out->used, - out->hdr.msg.len - out->used); - - if (ret < 0) - return false; - - out->used += ret; - if (out->used != out->hdr.msg.len) - return true; - - trace_io(conn, "OUT", out); - conn->out = NULL; - talloc_free(out); - - queue_next_event(conn); - - /* No longer busy? */ - if (!conn->out) - conn->state = OK; return true; } @@ -297,9 +295,9 @@ static int destroy_conn(void *_conn) FD_SET(conn->fd, &set); none.tv_sec = none.tv_usec = 0; - while (conn->out + while (!list_empty(&conn->out_list) && select(conn->fd+1, NULL, &set, NULL, &none) == 1) - if (!write_message(conn)) + if (!write_messages(conn)) break; close(conn->fd); } @@ -326,9 +324,9 @@ static int initialize_set(fd_set *inset, fd_set *outset, int sock, int ro_sock) list_for_each_entry(i, &connections, list) { if (i->domain) continue; - if (i->state == OK) + if (list_empty(&i->out_list)) FD_SET(i->fd, inset); - if (i->out) + if (!list_empty(&i->out_list)) FD_SET(i->fd, outset); if (i->fd > max) max = i->fd; @@ -594,14 +592,7 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, bdata->hdr.msg.len = len; memcpy(bdata->buffer, data, len); - /* There might be an event going out now. Queue behind it. */ - if (conn->out) { - assert(conn->out->hdr.msg.type == XS_WATCH_EVENT); - assert(!conn->waiting_reply); - conn->waiting_reply = bdata; - } else - conn->out = bdata; - conn->state = BUSY; + list_add_tail(&bdata->list, &conn->out_list); } /* Some routines (write, mkdir, etc) just need a non-error return */ @@ -1148,8 +1139,6 @@ static void consider_message(struct connection *conn) enum xsd_sockmsg_type volatile type = conn->in->hdr.msg.type; jmp_buf talloc_fail; - assert(conn->state == OK); - /* For simplicity, we kill the connection on OOM. */ talloc_set_fail_handler(out_of_mem, &talloc_fail); if (setjmp(talloc_fail)) { @@ -1186,10 +1175,7 @@ end: static void handle_input(struct connection *conn) { int bytes; - struct buffered_data *in; - - assert(conn->state == OK); - in = conn->in; + struct buffered_data *in = conn->in; /* Not finished header yet? */ if (in->inhdr) { @@ -1237,7 +1223,7 @@ bad_client: static void handle_output(struct connection *conn) { - if (!write_message(conn)) + if (!write_messages(conn)) talloc_free(conn); } @@ -1254,8 +1240,6 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) if (!new) return NULL; - new->state = OK; - new->out = new->waiting_reply = NULL; new->fd = -1; new->id = 0; new->domain = NULL; @@ -1263,6 +1247,7 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) new->write = write; new->read = read; new->can_write = true; + INIT_LIST_HEAD(&new->out_list); INIT_LIST_HEAD(&new->watches); talloc_set_fail_handler(out_of_mem, &talloc_fail); @@ -1317,23 +1302,17 @@ void dump_connection(void) list_for_each_entry(i, &connections, list) { printf("Connection %p:\n", i); printf(" state = %s\n", - i->state == OK ? "OK" - : i->state == BUSY ? "BUSY" - : "INVALID"); + list_empty(&i->out_list) ? "OK" : "BUSY"); if (i->id) printf(" id = %i\n", i->id); if (!i->in->inhdr || i->in->used) printf(" got %i bytes of %s\n", i->in->used, i->in->inhdr ? "header" : "data"); +#if 0 if (i->out) printf(" sending message %s (%s) out\n", sockmsg_string(i->out->hdr.msg.type), i->out->buffer); - if (i->waiting_reply) - printf(" ... and behind is queued %s (%s)\n", - sockmsg_string(i->waiting_reply->hdr.msg.type), - i->waiting_reply->buffer); -#if 0 if (i->transaction) dump_transaction(i); if (i->domain) @@ -1604,3 +1583,13 @@ int main(int argc, char *argv[]) max = initialize_set(&inset, &outset, *sock, *ro_sock); } } + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index e017bddf42..c50936f1bc 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -31,14 +31,19 @@ struct buffered_data { + struct list_head list; + /* Are we still doing the header? */ bool inhdr; + /* How far are we? */ unsigned int used; + union { struct xsd_sockmsg msg; char raw[sizeof(struct xsd_sockmsg)]; } hdr; + /* The actual data. */ char *buffer; }; @@ -47,14 +52,6 @@ struct connection; typedef int connwritefn_t(struct connection *, const void *, unsigned int); typedef int connreadfn_t(struct connection *, void *, unsigned int); -enum state -{ - /* Doing action, not listening */ - BUSY, - /* Completed */ - OK, -}; - struct connection { struct list_head list; @@ -62,12 +59,9 @@ struct connection /* The file descriptor we came in on. */ int fd; - /* Who am I? 0 for socket connections. */ + /* Who am I? 0 for socket connections. */ domid_t id; - /* Blocked on transaction? Busy? */ - enum state state; - /* Is this a read-only connection? */ bool can_write; @@ -75,10 +69,7 @@ struct connection struct buffered_data *in; /* Buffered output data */ - struct buffered_data *out; - - /* If we had a watch fire outgoing when we needed to reply... */ - struct buffered_data *waiting_reply; + struct list_head out_list; /* My transaction, if any. */ struct transaction *transaction; @@ -172,3 +163,13 @@ void trace(const char *fmt, ...); extern int event_fd; #endif /* _XENSTORED_CORE_H */ + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index a7cd4493ad..15c98bfb49 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -276,12 +276,14 @@ void handle_event(void) bool domain_can_read(struct connection *conn) { - return conn->state == OK && buffer_has_input(conn->domain->input); + return (list_empty(&conn->out_list) && + buffer_has_input(conn->domain->input)); } bool domain_can_write(struct connection *conn) { - return conn->out && buffer_has_output_room(conn->domain->output); + return (!list_empty(&conn->out_list) && + buffer_has_output_room(conn->domain->output)); } static struct domain *new_domain(void *context, domid_t domid, diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c index dfb0cd1a3e..6f3c2e4e03 100644 --- a/tools/xenstore/xenstored_watch.c +++ b/tools/xenstore/xenstored_watch.c @@ -32,17 +32,6 @@ #include "xenstored_test.h" #include "xenstored_domain.h" -/* FIXME: time out unacked watches. */ -struct watch_event -{ - /* The events on this watch. */ - struct list_head list; - - /* Data to send (node\0token\0). */ - unsigned int len; - char *data; -}; - struct watch { /* Watches on this connection */ @@ -58,50 +47,17 @@ struct watch char *node; }; -/* Look through our watches: if any of them have an event, queue it. */ -void queue_next_event(struct connection *conn) -{ - struct watch_event *event; - struct watch *watch; - - /* We had a reply queued already? Send it: other end will - * discard watch. */ - if (conn->waiting_reply) { - conn->out = conn->waiting_reply; - conn->waiting_reply = NULL; - return; - } - - list_for_each_entry(watch, &conn->watches, list) { - event = list_top(&watch->events, struct watch_event, list); - if (event) { - list_del(&event->list); - talloc_free(event); - send_reply(conn,XS_WATCH_EVENT,event->data,event->len); - break; - } - } -} - -static int destroy_watch_event(void *_event) -{ - struct watch_event *event = _event; - - trace_destroy(event, "watch_event"); - return 0; -} - static void add_event(struct connection *conn, struct watch *watch, const char *name) { - struct watch_event *event; + /* Data to send (node\0token\0). */ + unsigned int len; + char *data; if (!check_event_node(name)) { /* Can this conn load node, or see that it doesn't exist? */ - struct node *node; - - node = get_node(conn, name, XS_PERM_READ); + struct node *node = get_node(conn, name, XS_PERM_READ); if (!node && errno != ENOENT) return; } @@ -112,14 +68,12 @@ static void add_event(struct connection *conn, name++; } - event = talloc(watch, struct watch_event); - event->len = strlen(name) + 1 + strlen(watch->token) + 1; - event->data = talloc_array(event, char, event->len); - strcpy(event->data, name); - strcpy(event->data + strlen(name) + 1, watch->token); - talloc_set_destructor(event, destroy_watch_event); - list_add_tail(&event->list, &watch->events); - trace_create(event, "watch_event"); + len = strlen(name) + 1 + strlen(watch->token) + 1; + data = talloc_array(watch, char, len); + strcpy(data, name); + strcpy(data + strlen(name) + 1, watch->token); + send_reply(conn, XS_WATCH_EVENT, data, len); + talloc_free(data); } /* FIXME: we fail to fire on out of memory. Should drop connections. */ @@ -139,11 +93,6 @@ void fire_watches(struct connection *conn, const char *name, bool recurse) add_event(i, watch, name); else if (recurse && is_child(watch->node, name)) add_event(i, watch, watch->node); - else - continue; - /* If connection not doing anything, queue this. */ - if (i->state == OK) - queue_next_event(i); } } } @@ -231,13 +180,19 @@ void do_unwatch(struct connection *conn, struct buffered_data *in) void dump_watches(struct connection *conn) { struct watch *watch; - struct watch_event *event; - list_for_each_entry(watch, &conn->watches, list) { + list_for_each_entry(watch, &conn->watches, list) printf(" watch on %s token %s\n", watch->node, watch->token); - list_for_each_entry(event, &watch->events, list) - printf(" event: %s\n", event->data); - } } #endif + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/tools/xenstore/xenstored_watch.h b/tools/xenstore/xenstored_watch.h index ed8892c4aa..2eccff9476 100644 --- a/tools/xenstore/xenstored_watch.h +++ b/tools/xenstore/xenstored_watch.h @@ -23,17 +23,9 @@ #include "xenstored_core.h" void do_watch(struct connection *conn, struct buffered_data *in); -void do_watch_ack(struct connection *conn, const char *token); void do_unwatch(struct connection *conn, struct buffered_data *in); -/* Is this a watch event message for this connection? */ -bool is_watch_event(struct connection *conn, struct buffered_data *out); - -/* Look through our watches: if any of them have an event, queue it. */ -void queue_next_event(struct connection *conn); - -/* Fire all watches: recurse means all the children are affected (ie. rm). - */ +/* Fire all watches: recurse means all the children are affected (ie. rm). */ void fire_watches(struct connection *conn, const char *name, bool recurse); void dump_watches(struct connection *conn); diff --git a/xen/include/public/io/xs_wire.h b/xen/include/public/io/xs_wire.h index 3c26cc0d80..4ab5633b8a 100644 --- a/xen/include/public/io/xs_wire.h +++ b/xen/include/public/io/xs_wire.h @@ -30,23 +30,23 @@ enum xsd_sockmsg_type { - XS_DEBUG, - XS_DIRECTORY, - XS_READ, - XS_GET_PERMS, - XS_WATCH, - XS_UNWATCH, - XS_TRANSACTION_START, - XS_TRANSACTION_END, - XS_INTRODUCE, - XS_RELEASE, - XS_GET_DOMAIN_PATH, - XS_WRITE, - XS_MKDIR, - XS_RM, - XS_SET_PERMS, - XS_WATCH_EVENT, - XS_ERROR, + XS_DEBUG, + XS_DIRECTORY, + XS_READ, + XS_GET_PERMS, + XS_WATCH, + XS_UNWATCH, + XS_TRANSACTION_START, + XS_TRANSACTION_END, + XS_INTRODUCE, + XS_RELEASE, + XS_GET_DOMAIN_PATH, + XS_WRITE, + XS_MKDIR, + XS_RM, + XS_SET_PERMS, + XS_WATCH_EVENT, + XS_ERROR, }; #define XS_WRITE_NONE "NONE" @@ -56,38 +56,40 @@ enum xsd_sockmsg_type /* We hand errors as strings, for portability. */ struct xsd_errors { - int errnum; - const char *errstring; + int errnum; + const char *errstring; }; #define XSD_ERROR(x) { x, #x } static struct xsd_errors xsd_errors[] __attribute__((unused)) = { - XSD_ERROR(EINVAL), - XSD_ERROR(EACCES), - XSD_ERROR(EEXIST), - XSD_ERROR(EISDIR), - XSD_ERROR(ENOENT), - XSD_ERROR(ENOMEM), - XSD_ERROR(ENOSPC), - XSD_ERROR(EIO), - XSD_ERROR(ENOTEMPTY), - XSD_ERROR(ENOSYS), - XSD_ERROR(EROFS), - XSD_ERROR(EBUSY), - XSD_ERROR(EAGAIN), - XSD_ERROR(EISCONN), + XSD_ERROR(EINVAL), + XSD_ERROR(EACCES), + XSD_ERROR(EEXIST), + XSD_ERROR(EISDIR), + XSD_ERROR(ENOENT), + XSD_ERROR(ENOMEM), + XSD_ERROR(ENOSPC), + XSD_ERROR(EIO), + XSD_ERROR(ENOTEMPTY), + XSD_ERROR(ENOSYS), + XSD_ERROR(EROFS), + XSD_ERROR(EBUSY), + XSD_ERROR(EAGAIN), + XSD_ERROR(EISCONN), }; struct xsd_sockmsg { - u32 type; - u32 len; /* Length of data following this. */ + u32 type; /* XS_??? */ + u32 req_id;/* Request identifier, echoed in daemon's response. */ + u32 tx_id; /* Transaction id (0 if not related to a transaction). */ + u32 len; /* Length of data following this. */ - /* Generally followed by nul-terminated string(s). */ + /* Generally followed by nul-terminated string(s). */ }; enum xs_watch_type { - XS_WATCH_PATH = 0, - XS_WATCH_TOKEN, + XS_WATCH_PATH = 0, + XS_WATCH_TOKEN, }; #endif /* _XS_WIRE_H */ From 4d423f9a656ad65e814f15b7a3015492ddb3f1be Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 10 Oct 2005 11:37:10 +0100 Subject: [PATCH 14/42] No need to gate xenstored reading requests from a connection on whether there are pending replies/watches. Signed-off-by: Keir Fraser --- tools/xenstore/xenstored_core.c | 3 +-- tools/xenstore/xenstored_domain.c | 3 +-- tools/xenstore/xenstored_transaction.c | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 4c998bea70..50bdee9a66 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -324,8 +324,7 @@ static int initialize_set(fd_set *inset, fd_set *outset, int sock, int ro_sock) list_for_each_entry(i, &connections, list) { if (i->domain) continue; - if (list_empty(&i->out_list)) - FD_SET(i->fd, inset); + FD_SET(i->fd, inset); if (!list_empty(&i->out_list)) FD_SET(i->fd, outset); if (i->fd > max) diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index 15c98bfb49..e35990b12d 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -276,8 +276,7 @@ void handle_event(void) bool domain_can_read(struct connection *conn) { - return (list_empty(&conn->out_list) && - buffer_has_input(conn->domain->input)); + return buffer_has_input(conn->domain->input); } bool domain_can_write(struct connection *conn) diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c index c0b4f3206e..640d10540f 100644 --- a/tools/xenstore/xenstored_transaction.c +++ b/tools/xenstore/xenstored_transaction.c @@ -154,9 +154,9 @@ void do_transaction_end(struct connection *conn, const char *arg) return; } - /* Set to NULL so fire_watches sends events, tdb_context works. */ trans = conn->transaction; conn->transaction = NULL; + /* Attach transaction to arg for auto-cleanup */ talloc_steal(arg, trans); From 56a738f7ff3f685619b280153f52d4b25177f97a Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Mon, 10 Oct 2005 14:42:38 +0100 Subject: [PATCH 15/42] Added error logging to the block hotplug script, and support facilities for that. Signed-off-by: Ewan Mellor --- tools/examples/Makefile | 1 + tools/examples/block | 13 ++++++------- tools/examples/xen-hotplug-common.sh | 26 ++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 tools/examples/xen-hotplug-common.sh diff --git a/tools/examples/Makefile b/tools/examples/Makefile index e09a35a8ac..83a9f7c101 100644 --- a/tools/examples/Makefile +++ b/tools/examples/Makefile @@ -24,6 +24,7 @@ XEN_SCRIPTS += network-route vif-route XEN_SCRIPTS += network-nat vif-nat XEN_SCRIPTS += block XEN_SCRIPTS += block-enbd +XEN_SCRIPTS += xen-hotplug-common.sh XEN_HOTPLUG_DIR = /etc/hotplug XEN_HOTPLUG_SCRIPTS = xen-backend.agent diff --git a/tools/examples/block b/tools/examples/block index 4fec0d6597..2e383bb3a6 100644 --- a/tools/examples/block +++ b/tools/examples/block @@ -1,8 +1,7 @@ #!/bin/sh -set -e - -export PATH=/sbin:/bin:/usr/bin:/usr/sbin:$PATH +dir=$(dirname "$0") +. "$dir/xen-hotplug-common.sh" expand_dev() { local dev @@ -25,15 +24,15 @@ write_dev() { major=$(stat -L -c %t "$1") minor=$(stat -L -c %T "$1") pdev=$(printf "0x%02x%02x" 0x$major 0x$minor) - xenstore-write "$XENBUS_PATH"/physical-device $pdev \ + xenstore_write "$XENBUS_PATH"/physical-device $pdev \ "$XENBUS_PATH"/node $1 } -t=$(xenstore-read "$XENBUS_PATH"/type) +t=$(xenstore_read "$XENBUS_PATH"/type || true) case $1 in bind) - p=$(xenstore-read "$XENBUS_PATH"/params) + p=$(xenstore_read "$XENBUS_PATH"/params) case $t in phy) dev=$(expand_dev $p) @@ -60,7 +59,7 @@ case $1 in ;; unbind) - node=$(xenstore-read "$XENBUS_PATH"/node) + node=$(xenstore_read "$XENBUS_PATH"/node) case $t in phy) exit 0 diff --git a/tools/examples/xen-hotplug-common.sh b/tools/examples/xen-hotplug-common.sh new file mode 100644 index 0000000000..b1e1be6275 --- /dev/null +++ b/tools/examples/xen-hotplug-common.sh @@ -0,0 +1,26 @@ +set -e + +export PATH=/sbin:/bin:/usr/bin:/usr/sbin:$PATH + +log() { + local level="$1" + shift + logger -p "daemon.$level" -- "$0:" "$@" || echo "$0 $@" >&2 +} + +xenstore_read() { + local v=$(xenstore-read "$XENBUS_PATH"/type || true) + if [ "$v" == "" ] + then + log error "xenstore-read $XENBUS_PATH/type failed." + exit 1 + fi + echo "$v" +} + +xenstore_write() { + log debug "Writing $@ to xenstore." + xenstore-write "$@" || log error "Writing $@ to xenstore failed." +} + +log debug "$@" "XENBUS_PATH=$XENBUS_PATH" From bddd41366dca057dfbd5204193931f78dbd686a6 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 10 Oct 2005 15:38:01 +0100 Subject: [PATCH 16/42] xenstored now supports multiple concurrent transactions per connection, plus interleaving of transactional and non-transactional accesses. A transaction identifier is added to the xsd_sockmsg header structure (0 means 'not in context of a transaction'). The user and kernel xs interfaces accept a pointer to a transaction handle where appropriate -- currently this is directly cast to an integer identifier in the client library / kernel driver, but will allow for keeping extra dynamic client-side state in future if we need to. The transaction mutex has now gone. It's replaced with a read-write mutex, but this is only acquired for exclusive access during suspend/resume, to ensure there are no in-progress transactions. Signed-off-by: Keir Fraser --- .../drivers/xen/xenbus/xenbus_dev.c | 41 ++++- .../drivers/xen/xenbus/xenbus_xs.c | 170 ++++++------------ tools/xenstore/utils.h | 30 ++++ tools/xenstore/xenstore_client.c | 16 +- tools/xenstore/xenstored_core.c | 91 ++++++---- tools/xenstore/xenstored_core.h | 6 +- tools/xenstore/xenstored_transaction.c | 59 ++++-- tools/xenstore/xenstored_transaction.h | 5 +- tools/xenstore/xs.c | 111 +++++------- 9 files changed, 279 insertions(+), 250 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c index cd577451ce..0731ff45f3 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c @@ -45,8 +45,14 @@ #include #include +struct xenbus_dev_transaction { + struct list_head list; + struct xenbus_transaction *handle; +}; + struct xenbus_dev_data { - int in_transaction; + /* In-progress transaction. */ + struct list_head transactions; /* Partial request. */ unsigned int len; @@ -103,6 +109,7 @@ static ssize_t xenbus_dev_write(struct file *filp, size_t len, loff_t *ppos) { struct xenbus_dev_data *u = filp->private_data; + struct xenbus_dev_transaction *trans; void *reply; int err = 0; @@ -129,13 +136,24 @@ static ssize_t xenbus_dev_write(struct file *filp, case XS_RM: case XS_SET_PERMS: reply = xenbus_dev_request_and_reply(&u->u.msg); - if (IS_ERR(reply)) + if (IS_ERR(reply)) { err = PTR_ERR(reply); - else { - if (u->u.msg.type == XS_TRANSACTION_START) - u->in_transaction = 1; - if (u->u.msg.type == XS_TRANSACTION_END) - u->in_transaction = 0; + } else { + if (u->u.msg.type == XS_TRANSACTION_START) { + trans = kmalloc(sizeof(*trans), GFP_KERNEL); + trans->handle = (struct xenbus_transaction *) + simple_strtoul(reply, NULL, 0); + list_add(&trans->list, &u->transactions); + } else if (u->u.msg.type == XS_TRANSACTION_END) { + list_for_each_entry(trans, &u->transactions, + list) + if ((unsigned long)trans->handle == + (unsigned long)u->u.msg.tx_id) + break; + BUG_ON(&trans->list == &u->transactions); + list_del(&trans->list); + kfree(trans); + } queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); queue_reply(u, (char *)reply, u->u.msg.len); kfree(reply); @@ -169,6 +187,7 @@ static int xenbus_dev_open(struct inode *inode, struct file *filp) return -ENOMEM; memset(u, 0, sizeof(*u)); + INIT_LIST_HEAD(&u->transactions); init_waitqueue_head(&u->read_waitq); filp->private_data = u; @@ -179,9 +198,13 @@ static int xenbus_dev_open(struct inode *inode, struct file *filp) static int xenbus_dev_release(struct inode *inode, struct file *filp) { struct xenbus_dev_data *u = filp->private_data; + struct xenbus_dev_transaction *trans, *tmp; - if (u->in_transaction) - xenbus_transaction_end((struct xenbus_transaction *)1, 1); + list_for_each_entry_safe(trans, tmp, &u->transactions, list) { + xenbus_transaction_end(trans->handle, 1); + list_del(&trans->list); + kfree(trans); + } kfree(u); diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c index 2df33487ea..1b53fd73f5 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @@ -71,9 +71,8 @@ struct xs_handle { /* One request at a time. */ struct semaphore request_mutex; - /* One transaction at a time. */ - struct semaphore transaction_mutex; - int transaction_pid; + /* Protect transactions against save/restore. */ + struct rw_semaphore suspend_mutex; }; static struct xs_handle xs_state; @@ -81,29 +80,6 @@ static struct xs_handle xs_state; static LIST_HEAD(watches); static DEFINE_SPINLOCK(watches_lock); -/* Can wait on !xs_resuming for suspend/resume cycle to complete. */ -static int xs_resuming; -static DECLARE_WAIT_QUEUE_HEAD(xs_resuming_waitq); - -static void request_mutex_acquire(void) -{ - /* - * We can't distinguish non-transactional from transactional - * requests right now. So temporarily acquire the transaction mutex - * if this task is outside transaction context. - */ - if (xs_state.transaction_pid != current->pid) - down(&xs_state.transaction_mutex); - down(&xs_state.request_mutex); -} - -static void request_mutex_release(void) -{ - up(&xs_state.request_mutex); - if (xs_state.transaction_pid != current->pid) - up(&xs_state.transaction_mutex); -} - static int get_error(const char *errorstring) { unsigned int i; @@ -152,17 +128,17 @@ static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) /* Emergency write. */ void xenbus_debug_write(const char *str, unsigned int count) { - struct xsd_sockmsg msg; + struct xsd_sockmsg msg = { 0 }; msg.type = XS_DEBUG; msg.len = sizeof("print") + count + 1; - request_mutex_acquire(); + down(&xs_state.request_mutex); xb_write(&msg, sizeof(msg)); xb_write("print", sizeof("print")); xb_write(str, count); xb_write("", 1); - request_mutex_release(); + up(&xs_state.request_mutex); } void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) @@ -171,12 +147,10 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) struct xsd_sockmsg req_msg = *msg; int err; - if (req_msg.type == XS_TRANSACTION_START) { - down(&xs_state.transaction_mutex); - xs_state.transaction_pid = current->pid; - } + if (req_msg.type == XS_TRANSACTION_START) + down_read(&xs_state.suspend_mutex); - request_mutex_acquire(); + down(&xs_state.request_mutex); err = xb_write(msg, sizeof(*msg) + msg->len); if (err) { @@ -186,20 +160,19 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) ret = read_reply(&msg->type, &msg->len); } - request_mutex_release(); + up(&xs_state.request_mutex); if ((msg->type == XS_TRANSACTION_END) || ((req_msg.type == XS_TRANSACTION_START) && - (msg->type == XS_ERROR))) { - xs_state.transaction_pid = -1; - up(&xs_state.transaction_mutex); - } + (msg->type == XS_ERROR))) + up_read(&xs_state.suspend_mutex); return ret; } /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ -static void *xs_talkv(enum xsd_sockmsg_type type, +static void *xs_talkv(struct xenbus_transaction *t, + enum xsd_sockmsg_type type, const struct kvec *iovec, unsigned int num_vecs, unsigned int *len) @@ -209,12 +182,13 @@ static void *xs_talkv(enum xsd_sockmsg_type type, unsigned int i; int err; + msg.tx_id = (u32)(unsigned long)t; msg.type = type; msg.len = 0; for (i = 0; i < num_vecs; i++) msg.len += iovec[i].iov_len; - request_mutex_acquire(); + down(&xs_state.request_mutex); err = xb_write(&msg, sizeof(msg)); if (err) { @@ -225,14 +199,14 @@ static void *xs_talkv(enum xsd_sockmsg_type type, for (i = 0; i < num_vecs; i++) { err = xb_write(iovec[i].iov_base, iovec[i].iov_len);; if (err) { - request_mutex_release(); + up(&xs_state.request_mutex); return ERR_PTR(err); } } ret = read_reply(&msg.type, len); - request_mutex_release(); + up(&xs_state.request_mutex); if (IS_ERR(ret)) return ret; @@ -248,14 +222,16 @@ static void *xs_talkv(enum xsd_sockmsg_type type, } /* Simplified version of xs_talkv: single message. */ -static void *xs_single(enum xsd_sockmsg_type type, - const char *string, unsigned int *len) +static void *xs_single(struct xenbus_transaction *t, + enum xsd_sockmsg_type type, + const char *string, + unsigned int *len) { struct kvec iovec; iovec.iov_base = (void *)string; iovec.iov_len = strlen(string) + 1; - return xs_talkv(type, &iovec, 1, len); + return xs_talkv(t, type, &iovec, 1, len); } /* Many commands only need an ack, don't care what it says. */ @@ -322,7 +298,7 @@ char **xenbus_directory(struct xenbus_transaction *t, char *strings; unsigned int len; - strings = xs_single(XS_DIRECTORY, join(dir, node), &len); + strings = xs_single(t, XS_DIRECTORY, join(dir, node), &len); if (IS_ERR(strings)) return (char **)strings; @@ -352,7 +328,7 @@ EXPORT_SYMBOL(xenbus_exists); void *xenbus_read(struct xenbus_transaction *t, const char *dir, const char *node, unsigned int *len) { - return xs_single(XS_READ, join(dir, node), len); + return xs_single(t, XS_READ, join(dir, node), len); } EXPORT_SYMBOL(xenbus_read); @@ -372,7 +348,7 @@ int xenbus_write(struct xenbus_transaction *t, iovec[1].iov_base = (void *)string; iovec[1].iov_len = strlen(string); - return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); + return xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); } EXPORT_SYMBOL(xenbus_write); @@ -380,14 +356,14 @@ EXPORT_SYMBOL(xenbus_write); int xenbus_mkdir(struct xenbus_transaction *t, const char *dir, const char *node) { - return xs_error(xs_single(XS_MKDIR, join(dir, node), NULL)); + return xs_error(xs_single(t, XS_MKDIR, join(dir, node), NULL)); } EXPORT_SYMBOL(xenbus_mkdir); /* Destroy a file or directory (directories must be empty). */ int xenbus_rm(struct xenbus_transaction *t, const char *dir, const char *node) { - return xs_error(xs_single(XS_RM, join(dir, node), NULL)); + return xs_error(xs_single(t, XS_RM, join(dir, node), NULL)); } EXPORT_SYMBOL(xenbus_rm); @@ -396,18 +372,21 @@ EXPORT_SYMBOL(xenbus_rm); */ struct xenbus_transaction *xenbus_transaction_start(void) { - int err; + char *id_str; + unsigned long id; - down(&xs_state.transaction_mutex); - xs_state.transaction_pid = current->pid; + down_read(&xs_state.suspend_mutex); - err = xs_error(xs_single(XS_TRANSACTION_START, "", NULL)); - if (err) { - xs_state.transaction_pid = -1; - up(&xs_state.transaction_mutex); + id_str = xs_single(NULL, XS_TRANSACTION_START, "", NULL); + if (IS_ERR(id_str)) { + up_read(&xs_state.suspend_mutex); + return (struct xenbus_transaction *)id_str; } - return err ? ERR_PTR(err) : (struct xenbus_transaction *)1; + id = simple_strtoul(id_str, NULL, 0); + kfree(id_str); + + return (struct xenbus_transaction *)id; } EXPORT_SYMBOL(xenbus_transaction_start); @@ -419,17 +398,14 @@ int xenbus_transaction_end(struct xenbus_transaction *t, int abort) char abortstr[2]; int err; - BUG_ON(t == NULL); - if (abort) strcpy(abortstr, "F"); else strcpy(abortstr, "T"); - err = xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL)); + err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL)); - xs_state.transaction_pid = -1; - up(&xs_state.transaction_mutex); + up_read(&xs_state.suspend_mutex); return err; } @@ -567,7 +543,8 @@ static int xs_watch(const char *path, const char *token) iov[1].iov_base = (void *)token; iov[1].iov_len = strlen(token) + 1; - return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL)); + return xs_error(xs_talkv(NULL, XS_WATCH, iov, + ARRAY_SIZE(iov), NULL)); } static int xs_unwatch(const char *path, const char *token) @@ -579,7 +556,8 @@ static int xs_unwatch(const char *path, const char *token) iov[1].iov_base = (char *)token; iov[1].iov_len = strlen(token) + 1; - return xs_error(xs_talkv(XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL)); + return xs_error(xs_talkv(NULL, XS_UNWATCH, iov, + ARRAY_SIZE(iov), NULL)); } static struct xenbus_watch *find_watch(const char *token) @@ -604,6 +582,8 @@ int register_xenbus_watch(struct xenbus_watch *watch) sprintf(token, "%lX", (long)watch); + down_read(&xs_state.suspend_mutex); + spin_lock(&watches_lock); BUG_ON(find_watch(token)); spin_unlock(&watches_lock); @@ -617,6 +597,8 @@ int register_xenbus_watch(struct xenbus_watch *watch) spin_unlock(&watches_lock); } + up_read(&xs_state.suspend_mutex); + return err; } EXPORT_SYMBOL(register_xenbus_watch); @@ -628,20 +610,21 @@ void unregister_xenbus_watch(struct xenbus_watch *watch) sprintf(token, "%lX", (long)watch); + down_read(&xs_state.suspend_mutex); + spin_lock(&watches_lock); BUG_ON(!find_watch(token)); list_del(&watch->list); spin_unlock(&watches_lock); - /* Ensure xs_resume() is not in progress (see comments there). */ - wait_event(xs_resuming_waitq, !xs_resuming); - err = xs_unwatch(watch->node, token); if (err) printk(KERN_WARNING "XENBUS Failed to release watch %s: %i\n", watch->node, err); + up_read(&xs_state.suspend_mutex); + /* Make sure watch is not in use. */ flush_scheduled_work(); } @@ -649,58 +632,24 @@ EXPORT_SYMBOL(unregister_xenbus_watch); void xs_suspend(void) { - down(&xs_state.transaction_mutex); + down_write(&xs_state.suspend_mutex); down(&xs_state.request_mutex); } void xs_resume(void) { - struct list_head *ent, *prev_ent = &watches; struct xenbus_watch *watch; char token[sizeof(watch) * 2 + 1]; - /* Protect against concurrent unregistration and freeing of watches. */ - BUG_ON(xs_resuming); - xs_resuming = 1; - up(&xs_state.request_mutex); - up(&xs_state.transaction_mutex); - /* - * Iterate over the watch list re-registering each node. We must - * be careful about concurrent registrations and unregistrations. - * We search for the node immediately following the previously - * re-registered node. If we get no match then either we are done - * (previous node is last in list) or the node was unregistered, in - * which case we restart from the beginning of the list. - * register_xenbus_watch() + unregister_xenbus_watch() is safe because - * it will only ever move a watch node earlier in the list, so it - * cannot cause us to skip nodes. - */ - for (;;) { - spin_lock(&watches_lock); - list_for_each(ent, &watches) - if (ent->prev == prev_ent) - break; - spin_unlock(&watches_lock); - - /* No match because prev_ent is at the end of the list? */ - if ((ent == &watches) && (watches.prev == prev_ent)) - break; /* We're done! */ - - if ((prev_ent = ent) != &watches) { - /* - * Safe even with watch_lock not held. We are saved by - * (xs_resumed==1) check in unregister_xenbus_watch. - */ - watch = list_entry(ent, struct xenbus_watch, list); - sprintf(token, "%lX", (long)watch); - xs_watch(watch->node, token); - } + /* No need for watches_lock: the suspend_mutex is sufficient. */ + list_for_each_entry(watch, &watches, list) { + sprintf(token, "%lX", (long)watch); + xs_watch(watch->node, token); } - xs_resuming = 0; - wake_up(&xs_resuming_waitq); + up_write(&xs_state.suspend_mutex); } static void xenbus_fire_watch(void *arg) @@ -801,8 +750,7 @@ int xs_init(void) init_waitqueue_head(&xs_state.reply_waitq); init_MUTEX(&xs_state.request_mutex); - init_MUTEX(&xs_state.transaction_mutex); - xs_state.transaction_pid = -1; + init_rwsem(&xs_state.suspend_mutex); /* Initialize the shared memory rings to talk to xenstored */ err = xb_init_comms(); diff --git a/tools/xenstore/utils.h b/tools/xenstore/utils.h index 5fbfceeaa9..df82c1c5ef 100644 --- a/tools/xenstore/utils.h +++ b/tools/xenstore/utils.h @@ -55,4 +55,34 @@ void xprintf(const char *fmt, ...); #define dprintf(_fmt, _args...) ((void)0) #endif +/* + * Mux errno values onto returned pointers. + */ + +static inline void *ERR_PTR(long error) +{ + return (void *)error; +} + +static inline long PTR_ERR(const void *ptr) +{ + return (long)ptr; +} + +static inline long IS_ERR(const void *ptr) +{ + return ((unsigned long)ptr > (unsigned long)-1000L); +} + + #endif /* _UTILS_H */ + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/tools/xenstore/xenstore_client.c b/tools/xenstore/xenstore_client.c index 5370d43e99..5f69da53c9 100644 --- a/tools/xenstore/xenstore_client.c +++ b/tools/xenstore/xenstore_client.c @@ -34,15 +34,11 @@ main(int argc, char **argv) struct xs_handle *xsh; struct xs_transaction_handle *xth; bool success; - int ret = 0; + int ret = 0, socket = 0; #if defined(CLIENT_read) || defined(CLIENT_list) int prefix = 0; #endif - xsh = xs_domain_open(); - if (xsh == NULL) - err(1, "xs_domain_open"); - while (1) { int c, index = 0; static struct option long_options[] = { @@ -50,10 +46,11 @@ main(int argc, char **argv) #if defined(CLIENT_read) || defined(CLIENT_list) {"prefix", 0, 0, 'p'}, #endif + {"socket", 0, 0, 's'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "h" + c = getopt_long(argc, argv, "hs" #if defined(CLIENT_read) || defined(CLIENT_list) "p" #endif @@ -65,6 +62,9 @@ main(int argc, char **argv) case 'h': usage(argv[0]); /* NOTREACHED */ + case 's': + socket = 1; + break; #if defined(CLIENT_read) || defined(CLIENT_list) case 'p': prefix = 1; @@ -84,6 +84,10 @@ main(int argc, char **argv) } #endif + xsh = socket ? xs_daemon_open() : xs_domain_open(); + if (xsh == NULL) + err(1, socket ? "xs_daemon_open" : "xs_domain_open"); + again: xth = xs_transaction_start(xsh); if (xth == NULL) diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 50bdee9a66..753f8b0eee 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -238,47 +238,48 @@ void trace(const char *fmt, ...) static bool write_messages(struct connection *conn) { int ret; - struct buffered_data *out, *tmp; + struct buffered_data *out; - list_for_each_entry_safe(out, tmp, &conn->out_list, list) { - if (out->inhdr) { - if (verbose) - xprintf("Writing msg %s (%s) out to %p\n", - sockmsg_string(out->hdr.msg.type), - out->buffer, conn); - ret = conn->write(conn, out->hdr.raw + out->used, - sizeof(out->hdr) - out->used); - if (ret < 0) - return false; - - out->used += ret; - if (out->used < sizeof(out->hdr)) - return true; - - out->inhdr = false; - out->used = 0; - - /* Second write might block if non-zero. */ - if (out->hdr.msg.len && !conn->domain) - return true; - } - - ret = conn->write(conn, out->buffer + out->used, - out->hdr.msg.len - out->used); + out = list_top(&conn->out_list, struct buffered_data, list); + if (out == NULL) + return true; + if (out->inhdr) { + if (verbose) + xprintf("Writing msg %s (%s) out to %p\n", + sockmsg_string(out->hdr.msg.type), + out->buffer, conn); + ret = conn->write(conn, out->hdr.raw + out->used, + sizeof(out->hdr) - out->used); if (ret < 0) return false; out->used += ret; - if (out->used != out->hdr.msg.len) + if (out->used < sizeof(out->hdr)) return true; - trace_io(conn, "OUT", out); + out->inhdr = false; + out->used = 0; - list_del(&out->list); - talloc_free(out); + /* Second write might block if non-zero. */ + if (out->hdr.msg.len && !conn->domain) + return true; } + ret = conn->write(conn, out->buffer + out->used, + out->hdr.msg.len - out->used); + if (ret < 0) + return false; + + out->used += ret; + if (out->used != out->hdr.msg.len) + return true; + + trace_io(conn, "OUT", out); + + list_del(&out->list); + talloc_free(out); + return true; } @@ -1042,6 +1043,17 @@ static void do_set_perms(struct connection *conn, struct buffered_data *in) */ static void process_message(struct connection *conn, struct buffered_data *in) { + struct transaction *trans; + + trans = transaction_lookup(conn, in->hdr.msg.tx_id); + if (IS_ERR(trans)) { + send_error(conn, -PTR_ERR(trans)); + return; + } + + assert(conn->transaction == NULL); + conn->transaction = trans; + switch (in->hdr.msg.type) { case XS_DIRECTORY: send_directory(conn, onearg(in)); @@ -1116,11 +1128,13 @@ static void process_message(struct connection *conn, struct buffered_data *in) do_get_domain_path(conn, onearg(in)); break; - case XS_WATCH_EVENT: default: eprintf("Client unknown operation %i", in->hdr.msg.type); send_error(conn, ENOSYS); + break; } + + conn->transaction = NULL; } static int out_of_mem(void *data) @@ -1239,15 +1253,14 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) if (!new) return NULL; + memset(new, 0, sizeof(*new)); new->fd = -1; - new->id = 0; - new->domain = NULL; - new->transaction = NULL; new->write = write; new->read = read; new->can_write = true; INIT_LIST_HEAD(&new->out_list); INIT_LIST_HEAD(&new->watches); + INIT_LIST_HEAD(&new->transaction_list); talloc_set_fail_handler(out_of_mem, &talloc_fail); if (setjmp(talloc_fail)) { @@ -1410,6 +1423,7 @@ static void daemonize(void) static struct option options[] = { + { "no-domain-init", 0, NULL, 'D' }, { "pid-file", 1, NULL, 'F' }, { "no-fork", 0, NULL, 'N' }, { "output-pid", 0, NULL, 'P' }, @@ -1424,11 +1438,15 @@ int main(int argc, char *argv[]) fd_set inset, outset; bool dofork = true; bool outputpid = false; + bool no_domain_init = false; const char *pidfile = NULL; - while ((opt = getopt_long(argc, argv, "F:NPT:V", options, + while ((opt = getopt_long(argc, argv, "DF:NPT:V", options, NULL)) != -1) { switch (opt) { + case 'D': + no_domain_init = true; + break; case 'F': pidfile = optarg; break; @@ -1501,7 +1519,8 @@ int main(int argc, char *argv[]) setup_structure(); /* Listen to hypervisor. */ - event_fd = domain_init(); + if (!no_domain_init) + event_fd = domain_init(); /* Restore existing connections. */ restore_existing_connections(); diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_core.h index c50936f1bc..600e95a6f8 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -71,9 +71,13 @@ struct connection /* Buffered output data */ struct list_head out_list; - /* My transaction, if any. */ + /* Transaction context for current request (NULL if none). */ struct transaction *transaction; + /* List of in-progress transactions. */ + struct list_head transaction_list; + u32 next_transaction_id; + /* The domain I'm associated with, if any. */ struct domain *domain; diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c index 640d10540f..988ea5d0fb 100644 --- a/tools/xenstore/xenstored_transaction.c +++ b/tools/xenstore/xenstored_transaction.c @@ -37,7 +37,7 @@ struct changed_node { - /* The list within this transaction. */ + /* List of all changed nodes in the context of this transaction. */ struct list_head list; /* The name of the node. */ @@ -49,15 +49,15 @@ struct changed_node struct transaction { - /* Global list of transactions. */ + /* List of all transactions active on this connection. */ struct list_head list; + /* Connection-local identifier for this transaction. */ + u32 id; + /* Generation when transaction started. */ unsigned int generation; - /* My owner (conn->transaction == me). */ - struct connection *conn; - /* TDB to work on, and filename */ TDB_CONTEXT *tdb; char *tdb_name; @@ -65,7 +65,7 @@ struct transaction /* List of changed nodes. */ struct list_head changes; }; -static LIST_HEAD(transactions); + static unsigned int generation; /* Return tdb context to use for this connection. */ @@ -100,7 +100,6 @@ static int destroy_transaction(void *_transaction) { struct transaction *trans = _transaction; - list_del(&trans->list); trace_destroy(trans, "transaction"); if (trans->tdb) tdb_close(trans->tdb); @@ -108,10 +107,26 @@ static int destroy_transaction(void *_transaction) return 0; } -void do_transaction_start(struct connection *conn, struct buffered_data *in) +struct transaction *transaction_lookup(struct connection *conn, u32 id) { struct transaction *trans; + if (id == 0) + return NULL; + + list_for_each_entry(trans, &conn->transaction_list, list) + if (trans->id == id) + return trans; + + return ERR_PTR(-ENOENT); +} + +void do_transaction_start(struct connection *conn, struct buffered_data *in) +{ + struct transaction *trans, *exists; + char id_str[20]; + + /* We don't support nested transactions. */ if (conn->transaction) { send_error(conn, EBUSY); return; @@ -120,7 +135,6 @@ void do_transaction_start(struct connection *conn, struct buffered_data *in) /* Attach transaction to input for autofree until it's complete */ trans = talloc(in, struct transaction); INIT_LIST_HEAD(&trans->changes); - trans->conn = conn; trans->generation = generation; trans->tdb_name = talloc_asprintf(trans, "%s.%p", xs_daemon_tdb(), trans); @@ -132,11 +146,19 @@ void do_transaction_start(struct connection *conn, struct buffered_data *in) /* Make it close if we go away. */ talloc_steal(trans, trans->tdb); + /* Pick an unused transaction identifier. */ + do { + trans->id = conn->next_transaction_id; + exists = transaction_lookup(conn, conn->next_transaction_id++); + } while (!IS_ERR(exists)); + /* Now we own it. */ - conn->transaction = talloc_steal(conn, trans); - list_add_tail(&trans->list, &transactions); + list_add_tail(&trans->list, &conn->transaction_list); + talloc_steal(conn, trans); talloc_set_destructor(trans, destroy_transaction); - send_ack(conn, XS_TRANSACTION_START); + + sprintf(id_str, "%u", trans->id); + send_reply(conn, XS_TRANSACTION_START, id_str, strlen(id_str)+1); } void do_transaction_end(struct connection *conn, const char *arg) @@ -149,13 +171,13 @@ void do_transaction_end(struct connection *conn, const char *arg) return; } - if (!conn->transaction) { + if ((trans = conn->transaction) == NULL) { send_error(conn, ENOENT); return; } - trans = conn->transaction; conn->transaction = NULL; + list_del(&trans->list); /* Attach transaction to arg for auto-cleanup */ talloc_steal(arg, trans); @@ -181,3 +203,12 @@ void do_transaction_end(struct connection *conn, const char *arg) send_ack(conn, XS_TRANSACTION_END); } +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h index 2617339940..992791f7a9 100644 --- a/tools/xenstore/xenstored_transaction.h +++ b/tools/xenstore/xenstored_transaction.h @@ -25,10 +25,11 @@ struct transaction; void do_transaction_start(struct connection *conn, struct buffered_data *node); void do_transaction_end(struct connection *conn, const char *arg); -bool transaction_block(struct connection *conn); +struct transaction *transaction_lookup(struct connection *conn, u32 id); /* This node was changed: can fail and longjmp. */ -void add_change_node(struct transaction *trans, const char *node, bool recurse); +void add_change_node(struct transaction *trans, const char *node, + bool recurse); /* Return tdb context to use for this connection. */ TDB_CONTEXT *tdb_transaction_context(struct transaction *trans); diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c index 89b42ba734..acd71108d9 100644 --- a/tools/xenstore/xs.c +++ b/tools/xenstore/xs.c @@ -75,37 +75,10 @@ struct xs_handle { /* One request at a time. */ pthread_mutex_t request_mutex; - - /* One transaction at a time. */ - pthread_mutex_t transaction_mutex; - pthread_t transaction_pthread; -}; - -struct xs_transaction_handle { - int id; }; static void *read_thread(void *arg); -static void request_mutex_acquire(struct xs_handle *h) -{ - /* - * We can't distinguish non-transactional from transactional - * requests right now. So temporarily acquire the transaction mutex - * if this task is outside transaction context. - */ - if (h->transaction_pthread != pthread_self()) - pthread_mutex_lock(&h->transaction_mutex); - pthread_mutex_lock(&h->request_mutex); -} - -static void request_mutex_release(struct xs_handle *h) -{ - pthread_mutex_unlock(&h->request_mutex); - if (h->transaction_pthread != pthread_self()) - pthread_mutex_unlock(&h->transaction_mutex); -} - int xs_fileno(struct xs_handle *h) { char c = 0; @@ -186,8 +159,6 @@ static struct xs_handle *get_handle(const char *connect_to) pthread_cond_init(&h->reply_condvar, NULL); pthread_mutex_init(&h->request_mutex, NULL); - pthread_mutex_init(&h->transaction_mutex, NULL); - h->transaction_pthread = -1; if (pthread_create(&h->read_thr, NULL, read_thread, h) != 0) goto error; @@ -223,7 +194,6 @@ void xs_daemon_close(struct xs_handle *h) { struct xs_stored_msg *msg, *tmsg; - pthread_mutex_lock(&h->transaction_mutex); pthread_mutex_lock(&h->request_mutex); pthread_mutex_lock(&h->reply_mutex); pthread_mutex_lock(&h->watch_mutex); @@ -242,7 +212,6 @@ void xs_daemon_close(struct xs_handle *h) free(msg); } - pthread_mutex_unlock(&h->transaction_mutex); pthread_mutex_unlock(&h->request_mutex); pthread_mutex_unlock(&h->reply_mutex); pthread_mutex_unlock(&h->watch_mutex); @@ -321,8 +290,10 @@ static void *read_reply( } /* Send message to xs, get malloc'ed reply. NULL and set errno on error. */ -static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type, - const struct iovec *iovec, unsigned int num_vecs, +static void *xs_talkv(struct xs_handle *h, struct xs_transaction_handle *t, + enum xsd_sockmsg_type type, + const struct iovec *iovec, + unsigned int num_vecs, unsigned int *len) { struct xsd_sockmsg msg; @@ -331,6 +302,7 @@ static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type, unsigned int i; struct sigaction ignorepipe, oldact; + msg.tx_id = (u32)(unsigned long)t; msg.type = type; msg.len = 0; for (i = 0; i < num_vecs; i++) @@ -341,7 +313,7 @@ static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type, ignorepipe.sa_flags = 0; sigaction(SIGPIPE, &ignorepipe, &oldact); - request_mutex_acquire(h); + pthread_mutex_lock(&h->request_mutex); if (!xs_write_all(h->fd, &msg, sizeof(msg))) goto fail; @@ -354,7 +326,7 @@ static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type, if (!ret) goto fail; - request_mutex_release(h); + pthread_mutex_unlock(&h->request_mutex); sigaction(SIGPIPE, &oldact, NULL); if (msg.type == XS_ERROR) { @@ -375,7 +347,7 @@ static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type, fail: /* We're in a bad state, so close fd. */ saved_errno = errno; - request_mutex_release(h); + pthread_mutex_unlock(&h->request_mutex); sigaction(SIGPIPE, &oldact, NULL); close_fd: close(h->fd); @@ -393,14 +365,16 @@ static void free_no_errno(void *p) } /* Simplified version of xs_talkv: single message. */ -static void *xs_single(struct xs_handle *h, enum xsd_sockmsg_type type, - const char *string, unsigned int *len) +static void *xs_single(struct xs_handle *h, struct xs_transaction_handle *t, + enum xsd_sockmsg_type type, + const char *string, + unsigned int *len) { struct iovec iovec; iovec.iov_base = (void *)string; iovec.iov_len = strlen(string) + 1; - return xs_talkv(h, type, &iovec, 1, len); + return xs_talkv(h, t, type, &iovec, 1, len); } static bool xs_bool(char *reply) @@ -417,7 +391,7 @@ char **xs_directory(struct xs_handle *h, struct xs_transaction_handle *t, char *strings, *p, **ret; unsigned int len; - strings = xs_single(h, XS_DIRECTORY, path, &len); + strings = xs_single(h, t, XS_DIRECTORY, path, &len); if (!strings) return NULL; @@ -446,7 +420,7 @@ char **xs_directory(struct xs_handle *h, struct xs_transaction_handle *t, void *xs_read(struct xs_handle *h, struct xs_transaction_handle *t, const char *path, unsigned int *len) { - return xs_single(h, XS_READ, path, len); + return xs_single(h, t, XS_READ, path, len); } /* Write the value of a single file. @@ -462,7 +436,8 @@ bool xs_write(struct xs_handle *h, struct xs_transaction_handle *t, iovec[1].iov_base = (void *)data; iovec[1].iov_len = len; - return xs_bool(xs_talkv(h, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); + return xs_bool(xs_talkv(h, t, XS_WRITE, iovec, + ARRAY_SIZE(iovec), NULL)); } /* Create a new directory. @@ -471,7 +446,7 @@ bool xs_write(struct xs_handle *h, struct xs_transaction_handle *t, bool xs_mkdir(struct xs_handle *h, struct xs_transaction_handle *t, const char *path) { - return xs_bool(xs_single(h, XS_MKDIR, path, NULL)); + return xs_bool(xs_single(h, t, XS_MKDIR, path, NULL)); } /* Destroy a file or directory (directories must be empty). @@ -480,7 +455,7 @@ bool xs_mkdir(struct xs_handle *h, struct xs_transaction_handle *t, bool xs_rm(struct xs_handle *h, struct xs_transaction_handle *t, const char *path) { - return xs_bool(xs_single(h, XS_RM, path, NULL)); + return xs_bool(xs_single(h, t, XS_RM, path, NULL)); } /* Get permissions of node (first element is owner). @@ -494,7 +469,7 @@ struct xs_permissions *xs_get_permissions(struct xs_handle *h, unsigned int len; struct xs_permissions *ret; - strings = xs_single(h, XS_GET_PERMS, path, &len); + strings = xs_single(h, t, XS_GET_PERMS, path, &len); if (!strings) return NULL; @@ -544,7 +519,7 @@ bool xs_set_permissions(struct xs_handle *h, goto unwind; } - if (!xs_bool(xs_talkv(h, XS_SET_PERMS, iov, 1+num_perms, NULL))) + if (!xs_bool(xs_talkv(h, t, XS_SET_PERMS, iov, 1+num_perms, NULL))) goto unwind; for (i = 0; i < num_perms; i++) free(iov[i+1].iov_base); @@ -571,7 +546,8 @@ bool xs_watch(struct xs_handle *h, const char *path, const char *token) iov[1].iov_base = (void *)token; iov[1].iov_len = strlen(token) + 1; - return xs_bool(xs_talkv(h, XS_WATCH, iov, ARRAY_SIZE(iov), NULL)); + return xs_bool(xs_talkv(h, NULL, XS_WATCH, iov, + ARRAY_SIZE(iov), NULL)); } /* Find out what node change was on (will block if nothing pending). @@ -637,7 +613,8 @@ bool xs_unwatch(struct xs_handle *h, const char *path, const char *token) iov[1].iov_base = (char *)token; iov[1].iov_len = strlen(token) + 1; - return xs_bool(xs_talkv(h, XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL)); + return xs_bool(xs_talkv(h, NULL, XS_UNWATCH, iov, + ARRAY_SIZE(iov), NULL)); } /* Start a transaction: changes by others will not be seen during this @@ -647,18 +624,17 @@ bool xs_unwatch(struct xs_handle *h, const char *path, const char *token) */ struct xs_transaction_handle *xs_transaction_start(struct xs_handle *h) { - bool rc; + char *id_str; + unsigned long id; - pthread_mutex_lock(&h->transaction_mutex); - h->transaction_pthread = pthread_self(); + id_str = xs_single(h, NULL, XS_TRANSACTION_START, "", NULL); + if (id_str == NULL) + return NULL; - rc = xs_bool(xs_single(h, XS_TRANSACTION_START, "", NULL)); - if (!rc) { - h->transaction_pthread = -1; - pthread_mutex_unlock(&h->transaction_mutex); - } + id = strtoul(id_str, NULL, 0); + free(id_str); - return (struct xs_transaction_handle *)rc; + return (struct xs_transaction_handle *)id; } /* End a transaction. @@ -670,22 +646,13 @@ bool xs_transaction_end(struct xs_handle *h, struct xs_transaction_handle *t, bool abort) { char abortstr[2]; - bool rc; - - if (t == NULL) - return -EINVAL; if (abort) strcpy(abortstr, "F"); else strcpy(abortstr, "T"); - rc = xs_bool(xs_single(h, XS_TRANSACTION_END, abortstr, NULL)); - - h->transaction_pthread = -1; - pthread_mutex_unlock(&h->transaction_mutex); - - return rc; + return xs_bool(xs_single(h, t, XS_TRANSACTION_END, abortstr, NULL)); } /* Introduce a new domain. @@ -713,7 +680,8 @@ bool xs_introduce_domain(struct xs_handle *h, domid_t domid, unsigned long mfn, iov[3].iov_base = (char *)path; iov[3].iov_len = strlen(path) + 1; - return xs_bool(xs_talkv(h, XS_INTRODUCE, iov, ARRAY_SIZE(iov), NULL)); + return xs_bool(xs_talkv(h, NULL, XS_INTRODUCE, iov, + ARRAY_SIZE(iov), NULL)); } bool xs_release_domain(struct xs_handle *h, domid_t domid) @@ -722,7 +690,7 @@ bool xs_release_domain(struct xs_handle *h, domid_t domid) sprintf(domid_str, "%u", domid); - return xs_bool(xs_single(h, XS_RELEASE, domid_str, NULL)); + return xs_bool(xs_single(h, NULL, XS_RELEASE, domid_str, NULL)); } char *xs_get_domain_path(struct xs_handle *h, domid_t domid) @@ -731,7 +699,7 @@ char *xs_get_domain_path(struct xs_handle *h, domid_t domid) sprintf(domid_str, "%u", domid); - return xs_single(h, XS_GET_DOMAIN_PATH, domid_str, NULL); + return xs_single(h, NULL, XS_GET_DOMAIN_PATH, domid_str, NULL); } /* Only useful for DEBUG versions */ @@ -745,7 +713,8 @@ char *xs_debug_command(struct xs_handle *h, const char *cmd, iov[1].iov_base = data; iov[1].iov_len = len; - return xs_talkv(h, XS_DEBUG, iov, ARRAY_SIZE(iov), NULL); + return xs_talkv(h, NULL, XS_DEBUG, iov, + ARRAY_SIZE(iov), NULL); } static void *read_thread(void *arg) From dc988367d85b873d0fb292dbfc04cbf0c2134ab3 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Mon, 10 Oct 2005 16:15:48 +0100 Subject: [PATCH 17/42] Rewritten XendLogging to not be a singleton class, and not have methods used from nowhere at all. Log to a temporary file if permission is denied to log to /var/log/xend.log, as happens when you are not root. Fixes bug #305. Remove all the log-related garbage from XendRoot -- just about every module was going straight to XendLogging.log already, so there was no need to have XendRoot replicate this functionality. Remove XendRoot.event_handler, which hasn't been in use since the EventServer was removed. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendLogging.py | 137 +++++++++++---------- tools/python/xen/xend/XendRoot.py | 92 ++------------ tools/python/xen/xend/server/SrvXendLog.py | 7 +- tools/python/xen/xend/server/event.py | 6 +- 4 files changed, 90 insertions(+), 152 deletions(-) diff --git a/tools/python/xen/xend/XendLogging.py b/tools/python/xen/xend/XendLogging.py index 367c0b63f9..9c78f92236 100644 --- a/tools/python/xen/xend/XendLogging.py +++ b/tools/python/xen/xend/XendLogging.py @@ -13,79 +13,82 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray +# Copyright (C) 2005 XenSource Ltd #============================================================================ + +import tempfile import types import logging -from logging import Formatter, StreamHandler -from logging.handlers import RotatingFileHandler +import logging.handlers -class XendLogging: - KB = 1024 - MB = 1024 * KB - - maxBytes = 1 * MB - backupCount = 5 +__all__ = [ 'log', 'init', 'getLogFilename', 'addLogStderr', + 'removeLogStderr' ] - logStderrFormat = "[%(name)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s" - logFileFormat = "[%(asctime)s %(name)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s" - dateFormat = "%Y-%m-%d %H:%M:%S" - - def __init__(self, filename, level=logging.INFO, maxBytes=None, backupCount=None): - """Initialise logging. Logs to 'filename' by default, but does not log to - stderr unless addLogStderr() is called. - """ - self.setLevel(level) - if maxBytes: - self.maxBytes = maxBytes - if backupCount: - self.backupCount = backupCount - self.initLogFile(filename) - self.initLogStderr() - - def setLevel(self, level): - if isinstance(level, types.StringType): - level = logging._levelNames[level] - self.getLogger().setLevel(level) - self.level = level - - def getLogger(self): - return logging.getLogger("xend") - - def initLogFile(self, filename): - """Create the file logger and add it. - """ - self.logfile = RotatingFileHandler(filename, - mode='a', - maxBytes=self.maxBytes, - backupCount=self.backupCount) - self.logfilename = filename - self.logfile.setFormatter(Formatter(self.logFileFormat, self.dateFormat)) - self.getLogger().addHandler(self.logfile) - - def getLogFile(self): - return self.logfile - - def getLogFilename(self): - return self.logfilename - - def initLogStderr(self): - """Create the stderr logger, but don't add it. - """ - self.logstderr = StreamHandler() - self.logstderr.setFormatter(Formatter(self.logStderrFormat, self.dateFormat)) - - def addLogStderr(self): - """Add logging to stderr.""" - self.getLogger().addHandler(self.logstderr) - - def removeLogStderr(self): - """Remove logging to stderr.""" - self.getLogger().removeHandler(self.logstderr) - - def getLogStderr(self): - return self.logstderr log = logging.getLogger("xend") - + + +DEFAULT_MAX_BYTES = 1 << 20 # 1MB +DEFAULT_BACKUP_COUNT = 5 + +STDERR_FORMAT = "[%(name)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s" +LOGFILE_FORMAT = "[%(asctime)s %(name)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s" +DATE_FORMAT = "%Y-%m-%d %H:%M:%S" + + +stderrHandler = logging.StreamHandler() +stderrHandler.setFormatter(logging.Formatter(STDERR_FORMAT, DATE_FORMAT)) + +logfilename = None + + +def init(filename, level=logging.INFO, maxBytes=None, backupCount=None): + """Initialise logging. Logs to 'filename' by default, but does not log to + stderr unless addLogStderr() is called. + """ + + def openFileHandler(fname): + return logging.handlers.RotatingFileHandler(fname, + mode='a', + maxBytes=maxBytes, + backupCount=backupCount) + + if not maxBytes: + maxBytes = DEFAULT_MAX_BYTES + if not backupCount: + backupCount = DEFAULT_BACKUP_COUNT + + # Rather unintuitively, getLevelName will get the number corresponding to + # a level name, as well as getting the name corresponding to a level + # number. setLevel seems to take the number only though, so convert if we + # are given a string. + if isinstance(level, types.StringType): + level = logging.getLevelName(level) + + log.setLevel(level) + + try: + fileHandler = openFileHandler(filename) + logfilename = filename + except IOError: + logfilename = tempfile.mkstemp("-xend.log")[1] + fileHandler = openFileHandler(logfilename) + + fileHandler.setFormatter(logging.Formatter(LOGFILE_FORMAT, DATE_FORMAT)) + log.addHandler(fileHandler) + + +def getLogFilename(): + return logfilename + + +def addLogStderr(): + """Add logging to stderr.""" + log.addHandler(stderrHandler) + + +def removeLogStderr(): + """Remove logging to stderr.""" + log.removeHandler(stderrHandler) diff --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py index f170b1192b..85a13286dd 100644 --- a/tools/python/xen/xend/XendRoot.py +++ b/tools/python/xen/xend/XendRoot.py @@ -13,6 +13,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray +# Copyright (C) 2005 XenSource Ltd #============================================================================ """Xend root class. @@ -29,7 +30,7 @@ import os.path import string import sys -from XendLogging import XendLogging +import XendLogging from XendError import XendError import sxp @@ -92,7 +93,6 @@ class XendRoot: def __init__(self): self.config_path = None self.config = None - self.logging = None self.configure() @@ -114,84 +114,22 @@ class XendRoot: """ return self.components.get(name) - def _format(self, msg, args): - if args: - return str(msg) % args - else: - return str(msg) - - def _log(self, mode, fmt, args): - """Logging function that uses the logger if it exists, otherwise - logs to stderr. We use this for XendRoot log messages because - they may be logged before the logger has been configured. - Other components can safely use the logger. + def _logError(self, fmt, args): + """Logging function to log to stderr. We use this for XendRoot log + messages because they may be logged before the logger has been + configured. Other components can safely use the logger. """ - log = self.get_logger() - if mode not in ['warning', 'info', 'debug', 'error']: - mode = 'info' - level = mode.upper() - if log: - getattr(log, mode)(fmt, *args) - else: - print >>sys.stderr, "xend", "[%s]" % level, self._format(fmt, args) - - def logDebug(self, fmt, *args): - """Log a debug message. - - @param fmt: message format - @param args: arguments - """ - self._log('debug', fmt, args) - - def logInfo(self, fmt, *args): - """Log an info message. - - @param fmt: message format - @param args: arguments - """ - self._log('info', fmt, args) - - def logWarning(self, fmt, *args): - """Log a warning message. - - @param fmt: message format - @param args: arguments - """ - self._log('warning', fmt, args) - - def logError(self, fmt, *args): - """Log an error message. - - @param fmt: message format - @param args: arguments - """ - self._log('error', fmt, args) - - def event_handler(self, event, val): - self.logInfo("EVENT> %s %s", str(event), str(val)) + print >>sys.stderr, "xend [ERROR]", fmt % args def configure(self): self.set_config() - self.configure_logger() - - def configure_logger(self): logfile = self.get_config_value("logfile", self.logfile_default) loglevel = self.get_config_value("loglevel", self.loglevel_default) - self.logging = XendLogging(logfile, level=loglevel) + XendLogging.init(logfile, level = loglevel) from xen.xend.server import params if params.XEND_DEBUG: - self.logging.addLogStderr() - - def get_logging(self): - """Get the XendLogging instance. - """ - return self.logging - - def get_logger(self): - """Get the logger. - """ - return self.logging and self.logging.getLogger() + XendLogging.addLogStderr() def set_config(self): """If the config file exists, read it. If not, ignore it. @@ -200,7 +138,6 @@ class XendRoot: """ self.config_path = os.getenv(self.config_var, self.config_default) if os.path.exists(self.config_path): - #self.logInfo('Reading config file %s', self.config_path) try: fin = file(self.config_path, 'rb') try: @@ -210,10 +147,12 @@ class XendRoot: config.insert(0, 'xend-config') self.config = config except Exception, ex: - self.logError('Reading config file %s: %s', self.config_path, str(ex)) + self._logError('Reading config file %s: %s', + self.config_path, str(ex)) raise else: - self.logError('Config file does not exist: %s', self.config_path) + self._logError('Config file does not exist: %s', + self.config_path) self.config = ['xend-config'] def get_config(self, name=None): @@ -339,11 +278,6 @@ def instance(): inst = XendRoot() return inst -def logger(): - """Get the logger. - """ - return instance().get_logger() - def add_component(name, val): """Register a component with XendRoot. This is used to work-round import cycles. diff --git a/tools/python/xen/xend/server/SrvXendLog.py b/tools/python/xen/xend/server/SrvXendLog.py index e91127e4d0..a0dc67aa2d 100644 --- a/tools/python/xen/xend/server/SrvXendLog.py +++ b/tools/python/xen/xend/server/SrvXendLog.py @@ -13,11 +13,12 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray +# Copyright (C) 2005 XenSource Ltd #============================================================================ from xen.web import static -from xen.xend import XendRoot +from xen.xend import XendLogging from xen.web.SrvDir import SrvDir @@ -27,8 +28,8 @@ class SrvXendLog(SrvDir): def __init__(self): SrvDir.__init__(self) - logging = XendRoot.instance().get_logging() - self.logfile = static.File(logging.getLogFilename(), defaultType="text/plain") + self.logfile = static.File(XendLogging.getLogFilename(), + defaultType="text/plain") self.logfile.type = "text/plain" self.logfile.encoding = None diff --git a/tools/python/xen/xend/server/event.py b/tools/python/xen/xend/server/event.py index c9d3257738..bf0521c764 100644 --- a/tools/python/xen/xend/server/event.py +++ b/tools/python/xen/xend/server/event.py @@ -25,6 +25,7 @@ from xen.xend import scheduler from xen.xend import sxp from xen.xend import PrettyPrint from xen.xend.XendError import XendError +from xen.xend import XendLogging from xen.xend import XendRoot @@ -146,11 +147,10 @@ class EventProtocol(protocol.Protocol): def op_log_stderr(self, _, v): mode = v[1] - logging = xroot.get_logging() if mode == 'on': - logging.addLogStderr() + XendLogging.addLogStderr() else: - logging.removeLogStderr() + XendLogging.removeLogStderr() def op_domain_ls(self, _1, _2): xd = xroot.get_component("xen.xend.XendDomain") From 4aff323032c509f3b412e48d0046ddf94d684227 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 10 Oct 2005 16:57:41 +0100 Subject: [PATCH 18/42] Fire watch callbacks on their own workqueue. Mainly this is to make debugging easier (it's hard if an error takes out the default workqueue!). Also, watch callbacks can be arbitrarily long-lived, so it's more polite. Signed-off-by: Keir Fraser --- .../drivers/xen/xenbus/xenbus_xs.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c index 1b53fd73f5..edf5f99af4 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @@ -79,6 +79,7 @@ static struct xs_handle xs_state; static LIST_HEAD(watches); static DEFINE_SPINLOCK(watches_lock); +static struct workqueue_struct *watches_workq; static int get_error(const char *errorstring) { @@ -626,7 +627,7 @@ void unregister_xenbus_watch(struct xenbus_watch *watch) up_read(&xs_state.suspend_mutex); /* Make sure watch is not in use. */ - flush_scheduled_work(); + flush_workqueue(watches_workq); } EXPORT_SYMBOL(unregister_xenbus_watch); @@ -708,7 +709,7 @@ static int process_msg(void) msg->u.watch.handle = find_watch( msg->u.watch.vec[XS_WATCH_TOKEN]); if (msg->u.watch.handle != NULL) { - schedule_work(&msg->u.watch.work); + queue_work(watches_workq, &msg->u.watch.work); } else { kfree(msg->u.watch.vec); kfree(msg); @@ -737,9 +738,6 @@ static int read_thread(void *unused) } } -/* -** Initialize the interface to xenstore. -*/ int xs_init(void) { int err; @@ -756,8 +754,12 @@ int xs_init(void) err = xb_init_comms(); if (err) return err; - - reader = kthread_run(read_thread, NULL, "xenbusd"); + + /* Create our own workqueue for executing watch callbacks. */ + watches_workq = create_singlethread_workqueue("xenwatch"); + BUG_ON(watches_workq == NULL); + + reader = kthread_run(read_thread, NULL, "xenbus"); if (IS_ERR(reader)) return PTR_ERR(reader); From ca59410b89e394977e3c954ba47c134f05a7b067 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 10 Oct 2005 18:16:03 +0100 Subject: [PATCH 19/42] Fix cancellation of pending watch events on watch unregistration. Use wait_event_interruptible() so that our kernel threads spend their time in the more acceptable 'S' state rather than the more worrying 'D' state. Signed-off-by: Keir Fraser --- .../drivers/xen/xenbus/xenbus_comms.c | 8 +- .../drivers/xen/xenbus/xenbus_probe.c | 25 +--- .../drivers/xen/xenbus/xenbus_xs.c | 110 +++++++++++++----- 3 files changed, 89 insertions(+), 54 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c index aa2e90b7cb..a4842df4af 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c @@ -128,7 +128,7 @@ int xb_write(const void *data, unsigned len) void *dst; unsigned int avail; - wait_event(xb_waitq, output_avail(out)); + wait_event_interruptible(xb_waitq, output_avail(out)); mb(); h = *out; @@ -136,6 +136,8 @@ int xb_write(const void *data, unsigned len) return -EIO; dst = get_output_chunk(&h, out->buf, &avail); + if (avail == 0) + continue; if (avail > len) avail = len; memcpy(dst, data, avail); @@ -167,7 +169,7 @@ int xb_read(void *data, unsigned len) unsigned int avail; const char *src; - wait_event(xb_waitq, xs_input_avail()); + wait_event_interruptible(xb_waitq, xs_input_avail()); mb(); h = *in; @@ -175,6 +177,8 @@ int xb_read(void *data, unsigned len) return -EIO; src = get_input_chunk(&h, in->buf, &avail); + if (avail == 0) + continue; if (avail > len) avail = len; was_full = !output_avail(&h); diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c index 77a9c1bbc1..09d0d8db95 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -43,9 +43,6 @@ static struct notifier_block *xenstore_chain; -/* Now used to protect xenbus probes against save/restore. */ -static DECLARE_MUTEX(xenbus_lock); - /* If something in array of ids matches this device, return it. */ static const struct xenbus_device_id * match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) @@ -232,18 +229,13 @@ static int xenbus_dev_remove(struct device *_dev) static int xenbus_register_driver_common(struct xenbus_driver *drv, struct xen_bus_type *bus) { - int err; - drv->driver.name = drv->name; drv->driver.bus = &bus->bus; drv->driver.owner = drv->owner; drv->driver.probe = xenbus_dev_probe; drv->driver.remove = xenbus_dev_remove; - down(&xenbus_lock); - err = driver_register(&drv->driver); - up(&xenbus_lock); - return err; + return driver_register(&drv->driver); } int xenbus_register_driver(struct xenbus_driver *drv) @@ -259,9 +251,7 @@ int xenbus_register_backend(struct xenbus_driver *drv) void xenbus_unregister_driver(struct xenbus_driver *drv) { - down(&xenbus_lock); driver_unregister(&drv->driver); - up(&xenbus_lock); } EXPORT_SYMBOL(xenbus_unregister_driver); @@ -624,8 +614,6 @@ static int resume_dev(struct device *dev, void *data) void xenbus_suspend(void) { - /* We keep lock, so no comms can happen as page moves. */ - down(&xenbus_lock); bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev); bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev); xs_suspend(); @@ -637,32 +625,25 @@ void xenbus_resume(void) xs_resume(); bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev); bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev); - up(&xenbus_lock); } int register_xenstore_notifier(struct notifier_block *nb) { int ret = 0; - down(&xenbus_lock); - if (xen_start_info->store_evtchn) { ret = nb->notifier_call(nb, 0, NULL); } else { notifier_chain_register(&xenstore_chain, nb); } - up(&xenbus_lock); - return ret; } EXPORT_SYMBOL(register_xenstore_notifier); void unregister_xenstore_notifier(struct notifier_block *nb) { - down(&xenbus_lock); notifier_chain_unregister(&xenstore_chain, nb); - up(&xenbus_lock); } EXPORT_SYMBOL(unregister_xenstore_notifier); @@ -683,16 +664,16 @@ int do_xenbus_probe(void *unused) return err; } - down(&xenbus_lock); /* Enumerate devices in xenstore. */ xenbus_probe_devices(&xenbus_frontend); xenbus_probe_devices(&xenbus_backend); + /* Watch for changes. */ register_xenbus_watch(&fe_watch); register_xenbus_watch(&be_watch); + /* Notify others that xenstore is up */ notifier_call_chain(&xenstore_chain, 0, 0); - up(&xenbus_lock); return 0; } diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c index edf5f99af4..3104fda41d 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @@ -43,18 +43,18 @@ #define streq(a, b) (strcmp((a), (b)) == 0) struct xs_stored_msg { + struct list_head list; + struct xsd_sockmsg hdr; union { - /* Stored replies. */ + /* Queued replies. */ struct { - struct list_head list; char *body; } reply; - /* Queued watch callbacks. */ + /* Queued watch events. */ struct { - struct work_struct work; struct xenbus_watch *handle; char **vec; unsigned int vec_size; @@ -77,9 +77,23 @@ struct xs_handle { static struct xs_handle xs_state; +/* List of registered watches, and a lock to protect it. */ static LIST_HEAD(watches); static DEFINE_SPINLOCK(watches_lock); -static struct workqueue_struct *watches_workq; + +/* List of pending watch calbback events, and a lock to protect it. */ +static LIST_HEAD(watch_events); +static DEFINE_SPINLOCK(watch_events_lock); + +/* + * Details of the xenwatch callback kernel thread. The thread waits on the + * watch_events_waitq for work to do (queued on watch_events list). When it + * wakes up it acquires the xenwatch_mutex before reading the list and + * carrying out work. + */ +static pid_t xenwatch_pid; +static DECLARE_MUTEX(xenwatch_mutex); +static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq); static int get_error(const char *errorstring) { @@ -105,14 +119,14 @@ static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) while (list_empty(&xs_state.reply_list)) { spin_unlock(&xs_state.reply_lock); - wait_event(xs_state.reply_waitq, - !list_empty(&xs_state.reply_list)); + wait_event_interruptible(xs_state.reply_waitq, + !list_empty(&xs_state.reply_list)); spin_lock(&xs_state.reply_lock); } msg = list_entry(xs_state.reply_list.next, - struct xs_stored_msg, u.reply.list); - list_del(&msg->u.reply.list); + struct xs_stored_msg, list); + list_del(&msg->list); spin_unlock(&xs_state.reply_lock); @@ -606,6 +620,7 @@ EXPORT_SYMBOL(register_xenbus_watch); void unregister_xenbus_watch(struct xenbus_watch *watch) { + struct xs_stored_msg *msg, *tmp; char token[sizeof(watch) * 2 + 1]; int err; @@ -626,8 +641,22 @@ void unregister_xenbus_watch(struct xenbus_watch *watch) up_read(&xs_state.suspend_mutex); - /* Make sure watch is not in use. */ - flush_workqueue(watches_workq); + /* Cancel pending watch events. */ + spin_lock(&watch_events_lock); + list_for_each_entry_safe(msg, tmp, &watch_events, list) { + if (msg->u.watch.handle != watch) + continue; + list_del(&msg->list); + kfree(msg->u.watch.vec); + kfree(msg); + } + spin_unlock(&watch_events_lock); + + /* Flush any currently-executing callback, unless we are it. :-) */ + if (current->pid != xenwatch_pid) { + down(&xenwatch_mutex); + up(&xenwatch_mutex); + } } EXPORT_SYMBOL(unregister_xenbus_watch); @@ -653,16 +682,35 @@ void xs_resume(void) up_write(&xs_state.suspend_mutex); } -static void xenbus_fire_watch(void *arg) +static int xenwatch_thread(void *unused) { - struct xs_stored_msg *msg = arg; + struct list_head *ent; + struct xs_stored_msg *msg; - msg->u.watch.handle->callback(msg->u.watch.handle, - (const char **)msg->u.watch.vec, - msg->u.watch.vec_size); + for (;;) { + wait_event_interruptible(watch_events_waitq, + !list_empty(&watch_events)); - kfree(msg->u.watch.vec); - kfree(msg); + down(&xenwatch_mutex); + + spin_lock(&watch_events_lock); + ent = watch_events.next; + if (ent != &watch_events) + list_del(ent); + spin_unlock(&watch_events_lock); + + if (ent != &watch_events) { + msg = list_entry(ent, struct xs_stored_msg, list); + msg->u.watch.handle->callback( + msg->u.watch.handle, + (const char **)msg->u.watch.vec, + msg->u.watch.vec_size); + kfree(msg->u.watch.vec); + kfree(msg); + } + + up(&xenwatch_mutex); + } } static int process_msg(void) @@ -696,8 +744,6 @@ static int process_msg(void) body[msg->hdr.len] = '\0'; if (msg->hdr.type == XS_WATCH_EVENT) { - INIT_WORK(&msg->u.watch.work, xenbus_fire_watch, msg); - msg->u.watch.vec = split(body, msg->hdr.len, &msg->u.watch.vec_size); if (IS_ERR(msg->u.watch.vec)) { @@ -709,7 +755,10 @@ static int process_msg(void) msg->u.watch.handle = find_watch( msg->u.watch.vec[XS_WATCH_TOKEN]); if (msg->u.watch.handle != NULL) { - queue_work(watches_workq, &msg->u.watch.work); + spin_lock(&watch_events_lock); + list_add_tail(&msg->list, &watch_events); + wake_up(&watch_events_waitq); + spin_unlock(&watch_events_lock); } else { kfree(msg->u.watch.vec); kfree(msg); @@ -718,7 +767,7 @@ static int process_msg(void) } else { msg->u.reply.body = body; spin_lock(&xs_state.reply_lock); - list_add_tail(&msg->u.reply.list, &xs_state.reply_list); + list_add_tail(&msg->list, &xs_state.reply_list); spin_unlock(&xs_state.reply_lock); wake_up(&xs_state.reply_waitq); } @@ -726,7 +775,7 @@ static int process_msg(void) return 0; } -static int read_thread(void *unused) +static int xenbus_thread(void *unused) { int err; @@ -741,7 +790,7 @@ static int read_thread(void *unused) int xs_init(void) { int err; - struct task_struct *reader; + struct task_struct *task; INIT_LIST_HEAD(&xs_state.reply_list); spin_lock_init(&xs_state.reply_lock); @@ -755,13 +804,14 @@ int xs_init(void) if (err) return err; - /* Create our own workqueue for executing watch callbacks. */ - watches_workq = create_singlethread_workqueue("xenwatch"); - BUG_ON(watches_workq == NULL); + task = kthread_run(xenwatch_thread, NULL, "xenwatch"); + if (IS_ERR(task)) + return PTR_ERR(task); + xenwatch_pid = task->pid; - reader = kthread_run(read_thread, NULL, "xenbus"); - if (IS_ERR(reader)) - return PTR_ERR(reader); + task = kthread_run(xenbus_thread, NULL, "xenbus"); + if (IS_ERR(task)) + return PTR_ERR(task); return 0; } From 27d7a341944c7662d5c0d49192039df96f2d495c Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Mon, 10 Oct 2005 18:58:46 +0100 Subject: [PATCH 20/42] Fix completely broken xenstore_read function. Signed-off-by: Ewan Mellor --- tools/examples/xen-hotplug-common.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/examples/xen-hotplug-common.sh b/tools/examples/xen-hotplug-common.sh index b1e1be6275..aa0f7fabc8 100644 --- a/tools/examples/xen-hotplug-common.sh +++ b/tools/examples/xen-hotplug-common.sh @@ -9,10 +9,10 @@ log() { } xenstore_read() { - local v=$(xenstore-read "$XENBUS_PATH"/type || true) + local v=$(xenstore-read "$@" || true) if [ "$v" == "" ] then - log error "xenstore-read $XENBUS_PATH/type failed." + log error "xenstore-read $@ failed." exit 1 fi echo "$v" From 99bc4ba13a2cf8dd2ed4ceac43cebbdda4c07bb9 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Mon, 10 Oct 2005 18:59:57 +0100 Subject: [PATCH 21/42] Mention -s option in usage. Signed-off-by: Ewan Mellor --- tools/xenstore/xenstore_client.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/xenstore/xenstore_client.c b/tools/xenstore/xenstore_client.c index 5f69da53c9..e4ef31caec 100644 --- a/tools/xenstore/xenstore_client.c +++ b/tools/xenstore/xenstore_client.c @@ -20,11 +20,11 @@ static void usage(const char *progname) { #if defined(CLIENT_read) - errx(1, "Usage: %s [-h] [-p] key [...]", progname); + errx(1, "Usage: %s [-h] [-p] [-s] key [...]", progname); #elif defined(CLIENT_write) - errx(1, "Usage: %s [-h] key value [...]", progname); + errx(1, "Usage: %s [-h] [-s] key value [...]", progname); #elif defined(CLIENT_rm) || defined(CLIENT_exists) || defined(CLIENT_list) - errx(1, "Usage: %s [-h] key [...]", progname); + errx(1, "Usage: %s [-h] [-s] key [...]", progname); #endif } From bcdb3520757e11d89d2cb16987e23fdd5a8fbe3a Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Mon, 10 Oct 2005 19:04:03 +0100 Subject: [PATCH 22/42] When a domain is introduced to xenstored, check whether this has already happened, and only return EINVAL if the event channel details have changed. This allows Xend to introduce domains when it starts without having to be concerned about whether xenstored has restarted at the same time. This behaviour used to be subsumed by the bind_interdomain semantics for existing channels, but in the simplification of that interface, the check must now move to userspace. Signed-off-by: Ewan Mellor --- tools/xenstore/xenstored_domain.c | 83 ++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 23 deletions(-) diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index e35990b12d..f2b847c4e9 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -53,6 +53,14 @@ struct domain /* Event channel port */ u16 port; + /* The remote end of the event channel, used only to validate + repeated domain introductions. */ + u16 remote_port; + + /* The mfn associated with the event channel, used only to validate + repeated domain introductions. */ + unsigned long mfn; + /* Domain path in store. */ char *path; @@ -322,14 +330,35 @@ static struct domain *new_domain(void *context, domid_t domid, domain->port = rc; domain->conn = new_connection(writechn, readchn); domain->conn->domain = domain; + + domain->remote_port = port; + domain->mfn = mfn; + return domain; } + +static struct domain *find_domain_by_domid(domid_t domid) +{ + struct domain *i; + + list_for_each_entry(i, &domains, list) { + if (i->domid == domid) + return i; + } + return NULL; +} + + /* domid, mfn, evtchn, path */ void do_introduce(struct connection *conn, struct buffered_data *in) { struct domain *domain; char *vec[4]; + domid_t domid; + unsigned long mfn; + u16 port; + const char *path; if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) { send_error(conn, EINVAL); @@ -341,38 +370,46 @@ void do_introduce(struct connection *conn, struct buffered_data *in) return; } + domid = atoi(vec[0]); + mfn = atol(vec[1]); + port = atoi(vec[2]); + path = vec[3]; + /* Sanity check args. */ - if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3])) { + if ((port <= 0) || !is_valid_nodename(path)) { send_error(conn, EINVAL); return; } - /* Hang domain off "in" until we're finished. */ - domain = new_domain(in, atoi(vec[0]), atol(vec[1]), atol(vec[2]), - vec[3]); - if (!domain) { - send_error(conn, errno); - return; + + domain = find_domain_by_domid(domid); + + if (domain == NULL) { + /* Hang domain off "in" until we're finished. */ + domain = new_domain(in, domid, mfn, port, path); + if (!domain) { + send_error(conn, errno); + return; + } + + /* Now domain belongs to its connection. */ + talloc_steal(domain->conn, domain); + + fire_watches(conn, "@introduceDomain", false); + } + else { + /* Check that the given details match the ones we have + previously recorded. */ + if (port != domain->remote_port || + mfn != domain->mfn || + strcmp(path, domain->path) != 0) { + send_error(conn, EINVAL); + return; + } } - - /* Now domain belongs to its connection. */ - talloc_steal(domain->conn, domain); - - fire_watches(conn, "@introduceDomain", false); send_ack(conn, XS_INTRODUCE); } -static struct domain *find_domain_by_domid(domid_t domid) -{ - struct domain *i; - - list_for_each_entry(i, &domains, list) { - if (i->domid == domid) - return i; - } - return NULL; -} - /* domid */ void do_release(struct connection *conn, const char *domid_str) { From d0c7f9b2ad9d9d93d6eb02e6d8ae9a48ac36c9ad Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Mon, 10 Oct 2005 19:06:14 +0100 Subject: [PATCH 23/42] This patch fixes an error in the xm create path when the xc.domain_create call fails (eg, when ACM policy prevents creation of a domain). When xc.domain_create fails, dompath never gets set. Signed-off-by: Tom Lendacky --- tools/python/xen/xend/XendDomainInfo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index c9711808a8..cc949d15e0 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1087,7 +1087,8 @@ class XendDomainInfo: log.debug("XendDomainInfo.destroy: domid=%s", self.domid) self.cleanupVm() - self.destroyDomain() + if self.dompath is not None: + self.destroyDomain() def destroyDomain(self): From 69f01037a446b4415cc3e0fcc16ed745f91d5bbd Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 10 Oct 2005 20:56:46 +0100 Subject: [PATCH 24/42] Kernel makefiles do not define $(LN). Signed-off-by: Rik van Riel --- linux-2.6-xen-sparse/arch/xen/boot/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-2.6-xen-sparse/arch/xen/boot/Makefile b/linux-2.6-xen-sparse/arch/xen/boot/Makefile index 7691940488..8a3707164b 100644 --- a/linux-2.6-xen-sparse/arch/xen/boot/Makefile +++ b/linux-2.6-xen-sparse/arch/xen/boot/Makefile @@ -8,4 +8,4 @@ vmlinux-stripped: vmlinux FORCE $(call if_changed,objcopy) bzImage: vmlinuz - $(Q)$(LN) -sf ../../../vmlinuz $(srctree)/arch/xen/boot/bzImage + $(Q)ln -sf ../../../vmlinuz $(srctree)/arch/xen/boot/bzImage From 6c85226944620919bfff45ecdc78c79c9f9de905 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 10 Oct 2005 21:08:16 +0100 Subject: [PATCH 25/42] Local repo version number in Xen boot log. Signed-off-by: Dan Smith --- xen/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/Makefile b/xen/Makefile index 778f77ae46..3a6ac70928 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -95,7 +95,7 @@ include/xen/compile.h: include/xen/compile.h.in include/xen/banner.h -e 's/@@version@@/$(XEN_VERSION)/g' \ -e 's/@@subversion@@/$(XEN_SUBVERSION)/g' \ -e 's/@@extraversion@@/$(XEN_EXTRAVERSION)/g' \ - -e 's!@@changeset@@!$(shell (hg parents | awk -F: '/^changeset/{CS=$$3};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 2>/dev/null || (head -n 6 ChangeLog | awk -F: '/^changeset/{CS=$$3};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 2>/dev/null || echo information unavailable)!g' \ + -e 's!@@changeset@@!$(shell (hg parents | awk '{FS="changeset:[ ]+"}/^changeset/{CS=$$2};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 2>/dev/null || (head -n 6 ChangeLog | awk -F: '/^changeset/{CS=$$3};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 2>/dev/null || echo information unavailable)!g' \ < include/xen/compile.h.in > $@.new @cat include/xen/banner.h >> $@.new @mv -f $@.new $@ From c6934f25c7866474c9c40aac086614c77fd779f8 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 10 Oct 2005 21:45:31 +0100 Subject: [PATCH 26/42] Fix changeset banner for source tarballs. Signed-off-by: Keir Fraser --- xen/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/Makefile b/xen/Makefile index 3a6ac70928..d3a0bfd04d 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -95,7 +95,7 @@ include/xen/compile.h: include/xen/compile.h.in include/xen/banner.h -e 's/@@version@@/$(XEN_VERSION)/g' \ -e 's/@@subversion@@/$(XEN_SUBVERSION)/g' \ -e 's/@@extraversion@@/$(XEN_EXTRAVERSION)/g' \ - -e 's!@@changeset@@!$(shell (hg parents | awk '{FS="changeset:[ ]+"}/^changeset/{CS=$$2};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 2>/dev/null || (head -n 6 ChangeLog | awk -F: '/^changeset/{CS=$$3};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 2>/dev/null || echo information unavailable)!g' \ + -e 's!@@changeset@@!$(shell ((hg parents || head -n 7 ../ChangeLog || echo date: unavailable) | awk '{FS="changeset:[ ]+"}/^changeset/{CS=$$2};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 2>/dev/null)!g' \ < include/xen/compile.h.in > $@.new @cat include/xen/banner.h >> $@.new @mv -f $@.new $@ From 5119e92a7313ea92120fc79d4aec17f73a1d8472 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Tue, 11 Oct 2005 00:03:00 +0100 Subject: [PATCH 27/42] Fix for "unsubscriptable object" error, courtesy of Kurt Garloff -- missing comma in op_mem_target_set. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvDomain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 7dd7d16da4..f7255e325e 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -129,7 +129,7 @@ class SrvDomain(SrvDir): def op_mem_target_set(self, op, req): - return self.call(self.dom.setMemoryTarget + return self.call(self.dom.setMemoryTarget, [['target', 'int']], req) From 57a851d3a6226f7a62673a79ceb3b265fd1b6a8e Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 11 Oct 2005 10:01:23 +0100 Subject: [PATCH 28/42] Fix the legacy %-build targets for dist installation of guest kernels. Signed-off-by: Keir Fraser --- Makefile | 2 +- buildconfigs/Rules.mk | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 10b1fc8715..7b513c6209 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ install-tools: $(MAKE) -C tools install install-kernels: - for i in $(XKERNELS) ; do $(MAKE) $$i-build || exit 1; done + for i in $(XKERNELS) ; do $(MAKE) $$i-install || exit 1; done install-docs: sh ./docs/check_pkgs && $(MAKE) -C docs install || true diff --git a/buildconfigs/Rules.mk b/buildconfigs/Rules.mk index e44a84e542..19887c5117 100644 --- a/buildconfigs/Rules.mk +++ b/buildconfigs/Rules.mk @@ -87,9 +87,17 @@ ref-%/.valid-ref: pristine-%/.valid-pristine touch $@ # update timestamp to avoid rebuild endif -%-build: +%-install: $(MAKE) -f buildconfigs/mk.$* build +%-dist: DESTDIR=$(DISTDIR)/install +%-dist: %-install + @: # do nothing + +# Legacy dist target +%-build: %-dist + @: # do nothing + %-delete: $(MAKE) -f buildconfigs/mk.$* delete From 167d80d0f244178beffcd0eb8cbdfb6d0305624d Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 11 Oct 2005 10:03:54 +0100 Subject: [PATCH 29/42] Fix 64-bit compile of pygrub. From Charles Duffy. --- tools/pygrub/src/fsys/reiser/reisermodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pygrub/src/fsys/reiser/reisermodule.c b/tools/pygrub/src/fsys/reiser/reisermodule.c index dea7152593..6f2161114a 100644 --- a/tools/pygrub/src/fsys/reiser/reisermodule.c +++ b/tools/pygrub/src/fsys/reiser/reisermodule.c @@ -46,7 +46,7 @@ void file_dal_close(dal_t *dal) { if (!dal) return; - close((int)dal->dev); + close((size_t)dal->dev); dal_free(dal); } From e248dc43ae6f8f4028f34bf8b3d01b83a59795f0 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Tue, 11 Oct 2005 10:29:29 +0100 Subject: [PATCH 30/42] Added xsls utility, which recursively lists the contents of the store. Signed-off-by: Ewan Mellor --- .hgignore | 1 + tools/xenstore/Makefile | 6 +++++- tools/xenstore/xsls.c | 47 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tools/xenstore/xsls.c diff --git a/.hgignore b/.hgignore index 72b8f826d7..a4e2a8ee32 100644 --- a/.hgignore +++ b/.hgignore @@ -161,6 +161,7 @@ ^tools/xenstore/xs_tdb_dump$ ^tools/xenstore/xs_test$ ^tools/xenstore/xs_watch_stress$ +^tools/xenstore/xsls$ ^tools/xentrace/xenctx$ ^tools/xentrace/xentrace$ ^xen/BLOG$ diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index 212ae13e4a..5d29ad301a 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -27,7 +27,7 @@ CLIENTS := xenstore-exists xenstore-list xenstore-read xenstore-rm CLIENTS += xenstore-write CLIENTS_OBJS := $(patsubst xenstore-%,xenstore_%.o,$(CLIENTS)) -all: libxenstore.so xenstored $(CLIENTS) xs_tdb_dump +all: libxenstore.so xenstored $(CLIENTS) xs_tdb_dump xsls testcode: xs_test xenstored_test xs_random @@ -40,6 +40,9 @@ $(CLIENTS): xenstore-%: xenstore_%.o $(CLIENTS_OBJS): xenstore_%.o: xenstore_client.c $(COMPILE.c) -DCLIENT_$(*F) -o $@ $< +xsls: xsls.o + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl -L. -lxenstore -o $@ + xenstored_test: xenstored_core_test.o xenstored_watch_test.o xenstored_domain_test.o xenstored_transaction_test.o xs_lib.o talloc_test.o fake_libxc.o utils.o tdb.o $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ @@ -134,6 +137,7 @@ install: libxenstore.so xenstored $(CLIENTS) $(INSTALL_DIR) -p $(DESTDIR)/usr/include $(INSTALL_PROG) xenstored $(DESTDIR)/usr/sbin $(INSTALL_PROG) $(CLIENTS) $(DESTDIR)/usr/bin + $(INSTALL_PROG) xsls $(DESTDIR)/usr/bin $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR) $(INSTALL_DATA) libxenstore.so $(DESTDIR)/usr/$(LIBDIR) $(INSTALL_DATA) xs.h $(DESTDIR)/usr/include diff --git a/tools/xenstore/xsls.c b/tools/xenstore/xsls.c new file mode 100644 index 0000000000..f8cf24536a --- /dev/null +++ b/tools/xenstore/xsls.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include + +void print_dir(struct xs_handle *h, char *path, int cur_depth) +{ + char **e; + char newpath[512], *val; + int num, i, len; + + e = xs_directory(h, NULL, path, &num); + if (e == NULL) + err(1, "xs_directory (%s)", path); + + for (i = 0; i (151 - strlen(e[i]))) + printf(" = \"%.*s...\"\n", 148 - strlen(e[i]), val); + else + printf(" = \"%s\"\n", val); + free(val); + print_dir(h, newpath, cur_depth+1); + } + free(e); +} + +int main(int argc, char *argv[]) +{ + struct xs_handle *xsh = xs_daemon_open(); + + if (xsh == NULL) + err(1, "xs_daemon_open"); + + print_dir(xsh, argc == 1 ? "/" : argv[1], 0); + + return 0; +} From a499c2d2ddc31284451c8dcf752fd619cb69c662 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Tue, 11 Oct 2005 10:30:13 +0100 Subject: [PATCH 31/42] Added doccomment. Signed-off-by: Ewan Mellor --- tools/python/xen/util/asserts.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/python/xen/util/asserts.py b/tools/python/xen/util/asserts.py index 78f4c1b4a8..dd3cb7f852 100644 --- a/tools/python/xen/util/asserts.py +++ b/tools/python/xen/util/asserts.py @@ -17,6 +17,11 @@ def isCharConvertible(c): + """Assert that the given value is convertible to a character using the %c + conversion. This implies that c is either an integer, or a character + (i.e. a string of length 1). + """ + assert (isinstance(c, int) or (isinstance(c, str) and len(c) == 1)), "%s is not convertible to a character" % c From 9a60ba6eb89b6421752152ae1acbde0bde832b2e Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Tue, 11 Oct 2005 10:32:03 +0100 Subject: [PATCH 32/42] Fix broken xm commands. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvDomain.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index f7255e325e..a5c5dbfee7 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -135,24 +135,24 @@ class SrvDomain(SrvDir): def op_devices(self, op, req): return self.call(self.dom.getDeviceSxprs, - [['deviceClass', 'str']], + [['type', 'str']], req) def op_device_create(self, op, req): return self.call(self.dom.device_create, - [['dev_config', 'sxpr']], + [['config', 'sxpr']], req) def op_device_destroy(self, op, req): return self.call(self.dom.destroyDevice, - [['deviceClass', 'str'], - ['devid', 'int']], + [['type', 'str'], + ['dev', 'int']], req) def op_device_configure(self, op, req): return self.call(self.dom.device_configure, - [['dev_config', 'sxpr'], - ['devid', 'int']], + [['config', 'sxpr'], + ['dev', 'int']], req) From 72e4987ea302ec5c4465dff23aa002b312cc3046 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Tue, 11 Oct 2005 10:33:31 +0100 Subject: [PATCH 33/42] Added missing global statement, to ensure that the logfilename variable is updated. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendLogging.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/python/xen/xend/XendLogging.py b/tools/python/xen/xend/XendLogging.py index 9c78f92236..8e54d94bf1 100644 --- a/tools/python/xen/xend/XendLogging.py +++ b/tools/python/xen/xend/XendLogging.py @@ -49,6 +49,8 @@ def init(filename, level=logging.INFO, maxBytes=None, backupCount=None): stderr unless addLogStderr() is called. """ + global logfilename + def openFileHandler(fname): return logging.handlers.RotatingFileHandler(fname, mode='a', From 4ab0181e5218bf44c7ebffe820fae209dd65a66a Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 11 Oct 2005 11:59:15 +0100 Subject: [PATCH 34/42] Fix xenbus internal join() function to be concurrency safe (no static string buffer). Signed-off-by: Keir Fraser --- .../drivers/xen/xenbus/xenbus_xs.c | 59 ++++++++++++++++--- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c index 3104fda41d..ad44cf100a 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @@ -269,18 +269,22 @@ static unsigned int count_strings(const char *strings, unsigned int len) return num; } -/* Return the path to dir with /name appended. */ +/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ static char *join(const char *dir, const char *name) { - static char buffer[4096]; + char *buffer; - BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer)); + buffer = kmalloc(strlen(dir) + strlen("/") + strlen(name) + 1, + GFP_KERNEL); + if (buffer == NULL) + return ERR_PTR(-ENOMEM); strcpy(buffer, dir); if (!streq(name, "")) { strcat(buffer, "/"); strcat(buffer, name); } + return buffer; } @@ -310,10 +314,15 @@ static char **split(char *strings, unsigned int len, unsigned int *num) char **xenbus_directory(struct xenbus_transaction *t, const char *dir, const char *node, unsigned int *num) { - char *strings; + char *strings, *path; unsigned int len; - strings = xs_single(t, XS_DIRECTORY, join(dir, node), &len); + path = join(dir, node); + if (IS_ERR(path)) + return (char **)path; + + strings = xs_single(t, XS_DIRECTORY, path, &len); + kfree(path); if (IS_ERR(strings)) return (char **)strings; @@ -343,7 +352,16 @@ EXPORT_SYMBOL(xenbus_exists); void *xenbus_read(struct xenbus_transaction *t, const char *dir, const char *node, unsigned int *len) { - return xs_single(t, XS_READ, join(dir, node), len); + char *path; + void *ret; + + path = join(dir, node); + if (IS_ERR(path)) + return (void *)path; + + ret = xs_single(t, XS_READ, path, len); + kfree(path); + return ret; } EXPORT_SYMBOL(xenbus_read); @@ -355,15 +373,20 @@ int xenbus_write(struct xenbus_transaction *t, { const char *path; struct kvec iovec[2]; + int ret; path = join(dir, node); + if (IS_ERR(path)) + return PTR_ERR(path); iovec[0].iov_base = (void *)path; iovec[0].iov_len = strlen(path) + 1; iovec[1].iov_base = (void *)string; iovec[1].iov_len = strlen(string); - return xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); + ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); + kfree(path); + return ret; } EXPORT_SYMBOL(xenbus_write); @@ -371,14 +394,32 @@ EXPORT_SYMBOL(xenbus_write); int xenbus_mkdir(struct xenbus_transaction *t, const char *dir, const char *node) { - return xs_error(xs_single(t, XS_MKDIR, join(dir, node), NULL)); + char *path; + int ret; + + path = join(dir, node); + if (IS_ERR(path)) + return PTR_ERR(path); + + ret = xs_error(xs_single(t, XS_MKDIR, path, NULL)); + kfree(path); + return ret; } EXPORT_SYMBOL(xenbus_mkdir); /* Destroy a file or directory (directories must be empty). */ int xenbus_rm(struct xenbus_transaction *t, const char *dir, const char *node) { - return xs_error(xs_single(t, XS_RM, join(dir, node), NULL)); + char *path; + int ret; + + path = join(dir, node); + if (IS_ERR(path)) + return PTR_ERR(path); + + ret = xs_error(xs_single(t, XS_RM, path, NULL)); + kfree(path); + return ret; } EXPORT_SYMBOL(xenbus_rm); From 11dde699b056cc7a4941e96449b0bec29fcdc265 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 11 Oct 2005 12:39:03 +0100 Subject: [PATCH 35/42] Echo request and transaction identifiers in xenstored replies (and set to zero for async watch events). Signed-off-by: Keir Fraser --- tools/xenstore/xenstored_core.c | 54 +++++++++++++++------------------ 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 753f8b0eee..d87f9b9dce 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -539,6 +539,9 @@ static struct buffered_data *new_buffer(void *ctx) struct buffered_data *data; data = talloc(ctx, struct buffered_data); + if (data == NULL) + return NULL; + data->inhdr = true; data->used = 0; data->buffer = NULL; @@ -583,15 +586,24 @@ void send_reply(struct connection *conn, enum xsd_sockmsg_type type, { struct buffered_data *bdata; - /* When data gets freed, we want list entry is destroyed (so - * list entry is a child). */ + /* Message is a child of the connection context for auto-cleanup. */ bdata = new_buffer(conn); bdata->buffer = talloc_array(bdata, char, len); + /* Echo request header in reply unless this is an async watch event. */ + if (type != XS_WATCH_EVENT) { + memcpy(&bdata->hdr.msg, &conn->in->hdr.msg, + sizeof(struct xsd_sockmsg)); + } else { + memset(&bdata->hdr.msg, 0, sizeof(struct xsd_sockmsg)); + } + + /* Update relevant header fields and fill in the message body. */ bdata->hdr.msg.type = type; bdata->hdr.msg.len = len; memcpy(bdata->buffer, data, len); + /* Queue for later transmission. */ list_add_tail(&bdata->list, &conn->out_list); } @@ -1144,36 +1156,25 @@ static int out_of_mem(void *data) static void consider_message(struct connection *conn) { - /* - * 'volatile' qualifier prevents register allocation which fixes: - * warning: variable 'xxx' might be clobbered by 'longjmp' or 'vfork' - */ - struct buffered_data *volatile in = NULL; - enum xsd_sockmsg_type volatile type = conn->in->hdr.msg.type; jmp_buf talloc_fail; + if (verbose) + xprintf("Got message %s len %i from %p\n", + sockmsg_string(conn->in->hdr.msg.type), + conn->in->hdr.msg.len, conn); + /* For simplicity, we kill the connection on OOM. */ talloc_set_fail_handler(out_of_mem, &talloc_fail); if (setjmp(talloc_fail)) { - /* Free in before conn, in case it needs something. */ - talloc_free(in); talloc_free(conn); goto end; } - if (verbose) - xprintf("Got message %s len %i from %p\n", - sockmsg_string(type), conn->in->hdr.msg.len, conn); + process_message(conn, conn->in); - /* Careful: process_message may free connection. We detach - * "in" beforehand and allocate the new buffer to avoid - * touching conn after process_message. - */ - in = talloc_steal(talloc_autofree_context(), conn->in); + talloc_free(conn->in); conn->in = new_buffer(conn); - process_message(conn, in); - talloc_free(in); end: talloc_set_fail_handler(NULL, NULL); if (talloc_total_blocks(NULL) @@ -1242,12 +1243,7 @@ static void handle_output(struct connection *conn) struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) { - /* - * 'volatile' qualifier prevents register allocation which fixes: - * warning: variable 'xxx' might be clobbered by 'longjmp' or 'vfork' - */ - struct connection *volatile new; - jmp_buf talloc_fail; + struct connection *new; new = talloc(talloc_autofree_context(), struct connection); if (!new) @@ -1262,13 +1258,11 @@ struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) INIT_LIST_HEAD(&new->watches); INIT_LIST_HEAD(&new->transaction_list); - talloc_set_fail_handler(out_of_mem, &talloc_fail); - if (setjmp(talloc_fail)) { + new->in = new_buffer(new); + if (new->in == NULL) { talloc_free(new); return NULL; } - new->in = new_buffer(new); - talloc_set_fail_handler(NULL, NULL); list_add_tail(&new->list, &connections); talloc_set_destructor(new, destroy_conn); From 490bab7b96c76d645c143e37a4adad5a3f597bbf Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 11 Oct 2005 13:02:59 +0100 Subject: [PATCH 36/42] Xenstore client library spawns a reader thread the first time a watch is registered. Before this it is fine for caller threads to read the comms channel directly as no async messages will be received. This avoids various user tools needlessly creating three threads where one will do the job. Signed-off-by: Keir Fraser --- tools/xenstore/xs.c | 166 +++++++++++++++++++++++++------------------- 1 file changed, 93 insertions(+), 73 deletions(-) diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c index acd71108d9..e8a870e2a8 100644 --- a/tools/xenstore/xs.c +++ b/tools/xenstore/xs.c @@ -52,6 +52,7 @@ struct xs_handle { * signals waiters. */ pthread_t read_thr; + int read_thr_exists; /* * A list of fired watch messages, protected by a mutex. Users can @@ -77,6 +78,7 @@ struct xs_handle { pthread_mutex_t request_mutex; }; +static int read_message(struct xs_handle *h); static void *read_thread(void *arg); int xs_fileno(struct xs_handle *h) @@ -131,7 +133,7 @@ static struct xs_handle *get_handle(const char *connect_to) int fd = -1, saved_errno; if (stat(connect_to, &buf) != 0) - goto error; + return NULL; if (S_ISSOCK(buf.st_mode)) fd = get_socket(connect_to); @@ -139,11 +141,17 @@ static struct xs_handle *get_handle(const char *connect_to) fd = get_dev(connect_to); if (fd == -1) - goto error; + return NULL; h = malloc(sizeof(*h)); - if (h == NULL) - goto error; + if (h == NULL) { + saved_errno = errno; + close(fd); + errno = saved_errno; + return NULL; + } + + memset(h, 0, sizeof(*h)); h->fd = fd; @@ -160,19 +168,7 @@ static struct xs_handle *get_handle(const char *connect_to) pthread_mutex_init(&h->request_mutex, NULL); - if (pthread_create(&h->read_thr, NULL, read_thread, h) != 0) - goto error; - return h; - - error: - saved_errno = errno; - if (h != NULL) - free(h); - if (fd != -1) - close(fd); - errno = saved_errno; - return NULL; } struct xs_handle *xs_daemon_open(void) @@ -198,9 +194,11 @@ void xs_daemon_close(struct xs_handle *h) pthread_mutex_lock(&h->reply_mutex); pthread_mutex_lock(&h->watch_mutex); - /* XXX FIXME: May leak an unpublished message buffer. */ - pthread_cancel(h->read_thr); - pthread_join(h->read_thr, NULL); + if (h->read_thr_exists) { + /* XXX FIXME: May leak an unpublished message buffer. */ + pthread_cancel(h->read_thr); + pthread_join(h->read_thr, NULL); + } list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) { free(msg->body); @@ -271,6 +269,10 @@ static void *read_reply( struct xs_stored_msg *msg; char *body; + /* Read from comms channel ourselves if there is no reader thread. */ + if (!h->read_thr_exists && (read_message(h) == -1)) + return NULL; + pthread_mutex_lock(&h->reply_mutex); while (list_empty(&h->reply_list)) pthread_cond_wait(&h->reply_condvar, &h->reply_mutex); @@ -541,6 +543,17 @@ bool xs_watch(struct xs_handle *h, const char *path, const char *token) { struct iovec iov[2]; + /* We dynamically create a reader thread on demand. */ + pthread_mutex_lock(&h->request_mutex); + if (!h->read_thr_exists) { + if (pthread_create(&h->read_thr, NULL, read_thread, h) != 0) { + pthread_mutex_unlock(&h->request_mutex); + return false; + } + h->read_thr_exists = 1; + } + pthread_mutex_unlock(&h->request_mutex); + iov[0].iov_base = (void *)path; iov[0].iov_len = strlen(path) + 1; iov[1].iov_base = (void *)token; @@ -717,65 +730,72 @@ char *xs_debug_command(struct xs_handle *h, const char *cmd, ARRAY_SIZE(iov), NULL); } +static int read_message(struct xs_handle *h) +{ + struct xs_stored_msg *msg = NULL; + char *body = NULL; + int saved_errno; + + /* Allocate message structure and read the message header. */ + msg = malloc(sizeof(*msg)); + if (msg == NULL) + goto error; + if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr))) + goto error; + + /* Allocate and read the message body. */ + body = msg->body = malloc(msg->hdr.len + 1); + if (body == NULL) + goto error; + if (!read_all(h->fd, body, msg->hdr.len)) + goto error; + body[msg->hdr.len] = '\0'; + + if (msg->hdr.type == XS_WATCH_EVENT) { + pthread_mutex_lock(&h->watch_mutex); + + /* Kick users out of their select() loop. */ + if (list_empty(&h->watch_list) && + (h->watch_pipe[1] != -1)) + while (write(h->watch_pipe[1], body, 1) != 1) + continue; + + list_add_tail(&msg->list, &h->watch_list); + pthread_cond_signal(&h->watch_condvar); + + pthread_mutex_unlock(&h->watch_mutex); + } else { + pthread_mutex_lock(&h->reply_mutex); + + /* There should only ever be one response pending! */ + if (!list_empty(&h->reply_list)) { + pthread_mutex_unlock(&h->reply_mutex); + goto error; + } + + list_add_tail(&msg->list, &h->reply_list); + pthread_cond_signal(&h->reply_condvar); + + pthread_mutex_unlock(&h->reply_mutex); + } + + return 0; + + error: + saved_errno = errno; + free(msg); + free(body); + errno = saved_errno; + return -1; +} + static void *read_thread(void *arg) { struct xs_handle *h = arg; - struct xs_stored_msg *msg = NULL; - char *body = NULL; - for (;;) { - msg = NULL; - body = NULL; + while (read_message(h) != -1) + continue; - /* Allocate message structure and read the message header. */ - msg = malloc(sizeof(*msg)); - if (msg == NULL) - goto error; - if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr))) - goto error; - - /* Allocate and read the message body. */ - body = msg->body = malloc(msg->hdr.len + 1); - if (body == NULL) - goto error; - if (!read_all(h->fd, body, msg->hdr.len)) - goto error; - body[msg->hdr.len] = '\0'; - - if (msg->hdr.type == XS_WATCH_EVENT) { - pthread_mutex_lock(&h->watch_mutex); - - /* Kick users out of their select() loop. */ - if (list_empty(&h->watch_list) && - (h->watch_pipe[1] != -1)) - while (write(h->watch_pipe[1], body, 1) != 1) - continue; - - list_add_tail(&msg->list, &h->watch_list); - pthread_cond_signal(&h->watch_condvar); - - pthread_mutex_unlock(&h->watch_mutex); - } else { - pthread_mutex_lock(&h->reply_mutex); - - /* There should only ever be one response pending! */ - if (!list_empty(&h->reply_list)) { - pthread_mutex_unlock(&h->reply_mutex); - goto error; - } - - list_add_tail(&msg->list, &h->reply_list); - pthread_cond_signal(&h->reply_condvar); - - pthread_mutex_unlock(&h->reply_mutex); - } - } - - error: - if (body != NULL) - free(body); - if (msg != NULL) - free(msg); return NULL; } From 4cd488119ecedb5c54bc8ee126adf48790a57349 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 11 Oct 2005 14:14:54 +0100 Subject: [PATCH 37/42] Publish the virtual console interface in public/io/console.h. Make the ring buffers a powe-of-two in size. Signed-off-by: Keir Fraser --- .../drivers/xen/console/xencons_ring.c | 75 ++++++----------- tools/console/daemon/io.c | 84 ++++++++++--------- xen/include/public/io/console.h | 23 +++++ 3 files changed, 96 insertions(+), 86 deletions(-) create mode 100644 xen/include/public/io/console.h diff --git a/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c b/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c index 346c2fd656..0b37773575 100644 --- a/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c +++ b/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c @@ -20,69 +20,48 @@ #include #include #include "xencons_ring.h" - -struct ring_head -{ - u32 cons; - u32 prod; - char buf[0]; -} __attribute__((packed)); +#include static int xencons_irq; +static xencons_receiver_func *xencons_receiver; -#define XENCONS_RING_SIZE (PAGE_SIZE/2 - sizeof (struct ring_head)) -#define XENCONS_IDX(cnt) ((cnt) % XENCONS_RING_SIZE) -#define XENCONS_FULL(ring) (((ring)->prod - (ring)->cons) == XENCONS_RING_SIZE) - -static inline struct ring_head *outring(void) +static inline struct xencons_interface *xencons_interface(void) { return mfn_to_virt(xen_start_info->console_mfn); } -static inline struct ring_head *inring(void) -{ - return mfn_to_virt(xen_start_info->console_mfn) + PAGE_SIZE/2; -} - - -/* don't block - write as much as possible and return */ -static int __xencons_ring_send( - struct ring_head *ring, const char *data, unsigned len) -{ - int copied = 0; - - mb(); - while (copied < len && !XENCONS_FULL(ring)) { - ring->buf[XENCONS_IDX(ring->prod)] = data[copied]; - ring->prod++; - copied++; - } - mb(); - - return copied; -} - int xencons_ring_send(const char *data, unsigned len) { - int sent = __xencons_ring_send(outring(), data, len); + int sent = 0; + struct xencons_interface *intf = xencons_interface(); + + while ((sent < len) && + (intf->out_prod - intf->out_cons) < sizeof(intf->out)) { + intf->out[MASK_XENCONS_IDX(intf->out_prod, intf->out)] = + data[sent]; + intf->out_prod++; + sent++; + } + /* Use evtchn: this is called early, before irq is set up. */ notify_remote_via_evtchn(xen_start_info->console_evtchn); + return sent; } - -static xencons_receiver_func *xencons_receiver; - static irqreturn_t handle_input(int irq, void *unused, struct pt_regs *regs) { - struct ring_head *ring = inring(); - while (ring->cons < ring->prod) { - if (xencons_receiver != NULL) { - xencons_receiver(ring->buf + XENCONS_IDX(ring->cons), - 1, regs); - } - ring->cons++; + struct xencons_interface *intf = xencons_interface(); + + while (intf->in_cons != intf->in_prod) { + if (xencons_receiver != NULL) + xencons_receiver( + intf->in + MASK_XENCONS_IDX(intf->in_cons, + intf->in), + 1, regs); + intf->in_cons++; } + return IRQ_HANDLED; } @@ -96,7 +75,7 @@ int xencons_ring_init(void) int err; if (xencons_irq) - unbind_evtchn_from_irqhandler(xencons_irq, inring()); + unbind_evtchn_from_irqhandler(xencons_irq, NULL); xencons_irq = 0; if (!xen_start_info->console_evtchn) @@ -104,7 +83,7 @@ int xencons_ring_init(void) err = bind_evtchn_to_irqhandler( xen_start_info->console_evtchn, - handle_input, 0, "xencons", inring()); + handle_input, 0, "xencons", NULL); if (err <= 0) { xprintk("XEN console request irq failed %i\n", err); return err; diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c index 01fb0730fc..990303b5e8 100644 --- a/tools/console/daemon/io.c +++ b/tools/console/daemon/io.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -62,25 +63,12 @@ struct domain char *conspath; int ring_ref; int local_port; - char *page; int evtchn_fd; + struct xencons_interface *interface; }; static struct domain *dom_head; -struct ring_head -{ - u32 cons; - u32 prod; - char buf[0]; -} __attribute__((packed)); - -#define PAGE_SIZE (getpagesize()) -#define XENCONS_RING_SIZE (PAGE_SIZE/2 - sizeof (struct ring_head)) -#define XENCONS_IDX(cnt) ((cnt) % XENCONS_RING_SIZE) -#define XENCONS_FULL(ring) (((ring)->prod - (ring)->cons) == XENCONS_RING_SIZE) -#define XENCONS_SPACE(ring) (XENCONS_RING_SIZE - ((ring)->prod - (ring)->cons)) - static void evtchn_notify(struct domain *dom) { struct ioctl_evtchn_notify notify; @@ -91,12 +79,12 @@ static void evtchn_notify(struct domain *dom) static void buffer_append(struct domain *dom) { struct buffer *buffer = &dom->buffer; - struct ring_head *ring = (struct ring_head *)dom->page; size_t size; - u32 oldcons; + XENCONS_RING_IDX oldcons; int notify = 0; + struct xencons_interface *intf = dom->interface; - while ((size = ring->prod - ring->cons) != 0) { + while ((size = (intf->out_prod - intf->out_cons)) != 0) { notify = 1; if ((buffer->capacity - buffer->size) < size) { @@ -108,12 +96,12 @@ static void buffer_append(struct domain *dom) } } - oldcons = ring->cons; - while (ring->cons < (oldcons + size)) { - buffer->data[buffer->size] = - ring->buf[XENCONS_IDX(ring->cons)]; + oldcons = intf->out_cons; + while ((intf->out_cons - oldcons) < size) { + buffer->data[buffer->size] = intf->out[ + MASK_XENCONS_IDX(intf->out_cons, intf->out)]; buffer->size++; - ring->cons++; + intf->out_cons++; } if (buffer->max_capacity && @@ -246,12 +234,13 @@ static int domain_create_ring(struct domain *dom) goto out; if (ring_ref != dom->ring_ref) { - if (dom->page) - munmap(dom->page, getpagesize()); - dom->page = xc_map_foreign_range(xc, dom->domid, getpagesize(), - PROT_READ|PROT_WRITE, - (unsigned long)ring_ref); - if (dom->page == NULL) { + if (dom->interface != NULL) + munmap(dom->interface, getpagesize()); + dom->interface = xc_map_foreign_range( + xc, dom->domid, getpagesize(), + PROT_READ|PROT_WRITE, + (unsigned long)ring_ref); + if (dom->interface == NULL) { err = EINVAL; goto out; } @@ -334,7 +323,7 @@ static struct domain *create_domain(int domid) dom->ring_ref = -1; dom->local_port = -1; - dom->page = NULL; + dom->interface = NULL; dom->evtchn_fd = -1; if (!watch_domain(dom, true)) @@ -396,9 +385,9 @@ static void shutdown_domain(struct domain *d) { d->is_dead = true; watch_domain(d, false); - if (d->page) - munmap(d->page, getpagesize()); - d->page = NULL; + if (d->interface != NULL) + munmap(d->interface, getpagesize()); + d->interface = NULL; if (d->evtchn_fd != -1) close(d->evtchn_fd); d->evtchn_fd = -1; @@ -426,13 +415,21 @@ void enum_domains(void) static void handle_tty_read(struct domain *dom) { - ssize_t len; + ssize_t len = 0; char msg[80]; - struct ring_head *inring = - (struct ring_head *)(dom->page + PAGE_SIZE/2); int i; + struct xencons_interface *intf = dom->interface; + XENCONS_RING_IDX filled = intf->in_prod - intf->in_cons; - len = read(dom->tty_fd, msg, MIN(XENCONS_SPACE(inring), sizeof(msg))); + if (sizeof(intf->in) > filled) + len = sizeof(intf->in) - filled; + if (len > sizeof(msg)) + len = sizeof(msg); + + if (len == 0) + return; + + len = read(dom->tty_fd, msg, len); if (len < 1) { close(dom->tty_fd); dom->tty_fd = -1; @@ -444,8 +441,9 @@ static void handle_tty_read(struct domain *dom) } } else if (domain_is_valid(dom->domid)) { for (i = 0; i < len; i++) { - inring->buf[XENCONS_IDX(inring->prod)] = msg[i]; - inring->prod++; + intf->in[MASK_XENCONS_IDX(intf->in_prod, intf->in)] = + msg[i]; + intf->in_prod++; } evtchn_notify(dom); } else { @@ -564,3 +562,13 @@ void handle_io(void) } } while (ret > -1); } + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/xen/include/public/io/console.h b/xen/include/public/io/console.h new file mode 100644 index 0000000000..a43729e467 --- /dev/null +++ b/xen/include/public/io/console.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * console.h + * + * Console I/O interface for Xen guest OSes. + * + * Copyright (c) 2005, Keir Fraser + */ + +#ifndef __XEN_PUBLIC_IO_CONSOLE_H__ +#define __XEN_PUBLIC_IO_CONSOLE_H__ + +typedef u32 XENCONS_RING_IDX; + +#define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1)) + +struct xencons_interface { + char in[1024]; + char out[2048]; + XENCONS_RING_IDX in_cons, in_prod; + XENCONS_RING_IDX out_cons, out_prod; +}; + +#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */ From 26f6adc1c824911e318908a87f73c40b6fc353ad Mon Sep 17 00:00:00 2001 From: "jrb44@freefall.cl.cam.ac.uk" Date: Tue, 11 Oct 2005 14:26:23 +0100 Subject: [PATCH 38/42] Added xsls to xenstore Makefile install dependencies to fix "make dist". Signed-off-by: James Bulpin --- tools/xenstore/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/xenstore/Makefile b/tools/xenstore/Makefile index 5d29ad301a..453f1abeb7 100644 --- a/tools/xenstore/Makefile +++ b/tools/xenstore/Makefile @@ -129,7 +129,7 @@ TAGS: tarball: clean cd .. && tar -c -j -v -h -f xenstore.tar.bz2 xenstore/ -install: libxenstore.so xenstored $(CLIENTS) +install: libxenstore.so xenstored xsls $(CLIENTS) $(INSTALL_DIR) -p $(DESTDIR)/var/run/xenstored $(INSTALL_DIR) -p $(DESTDIR)/var/lib/xenstored $(INSTALL_DIR) -p $(DESTDIR)/usr/bin From af1b5637f43be85942027749777c21bee4d84e65 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Tue, 11 Oct 2005 14:55:12 +0100 Subject: [PATCH 39/42] Allow parallel 32- and 64-bit Xen installations. Move xc_save, xc_restore, and xenconsole out of /usr/libexec/xen and into one of /usr/lib/xen/bin or /usr/lib64/xen/bin. Remove all the PATH hacking inside Xend, and rely upon the PATH being set correctly from outside. Added an auxbin module for handling the hacky stuff. Replace the few /usr/bin/python bang paths with /usr/bin/env python. Signed-off-by: Ewan Mellor --- Makefile | 2 +- tools/console/Makefile | 2 +- tools/misc/xend | 7 ++++--- tools/python/xen/util/Brctl.py | 1 - tools/python/xen/xend/XendCheckpoint.py | 12 ++++++++---- tools/python/xen/xend/server/SrvDaemon.py | 2 +- tools/python/xen/xend/sxp.py | 2 +- tools/python/xen/xm/create.py | 9 +++++++-- tools/python/xen/xm/main.py | 9 +++++---- tools/xcutils/Makefile | 2 +- 10 files changed, 29 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 7b513c6209..f38479b2d3 100644 --- a/Makefile +++ b/Makefile @@ -179,7 +179,7 @@ uninstall: rm -rf $(D)/usr/$(LIBDIR)/libxenctrl* $(D)/usr/$(LIBDIR)/libxenguest* rm -rf $(D)/usr/$(LIBDIR)/libxenstore* rm -rf $(D)/usr/$(LIBDIR)/python/xen $(D)/usr/$(LIBDIR)/xen - rm -rf $(D)/usr/libexec/xen + rm -rf $(D)/usr/$(LIBDIR)/xen/bin rm -rf $(D)/usr/sbin/xen* $(D)/usr/sbin/netfix $(D)/usr/sbin/xm rm -rf $(D)/usr/share/doc/xen rm -rf $(D)/usr/share/xen diff --git a/tools/console/Makefile b/tools/console/Makefile index 3e1471d99c..a27aa8e458 100644 --- a/tools/console/Makefile +++ b/tools/console/Makefile @@ -3,7 +3,7 @@ XEN_ROOT=../.. include $(XEN_ROOT)/tools/Rules.mk DAEMON_INSTALL_DIR = /usr/sbin -CLIENT_INSTALL_DIR = /usr/libexec/xen +CLIENT_INSTALL_DIR = /usr/$(LIBDIR)/xen/bin INSTALL = install INSTALL_PROG = $(INSTALL) -m0755 diff --git a/tools/misc/xend b/tools/misc/xend index e1a6b4f437..f2db3c100b 100644 --- a/tools/misc/xend +++ b/tools/misc/xend @@ -2,9 +2,10 @@ # -*- mode: python; -*- #============================================================================ # Copyright (C) 2004 Mike Wray +# Copyright (C) 2005 XenSource Ltd #============================================================================ -"""Xen management daemon. Lives in /usr/sbin. +"""Xen management daemon. Provides console server and HTTP management api. Run: @@ -67,14 +68,14 @@ def check_user(): def start_xenstored(): XENSTORED_TRACE = os.getenv("XENSTORED_TRACE") - cmd = "/usr/sbin/xenstored --pid-file=/var/run/xenstore.pid" + cmd = "xenstored --pid-file=/var/run/xenstore.pid" if XENSTORED_TRACE: cmd += " -T /var/log/xenstored-trace.log" s,o = commands.getstatusoutput(cmd) def start_consoled(): if os.fork() == 0: - os.execvp('/usr/sbin/xenconsoled', ['/usr/sbin/xenconsoled']) + os.execvp('xenconsoled', ['xenconsoled']) def main(): try: diff --git a/tools/python/xen/util/Brctl.py b/tools/python/xen/util/Brctl.py index 28506057f2..9ae8fdf51d 100644 --- a/tools/python/xen/util/Brctl.py +++ b/tools/python/xen/util/Brctl.py @@ -5,7 +5,6 @@ import os.path import re import sys -os.defpath = os.defpath + ':/sbin:/usr/sbin:/usr/local/sbin' CMD_IFCONFIG = 'ifconfig' CMD_ROUTE = 'route' CMD_BRCTL = 'brctl' diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py index 3d45bdb60a..d8ae85b91e 100644 --- a/tools/python/xen/xend/XendCheckpoint.py +++ b/tools/python/xen/xend/XendCheckpoint.py @@ -14,6 +14,8 @@ from struct import pack, unpack, calcsize from xen.util.xpopen import xPopen3 +import xen.util.auxbin + import xen.lowlevel.xc from xen.xend.xenstore.xsutil import IntroduceDomain @@ -21,9 +23,11 @@ from xen.xend.xenstore.xsutil import IntroduceDomain from XendError import XendError from XendLogging import log + SIGNATURE = "LinuxGuestRecord" -PATH_XC_SAVE = "/usr/libexec/xen/xc_save" -PATH_XC_RESTORE = "/usr/libexec/xen/xc_restore" +XC_SAVE = "xc_save" +XC_RESTORE = "xc_restore" + sizeof_int = calcsize("i") sizeof_unsigned_long = calcsize("L") @@ -64,7 +68,7 @@ def save(fd, dominfo, live): # enabled. Passing "0" simply uses the defaults compiled into # libxenguest; see the comments and/or code in xc_linux_save() for # more information. - cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd), + cmd = [xen.util.auxbin.pathTo(XC_SAVE), str(xc.handle()), str(fd), str(dominfo.getDomid()), "0", "0", str(int(live)) ] log.debug("[xc_save]: %s", string.join(cmd)) @@ -129,7 +133,7 @@ def restore(xd, fd): store_evtchn = dominfo.store_channel console_evtchn = dominfo.console_channel - cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd), + cmd = [xen.util.auxbin.pathTo(XC_RESTORE), str(xc.handle()), str(fd), str(dominfo.getDomid()), str(nr_pfns), str(store_evtchn), str(console_evtchn)] log.debug("[xc_restore]: %s", string.join(cmd)) diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 0248d18ab7..543502ad95 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -38,7 +38,7 @@ class Daemon: pythonex = '(?P\S*python\S*)' cmdex = '(?P.*)' procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$') - xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$') + xendre = re.compile('^\S+/xend\s*(start|restart)\s*.*$') procs = os.popen('ps -e -o pid,args 2>/dev/null') for proc in procs: pm = procre.match(proc) diff --git a/tools/python/xen/xend/sxp.py b/tools/python/xen/xend/sxp.py index 47c439c1d5..88a81cdc8a 100644 --- a/tools/python/xen/xend/sxp.py +++ b/tools/python/xen/xend/sxp.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #============================================================================ # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index a6498c72ad..5da1acc3da 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -14,11 +14,14 @@ #============================================================================ # Copyright (C) 2004, 2005 Mike Wray # Copyright (C) 2005 Nguyen Anh Quynh +# Copyright (C) 2005 XenSource Ltd #============================================================================ """Domain creation. """ import random +import os +import os.path import string import sys import socket @@ -36,6 +39,9 @@ from xen.util import blkif from xen.xm.opts import * +import console + + gopts = Opts(use="""[options] [vars] Create a domain. @@ -879,8 +885,7 @@ def main(argv): dom = make_domain(opts, config) if opts.vals.console_autoconnect: - cmd = "/usr/libexec/xen/xenconsole %d" % dom - os.execvp('/usr/libexec/xen/xenconsole', cmd.split()) + console.execConsole(dom) if __name__ == '__main__': main(sys.argv) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 615ef4ef60..082bdb6367 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -38,6 +38,8 @@ from xen.xend import PrettyPrint from xen.xend import sxp from xen.xm.opts import * +import console + shorthelp = """Usage: xm [args] Control, list, and manipulate Xen guest instances @@ -442,12 +444,11 @@ def xm_console(args): from xen.xend.XendClient import server info = server.xend_domain(dom) domid = int(sxp.child_value(info, 'domid', '-1')) - cmd = "/usr/libexec/xen/xenconsole %d" % domid - os.execvp('/usr/libexec/xen/xenconsole', cmd.split()) - console = sxp.child(info, "console") + console.execConsole(domid) + def xm_top(args): - os.execv('/usr/sbin/xentop', ['/usr/sbin/xentop']) + os.execvp('xentop', ['xentop']) def xm_dmesg(args): diff --git a/tools/xcutils/Makefile b/tools/xcutils/Makefile index 2a0d13b4ce..b7de270e07 100644 --- a/tools/xcutils/Makefile +++ b/tools/xcutils/Makefile @@ -15,7 +15,7 @@ INSTALL_DIR = $(INSTALL) -d -m0755 XEN_ROOT = ../.. include $(XEN_ROOT)/tools/Rules.mk -PROGRAMS_INSTALL_DIR = /usr/libexec/xen +PROGRAMS_INSTALL_DIR = /usr/$(LIBDIR)/xen/bin INCLUDES += -I $(XEN_LIBXC) From ed7f93c25bb3d01852c2282fa6ff6a39cbd83835 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Tue, 11 Oct 2005 14:57:28 +0100 Subject: [PATCH 40/42] Remove bang path. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvServer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py index 59c0732c91..4a4f9f4946 100644 --- a/tools/python/xen/xend/server/SrvServer.py +++ b/tools/python/xen/xend/server/SrvServer.py @@ -1,4 +1,3 @@ -#!/usr/bin/python #============================================================================ # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public From 562df476678124f328adc4cc56aac69bad9844f6 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Tue, 11 Oct 2005 14:59:52 +0100 Subject: [PATCH 41/42] Added auxbin module, for handling auxillary binaries. Signed-off-by: Ewan Mellor --- tools/python/xen/util/auxbin.py | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tools/python/xen/util/auxbin.py diff --git a/tools/python/xen/util/auxbin.py b/tools/python/xen/util/auxbin.py new file mode 100644 index 0000000000..b6ba6cff9f --- /dev/null +++ b/tools/python/xen/util/auxbin.py @@ -0,0 +1,44 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2005 XenSource Ltd +#============================================================================ + + +LIB_BIN_32 = "/usr/lib/xen/bin" +LIB_BIN_64 = "/usr/lib64/xen/bin" + + +import os +import os.path + + +def execute(exe, args = None): + exepath = pathTo(exe) + a = [ exepath ] + if args: + a.extend(args) + os.execv(exepath, a) + + +def pathTo(exe): + return os.path.join(path(), exe) + + +def path(): + machine = os.uname()[4] + if machine.find('64') != -1 and os.path.exists(LIB_BIN_64): + return LIB_BIN_64 + else: + return LIB_BIN_32 From 2d15771b61e6803f120cc0bce76c5e2f1bdb1eb3 Mon Sep 17 00:00:00 2001 From: "emellor@ewan" Date: Tue, 11 Oct 2005 15:01:43 +0100 Subject: [PATCH 42/42] Bring out the common console-handling code from main.py and create.py. Signed-off-by: Ewan Mellor --- tools/python/xen/xm/console.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tools/python/xen/xm/console.py diff --git a/tools/python/xen/xm/console.py b/tools/python/xen/xm/console.py new file mode 100644 index 0000000000..95f5a3a0e3 --- /dev/null +++ b/tools/python/xen/xm/console.py @@ -0,0 +1,26 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2005 XenSource Ltd +#============================================================================ + + +XENCONSOLE = "xenconsole" + + +import xen.util.auxbin + + +def execConsole(domid): + xen.util.auxbin.execute(XENCONSOLE, [str(domid)])