direct-io.hg

changeset 11387:e01441c9a607

[POWERPC] merge with xen-unstable.hg
author Hollis Blanchard <hollisb@us.ibm.com>
date Wed Aug 30 14:09:31 2006 -0500 (2006-08-30)
parents 18ce855ff594 a39ad4c78850
children 50aea0ec406b
files
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c	Tue Aug 29 17:53:57 2006 -0500
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c	Wed Aug 30 14:09:31 2006 -0500
     1.3 @@ -114,8 +114,8 @@ typedef struct domid_translate {
     1.4  } domid_translate_t ;
     1.5  
     1.6  
     1.7 -domid_translate_t  translate_domid[MAX_TAP_DEV];
     1.8 -tap_blkif_t *tapfds[MAX_TAP_DEV];
     1.9 +static domid_translate_t  translate_domid[MAX_TAP_DEV];
    1.10 +static tap_blkif_t *tapfds[MAX_TAP_DEV];
    1.11  
    1.12  static int __init set_blkif_reqs(char *str)
    1.13  {
    1.14 @@ -1118,7 +1118,7 @@ static int do_block_io_op(blkif_t *blkif
    1.15  			       "ring does not exist!\n");
    1.16  			print_dbug = 0; /*We only print this message once*/
    1.17  		}
    1.18 -		return 1;
    1.19 +		return 0;
    1.20  	}
    1.21  
    1.22  	info = tapfds[blkif->dev_num];
    1.23 @@ -1127,7 +1127,7 @@ static int do_block_io_op(blkif_t *blkif
    1.24  			WPRINTK("Can't get UE info!\n");
    1.25  			print_dbug = 0;
    1.26  		}
    1.27 -		return 1;
    1.28 +		return 0;
    1.29  	}
    1.30  
    1.31  	while (rc != rp) {
     2.1 --- a/tools/blktap/drivers/block-aio.c	Tue Aug 29 17:53:57 2006 -0500
     2.2 +++ b/tools/blktap/drivers/block-aio.c	Wed Aug 30 14:09:31 2006 -0500
     2.3 @@ -52,7 +52,7 @@
     2.4   */
     2.5  #define REQUEST_ASYNC_FD 1
     2.6  
     2.7 -#define MAX_AIO_REQS (MAX_REQUESTS * MAX_SEGMENTS_PER_REQ * 8)
     2.8 +#define MAX_AIO_REQS (MAX_REQUESTS * MAX_SEGMENTS_PER_REQ)
     2.9  
    2.10  struct pending_aio {
    2.11  	td_callback_t cb;
    2.12 @@ -146,7 +146,7 @@ int tdaio_open (struct td_state *s, cons
    2.13  	struct tdaio_state *prv = (struct tdaio_state *)s->private;
    2.14  	s->private = prv;
    2.15  
    2.16 -	DPRINTF("XXX: block-aio open('%s')", name);
    2.17 +	DPRINTF("block-aio open('%s')", name);
    2.18  	/* Initialize AIO */
    2.19  	prv->iocb_free_count = MAX_AIO_REQS;
    2.20  	prv->iocb_queued     = 0;
    2.21 @@ -156,9 +156,18 @@ int tdaio_open (struct td_state *s, cons
    2.22  
    2.23  	if (prv->poll_fd < 0) {
    2.24  		ret = prv->poll_fd;
    2.25 -		DPRINTF("Couldn't get fd for AIO poll support.  This is "
    2.26 -			"probably because your kernel does not have the "
    2.27 -			"aio-poll patch applied.\n");
    2.28 +                if (ret == -EAGAIN) {
    2.29 +                        DPRINTF("Couldn't setup AIO context.  If you are "
    2.30 +                                "trying to concurrently use a large number "
    2.31 +                                "of blktap-based disks, you may need to "
    2.32 +                                "increase the system-wide aio request limit. "
    2.33 +                                "(e.g. 'echo echo 1048576 > /proc/sys/fs/"
    2.34 +                                "aio-max-nr')\n");
    2.35 +                } else {
    2.36 +                        DPRINTF("Couldn't get fd for AIO poll support.  This "
    2.37 +                                "is probably because your kernel does not "
    2.38 +                                "have the aio-poll patch applied.\n");
    2.39 +                }
    2.40  		goto done;
    2.41  	}
    2.42  
     3.1 --- a/tools/blktap/drivers/block-qcow.c	Tue Aug 29 17:53:57 2006 -0500
     3.2 +++ b/tools/blktap/drivers/block-qcow.c	Wed Aug 30 14:09:31 2006 -0500
     3.3 @@ -51,7 +51,7 @@
     3.4  /******AIO DEFINES******/
     3.5  #define REQUEST_ASYNC_FD 1
     3.6  #define MAX_QCOW_IDS  0xFFFF
     3.7 -#define MAX_AIO_REQS (MAX_REQUESTS * MAX_SEGMENTS_PER_REQ * 8)
     3.8 +#define MAX_AIO_REQS (MAX_REQUESTS * MAX_SEGMENTS_PER_REQ)
     3.9  
    3.10  struct pending_aio {
    3.11          td_callback_t cb;
    3.12 @@ -176,10 +176,21 @@ static int init_aio_state(struct td_stat
    3.13          s->aio_ctx = (io_context_t) REQUEST_ASYNC_FD;   
    3.14          s->poll_fd = io_setup(MAX_AIO_REQS, &s->aio_ctx);
    3.15  
    3.16 -        if (s->poll_fd < 0) {
    3.17 -                DPRINTF("Retrieving Async poll fd failed\n");
    3.18 +	if (s->poll_fd < 0) {
    3.19 +                if (s->poll_fd == -EAGAIN) {
    3.20 +                        DPRINTF("Couldn't setup AIO context.  If you are "
    3.21 +                                "trying to concurrently use a large number "
    3.22 +                                "of blktap-based disks, you may need to "
    3.23 +                                "increase the system-wide aio request limit. "
    3.24 +                                "(e.g. 'echo echo 1048576 > /proc/sys/fs/"
    3.25 +                                "aio-max-nr')\n");
    3.26 +                } else {
    3.27 +                        DPRINTF("Couldn't get fd for AIO poll support.  This "
    3.28 +                                "is probably because your kernel does not "
    3.29 +                                "have the aio-poll patch applied.\n");
    3.30 +                }
    3.31  		goto fail;
    3.32 -        }
    3.33 +	}
    3.34  
    3.35          for (i=0;i<MAX_AIO_REQS;i++)
    3.36                  s->iocb_free[i] = &s->iocb_list[i];
     4.1 --- a/tools/blktap/drivers/tapdisk.c	Tue Aug 29 17:53:57 2006 -0500
     4.2 +++ b/tools/blktap/drivers/tapdisk.c	Wed Aug 30 14:09:31 2006 -0500
     4.3 @@ -110,6 +110,7 @@ static void unmap_disk(struct td_state *
     4.4  	free(s->fd_entry);
     4.5  	free(s->blkif);
     4.6  	free(s->ring_info);
     4.7 +        free(s->private);
     4.8  	free(s);
     4.9  
    4.10  	return;
     5.1 --- a/tools/blktap/lib/xs_api.c	Tue Aug 29 17:53:57 2006 -0500
     5.2 +++ b/tools/blktap/lib/xs_api.c	Wed Aug 30 14:09:31 2006 -0500
     5.3 @@ -204,7 +204,7 @@ char *get_dom_domid(struct xs_handle *h,
     5.4  int convert_dev_name_to_num(char *name) {
     5.5  	char *p_sd, *p_hd, *p_xvd, *p_plx, *p, *alpha,*ptr;
     5.6  	int majors[10] = {3,22,33,34,56,57,88,89,90,91};
     5.7 -	int maj,i;
     5.8 +	int maj,i,ret = 0;
     5.9  
    5.10  	asprintf(&p_sd,"/dev/sd");
    5.11  	asprintf(&p_hd,"/dev/hd");
    5.12 @@ -221,7 +221,7 @@ int convert_dev_name_to_num(char *name) 
    5.13  			*ptr++;
    5.14  		}
    5.15  		*p++;
    5.16 -		return BASE_DEV_VAL + (16*i) + atoi(p);
    5.17 +		ret = BASE_DEV_VAL + (16*i) + atoi(p);
    5.18  	} else if (strstr(name, p_hd) != NULL) {
    5.19  		p = name + strlen(p_hd);
    5.20  		for (i = 0, ptr = alpha; i < strlen(alpha); i++) {
    5.21 @@ -229,7 +229,7 @@ int convert_dev_name_to_num(char *name) 
    5.22  			*ptr++;
    5.23  		}
    5.24  		*p++;
    5.25 -		return (majors[i/2]*256) + atoi(p);
    5.26 +		ret = (majors[i/2]*256) + atoi(p);
    5.27  
    5.28  	} else if (strstr(name, p_xvd) != NULL) {
    5.29  		p = name + strlen(p_xvd);
    5.30 @@ -238,17 +238,24 @@ int convert_dev_name_to_num(char *name) 
    5.31  			*ptr++;
    5.32  		}
    5.33  		*p++;
    5.34 -		return (202*256) + (16*i) + atoi(p);
    5.35 +		ret = (202*256) + (16*i) + atoi(p);
    5.36  
    5.37  	} else if (strstr(name, p_plx) != NULL) {
    5.38  		p = name + strlen(p_plx);
    5.39 -		return atoi(p);
    5.40 +		ret = atoi(p);
    5.41  
    5.42  	} else {
    5.43  		DPRINTF("Unknown device type, setting to default.\n");
    5.44 -		return BASE_DEV_VAL;
    5.45 +		ret = BASE_DEV_VAL;
    5.46  	}
    5.47 -	return 0;
    5.48 +
    5.49 +        free(p_sd);
    5.50 +        free(p_hd);
    5.51 +        free(p_xvd);
    5.52 +        free(p_plx);
    5.53 +        free(alpha);
    5.54 +        
    5.55 +	return ret;
    5.56  }
    5.57  
    5.58  /**
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/python/xen/xend/FlatDeviceTree.py	Wed Aug 30 14:09:31 2006 -0500
     6.3 @@ -0,0 +1,323 @@
     6.4 +#!/usr/bin/env python
     6.5 +#
     6.6 +# This library is free software; you can redistribute it and/or
     6.7 +# modify it under the terms of version 2.1 of the GNU Lesser General Public
     6.8 +# License as published by the Free Software Foundation.
     6.9 +#
    6.10 +# This library is distributed in the hope that it will be useful,
    6.11 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.12 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    6.13 +# Lesser General Public License for more details.
    6.14 +#
    6.15 +# You should have received a copy of the GNU Lesser General Public
    6.16 +# License along with this library; if not, write to the Free Software
    6.17 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    6.18 +#
    6.19 +# Copyright (C) IBM Corp. 2006
    6.20 +#
    6.21 +# Authors: Hollis Blanchard <hollisb@us.ibm.com>
    6.22 +
    6.23 +import os
    6.24 +import sys
    6.25 +import struct
    6.26 +import stat
    6.27 +import re
    6.28 +
    6.29 +_OF_DT_HEADER = int("d00dfeed", 16) # avoid signed/unsigned FutureWarning
    6.30 +_OF_DT_BEGIN_NODE = 0x1
    6.31 +_OF_DT_END_NODE = 0x2
    6.32 +_OF_DT_PROP = 0x3
    6.33 +_OF_DT_END = 0x9
    6.34 +
    6.35 +def _bincat(seq, separator=''):
    6.36 +    '''Concatenate the contents of seq into a bytestream.'''
    6.37 +    strs = []
    6.38 +    for item in seq:
    6.39 +        if type(item) == type(0):
    6.40 +            strs.append(struct.pack(">I", item))
    6.41 +        else:
    6.42 +            try:
    6.43 +                strs.append(item.to_bin())
    6.44 +            except AttributeError, e:
    6.45 +                strs.append(item)
    6.46 +    return separator.join(strs)
    6.47 +
    6.48 +def _alignup(val, alignment):
    6.49 +    return (val + alignment - 1) & ~(alignment - 1)
    6.50 +
    6.51 +def _pad(buf, alignment):
    6.52 +    '''Pad bytestream with NULLs to specified alignment.'''
    6.53 +    padlen = _alignup(len(buf), alignment)
    6.54 +    return buf + '\0' * (padlen - len(buf))
    6.55 +    # not present in Python 2.3:
    6.56 +    #return buf.ljust(_padlen, '\0')
    6.57 +
    6.58 +def _indent(item):
    6.59 +    indented = []
    6.60 +    for line in str(item).splitlines(True):
    6.61 +        indented.append('    ' + line)
    6.62 +    return ''.join(indented)
    6.63 +
    6.64 +class _Property:
    6.65 +    _nonprint = re.compile('[\000-\037\200-\377]')
    6.66 +    def __init__(self, node, name, value):
    6.67 +        self.node = node
    6.68 +        self.value = value
    6.69 +        self.name = name
    6.70 +        self.node.tree.stradd(name)
    6.71 +
    6.72 +    def __str__(self):
    6.73 +        result = self.name
    6.74 +        if self.value:
    6.75 +            searchtext = self.value
    6.76 +            # it's ok for a string to end in NULL
    6.77 +            if searchtext.find('\000') == len(searchtext)-1:
    6.78 +                searchtext = searchtext[:-1]
    6.79 +            m = self._nonprint.search(searchtext)
    6.80 +            if m:
    6.81 +                bytes = struct.unpack("B" * len(self.value), self.value)
    6.82 +                hexbytes = [ '%02x' % b for b in bytes ]
    6.83 +                words = []
    6.84 +                for i in range(0, len(self.value), 4):
    6.85 +                    words.append(''.join(hexbytes[i:i+4]))
    6.86 +                v = '<' + ' '.join(words) + '>'
    6.87 +            else:
    6.88 +                v = '"%s"' % self.value
    6.89 +            result += ': ' + v
    6.90 +        return result
    6.91 +
    6.92 +    def to_bin(self):
    6.93 +        offset = self.node.tree.stroffset(self.name)
    6.94 +        return struct.pack('>III', _OF_DT_PROP, len(self.value), offset) \
    6.95 +            + _pad(self.value, 4)
    6.96 +
    6.97 +class _Node:
    6.98 +    def __init__(self, tree, name):
    6.99 +        self.tree = tree
   6.100 +        self.name = name
   6.101 +        self.props = {}
   6.102 +        self.children = {}
   6.103 +        self.phandle = 0
   6.104 +
   6.105 +    def __str__(self):
   6.106 +        propstrs = [ _indent(prop) for prop in self.props.values() ]
   6.107 +        childstrs = [ _indent(child) for child in self.children.values() ]
   6.108 +        return '%s:\n%s\n%s' % (self.name, '\n'.join(propstrs),
   6.109 +            '\n'.join(childstrs))
   6.110 +
   6.111 +    def to_bin(self):
   6.112 +        name = _pad(self.name + '\0', 4)
   6.113 +        return struct.pack('>I', _OF_DT_BEGIN_NODE) + \
   6.114 +                name + \
   6.115 +                _bincat(self.props.values()) + \
   6.116 +                _bincat(self.children.values()) + \
   6.117 +                struct.pack('>I', _OF_DT_END_NODE)
   6.118 +
   6.119 +    def addprop(self, propname, *cells):
   6.120 +        '''setprop with duplicate error-checking.'''
   6.121 +        if propname in self.props:
   6.122 +            raise AttributeError('%s/%s already exists' % (self.name, propname))
   6.123 +        self.setprop(propname, *cells)
   6.124 +
   6.125 +    def setprop(self, propname, *cells):
   6.126 +        self.props[propname] = _Property(self, propname, _bincat(cells))
   6.127 +
   6.128 +    def addnode(self, nodename):
   6.129 +        '''newnode with duplicate error-checking.'''
   6.130 +        if nodename in self.children:
   6.131 +            raise AttributeError('%s/%s already exists' % (self.name, nodename))
   6.132 +        return self.newnode(nodename)
   6.133 +
   6.134 +    def newnode(self, nodename):
   6.135 +        node = _Node(self.tree, nodename)
   6.136 +        self.children[nodename] = node
   6.137 +        return node
   6.138 +
   6.139 +    def getprop(self, propname):
   6.140 +        return self.props[propname]
   6.141 +
   6.142 +    def getchild(self, nodename):
   6.143 +        return self.children[nodename]
   6.144 +
   6.145 +    def get_phandle(self):
   6.146 +        if self.phandle:
   6.147 +            return self.phandle
   6.148 +        self.phandle = self.tree.alloc_phandle()
   6.149 +        self.addprop('linux,phandle', self.phandle)
   6.150 +        return self.phandle
   6.151 +
   6.152 +class _Header:
   6.153 +    def __init__(self):
   6.154 +        self.magic = 0
   6.155 +        self.totalsize = 0
   6.156 +        self.off_dt_struct = 0
   6.157 +        self.off_dt_strings = 0
   6.158 +        self.off_mem_rsvmap = 0
   6.159 +        self.version = 0
   6.160 +        self.last_comp_version = 0
   6.161 +        self.boot_cpuid_phys = 0
   6.162 +        self.size_dt_strings = 0
   6.163 +    def to_bin(self):
   6.164 +        return struct.pack('>9I',
   6.165 +            self.magic,
   6.166 +            self.totalsize,
   6.167 +            self.off_dt_struct,
   6.168 +            self.off_dt_strings,
   6.169 +            self.off_mem_rsvmap,
   6.170 +            self.version,
   6.171 +            self.last_comp_version,
   6.172 +            self.boot_cpuid_phys,
   6.173 +            self.size_dt_strings)
   6.174 +
   6.175 +class _StringBlock:
   6.176 +    def __init__(self):
   6.177 +        self.table = []
   6.178 +    def to_bin(self):
   6.179 +        return _bincat(self.table, '\0') + '\0'
   6.180 +    def add(self, str):
   6.181 +        self.table.append(str)
   6.182 +    def getoffset(self, str):
   6.183 +        return self.to_bin().index(str + '\0')
   6.184 +
   6.185 +class Tree(_Node):
   6.186 +    def __init__(self):
   6.187 +        self.last_phandle = 0
   6.188 +        self.strings = _StringBlock()
   6.189 +        self.reserved = [(0, 0)]
   6.190 +        _Node.__init__(self, self, '\0')
   6.191 +
   6.192 +    def alloc_phandle(self):
   6.193 +        self.last_phandle += 1
   6.194 +        return self.last_phandle
   6.195 +
   6.196 +    def stradd(self, str):
   6.197 +        return self.strings.add(str)
   6.198 +
   6.199 +    def stroffset(self, str):
   6.200 +        return self.strings.getoffset(str)
   6.201 +
   6.202 +    def reserve(self, start, len):
   6.203 +        self.reserved.insert(0, (start, len))
   6.204 +
   6.205 +    def to_bin(self):
   6.206 +        # layout:
   6.207 +        #   header
   6.208 +        #   reservation map
   6.209 +        #   string block
   6.210 +        #   data block
   6.211 +
   6.212 +        datablock = _Node.to_bin(self)
   6.213 +
   6.214 +        r = [ struct.pack('>QQ', rsrv[0], rsrv[1]) for rsrv in self.reserved ]
   6.215 +        reserved = _bincat(r)
   6.216 +
   6.217 +        strblock = _pad(self.strings.to_bin(), 4)
   6.218 +        strblocklen = len(strblock)
   6.219 +
   6.220 +        header = _Header()
   6.221 +        header.magic = _OF_DT_HEADER
   6.222 +        header.off_mem_rsvmap = _alignup(len(header.to_bin()), 8)
   6.223 +        header.off_dt_strings = header.off_mem_rsvmap + len(reserved)
   6.224 +        header.off_dt_struct = header.off_dt_strings + strblocklen
   6.225 +        header.version = 0x10
   6.226 +        header.last_comp_version = 0x10
   6.227 +        header.boot_cpuid_phys = 0
   6.228 +        header.size_dt_strings = strblocklen
   6.229 +
   6.230 +        payload = reserved + \
   6.231 +                strblock + \
   6.232 +                datablock + \
   6.233 +                struct.pack('>I', _OF_DT_END)
   6.234 +        header.totalsize = len(payload) + _alignup(len(header.to_bin()), 8)
   6.235 +        return _pad(header.to_bin(), 8) + payload
   6.236 +
   6.237 +_host_devtree_root = '/proc/device-tree'
   6.238 +def _getprop(propname):
   6.239 +    '''Extract a property from the system's device tree.'''
   6.240 +    f = file(os.path.join(_host_devtree_root, propname), 'r')
   6.241 +    data = f.read()
   6.242 +    f.close()
   6.243 +    return data
   6.244 +
   6.245 +def _copynode(node, dirpath, propfilter):
   6.246 +    '''Extract all properties from a node in the system's device tree.'''
   6.247 +    dirents = os.listdir(dirpath)
   6.248 +    for dirent in dirents:
   6.249 +        fullpath = os.path.join(dirpath, dirent)
   6.250 +        st = os.lstat(fullpath)
   6.251 +        if stat.S_ISDIR(st.st_mode):
   6.252 +            child = node.addnode(dirent)
   6.253 +            _copytree(child, fullpath, propfilter)
   6.254 +        elif stat.S_ISREG(st.st_mode) and propfilter(fullpath):
   6.255 +            node.addprop(dirent, _getprop(fullpath))
   6.256 +
   6.257 +def _copytree(node, dirpath, propfilter):
   6.258 +    path = os.path.join(_host_devtree_root, dirpath)
   6.259 +    _copynode(node, path, propfilter)
   6.260 +
   6.261 +def build(imghandler):
   6.262 +    '''Construct a device tree by combining the domain's configuration and
   6.263 +    the host's device tree.'''
   6.264 +    root = Tree()
   6.265 +
   6.266 +    # 4 pages: start_info, console, store, shared_info
   6.267 +    root.reserve(0x3ffc000, 0x4000)
   6.268 +
   6.269 +    root.addprop('device_type', 'chrp-but-not-really\0')
   6.270 +    root.addprop('#size-cells', 2)
   6.271 +    root.addprop('#address-cells', 2)
   6.272 +    root.addprop('model', 'Momentum,Maple-D\0')
   6.273 +    root.addprop('compatible', 'Momentum,Maple\0')
   6.274 +
   6.275 +    xen = root.addnode('xen')
   6.276 +    xen.addprop('start-info', 0, 0x3ffc000, 0, 0x1000)
   6.277 +    xen.addprop('version', 'Xen-3.0-unstable\0')
   6.278 +    xen.addprop('reg', 0, imghandler.vm.domid, 0, 0)
   6.279 +    xen.addprop('domain-name', imghandler.vm.getName() + '\0')
   6.280 +    xencons = xen.addnode('console')
   6.281 +    xencons.addprop('interrupts', 1, 0)
   6.282 +
   6.283 +    # XXX split out RMA node
   6.284 +    mem = root.addnode('memory@0')
   6.285 +    totalmem = imghandler.vm.getMemoryTarget() * 1024
   6.286 +    mem.addprop('reg', 0, 0, 0, totalmem)
   6.287 +    mem.addprop('device_type', 'memory\0')
   6.288 +
   6.289 +    cpus = root.addnode('cpus')
   6.290 +    cpus.addprop('smp-enabled')
   6.291 +    cpus.addprop('#size-cells', 0)
   6.292 +    cpus.addprop('#address-cells', 1)
   6.293 +
   6.294 +    # Copy all properties the system firmware gave us, except for 'linux,'
   6.295 +    # properties, from 'cpus/@0', once for every vcpu. Hopefully all cpus are
   6.296 +    # identical...
   6.297 +    cpu0 = None
   6.298 +    def _nolinuxprops(fullpath):
   6.299 +        return not os.path.basename(fullpath).startswith('linux,')
   6.300 +    for i in range(imghandler.vm.getVCpuCount()):
   6.301 +        cpu = cpus.addnode('PowerPC,970@0')
   6.302 +        _copytree(cpu, 'cpus/PowerPC,970@0', _nolinuxprops)
   6.303 +        # and then overwrite what we need to
   6.304 +        pft_size = imghandler.vm.info.get('pft-size', 0x14)
   6.305 +        cpu.setprop('ibm,pft-size', 0, pft_size)
   6.306 +
   6.307 +        # set default CPU
   6.308 +        if cpu0 == None:
   6.309 +            cpu0 = cpu
   6.310 +
   6.311 +    chosen = root.addnode('chosen')
   6.312 +    chosen.addprop('cpu', cpu0.get_phandle())
   6.313 +    chosen.addprop('memory', mem.get_phandle())
   6.314 +    chosen.addprop('linux,stdout-path', '/xen/console\0')
   6.315 +    chosen.addprop('interrupt-controller', xen.get_phandle())
   6.316 +    chosen.addprop('bootargs', imghandler.cmdline + '\0')
   6.317 +    # xc_linux_load.c will overwrite these 64-bit properties later
   6.318 +    chosen.addprop('linux,initrd-start', 0, 0)
   6.319 +    chosen.addprop('linux,initrd-end', 0, 0)
   6.320 +
   6.321 +    if 1:
   6.322 +        f = file('/tmp/domU.dtb', 'w')
   6.323 +        f.write(root.to_bin())
   6.324 +        f.close()
   6.325 +
   6.326 +    return root
     7.1 --- a/tools/python/xen/xend/XendCheckpoint.py	Tue Aug 29 17:53:57 2006 -0500
     7.2 +++ b/tools/python/xen/xend/XendCheckpoint.py	Wed Aug 30 14:09:31 2006 -0500
     7.3 @@ -161,10 +161,12 @@ def restore(xd, fd):
     7.4          if handler.store_mfn is None or handler.console_mfn is None:
     7.5              raise XendError('Could not read store/console MFN')
     7.6  
     7.7 +        #Block until src closes connection
     7.8 +        os.read(fd, 1)
     7.9          dominfo.unpause()
    7.10 -
    7.11 +        
    7.12          dominfo.completeRestore(handler.store_mfn, handler.console_mfn)
    7.13 -
    7.14 +        
    7.15          return dominfo
    7.16      except:
    7.17          dominfo.destroy()
     8.1 --- a/tools/python/xen/xend/XendDomain.py	Tue Aug 29 17:53:57 2006 -0500
     8.2 +++ b/tools/python/xen/xend/XendDomain.py	Wed Aug 30 14:09:31 2006 -0500
     8.3 @@ -431,7 +431,8 @@ class XendDomain:
     8.4          sock.send("receive\n")
     8.5          sock.recv(80)
     8.6          XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst)
     8.7 -
     8.8 +        dominfo.testDeviceComplete()
     8.9 +        sock.close()
    8.10  
    8.11      def domain_save(self, domid, dst):
    8.12          """Start saving a domain to file.
     9.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Tue Aug 29 17:53:57 2006 -0500
     9.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Wed Aug 30 14:09:31 2006 -0500
     9.3 @@ -30,7 +30,6 @@ import string
     9.4  import time
     9.5  import threading
     9.6  import os
     9.7 -import math
     9.8  
     9.9  import xen.lowlevel.xc
    9.10  from xen.util import asserts
    9.11 @@ -703,6 +702,9 @@ class XendDomainInfo:
    9.12                  if security[idx][0] == 'ssidref':
    9.13                      to_store['security/ssidref'] = str(security[idx][1])
    9.14  
    9.15 +        if not self.readVm('xend/restart_count'):
    9.16 +            to_store['xend/restart_count'] = str(0)
    9.17 +
    9.18          log.debug("Storing VM details: %s", to_store)
    9.19  
    9.20          self.writeVm(to_store)
    9.21 @@ -824,6 +826,9 @@ class XendDomainInfo:
    9.22      def setResume(self, state):
    9.23          self.info['resume'] = state
    9.24  
    9.25 +    def getRestartCount(self):
    9.26 +        return self.readVm('xend/restart_count')
    9.27 +
    9.28      def refreshShutdown(self, xeninfo = None):
    9.29          # If set at the end of this method, a restart is required, with the
    9.30          # given reason.  This restart has to be done out of the scope of
    9.31 @@ -1280,34 +1285,28 @@ class XendDomainInfo:
    9.32                  for v in range(0, self.info['max_vcpu_id']+1):
    9.33                      xc.vcpu_setaffinity(self.domid, v, self.info['cpus'])
    9.34  
    9.35 -            # set domain maxmem in KiB
    9.36 -            xc.domain_setmaxmem(self.domid, self.info['maxmem'] * 1024)
    9.37 +            # set memory limit
    9.38 +            maxmem = self.image.getRequiredMemory(self.info['maxmem'] * 1024)
    9.39 +            xc.domain_setmaxmem(self.domid, maxmem)
    9.40  
    9.41 -            m = self.image.getDomainMemory(self.info['memory'] * 1024)
    9.42 +            mem_kb = self.image.getRequiredMemory(self.info['memory'] * 1024)
    9.43  
    9.44              # get the domain's shadow memory requirement
    9.45 -            sm = int(math.ceil(self.image.getDomainShadowMemory(m) / 1024.0))
    9.46 -            if self.info['shadow_memory'] > sm:
    9.47 -                sm = self.info['shadow_memory']
    9.48 +            shadow_kb = self.image.getRequiredShadowMemory(mem_kb)
    9.49 +            shadow_kb_req = self.info['shadow_memory'] * 1024
    9.50 +            if shadow_kb_req > shadow_kb:
    9.51 +                shadow_kb = shadow_kb_req
    9.52 +            shadow_mb = (shadow_kb + 1023) / 1024
    9.53  
    9.54              # Make sure there's enough RAM available for the domain
    9.55 -            balloon.free(m + sm * 1024)
    9.56 +            balloon.free(mem_kb + shadow_mb * 1024)
    9.57  
    9.58              # Set up the shadow memory
    9.59 -            sm = xc.shadow_mem_control(self.domid, mb=sm)
    9.60 -            self.info['shadow_memory'] = sm
    9.61 +            shadow_cur = xc.shadow_mem_control(self.domid, shadow_mb)
    9.62 +            self.info['shadow_memory'] = shadow_cur
    9.63  
    9.64 -            init_reservation = self.info['memory'] * 1024
    9.65 -            if os.uname()[4] in ('ia64', 'ppc64'):
    9.66 -                # Workaround for architectures that don't yet support
    9.67 -                # ballooning.
    9.68 -                init_reservation = m
    9.69 -                # Following line from xiantao.zhang@intel.com
    9.70 -                # Needed for IA64 until supports ballooning -- okay for PPC64?
    9.71 -                xc.domain_setmaxmem(self.domid, m)
    9.72 -
    9.73 -            xc.domain_memory_increase_reservation(self.domid, init_reservation,
    9.74 -                                                  0, 0)
    9.75 +            # initial memory allocation
    9.76 +            xc.domain_memory_increase_reservation(self.domid, mem_kb, 0, 0)
    9.77  
    9.78              self.createChannels()
    9.79  
    9.80 @@ -1495,6 +1494,21 @@ class XendDomainInfo:
    9.81              if rc != 0:
    9.82                  raise XendError("Device of type '%s' refuses migration." % n)
    9.83  
    9.84 +    def testDeviceComplete(self):
    9.85 +        """ For Block IO migration safety we must ensure that
    9.86 +        the device has shutdown correctly, i.e. all blocks are
    9.87 +        flushed to disk
    9.88 +        """
    9.89 +        while True:
    9.90 +            test = 0
    9.91 +            for i in self.getDeviceController('vbd').deviceIDs():
    9.92 +                test = 1
    9.93 +                log.info("Dev %s still active, looping...", i)
    9.94 +                time.sleep(0.1)
    9.95 +                
    9.96 +            if test == 0:
    9.97 +                break
    9.98 +
    9.99      def migrateDevices(self, network, dst, step, domName=''):
   9.100          """Notify the devices about migration
   9.101          """
   9.102 @@ -1615,6 +1629,9 @@ class XendDomainInfo:
   9.103              try:
   9.104                  new_dom = XendDomain.instance().domain_create(config)
   9.105                  new_dom.unpause()
   9.106 +                rst_cnt = self.readVm('xend/restart_count')
   9.107 +                rst_cnt = int(rst_cnt) + 1
   9.108 +                self.writeVm('xend/restart_count', str(rst_cnt))
   9.109                  new_dom.removeVm(RESTART_IN_PROGRESS)
   9.110              except:
   9.111                  if new_dom:
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/tools/python/xen/xend/arch.py	Wed Aug 30 14:09:31 2006 -0500
    10.3 @@ -0,0 +1,32 @@
    10.4 +#!/usr/bin/env python
    10.5 +#
    10.6 +# This library is free software; you can redistribute it and/or
    10.7 +# modify it under the terms of version 2.1 of the GNU Lesser General Public
    10.8 +# License as published by the Free Software Foundation.
    10.9 +#
   10.10 +# This library is distributed in the hope that it will be useful,
   10.11 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
   10.12 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   10.13 +# Lesser General Public License for more details.
   10.14 +#
   10.15 +# You should have received a copy of the GNU Lesser General Public
   10.16 +# License along with this library; if not, write to the Free Software
   10.17 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   10.18 +#
   10.19 +# Copyright (C) IBM Corp. 2006
   10.20 +#
   10.21 +# Authors: Hollis Blanchard <hollisb@us.ibm.com>
   10.22 +
   10.23 +import os
   10.24 +
   10.25 +_types = {
   10.26 +    "i386": "x86",
   10.27 +    "i486": "x86",
   10.28 +    "i586": "x86",
   10.29 +    "i686": "x86",
   10.30 +    "x86_64": "x86",
   10.31 +    "ia64": "ia64",
   10.32 +    "ppc": "powerpc",
   10.33 +    "ppc64": "powerpc",
   10.34 +}
   10.35 +type = _types.get(os.uname()[4], "unknown")
    11.1 --- a/tools/python/xen/xend/image.py	Tue Aug 29 17:53:57 2006 -0500
    11.2 +++ b/tools/python/xen/xend/image.py	Wed Aug 30 14:09:31 2006 -0500
    11.3 @@ -27,6 +27,8 @@ from xen.xend.XendError import VmError
    11.4  from xen.xend.XendLogging import log
    11.5  from xen.xend.server.netif import randomMAC
    11.6  from xen.xend.xenstore.xswatch import xswatch
    11.7 +from xen.xend import arch
    11.8 +from xen.xend import FlatDeviceTree
    11.9  
   11.10  
   11.11  xc = xen.lowlevel.xc.xc()
   11.12 @@ -141,19 +143,10 @@ class ImageHandler:
   11.13              raise VmError('Building domain failed: ostype=%s dom=%d err=%s'
   11.14                            % (self.ostype, self.vm.getDomid(), str(result)))
   11.15  
   11.16 -
   11.17 -    def getDomainMemory(self, mem_kb):
   11.18 -        """@return The memory required, in KiB, by the domain to store the
   11.19 -        given amount, also in KiB."""
   11.20 -        if os.uname()[4] != 'ia64':
   11.21 -            # A little extra because auto-ballooning is broken w.r.t. HVM
   11.22 -            # guests. Also, slack is necessary for live migration since that
   11.23 -            # uses shadow page tables.
   11.24 -            if 'hvm' in xc.xeninfo()['xen_caps']:
   11.25 -                mem_kb += 4*1024;
   11.26 +    def getRequiredMemory(self, mem_kb):
   11.27          return mem_kb
   11.28  
   11.29 -    def getDomainShadowMemory(self, mem_kb):
   11.30 +    def getRequiredShadowMemory(self, mem_kb):
   11.31          """@return The minimum shadow memory required, in KiB, for a domain 
   11.32          with mem_kb KiB of RAM."""
   11.33          # PV domains don't need any shadow memory
   11.34 @@ -197,10 +190,40 @@ class LinuxImageHandler(ImageHandler):
   11.35                                ramdisk        = self.ramdisk,
   11.36                                features       = self.vm.getFeatures())
   11.37  
   11.38 +class PPC_LinuxImageHandler(LinuxImageHandler):
   11.39 +
   11.40 +    ostype = "linux"
   11.41 +
   11.42 +    def configure(self, imageConfig, deviceConfig):
   11.43 +        LinuxImageHandler.configure(self, imageConfig, deviceConfig)
   11.44 +        self.imageConfig = imageConfig
   11.45 +
   11.46 +    def buildDomain(self):
   11.47 +        store_evtchn = self.vm.getStorePort()
   11.48 +        console_evtchn = self.vm.getConsolePort()
   11.49 +
   11.50 +        log.debug("dom            = %d", self.vm.getDomid())
   11.51 +        log.debug("image          = %s", self.kernel)
   11.52 +        log.debug("store_evtchn   = %d", store_evtchn)
   11.53 +        log.debug("console_evtchn = %d", console_evtchn)
   11.54 +        log.debug("cmdline        = %s", self.cmdline)
   11.55 +        log.debug("ramdisk        = %s", self.ramdisk)
   11.56 +        log.debug("vcpus          = %d", self.vm.getVCpuCount())
   11.57 +        log.debug("features       = %s", self.vm.getFeatures())
   11.58 +
   11.59 +        devtree = FlatDeviceTree.build(self)
   11.60 +
   11.61 +        return xc.linux_build(dom            = self.vm.getDomid(),
   11.62 +                              image          = self.kernel,
   11.63 +                              store_evtchn   = store_evtchn,
   11.64 +                              console_evtchn = console_evtchn,
   11.65 +                              cmdline        = self.cmdline,
   11.66 +                              ramdisk        = self.ramdisk,
   11.67 +                              features       = self.vm.getFeatures(),
   11.68 +                              arch_args      = devtree.to_bin())
   11.69 +
   11.70  class HVMImageHandler(ImageHandler):
   11.71  
   11.72 -    ostype = "hvm"
   11.73 -
   11.74      def configure(self, imageConfig, deviceConfig):
   11.75          ImageHandler.configure(self, imageConfig, deviceConfig)
   11.76  
   11.77 @@ -282,7 +305,7 @@ class HVMImageHandler(ImageHandler):
   11.78          for (name, info) in deviceConfig:
   11.79              if name == 'vbd':
   11.80                  uname = sxp.child_value(info, 'uname')
   11.81 -                if 'file:' in uname:
   11.82 +                if uname is not None and 'file:' in uname:
   11.83                      (_, vbdparam) = string.split(uname, ':', 1)
   11.84                      if not os.path.isfile(vbdparam):
   11.85                          raise VmError('Disk image does not exist: %s' %
   11.86 @@ -355,32 +378,6 @@ class HVMImageHandler(ImageHandler):
   11.87          os.waitpid(self.pid, 0)
   11.88          self.pid = 0
   11.89  
   11.90 -    def getDomainMemory(self, mem_kb):
   11.91 -        """@see ImageHandler.getDomainMemory"""
   11.92 -        if os.uname()[4] == 'ia64':
   11.93 -            page_kb = 16
   11.94 -            # ROM size for guest firmware, ioreq page and xenstore page
   11.95 -            extra_pages = 1024 + 2
   11.96 -        else:
   11.97 -            page_kb = 4
   11.98 -            # This was derived emperically:
   11.99 -            #   2.4 MB overhead per 1024 MB RAM + 8 MB constant
  11.100 -            #   + 4 to avoid low-memory condition
  11.101 -            extra_mb = (2.4/1024) * (mem_kb/1024.0) + 12;
  11.102 -            extra_pages = int( math.ceil( extra_mb*1024 / page_kb ))
  11.103 -        return mem_kb + extra_pages * page_kb
  11.104 -
  11.105 -    def getDomainShadowMemory(self, mem_kb):
  11.106 -        """@return The minimum shadow memory required, in KiB, for a domain 
  11.107 -        with mem_kb KiB of RAM."""
  11.108 -        if os.uname()[4] in ('ia64', 'ppc64'):
  11.109 -            # Explicit shadow memory is not a concept 
  11.110 -            return 0
  11.111 -        else:
  11.112 -            # 1MB per vcpu plus 4Kib/Mib of RAM.  This is higher than 
  11.113 -            # the minimum that Xen would allocate if no value were given.
  11.114 -            return 1024 * self.vm.getVCpuCount() + mem_kb / 256
  11.115 -
  11.116      def register_shutdown_watch(self):
  11.117          """ add xen store watch on control/shutdown """
  11.118          self.shutdownWatch = xswatch(self.vm.dompath + "/control/shutdown", \
  11.119 @@ -417,15 +414,51 @@ class HVMImageHandler(ImageHandler):
  11.120  
  11.121          return 1 # Keep watching
  11.122  
  11.123 -"""Table of image handler classes for virtual machine images.  Indexed by
  11.124 -image type.
  11.125 -"""
  11.126 -imageHandlerClasses = {}
  11.127 +class IA64_HVM_ImageHandler(HVMImageHandler):
  11.128  
  11.129 +    ostype = "hvm"
  11.130  
  11.131 -for h in LinuxImageHandler, HVMImageHandler:
  11.132 -    imageHandlerClasses[h.ostype] = h
  11.133 +    def getRequiredMemory(self, mem_kb):
  11.134 +        page_kb = 16
  11.135 +        # ROM size for guest firmware, ioreq page and xenstore page
  11.136 +        extra_pages = 1024 + 2
  11.137 +        return mem_kb + extra_pages * page_kb
  11.138  
  11.139 +    def getRequiredShadowMemory(self, mem_kb):
  11.140 +        # Explicit shadow memory is not a concept 
  11.141 +        return 0
  11.142 +
  11.143 +class X86_HVM_ImageHandler(HVMImageHandler):
  11.144 +
  11.145 +    ostype = "hvm"
  11.146 +
  11.147 +    def getRequiredMemory(self, mem_kb):
  11.148 +        page_kb = 4
  11.149 +        # This was derived emperically:
  11.150 +        #   2.4 MB overhead per 1024 MB RAM + 8 MB constant
  11.151 +        #   + 4 to avoid low-memory condition
  11.152 +        extra_mb = (2.4/1024) * (mem_kb/1024.0) + 12;
  11.153 +        extra_pages = int( math.ceil( extra_mb*1024 / page_kb ))
  11.154 +        return mem_kb + extra_pages * page_kb
  11.155 +
  11.156 +    def getRequiredShadowMemory(self, mem_kb):
  11.157 +        # 1MB per vcpu plus 4Kib/Mib of RAM.  This is higher than 
  11.158 +        # the minimum that Xen would allocate if no value were given.
  11.159 +        return 1024 * self.vm.getVCpuCount() + mem_kb / 256
  11.160 +
  11.161 +_handlers = {
  11.162 +    "powerpc": {
  11.163 +        "linux": PPC_LinuxImageHandler,
  11.164 +    },
  11.165 +    "ia64": {
  11.166 +        "linux": LinuxImageHandler,
  11.167 +        "hvm": IA64_HVM_ImageHandler,
  11.168 +    },
  11.169 +    "x86": {
  11.170 +        "linux": LinuxImageHandler,
  11.171 +        "hvm": X86_HVM_ImageHandler,
  11.172 +    },
  11.173 +}
  11.174  
  11.175  def findImageHandlerClass(image):
  11.176      """Find the image handler class for an image config.
  11.177 @@ -433,10 +466,10 @@ def findImageHandlerClass(image):
  11.178      @param image config
  11.179      @return ImageHandler subclass or None
  11.180      """
  11.181 -    ty = sxp.name(image)
  11.182 -    if ty is None:
  11.183 +    type = sxp.name(image)
  11.184 +    if type is None:
  11.185          raise VmError('missing image type')
  11.186 -    imageClass = imageHandlerClasses.get(ty)
  11.187 -    if imageClass is None:
  11.188 -        raise VmError('unknown image type: ' + ty)
  11.189 -    return imageClass
  11.190 +    try:
  11.191 +        return _handlers[arch.type][type]
  11.192 +    except KeyError:
  11.193 +        raise VmError('unknown image type: ' + type)
    12.1 --- a/tools/python/xen/xend/server/XMLRPCServer.py	Tue Aug 29 17:53:57 2006 -0500
    12.2 +++ b/tools/python/xen/xend/server/XMLRPCServer.py	Wed Aug 30 14:09:31 2006 -0500
    12.3 @@ -78,7 +78,8 @@ def get_log():
    12.4  methods = ['device_create', 'device_configure', 'destroyDevice',
    12.5             'getDeviceSxprs',
    12.6             'setMemoryTarget', 'setName', 'setVCpuCount', 'shutdown',
    12.7 -           'send_sysrq', 'getVCPUInfo', 'waitForDevices']
    12.8 +           'send_sysrq', 'getVCPUInfo', 'waitForDevices',
    12.9 +           'getRestartCount']
   12.10  
   12.11  exclude = ['domain_create', 'domain_restore']
   12.12  
    13.1 --- a/tools/python/xen/xend/server/blkif.py	Tue Aug 29 17:53:57 2006 -0500
    13.2 +++ b/tools/python/xen/xend/server/blkif.py	Wed Aug 30 14:09:31 2006 -0500
    13.3 @@ -52,10 +52,18 @@ class BlkifController(DevController):
    13.4          except ValueError:
    13.5              dev_type = "disk"
    13.6  
    13.7 -        try:
    13.8 -            (typ, params) = string.split(uname, ':', 1)
    13.9 -        except ValueError:
   13.10 -            (typ, params) = ("", "")
   13.11 +        if uname is None:
   13.12 +            if dev_type == 'cdrom':
   13.13 +                (typ, params) = ("", "")
   13.14 +            else:
   13.15 +                raise VmError(
   13.16 +                    'Block device must have physical details specified')
   13.17 +        else:
   13.18 +            try:
   13.19 +                (typ, params) = string.split(uname, ':', 1)
   13.20 +            except ValueError:
   13.21 +                (typ, params) = ("", "")
   13.22 +
   13.23          back = { 'dev'    : dev,
   13.24                   'type'   : typ,
   13.25                   'params' : params,
    14.1 --- a/tools/python/xen/xm/migrate.py	Tue Aug 29 17:53:57 2006 -0500
    14.2 +++ b/tools/python/xen/xm/migrate.py	Wed Aug 30 14:09:31 2006 -0500
    14.3 @@ -57,7 +57,8 @@ def main(argv):
    14.4          opts.usage()
    14.5          return
    14.6      if len(args) != 2:
    14.7 -        opts.err('Invalid arguments: ' + str(args))
    14.8 +        opts.usage()
    14.9 +        sys.exit(1)
   14.10      dom = args[0]
   14.11      dst = args[1]
   14.12      server.xend.domain.migrate(dom, dst, opts.vals.live, opts.vals.resource, opts.vals.port)
    15.1 --- a/tools/python/xen/xm/shutdown.py	Tue Aug 29 17:53:57 2006 -0500
    15.2 +++ b/tools/python/xen/xm/shutdown.py	Wed Aug 30 14:09:31 2006 -0500
    15.3 @@ -48,21 +48,48 @@ gopts.opt('reboot', short='R',
    15.4            fn=set_true, default=0,
    15.5            use='Shutdown and reboot.')
    15.6  
    15.7 +def wait_reboot(opts, doms, rcs):
    15.8 +    while doms:
    15.9 +        alive = server.xend.domains(0)
   15.10 +        reboot = []
   15.11 +        for d in doms:
   15.12 +            if d in alive:
   15.13 +                rc = server.xend.domain.getRestartCount(d)
   15.14 +                if rc == rcs[d]: continue
   15.15 +                reboot.append(d)
   15.16 +            else:
   15.17 +                opts.info("Domain %s destroyed for failed in rebooting" % d)
   15.18 +                doms.remove(d)
   15.19 +        for d in reboot:
   15.20 +            opts.info("Domain %s rebooted" % d)
   15.21 +            doms.remove(d)
   15.22 +        time.sleep(1)
   15.23 +    opts.info("All domains rebooted")
   15.24 +
   15.25 +def wait_shutdown(opts, doms):
   15.26 +    while doms:
   15.27 +        alive = server.xend.domains(0)
   15.28 +        dead = []
   15.29 +        for d in doms:
   15.30 +            if d in alive: continue
   15.31 +            dead.append(d)
   15.32 +        for d in dead:
   15.33 +            opts.info("Domain %s terminated" % d)
   15.34 +            doms.remove(d)
   15.35 +        time.sleep(1)
   15.36 +    opts.info("All domains terminated")
   15.37 +
   15.38  def shutdown(opts, doms, mode, wait):
   15.39 +    rcs = {}
   15.40      for d in doms:
   15.41 +        rcs[d] = server.xend.domain.getRestartCount(d)
   15.42          server.xend.domain.shutdown(d, mode)
   15.43 +
   15.44      if wait:
   15.45 -        while doms:
   15.46 -            alive = server.xend.domains(0)
   15.47 -            dead = []
   15.48 -            for d in doms:
   15.49 -                if d in alive: continue
   15.50 -                dead.append(d)
   15.51 -            for d in dead:
   15.52 -                opts.info("Domain %s terminated" % d)
   15.53 -                doms.remove(d)
   15.54 -            time.sleep(1)
   15.55 -        opts.info("All domains terminated")
   15.56 +        if mode == 'reboot':
   15.57 +            wait_reboot(opts, doms, rcs)
   15.58 +        else:
   15.59 +            wait_shutdown(opts, doms)
   15.60  
   15.61  def shutdown_mode(opts):
   15.62      if opts.vals.halt and opts.vals.reboot: