direct-io.hg
changeset 1754:095e969226c4
bitkeeper revision 1.1068 (40f2bd236qdLHUh6BZA_h_brBDxINw)
Merge ssh://xenbk@gandalf.hpl.hp.com//var/bk/xeno-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/iap10/xeno-clone/xeno.bk
Merge ssh://xenbk@gandalf.hpl.hp.com//var/bk/xeno-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/iap10/xeno-clone/xeno.bk
author | iap10@labyrinth.cl.cam.ac.uk |
---|---|
date | Mon Jul 12 16:32:35 2004 +0000 (2004-07-12) |
parents | 17be2261d755 2f1d50d10f6f |
children | ba1f4ebe0154 2ae481a95b81 |
files | linux-2.4.26-xen-sparse/arch/xen/defconfig-xen0 tools/libxc/xc_io.h tools/python/xen/xend/XendClient.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendMigrate.py tools/python/xen/xend/server/SrvDomain.py tools/python/xen/xend/server/SrvDomainDir.py tools/xfrd/Makefile tools/xfrd/xen_domain.c tools/xfrd/xfrd.c tools/xfrd/xfrd.h |
line diff
1.1 --- a/linux-2.4.26-xen-sparse/arch/xen/defconfig-xen0 Mon Jul 12 16:32:11 2004 +0000 1.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/defconfig-xen0 Mon Jul 12 16:32:35 2004 +0000 1.3 @@ -387,9 +387,22 @@ CONFIG_CHR_DEV_SG=y 1.4 # CONFIG_SCSI_AHA1542 is not set 1.5 # CONFIG_SCSI_AHA1740 is not set 1.6 CONFIG_SCSI_AACRAID=y 1.7 -# CONFIG_SCSI_AIC7XXX is not set 1.8 -# CONFIG_SCSI_AIC79XX is not set 1.9 -# CONFIG_SCSI_AIC7XXX_OLD is not set 1.10 +CONFIG_SCSI_AIC7XXX=y 1.11 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=32 1.12 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 1.13 +# CONFIG_AIC7XXX_PROBE_EISA_VL is not set 1.14 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set 1.15 +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set 1.16 +CONFIG_AIC7XXX_DEBUG_MASK=0 1.17 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set 1.18 +CONFIG_SCSI_AIC79XX=y 1.19 +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 1.20 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 1.21 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set 1.22 +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set 1.23 +# CONFIG_AIC79XX_DEBUG_ENABLE is not set 1.24 +CONFIG_AIC79XX_DEBUG_MASK=0 1.25 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set 1.26 # CONFIG_SCSI_DPT_I2O is not set 1.27 # CONFIG_SCSI_ADVANSYS is not set 1.28 # CONFIG_SCSI_IN2000 is not set 1.29 @@ -412,9 +425,11 @@ CONFIG_SCSI_BUSLOGIC=y 1.30 # CONFIG_SCSI_INIA100 is not set 1.31 # CONFIG_SCSI_NCR53C406A is not set 1.32 # CONFIG_SCSI_NCR53C7xx is not set 1.33 -# CONFIG_SCSI_SYM53C8XX_2 is not set 1.34 -# CONFIG_SCSI_NCR53C8XX is not set 1.35 -# CONFIG_SCSI_SYM53C8XX is not set 1.36 +CONFIG_SCSI_SYM53C8XX_2=y 1.37 +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 1.38 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 1.39 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 1.40 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set 1.41 # CONFIG_SCSI_PAS16 is not set 1.42 # CONFIG_SCSI_PCI2000 is not set 1.43 # CONFIG_SCSI_PCI2220I is not set
2.1 --- a/tools/libxc/xc_io.h Mon Jul 12 16:32:11 2004 +0000 2.2 +++ b/tools/libxc/xc_io.h Mon Jul 12 16:32:35 2004 +0000 2.3 @@ -1,6 +1,7 @@ 2.4 #ifndef __XC_XC_IO_H__ 2.5 #define __XC_XC_IO_H__ 2.6 2.7 +#include <errno.h> 2.8 #include "xc_private.h" 2.9 #include "iostream.h" 2.10 2.11 @@ -12,8 +13,21 @@ typedef struct XcIOContext { 2.12 IOStream *err; 2.13 char *vmconfig; 2.14 int vmconfig_n; 2.15 + int (*suspend)(u32 domain, void *data); 2.16 + void *data; 2.17 } XcIOContext; 2.18 2.19 +static inline int xcio_suspend_domain(XcIOContext *ctxt){ 2.20 + int err = 0; 2.21 + 2.22 + if(ctxt->suspend){ 2.23 + err = ctxt->suspend(ctxt->domain, ctxt->data); 2.24 + } else { 2.25 + err = -EINVAL; 2.26 + } 2.27 + return err; 2.28 +} 2.29 + 2.30 static inline int xcio_read(XcIOContext *ctxt, void *buf, int n){ 2.31 int rc; 2.32
3.1 --- a/tools/python/xen/xend/XendClient.py Mon Jul 12 16:32:11 2004 +0000 3.2 +++ b/tools/python/xen/xend/XendClient.py Mon Jul 12 16:32:35 2004 +0000 3.3 @@ -231,6 +231,11 @@ class Xend: 3.4 def xend_domain(self, id): 3.5 return xend_get(self.domainurl(id)) 3.6 3.7 + def xend_domain_configure(self, id, config): 3.8 + return xend_call(self.domainurl(id), 3.9 + {'op' : 'configure', 3.10 + 'config' : fileof(conf) }) 3.11 + 3.12 def xend_domain_unpause(self, id): 3.13 return xend_call(self.domainurl(id), 3.14 {'op' : 'unpause'})
4.1 --- a/tools/python/xen/xend/XendDomain.py Mon Jul 12 16:32:11 2004 +0000 4.2 +++ b/tools/python/xen/xend/XendDomain.py Mon Jul 12 16:32:35 2004 +0000 4.3 @@ -311,6 +311,42 @@ class XendDomain: 4.4 return dominfo 4.5 deferred.addCallback(fn) 4.6 return deferred 4.7 + 4.8 + def domain_configure(self, id, config): 4.9 + """Configure an existing domain. This is intended for internal 4.10 + use by domain restore and migrate. 4.11 + 4.12 + @param id: domain id 4.13 + @param config: configuration 4.14 + @return: deferred 4.15 + """ 4.16 + dom = int(id) 4.17 + dominfo = self.domain_get(dom) 4.18 + if not dominfo: 4.19 + raise ValueError("Invalid domain: " + str(id)) 4.20 + if dominfo.config: 4.21 + raise ValueError("Domain already configured: " + str(id)) 4.22 + def fn(dominfo): 4.23 + self._add_domain(dominfo.id, dominfo) 4.24 + return dominfo 4.25 + deferred = dominfo.construct(config) 4.26 + deferred.addCallback(fn) 4.27 + return deferred 4.28 + 4.29 + def domain_restore(self, src, progress=0): 4.30 + """Restore a domain from file. 4.31 + 4.32 + @param src: source file 4.33 + @param progress: output progress if true 4.34 + @return: deferred 4.35 + """ 4.36 + 4.37 + def fn(dominfo): 4.38 + self._add_domain(dominfo.id, dominfo) 4.39 + return dominfo 4.40 + deferred = XendDomainInfo.vm_restore(src, progress=progress) 4.41 + deferred.addCallback(fn) 4.42 + return deferred 4.43 4.44 def domain_get(self, id): 4.45 """Get up-to-date info about a domain. 4.46 @@ -346,6 +382,8 @@ class XendDomain: 4.47 - reboot: domain will restart. 4.48 - halt: domain will not restart (even if has autorestart set). 4.49 4.50 + Returns immediately. 4.51 + 4.52 @param id: domain id 4.53 @param reason: shutdown type: poweroff, reboot, suspend, halt 4.54 """ 4.55 @@ -443,7 +481,7 @@ class XendDomain: 4.56 4.57 def domain_destroy(self, id): 4.58 """Terminate domain immediately. 4.59 - Camcels any restart for the domain. 4.60 + Cancels any restart for the domain. 4.61 4.62 @param id: domain id 4.63 """ 4.64 @@ -456,6 +494,7 @@ class XendDomain: 4.65 """Start domain migration. 4.66 4.67 @param id: domain id 4.68 + @return: deferred 4.69 """ 4.70 # Need a cancel too? 4.71 # Don't forget to cancel restart for it. 4.72 @@ -464,41 +503,16 @@ class XendDomain: 4.73 return xmigrate.migrate_begin(dom, dst) 4.74 4.75 def domain_save(self, id, dst, progress=0): 4.76 - """Save domain state to file, destroy domain on success. 4.77 - Leave domain running on error. 4.78 + """Start saving a domain to file. 4.79 4.80 @param id: domain id 4.81 @param dst: destination file 4.82 @param progress: output progress if true 4.83 + @return: deferred 4.84 """ 4.85 dom = int(id) 4.86 - dominfo = self.domain_get(id) 4.87 - if not dominfo: 4.88 - return -1 4.89 - vmconfig = sxp.to_string(dominfo.sxpr()) 4.90 - self.domain_pause(id) 4.91 - eserver.inject('xend.domain.save', id) 4.92 - try: 4.93 - rc = xc.linux_save(dom=dom, state_file=dst, 4.94 - vmconfig=vmconfig, progress=progress) 4.95 - except: 4.96 - rc = -1 4.97 - if rc == 0: 4.98 - self.domain_destroy(id) 4.99 - else: 4.100 - self.domain_unpause(id) 4.101 - return rc 4.102 - 4.103 - def domain_restore(self, src, progress=0): 4.104 - """Restore domain from file. 4.105 - 4.106 - @param src : source file 4.107 - @param progress: output progress if true 4.108 - @return: domain object 4.109 - """ 4.110 - dominfo = XendDomainInfo.vm_restore(src, progress=progress) 4.111 - self._add_domain(dominfo.id, dominfo) 4.112 - return dominfo 4.113 + xmigrate = XendMigrate.instance() 4.114 + return xmigrate.save_begin(dom, dst) 4.115 4.116 def domain_pincpu(self, dom, cpu): 4.117 """Pin a domain to a cpu.
5.1 --- a/tools/python/xen/xend/XendMigrate.py Mon Jul 12 16:32:11 2004 +0000 5.2 +++ b/tools/python/xen/xend/XendMigrate.py Mon Jul 12 16:32:35 2004 +0000 5.3 @@ -1,5 +1,6 @@ 5.4 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 5.5 5.6 +import errno 5.7 import sys 5.8 import socket 5.9 import time 5.10 @@ -14,9 +15,12 @@ import sxp 5.11 import XendDB 5.12 import EventServer; eserver = EventServer.instance() 5.13 5.14 +"""The port for the migrate/save daemon xfrd.""" 5.15 XFRD_PORT = 8002 5.16 5.17 +"""The transfer protocol major version number.""" 5.18 XFR_PROTO_MAJOR = 1 5.19 +"""The transfer protocol minor version number.""" 5.20 XFR_PROTO_MINOR = 0 5.21 5.22 class Xfrd(Protocol): 5.23 @@ -46,7 +50,7 @@ class Xfrd(Protocol): 5.24 self.parser.input(data) 5.25 if self.parser.ready(): 5.26 val = self.parser.get_val() 5.27 - self.xinfo.dispatch(val) 5.28 + self.xinfo.dispatch(self, val) 5.29 if self.parser.at_eof(): 5.30 self.loseConnection() 5.31 5.32 @@ -55,16 +59,16 @@ class XfrdClientFactory(ClientFactory): 5.33 """Factory for clients of the migration/save daemon xfrd. 5.34 """ 5.35 5.36 - def __init__(self, minfo): 5.37 + def __init__(self, xinfo): 5.38 #ClientFactory.__init__(self) 5.39 - self.minfo = minfo 5.40 + self.xinfo = xinfo 5.41 5.42 def startedConnecting(self, connector): 5.43 print 'Started to connect', 'self=', self, 'connector=', connector 5.44 5.45 def buildProtocol(self, addr): 5.46 print 'buildProtocol>', addr 5.47 - return Migrate(self.minfo) 5.48 + return Xfrd(self.xinfo) 5.49 5.50 def clientConnectionLost(self, connector, reason): 5.51 print 'clientConnectionLost>', 'connector=', connector, 'reason=', reason 5.52 @@ -76,13 +80,15 @@ class XfrdInfo: 5.53 """Abstract class for info about a session with xfrd. 5.54 Has subclasses for save and migrate. 5.55 """ 5.56 - 5.57 + 5.58 + def __init__(self): 5.59 + from xen.xend import XendDomain 5.60 + self.xd = XendDomain.instance() 5.61 + self.deferred = defer.Deferred() 5.62 + 5.63 def vmconfig(self): 5.64 print 'vmconfig>' 5.65 - from xen.xend import XendDomain 5.66 - xd = XendDomain.instance() 5.67 - 5.68 - dominfo = xd.domain_get(self.src_dom) 5.69 + dominfo = self.xd.domain_get(self.src_dom) 5.70 print 'vmconfig>', type(dominfo), dominfo 5.71 if dominfo: 5.72 val = sxp.to_string(dominfo.sxpr()) 5.73 @@ -93,6 +99,8 @@ class XfrdInfo: 5.74 5.75 def error(self, err): 5.76 self.state = 'error' 5.77 + if not self.deferred.called: 5.78 + self.deferred.errback(err) 5.79 5.80 def dispatch(self, xfrd, val): 5.81 op = sxp.name(val) 5.82 @@ -100,38 +108,70 @@ class XfrdInfo: 5.83 if op.startswith('xfr_'): 5.84 fn = getattr(self, op, self.unknown) 5.85 else: 5.86 - fn = self.unknown() 5.87 - fn(xfrd, val) 5.88 + fn = self.unknown 5.89 + val = fn(xfrd, val) 5.90 + if val is not None: 5.91 + sxp.show(val, out=self.transport) 5.92 5.93 def unknown(self, xfrd, val): 5.94 print 'unknown>', val 5.95 + xfrd.loseConnection() 5.96 + return None 5.97 5.98 def xfr_err(self, xfrd, val): 5.99 - # If we get an error with non-zero code the migrate failed. 5.100 + # If we get an error with non-zero code the operation failed. 5.101 # An error with code zero indicates hello success. 5.102 print 'xfr_err>', val 5.103 - v = sxp.child(val) 5.104 + v = sxp.child0(val) 5.105 print 'xfr_err>', type(v), v 5.106 - err = int(sxp.child(val)) 5.107 + err = int(sxp.child0(val)) 5.108 if not err: return 5.109 self.error(err); 5.110 xfrd.loseConnection() 5.111 + #try: 5.112 + # self.xd.domain_unpause(self.src_dom) 5.113 + #except: 5.114 + # print >>sys.stdout, "Error unpausing domain:", self.src_dom 5.115 + return None 5.116 5.117 def xfr_progress(self, val): 5.118 print 'xfr_progress>', val 5.119 + return None 5.120 5.121 - def xfr_domain_pause(self, val): 5.122 - print 'xfr__domain_pause>', val 5.123 + def xfr_vm_pause(self, val): 5.124 + print 'xfr_vm_pause>', val 5.125 + try: 5.126 + vmid = sxp.child0(val) 5.127 + val = self.xd.domain_pause(vmid) 5.128 + except: 5.129 + val = errno.EINVAL 5.130 + return ['xfr.err', val] 5.131 5.132 - def xfr_domain_suspend(self, val): 5.133 - print 'xfr_domain_suspend>', val 5.134 + def xfr_vm_unpause(self, val): 5.135 + print 'xfr_vm_unpause>', val 5.136 + try: 5.137 + vmid = sxp.child0(val) 5.138 + val = self.xd.domain_unpause(vmid) 5.139 + except: 5.140 + val = errno.EINVAL 5.141 + return ['xfr.err', val] 5.142 + 5.143 + def xfr_vm_suspend(self, val): 5.144 + print 'xfr_vm_suspend>', val 5.145 + try: 5.146 + vmid = sxp.child0(val) 5.147 + val = self.xd.domain_shutdown(vmid, reason='suspend') 5.148 + except: 5.149 + val = errno.EINVAL 5.150 + return ['xfr.err', val] 5.151 5.152 class XendMigrateInfo(XfrdInfo): 5.153 """Representation of a migrate in-progress and its interaction with xfrd. 5.154 """ 5.155 5.156 - def __init__(self, id, dom, host, port): 5.157 - self.id = id 5.158 + def __init__(self, xid, dom, host, port): 5.159 + XfrdInfo.__init__(self) 5.160 + self.xid = xid 5.161 self.state = 'begin' 5.162 self.src_host = socket.gethostname() 5.163 self.src_dom = dom 5.164 @@ -139,10 +179,9 @@ class XendMigrateInfo(XfrdInfo): 5.165 self.dst_port = port 5.166 self.dst_dom = None 5.167 self.start = 0 5.168 - self.deferred = defer.Deferred() 5.169 5.170 def sxpr(self): 5.171 - sxpr = ['migrate', ['id', self.id], ['state', self.state] ] 5.172 + sxpr = ['migrate', ['id', self.xid], ['state', self.state] ] 5.173 sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ] 5.174 sxpr.append(sxpr_src) 5.175 sxpr_dst = ['dst', ['host', self.dst_host] ] 5.176 @@ -160,12 +199,15 @@ class XendMigrateInfo(XfrdInfo): 5.177 self.src_dom, 5.178 vmconfig, 5.179 self.dst_host, 5.180 - self.d.dst_port]) 5.181 + self.dst_port]) 5.182 5.183 def xfr_migrate_ok(self, val): 5.184 dom = int(sxp.child0(val)) 5.185 self.state = 'ok' 5.186 self.dst_dom = dom 5.187 + self.xd_domain_destroy(self.src_dom) 5.188 + if not self.deferred.called: 5.189 + self.deferred.callback(self) 5.190 5.191 def connectionLost(self, reason=None): 5.192 if self.state =='ok': 5.193 @@ -178,17 +220,17 @@ class XendSaveInfo(XfrdInfo): 5.194 """Representation of a save in-progress and its interaction with xfrd. 5.195 """ 5.196 5.197 - def __init__(self, id, dom, file): 5.198 - self.id = id 5.199 + def __init__(self, xid, dom, file): 5.200 + XfrdInfo.__init__(self) 5.201 + self.xid = xid 5.202 self.state = 'begin' 5.203 self.src_dom = dom 5.204 self.file = file 5.205 self.start = 0 5.206 - self.deferred = defer.Deferred() 5.207 5.208 def sxpr(self): 5.209 sxpr = ['save', 5.210 - ['id', self.id], 5.211 + ['id', self.xid], 5.212 ['state', self.state], 5.213 ['domain', self.src_dom], 5.214 ['file', self.file] ] 5.215 @@ -204,6 +246,9 @@ class XendSaveInfo(XfrdInfo): 5.216 def xfr_save_ok(self, val): 5.217 dom = int(sxp.child0(val)) 5.218 self.state = 'ok' 5.219 + self.xd_domain_destroy(self.src_dom) 5.220 + if not self.deferred.called: 5.221 + self.deferred.callback(self) 5.222 5.223 def connectionLost(self, reason=None): 5.224 if self.state =='ok': 5.225 @@ -217,7 +262,6 @@ class XendMigrate: 5.226 """External api for interaction with xfrd for migrate and save. 5.227 Singleton. 5.228 """ 5.229 - # Represents migration in progress. 5.230 # Use log for indications of begin/end/errors? 5.231 # Need logging of: domain create/halt, migrate begin/end/fail 5.232 # Log via event server? 5.233 @@ -226,53 +270,77 @@ class XendMigrate: 5.234 5.235 def __init__(self): 5.236 self.db = XendDB.XendDB(self.dbpath) 5.237 - self.migrate = {} 5.238 - self.migrate_db = self.db.fetchall("") 5.239 - self.id = 0 5.240 + self.session = {} 5.241 + self.session_db = self.db.fetchall("") 5.242 + self.xid = 0 5.243 5.244 def nextid(self): 5.245 - self.id += 1 5.246 - return "%d" % self.id 5.247 + self.xid += 1 5.248 + return "%d" % self.xid 5.249 5.250 def sync(self): 5.251 - self.db.saveall("", self.migrate_db) 5.252 + self.db.saveall("", self.session_db) 5.253 5.254 - def sync_migrate(self, id): 5.255 - self.db.save(id, self.migrate_db[id]) 5.256 + def sync_session(self, xid): 5.257 + print 'sync_session>', type(xid), xid, self.session_db[xid] 5.258 + self.db.save(xid, self.session_db[xid]) 5.259 5.260 def close(self): 5.261 pass 5.262 5.263 - def _add_migrate(self, id, info): 5.264 - self.migrate[id] = info 5.265 - self.migrate_db[id] = info.sxpr() 5.266 - self.sync_migrate(id) 5.267 + def _add_session(self, xid, info): 5.268 + self.session[xid] = info 5.269 + self.session_db[xid] = info.sxpr() 5.270 + self.sync_session(xid) 5.271 #eserver.inject('xend.migrate.begin', info.sxpr()) 5.272 5.273 - def _delete_migrate(self, id): 5.274 - #eserver.inject('xend.migrate.end', id) 5.275 - del self.migrate[id] 5.276 - del self.migrate_db[id] 5.277 - self.db.delete(id) 5.278 + def _delete_session(self, xid): 5.279 + #eserver.inject('xend.migrate.end', xid) 5.280 + del self.session[xid] 5.281 + del self.session_db[xid] 5.282 + self.db.delete(xid) 5.283 5.284 - def migrate_ls(self): 5.285 - return self.migrate.keys() 5.286 + def session_ls(self): 5.287 + return self.session.keys() 5.288 5.289 - def migrates(self): 5.290 - return self.migrate.values() 5.291 + def sessions(self): 5.292 + return self.session.values() 5.293 5.294 - def migrate_get(self, id): 5.295 - return self.migrate.get(id) 5.296 - 5.297 - def migrate_begin(self, dom, host, port=XFRD_PORT): 5.298 - # Check dom for existence, not migrating already. 5.299 - # Subscribe to migrate notifications (for updating). 5.300 - id = self.nextid() 5.301 - info = XendMigrateInfo(id, dom, host, port) 5.302 - self._add_migrate(id, info) 5.303 + def session_get(self, xid): 5.304 + return self.session.get(xid) 5.305 + 5.306 + def session_begin(self, info): 5.307 + self._add_session(info.xid, info) 5.308 mcf = XfrdClientFactory(info) 5.309 reactor.connectTCP('localhost', XFRD_PORT, mcf) 5.310 return info 5.311 + 5.312 + def migrate_begin(self, dom, host, port=XFRD_PORT): 5.313 + """Begin to migrate a domain to another host. 5.314 + 5.315 + @param dom: domain 5.316 + @param host: destination host 5.317 + @param port: destination port 5.318 + @return: deferred 5.319 + """ 5.320 + # Check dom for existence, not migrating already. 5.321 + # Subscribe to migrate notifications (for updating). 5.322 + xid = self.nextid() 5.323 + info = XendMigrateInfo(xid, dom, host, port) 5.324 + self.session_begin(info) 5.325 + return info.deferred 5.326 + 5.327 + def save_begin(self, dom, file): 5.328 + """Begin saving a domain to file. 5.329 + 5.330 + @param dom: domain 5.331 + @param file: destination file 5.332 + @return: deferred 5.333 + """ 5.334 + xid = self.nextid() 5.335 + info = XendSaveInfo(xid, dom, file) 5.336 + self.session_begin(info) 5.337 + return info.deferred 5.338 5.339 def instance(): 5.340 global inst
6.1 --- a/tools/python/xen/xend/server/SrvDomain.py Mon Jul 12 16:32:11 2004 +0000 6.2 +++ b/tools/python/xen/xend/server/SrvDomain.py Mon Jul 12 16:32:35 2004 +0000 6.3 @@ -18,6 +18,14 @@ class SrvDomain(SrvDir): 6.4 self.xd = XendDomain.instance() 6.5 self.xconsole = XendConsole.instance() 6.6 6.7 + def op_configure(self, op, req): 6.8 + fn = FormFn(self.xd.domain_configure, 6.9 + [['dom', 'int'], 6.10 + ['config', 'sxp']]) 6.11 + val = fn(req.args, {'dom': self.dom.id}) 6.12 + #todo: may need to add ok and err callbacks. 6.13 + return val 6.14 + 6.15 def op_unpause(self, op, req): 6.16 val = self.xd.domain_unpause(self.dom.id) 6.17 return val 6.18 @@ -27,7 +35,6 @@ class SrvDomain(SrvDir): 6.19 return val 6.20 6.21 def op_shutdown(self, op, req): 6.22 - #val = self.xd.domain_shutdown(self.dom.id) 6.23 fn = FormFn(self.xd.domain_shutdown, 6.24 [['dom', 'int'], 6.25 ['reason', 'str']]) 6.26 @@ -202,8 +209,22 @@ class SrvDomain(SrvDir): 6.27 req.write('<form method="post" action="%s">' % req.prePathURL()) 6.28 req.write('<input type="submit" name="op" value="unpause">') 6.29 req.write('<input type="submit" name="op" value="pause">') 6.30 + req.write('<input type="submit" name="op" value="destroy">') 6.31 + req.write('</form>') 6.32 + 6.33 + req.write('<form method="post" action="%s">' % req.prePathURL()) 6.34 req.write('<input type="submit" name="op" value="shutdown">') 6.35 - req.write('<input type="submit" name="op" value="destroy">') 6.36 + req.write('<input type="radio" name="reason" value="poweroff" checked>Poweroff<br>') 6.37 + req.write('<input type="radio" name="reason" value="halt">Halt<br>') 6.38 + req.write('<input type="radio" name="reason" value="reboot">Reboot<br>') 6.39 + req.write('</form>') 6.40 + 6.41 + req.write('<form method="post" action="%s">' % req.prePathURL()) 6.42 + req.write('<br><input type="submit" name="op" value="save">') 6.43 + req.write('To file: <input type="text" name="file">') 6.44 + req.write('</form>') 6.45 + 6.46 + req.write('<form method="post" action="%s">' % req.prePathURL()) 6.47 req.write('<br><input type="submit" name="op" value="migrate">') 6.48 - req.write('To: <input type="text" name="destination">') 6.49 + req.write('To host: <input type="text" name="destination">') 6.50 req.write('</form>')
7.1 --- a/tools/python/xen/xend/server/SrvDomainDir.py Mon Jul 12 16:32:11 2004 +0000 7.2 +++ b/tools/python/xen/xend/server/SrvDomainDir.py Mon Jul 12 16:32:35 2004 +0000 7.3 @@ -105,7 +105,10 @@ class SrvDomainDir(SrvDir): 7.4 7.5 def op_restore(self, op, req): 7.6 """Restore a domain from file. 7.7 + 7.8 + @return: deferred 7.9 """ 7.10 + #todo: return is deferred. May need ok and err callbacks. 7.11 fn = FormFn(self.xd.domain_restore, 7.12 [['file', 'str']]) 7.13 val = fn(req.args) 7.14 @@ -154,9 +157,10 @@ class SrvDomainDir(SrvDir): 7.15 req.write('<button type="submit" name="op" value="create">Create Domain</button>') 7.16 req.write('Config <input type="file" name="config"><br>') 7.17 req.write('</form>') 7.18 + 7.19 req.write('<form method="post" action="%s" enctype="multipart/form-data">' 7.20 % req.prePathURL()) 7.21 - req.write('<button type="submit" name="op" value="create">Restore Domain</button>') 7.22 + req.write('<button type="submit" name="op" value="restore">Restore Domain</button>') 7.23 req.write('State <input type="string" name="state"><br>') 7.24 req.write('</form>') 7.25
8.1 --- a/tools/xfrd/Makefile Mon Jul 12 16:32:11 2004 +0000 8.2 +++ b/tools/xfrd/Makefile Mon Jul 12 16:32:35 2004 +0000 8.3 @@ -18,6 +18,9 @@ INCLUDES += -I $(XEN_LINUX_INCLUDE) 8.4 vpath %.h $(XEN_XU) 8.5 INCLUDES += -I $(XEN_XU) 8.6 8.7 +vpath %.h $(XEN_LIBXC) 8.8 +INCLUDES += -I $(XEN_LIBXC) 8.9 + 8.10 vpath %c $(XEN_LIBXUTIL) 8.11 INCLUDES += -I $(XEN_LIBXUTIL) 8.12 8.13 @@ -28,7 +31,9 @@ UTIL_LIB_OBJ = $(UTIL_LIB_SRC:.c=.o) 8.14 XFRD_PROG_OBJ = $(XFRD_PROG_SRC:.c=.o) 8.15 XFRD_PROG_OBJ += $(UTIL_LIB) 8.16 8.17 -CPPFLAGS += -D _XEN_XFR_STUB_ 8.18 +# Flag controlling whether to use stubs. 8.19 +# Define to use stubs, undefine to use the real Xen functions. 8.20 +#CPPFLAGS += -D _XEN_XFR_STUB_ 8.21 8.22 CFLAGS += -g 8.23 CFLAGS += -Wall 8.24 @@ -38,15 +43,31 @@ CFLAGS += $(INCLUDES) 8.25 CFLAGS += -Wp,-MD,.$(@F).d 8.26 PROG_DEP = .*.d 8.27 8.28 -#LDFLAGS += -L $(COMPRESS_DIR) -lz 8.29 +#$(warning XFRD_PROG_OBJ= $(XFRD_PROG_OBJ)) 8.30 +#$(warning UTIL_LIB= $(UTIL_LIB)) 8.31 +#$(warning UTIL_LIB_OBJ= $(UTIL_LIB_OBJ)) 8.32 + 8.33 +# Libraries for xfrd. 8.34 +XFRD_LIBS := 8.35 + 8.36 +XFRD_LIBS += -L $(XEN_LIBXC) -lxc 8.37 +XFRD_LIBS += -L $(XEN_LIBXUTIL) -lxutil 8.38 8.39 -$(warning XFRD_PROG_OBJ= $(XFRD_PROG_OBJ)) 8.40 -$(warning UTIL_LIB= $(UTIL_LIB)) 8.41 -$(warning UTIL_LIB_OBJ= $(UTIL_LIB_OBJ)) 8.42 +# zlib library. 8.43 +XFRD_LIBS += -lz 8.44 + 8.45 +CURL_FLAGS = $(shell curl-config --cflags) 8.46 +CURL_LIBS = $(shell curl-config --libs) 8.47 +CFLAGS += $(CURL_FLAGS) 8.48 +# libcurl libraries. 8.49 +XFRD_LIBS += $(CURL_LIBS) 8.50 + 8.51 +#$(warning XFRD_LIBS = $(XFRD_LIBS)) 8.52 8.53 all: xfrd 8.54 8.55 -xfrd: $(XFRD_PROG_OBJ) -lz 8.56 +xfrd: $(XFRD_PROG_OBJ) 8.57 + $(CC) -o $@ $^ $(XFRD_LIBS) 8.58 8.59 .PHONY: install 8.60 install: xfrd 8.61 @@ -64,5 +85,6 @@ clean: 8.62 $(RM) *.o *.a *.so *~ xfrd 8.63 $(RM) $(PROG_DEP) 8.64 8.65 +$(XFRD_PROG_OBJ): Makefile 8.66 -include $(PROG_DEP) 8.67
9.1 --- a/tools/xfrd/xen_domain.c Mon Jul 12 16:32:11 2004 +0000 9.2 +++ b/tools/xfrd/xen_domain.c Mon Jul 12 16:32:35 2004 +0000 9.3 @@ -3,18 +3,48 @@ 9.4 #include <stdio.h> 9.5 9.6 #ifndef _XEN_XFR_STUB_ 9.7 -#include "dom0_defs.h" 9.8 -#include "mem_defs.h" 9.9 +#include "xc.h" 9.10 +#include "xc_io.h" 9.11 #endif 9.12 9.13 #include "xen_domain.h" 9.14 #include "marshal.h" 9.15 #include "xdr.h" 9.16 +#include "xfrd.h" 9.17 9.18 #define MODULE_NAME "XFRD" 9.19 #define DEBUG 1 9.20 #include "debug.h" 9.21 9.22 +#ifndef _XEN_XFR_STUB_ 9.23 +static int domain_suspend(u32 dom, void *data){ 9.24 + int err = 0; 9.25 + Conn *xend = data; 9.26 + 9.27 + dprintf("> dom=%lu data=%p\n", dom, data); 9.28 + err = xfr_vm_suspend(xend, dom); 9.29 + dprintf("< err=%d\n", err); 9.30 + return err; 9.31 +} 9.32 + 9.33 +static int xc_handle = 0; 9.34 + 9.35 +int xcinit(void){ 9.36 + if(xc_handle <= 0){ 9.37 + xc_handle = xc_interface_open(); 9.38 + } 9.39 + dprintf("< xc_handle=%d\n", xc_handle); 9.40 + return xc_handle; 9.41 +} 9.42 + 9.43 +void xcfini(void){ 9.44 + if(xc_handle > 0){ 9.45 + xc_interface_close(xc_handle); 9.46 + xc_handle = 0; 9.47 + } 9.48 +} 9.49 +#endif 9.50 + 9.51 /** Write domain state. 9.52 * 9.53 * At some point during this the domain is suspended, and then there's no way back. 9.54 @@ -22,10 +52,10 @@ 9.55 */ 9.56 int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n){ 9.57 int err = 0; 9.58 +#ifdef _XEN_XFR_STUB_ 9.59 char buf[1024]; 9.60 int n, k, d, buf_n; 9.61 dprintf("> dom=%d\n", dom); 9.62 -#ifdef _XEN_XFR_STUB_ 9.63 err = marshal_uint32(io, dom); 9.64 if(err) goto exit; 9.65 err = marshal_string(io, vmconfig, vmconfig_n); 9.66 @@ -41,8 +71,20 @@ int xen_domain_snd(Conn *xend, IOStream 9.67 dprintf("> k=%d n=%d\n", k, n); 9.68 } 9.69 9.70 + dom = 99; 9.71 + err = xfr_vm_suspend(xend, dom); 9.72 exit: 9.73 #else 9.74 + XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt; 9.75 + dprintf("> dom=%d\n", dom); 9.76 + ioctxt->domain = dom; 9.77 + ioctxt->io = io; 9.78 + ioctxt->info = iostdout; 9.79 + ioctxt->err = iostderr; 9.80 + ioctxt->data = xend; 9.81 + ioctxt->suspend = domain_suspend; 9.82 + 9.83 + err = xc_linux_save(xcinit(), ioctxt); 9.84 #endif 9.85 dprintf("< err=%d\n", err); 9.86 return err; 9.87 @@ -53,10 +95,10 @@ int xen_domain_snd(Conn *xend, IOStream 9.88 */ 9.89 int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n){ 9.90 int err = 0; 9.91 +#ifdef _XEN_XFR_STUB_ 9.92 char buf[1024]; 9.93 int n, k, d, buf_n; 9.94 dprintf(">\n"); 9.95 -#ifdef _XEN_XFR_STUB_ 9.96 err = unmarshal_uint32(io, dom); 9.97 if(err) goto exit; 9.98 err = unmarshal_new_string(io, vmconfig, vmconfig_n); 9.99 @@ -72,19 +114,104 @@ int xen_domain_rcv(IOStream *io, uint32_ 9.100 } 9.101 exit: 9.102 #else 9.103 + XcIOContext _ioctxt = {}, *ioctxt = &_ioctxt; 9.104 + dprintf(">\n"); 9.105 + ioctxt->io = io; 9.106 + ioctxt->info = iostdout; 9.107 + ioctxt->err = iostderr; 9.108 + 9.109 + err = xc_linux_restore(xcinit(), ioctxt); 9.110 #endif 9.111 dprintf("< err=%d\n", err); 9.112 return err; 9.113 } 9.114 9.115 -/** Configure a new domain. Talk to xend. Use libcurl? 9.116 +#include <curl/curl.h> 9.117 + 9.118 +static int do_curl_global_init = 1; 9.119 + 9.120 +static CURL *curlinit(void){ 9.121 + if(do_curl_global_init){ 9.122 + do_curl_global_init = 0; 9.123 + curl_global_init(CURL_GLOBAL_ALL); 9.124 + } 9.125 + return curl_easy_init(); 9.126 +} 9.127 + 9.128 +/** Configure a new domain. Talk to xend using libcurl. 9.129 */ 9.130 int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){ 9.131 int err = 0; 9.132 - dprintf(">\n"); 9.133 + CURL *curl = NULL; 9.134 + CURLcode curlcode = 0; 9.135 + char domainurl[128] = {}; 9.136 + int domainurl_n = sizeof(domainurl) - 1; 9.137 + int n; 9.138 + struct curl_httppost *form = NULL, *last = NULL; 9.139 + CURLFORMcode formcode = 0; 9.140 + 9.141 + dprintf("> dom=%u\n", dom); 9.142 + curl = curlinit(); 9.143 + if(!curl){ 9.144 + eprintf("> Could not init libcurl\n"); 9.145 + err = -ENOMEM; 9.146 + goto exit; 9.147 + } 9.148 + n = snprintf(domainurl, domainurl_n, 9.149 + "http://localhost:%d/xend/domain/%u", XEND_PORT, dom); 9.150 + if(n <= 0 || n >= domainurl_n){ 9.151 + err = -ENOMEM; 9.152 + eprintf("Out of memory in url.\n"); 9.153 + goto exit; 9.154 + } 9.155 + // Config field - set from vmconfig. 9.156 + formcode = curl_formadd(&form, &last, 9.157 + CURLFORM_COPYNAME, "config", 9.158 + CURLFORM_BUFFER, "config", 9.159 + CURLFORM_BUFFERPTR, vmconfig, 9.160 + CURLFORM_BUFFERLENGTH, vmconfig_n, 9.161 + CURLFORM_CONTENTTYPE, "application/octet-stream", 9.162 + CURLFORM_END); 9.163 + if(formcode){ 9.164 + eprintf("> Error adding config field.\n"); 9.165 + goto exit; 9.166 + } 9.167 + // Op field. 9.168 + formcode = curl_formadd(&form, &last, 9.169 + CURLFORM_COPYNAME, "op", 9.170 + CURLFORM_COPYCONTENTS, "configure", 9.171 + CURLFORM_END); 9.172 + 9.173 + if(formcode){ 9.174 + eprintf("> Error adding op field.\n"); 9.175 + goto exit; 9.176 + } 9.177 + // No progress meter. 9.178 + //curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); 9.179 + // Completely quiet. 9.180 + //curl_easy_setopt(curl, CURLOPT_MUTE, 1); 9.181 + // Set the URL. 9.182 + curl_easy_setopt(curl, CURLOPT_URL, domainurl); 9.183 + // POST the form. 9.184 + curl_easy_setopt(curl, CURLOPT_HTTPPOST, form); 9.185 + dprintf("> curl perform...\n"); 9.186 #ifdef _XEN_XFR_STUB_ 9.187 -#else 9.188 -#endif 9.189 + dprintf("> _XEN_XFR_STUB_ defined - not calling xend\n"); 9.190 + curlcode = 0; 9.191 +#else 9.192 + curlcode = curl_easy_perform(curl); 9.193 +#endif 9.194 + exit: 9.195 + if(curl) curl_easy_cleanup(curl); 9.196 + if(form) curl_formfree(form); 9.197 + if(formcode){ 9.198 + dprintf("> formcode=%d\n", formcode); 9.199 + err = -EINVAL; 9.200 + } 9.201 + if(curlcode){ 9.202 + dprintf("> curlcode=%d\n", curlcode); 9.203 + err = -EINVAL; 9.204 + } 9.205 dprintf("< err=%d\n", err); 9.206 return err; 9.207 }
10.1 --- a/tools/xfrd/xfrd.c Mon Jul 12 16:32:11 2004 +0000 10.2 +++ b/tools/xfrd/xfrd.c Mon Jul 12 16:32:35 2004 +0000 10.3 @@ -93,22 +93,26 @@ Sxpr oxfr_configure; // (xfr.configure < 10.4 Sxpr oxfr_err; // (xfr.err <code>) 10.5 Sxpr oxfr_hello; // (xfr.hello <major> <minor>) 10.6 Sxpr oxfr_migrate; // (xfr.migrate <vmid> <vmconfig> <host> <port>) 10.7 -Sxpr oxfr_ok; // (xfr.ok <value>) 10.8 +Sxpr oxfr_migrate_ok;// (xfr.migrate.ok <value>) 10.9 Sxpr oxfr_progress; // (xfr.progress <percent> <rate: kb/s>) 10.10 Sxpr oxfr_save; // (xfr.save <vmid> <vmconfig> <file>) 10.11 -Sxpr oxfr_suspend; // (xfr.suspend <vmid>) 10.12 +Sxpr oxfr_save_ok; // (xfr.save.ok) 10.13 +Sxpr oxfr_vm_suspend;// (xfr.vm.suspend <vmid>) 10.14 Sxpr oxfr_xfr; // (xfr.xfr <vmid>) 10.15 +Sxpr oxfr_xfr_ok; // (xfr.xfr.ok <vmid>) 10.16 10.17 void xfr_init(void){ 10.18 - oxfr_configure = intern("xfr.configure"); 10.19 - oxfr_err = intern("xfr.err"); 10.20 - oxfr_hello = intern("xfr.hello"); 10.21 - oxfr_migrate = intern("xfr.migrate"); 10.22 - oxfr_ok = intern("xfr.ok"); 10.23 - oxfr_progress = intern("xfr.progress"); 10.24 - oxfr_save = intern("xfr.save"); 10.25 - oxfr_suspend = intern("xfr.suspend"); 10.26 - oxfr_xfr = intern("xfr.xfr"); 10.27 + oxfr_configure = intern("xfr.configure"); 10.28 + oxfr_err = intern("xfr.err"); 10.29 + oxfr_hello = intern("xfr.hello"); 10.30 + oxfr_migrate = intern("xfr.migrate"); 10.31 + oxfr_migrate_ok = intern("xfr.migrate.ok"); 10.32 + oxfr_progress = intern("xfr.progress"); 10.33 + oxfr_save = intern("xfr.save"); 10.34 + oxfr_save_ok = intern("xfr.save.ok"); 10.35 + oxfr_vm_suspend = intern("xfr.vm.suspend"); 10.36 + oxfr_xfr = intern("xfr.xfr"); 10.37 + oxfr_xfr_ok = intern("xfr.xfr.ok"); 10.38 } 10.39 10.40 #ifndef TRUE 10.41 @@ -518,11 +522,27 @@ int xfr_send_xfr(Conn *conn, uint32_t vm 10.42 return (err < 0 ? err : 0); 10.43 } 10.44 10.45 -int xfr_send_ok(Conn *conn, uint32_t vmid){ 10.46 +int xfr_send_xfr_ok(Conn *conn, uint32_t vmid){ 10.47 int err = 0; 10.48 10.49 err = IOStream_print(conn->out, "(%s %d)", 10.50 - atom_name(oxfr_ok), vmid); 10.51 + atom_name(oxfr_xfr_ok), vmid); 10.52 + return (err < 0 ? err : 0); 10.53 +} 10.54 + 10.55 +int xfr_send_migrate_ok(Conn *conn, uint32_t vmid){ 10.56 + int err = 0; 10.57 + 10.58 + err = IOStream_print(conn->out, "(%s %d)", 10.59 + atom_name(oxfr_migrate_ok), vmid); 10.60 + return (err < 0 ? err : 0); 10.61 +} 10.62 + 10.63 +int xfr_send_save_ok(Conn *conn){ 10.64 + int err = 0; 10.65 + 10.66 + err = IOStream_print(conn->out, "(%s)", 10.67 + atom_name(oxfr_save_ok)); 10.68 return (err < 0 ? err : 0); 10.69 } 10.70 10.71 @@ -530,10 +550,24 @@ int xfr_send_suspend(Conn *conn, uint32_ 10.72 int err = 0; 10.73 10.74 err = IOStream_print(conn->out, "(%s %d)", 10.75 - atom_name(oxfr_suspend), vmid); 10.76 + atom_name(oxfr_vm_suspend), vmid); 10.77 return (err < 0 ? err : 0); 10.78 } 10.79 10.80 +/** Suspend a vm on behalf of save/migrate. 10.81 + */ 10.82 +int xfr_vm_suspend(Conn *xend, uint32_t vmid){ 10.83 + int err = 0; 10.84 + dprintf("> vmid=%u\n", vmid); 10.85 + err = xfr_send_suspend(xend, vmid); 10.86 + if(err) goto exit; 10.87 + IOStream_flush(xend->out); 10.88 + err = xfr_response(xend); 10.89 + exit: 10.90 + dprintf("< err=%d\n", err); 10.91 + return err; 10.92 +} 10.93 + 10.94 /** Get vm state. Send transfer message. 10.95 * 10.96 * @param peer connection 10.97 @@ -561,7 +595,7 @@ int xfr_send_state(XfrState *state, Conn 10.98 int errcode; 10.99 err = intof(sxpr_childN(sxpr, 0, ONONE), &errcode); 10.100 if(!err) err = errcode; 10.101 - } else if(sxpr_elementp(sxpr, oxfr_ok)){ 10.102 + } else if(sxpr_elementp(sxpr, oxfr_xfr_ok)){ 10.103 // Ok - get the new domain id. 10.104 err = intof(sxpr_childN(sxpr, 0, ONONE), &state->vmid_new); 10.105 xfr_error(peer, err); 10.106 @@ -592,7 +626,7 @@ int xfr_send_done(XfrState *state, Conn 10.107 err = xfr_error(xend, first_err); 10.108 } else { 10.109 // Report new domain id to xend. 10.110 - err = xfr_send_ok(xend, state->vmid_new); 10.111 + err = xfr_send_migrate_ok(xend, state->vmid_new); 10.112 } 10.113 10.114 XfrState_set_err(state, err); 10.115 @@ -677,17 +711,25 @@ int xfr_save(Args *args, XfrState *state 10.116 int err = 0; 10.117 IOStream *io = NULL; 10.118 10.119 + dprintf("> file=%s\n", file); 10.120 io = file_stream_fopen(file, "wb"); 10.121 if(!io){ 10.122 + dprintf("> Failed to open %s\n", file); 10.123 err = -EIO; 10.124 goto exit; 10.125 } 10.126 err = xen_domain_snd(xend, io, state->vmid, state->vmconfig, state->vmconfig_n); 10.127 + if(err){ 10.128 + err = xfr_error(xend, err); 10.129 + } else { 10.130 + err = xfr_send_save_ok(xend); 10.131 + } 10.132 exit: 10.133 if(io){ 10.134 IOStream_close(io); 10.135 IOStream_free(io); 10.136 } 10.137 + dprintf("< err=%d\n", err); 10.138 return err; 10.139 } 10.140 10.141 @@ -709,7 +751,7 @@ int xfr_recv(Args *args, XfrState *state 10.142 if(err) goto exit; 10.143 10.144 // Report new domain id to peer. 10.145 - err = xfr_send_ok(peer, state->vmid_new); 10.146 + err = xfr_send_xfr_ok(peer, state->vmid_new); 10.147 if(err) goto exit; 10.148 // Get the final ok. 10.149 err = xfr_response(peer);
11.1 --- a/tools/xfrd/xfrd.h Mon Jul 12 16:32:11 2004 +0000 11.2 +++ b/tools/xfrd/xfrd.h Mon Jul 12 16:32:35 2004 +0000 11.3 @@ -2,7 +2,7 @@ 11.4 #define _XFRD_XFRD_H_ 11.5 11.6 /** Xend port in host order. */ 11.7 -#define XEND_PORT 8001 11.8 +#define XEND_PORT 8000 11.9 11.10 /** Xfrd port in host order. */ 11.11 #define XFRD_PORT 8002 11.12 @@ -11,4 +11,6 @@ 11.13 #define XFR_PROTO_MAJOR 1 11.14 #define XFR_PROTO_MINOR 0 11.15 11.16 +struct Conn; 11.17 +extern int xfr_vm_suspend(struct Conn *xend, uint32_t vmid); 11.18 #endif