1 | #============================================================================ |
---|
2 | # This library is free software; you can redistribute it and/or |
---|
3 | # modify it under the terms of version 2.1 of the GNU Lesser General Public |
---|
4 | # License as published by the Free Software Foundation. |
---|
5 | # |
---|
6 | # This library is distributed in the hope that it will be useful, |
---|
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
9 | # Lesser General Public License for more details. |
---|
10 | # |
---|
11 | # You should have received a copy of the GNU Lesser General Public |
---|
12 | # License along with this library; if not, write to the Free Software |
---|
13 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
14 | #============================================================================ |
---|
15 | # Copyright (C) 2005 Mike Wray <mike.wray@hp.com> |
---|
16 | # Copyright (C) 2005-2007 XenSource Ltd |
---|
17 | #============================================================================ |
---|
18 | |
---|
19 | |
---|
20 | import os, string |
---|
21 | import re |
---|
22 | import math |
---|
23 | import signal |
---|
24 | |
---|
25 | import xen.lowlevel.xc |
---|
26 | from xen.xend.XendConstants import REVERSE_DOMAIN_SHUTDOWN_REASONS |
---|
27 | from xen.xend.XendError import VmError, XendError, HVMRequired |
---|
28 | from xen.xend.XendLogging import log |
---|
29 | from xen.xend.XendOptions import instance as xenopts |
---|
30 | from xen.xend.server.netif import randomMAC |
---|
31 | from xen.xend.xenstore.xswatch import xswatch |
---|
32 | from xen.xend import arch |
---|
33 | |
---|
34 | xc = xen.lowlevel.xc.xc() |
---|
35 | |
---|
36 | MAX_GUEST_CMDLINE = 1024 |
---|
37 | |
---|
38 | |
---|
39 | def create(vm, vmConfig): |
---|
40 | """Create an image handler for a vm. |
---|
41 | |
---|
42 | @return ImageHandler instance |
---|
43 | """ |
---|
44 | return findImageHandlerClass(vmConfig)(vm, vmConfig) |
---|
45 | |
---|
46 | |
---|
47 | class ImageHandler: |
---|
48 | """Abstract base class for image handlers. |
---|
49 | |
---|
50 | createImage() is called to configure and build the domain from its |
---|
51 | kernel image and ramdisk etc. |
---|
52 | |
---|
53 | The method buildDomain() is used to build the domain, and must be |
---|
54 | defined in a subclass. Usually this is the only method that needs |
---|
55 | defining in a subclass. |
---|
56 | |
---|
57 | The method createDeviceModel() is called to create the domain device |
---|
58 | model if it needs one. The default is to do nothing. |
---|
59 | |
---|
60 | The method destroy() is called when the domain is destroyed. |
---|
61 | The default is to do nothing. |
---|
62 | """ |
---|
63 | |
---|
64 | ostype = None |
---|
65 | |
---|
66 | |
---|
67 | def __init__(self, vm, vmConfig): |
---|
68 | self.vm = vm |
---|
69 | |
---|
70 | self.bootloader = False |
---|
71 | self.kernel = None |
---|
72 | self.ramdisk = None |
---|
73 | self.cmdline = None |
---|
74 | |
---|
75 | self.configure(vmConfig) |
---|
76 | |
---|
77 | def configure(self, vmConfig): |
---|
78 | """Config actions common to all unix-like domains.""" |
---|
79 | if '_temp_using_bootloader' in vmConfig: |
---|
80 | self.bootloader = True |
---|
81 | self.kernel = vmConfig['_temp_kernel'] |
---|
82 | self.cmdline = vmConfig['_temp_args'] |
---|
83 | self.ramdisk = vmConfig['_temp_ramdisk'] |
---|
84 | else: |
---|
85 | self.kernel = vmConfig['PV_kernel'] |
---|
86 | self.cmdline = vmConfig['PV_args'] |
---|
87 | self.ramdisk = vmConfig['PV_ramdisk'] |
---|
88 | self.vm.storeVm(("image/ostype", self.ostype), |
---|
89 | ("image/kernel", self.kernel), |
---|
90 | ("image/cmdline", self.cmdline), |
---|
91 | ("image/ramdisk", self.ramdisk)) |
---|
92 | |
---|
93 | |
---|
94 | def cleanupBootloading(self): |
---|
95 | if self.bootloader: |
---|
96 | self.unlink(self.kernel) |
---|
97 | self.unlink(self.ramdisk) |
---|
98 | |
---|
99 | |
---|
100 | def unlink(self, f): |
---|
101 | if not f: return |
---|
102 | try: |
---|
103 | os.unlink(f) |
---|
104 | except OSError, ex: |
---|
105 | log.warning("error removing bootloader file '%s': %s", f, ex) |
---|
106 | |
---|
107 | |
---|
108 | def createImage(self): |
---|
109 | """Entry point to create domain memory image. |
---|
110 | Override in subclass if needed. |
---|
111 | """ |
---|
112 | return self.createDomain() |
---|
113 | |
---|
114 | |
---|
115 | def createDomain(self): |
---|
116 | """Build the domain boot image. |
---|
117 | """ |
---|
118 | # Set params and call buildDomain(). |
---|
119 | |
---|
120 | if not os.path.isfile(self.kernel): |
---|
121 | raise VmError('Kernel image does not exist: %s' % self.kernel) |
---|
122 | if self.ramdisk and not os.path.isfile(self.ramdisk): |
---|
123 | raise VmError('Kernel ramdisk does not exist: %s' % self.ramdisk) |
---|
124 | if len(self.cmdline) >= MAX_GUEST_CMDLINE: |
---|
125 | log.warning('kernel cmdline too long, domain %d', |
---|
126 | self.vm.getDomid()) |
---|
127 | |
---|
128 | log.info("buildDomain os=%s dom=%d vcpus=%d", self.ostype, |
---|
129 | self.vm.getDomid(), self.vm.getVCpuCount()) |
---|
130 | |
---|
131 | result = self.buildDomain() |
---|
132 | |
---|
133 | if isinstance(result, dict): |
---|
134 | return result |
---|
135 | else: |
---|
136 | raise VmError('Building domain failed: ostype=%s dom=%d err=%s' |
---|
137 | % (self.ostype, self.vm.getDomid(), str(result))) |
---|
138 | |
---|
139 | def getRequiredAvailableMemory(self, mem_kb): |
---|
140 | """@param mem_kb The configured maxmem or memory, in KiB. |
---|
141 | @return The corresponding required amount of memory for the domain, |
---|
142 | also in KiB. This is normally the given mem_kb, but architecture- or |
---|
143 | image-specific code may override this to add headroom where |
---|
144 | necessary.""" |
---|
145 | return mem_kb |
---|
146 | |
---|
147 | def getRequiredInitialReservation(self): |
---|
148 | """@param mem_kb The configured memory, in KiB. |
---|
149 | @return The corresponding required amount of memory to be free, also |
---|
150 | in KiB. This is normally the same as getRequiredAvailableMemory, but |
---|
151 | architecture- or image-specific code may override this to |
---|
152 | add headroom where necessary.""" |
---|
153 | return self.getRequiredAvailableMemory(self.vm.getMemoryTarget()) |
---|
154 | |
---|
155 | def getRequiredMaximumReservation(self): |
---|
156 | """@param mem_kb The maximum possible memory, in KiB. |
---|
157 | @return The corresponding required amount of memory to be free, also |
---|
158 | in KiB. This is normally the same as getRequiredAvailableMemory, but |
---|
159 | architecture- or image-specific code may override this to |
---|
160 | add headroom where necessary.""" |
---|
161 | return self.getRequiredAvailableMemory(self.vm.getMemoryMaximum()) |
---|
162 | |
---|
163 | def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb): |
---|
164 | """@param shadow_mem_kb The configured shadow memory, in KiB. |
---|
165 | @param maxmem_kb The configured maxmem, in KiB. |
---|
166 | @return The corresponding required amount of shadow memory, also in |
---|
167 | KiB.""" |
---|
168 | # PV domains don't need any shadow memory |
---|
169 | return 0 |
---|
170 | |
---|
171 | def buildDomain(self): |
---|
172 | """Build the domain. Define in subclass.""" |
---|
173 | raise NotImplementedError() |
---|
174 | |
---|
175 | def createDeviceModel(self, restore = False): |
---|
176 | """Create device model for the domain (define in subclass if needed).""" |
---|
177 | pass |
---|
178 | |
---|
179 | def destroy(self): |
---|
180 | """Extra cleanup on domain destroy (define in subclass if needed).""" |
---|
181 | pass |
---|
182 | |
---|
183 | |
---|
184 | def recreate(self): |
---|
185 | pass |
---|
186 | |
---|
187 | |
---|
188 | class LinuxImageHandler(ImageHandler): |
---|
189 | |
---|
190 | ostype = "linux" |
---|
191 | |
---|
192 | def buildDomain(self): |
---|
193 | store_evtchn = self.vm.getStorePort() |
---|
194 | console_evtchn = self.vm.getConsolePort() |
---|
195 | |
---|
196 | mem_mb = self.getRequiredInitialReservation() / 1024 |
---|
197 | |
---|
198 | log.debug("domid = %d", self.vm.getDomid()) |
---|
199 | log.debug("memsize = %d", mem_mb) |
---|
200 | log.debug("image = %s", self.kernel) |
---|
201 | log.debug("store_evtchn = %d", store_evtchn) |
---|
202 | log.debug("console_evtchn = %d", console_evtchn) |
---|
203 | log.debug("cmdline = %s", self.cmdline) |
---|
204 | log.debug("ramdisk = %s", self.ramdisk) |
---|
205 | log.debug("vcpus = %d", self.vm.getVCpuCount()) |
---|
206 | log.debug("features = %s", self.vm.getFeatures()) |
---|
207 | |
---|
208 | return xc.linux_build(domid = self.vm.getDomid(), |
---|
209 | memsize = mem_mb, |
---|
210 | image = self.kernel, |
---|
211 | store_evtchn = store_evtchn, |
---|
212 | console_evtchn = console_evtchn, |
---|
213 | cmdline = self.cmdline, |
---|
214 | ramdisk = self.ramdisk, |
---|
215 | features = self.vm.getFeatures()) |
---|
216 | |
---|
217 | class PPC_LinuxImageHandler(LinuxImageHandler): |
---|
218 | |
---|
219 | ostype = "linux" |
---|
220 | |
---|
221 | def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb): |
---|
222 | """@param shadow_mem_kb The configured shadow memory, in KiB. |
---|
223 | @param maxmem_kb The configured maxmem, in KiB. |
---|
224 | @return The corresponding required amount of shadow memory, also in |
---|
225 | KiB. |
---|
226 | PowerPC currently uses "shadow memory" to refer to the hash table.""" |
---|
227 | return max(maxmem_kb / 64, shadow_mem_kb) |
---|
228 | |
---|
229 | |
---|
230 | |
---|
231 | class HVMImageHandler(ImageHandler): |
---|
232 | |
---|
233 | ostype = "hvm" |
---|
234 | |
---|
235 | def __init__(self, vm, vmConfig): |
---|
236 | ImageHandler.__init__(self, vm, vmConfig) |
---|
237 | self.shutdownWatch = None |
---|
238 | self.rebootFeatureWatch = None |
---|
239 | |
---|
240 | def configure(self, vmConfig): |
---|
241 | ImageHandler.configure(self, vmConfig) |
---|
242 | |
---|
243 | if not self.kernel: |
---|
244 | self.kernel = '/usr/lib/xen/boot/hvmloader' |
---|
245 | |
---|
246 | info = xc.xeninfo() |
---|
247 | if 'hvm' not in info['xen_caps']: |
---|
248 | raise HVMRequired() |
---|
249 | |
---|
250 | self.dmargs = self.parseDeviceModelArgs(vmConfig) |
---|
251 | self.device_model = vmConfig['platform'].get('device_model') |
---|
252 | if not self.device_model: |
---|
253 | raise VmError("hvm: missing device model") |
---|
254 | |
---|
255 | self.display = vmConfig['platform'].get('display') |
---|
256 | self.xauthority = vmConfig['platform'].get('xauthority') |
---|
257 | self.vncconsole = vmConfig['platform'].get('vncconsole') |
---|
258 | |
---|
259 | rtc_timeoffset = vmConfig['platform'].get('rtc_timeoffset') |
---|
260 | |
---|
261 | self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)), |
---|
262 | ("image/device-model", self.device_model), |
---|
263 | ("image/display", self.display)) |
---|
264 | self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset)) |
---|
265 | |
---|
266 | self.pid = None |
---|
267 | |
---|
268 | self.pae = int(vmConfig['platform'].get('pae', 0)) |
---|
269 | self.apic = int(vmConfig['platform'].get('apic', 0)) |
---|
270 | self.acpi = int(vmConfig['platform'].get('acpi', 0)) |
---|
271 | |
---|
272 | |
---|
273 | def buildDomain(self): |
---|
274 | store_evtchn = self.vm.getStorePort() |
---|
275 | |
---|
276 | mem_mb = self.getRequiredInitialReservation() / 1024 |
---|
277 | |
---|
278 | log.debug("domid = %d", self.vm.getDomid()) |
---|
279 | log.debug("image = %s", self.kernel) |
---|
280 | log.debug("store_evtchn = %d", store_evtchn) |
---|
281 | log.debug("memsize = %d", mem_mb) |
---|
282 | log.debug("vcpus = %d", self.vm.getVCpuCount()) |
---|
283 | log.debug("pae = %d", self.pae) |
---|
284 | log.debug("acpi = %d", self.acpi) |
---|
285 | log.debug("apic = %d", self.apic) |
---|
286 | |
---|
287 | rc = xc.hvm_build(domid = self.vm.getDomid(), |
---|
288 | image = self.kernel, |
---|
289 | store_evtchn = store_evtchn, |
---|
290 | memsize = mem_mb, |
---|
291 | vcpus = self.vm.getVCpuCount(), |
---|
292 | pae = self.pae, |
---|
293 | acpi = self.acpi, |
---|
294 | apic = self.apic) |
---|
295 | rc['notes'] = { 'SUSPEND_CANCEL': 1 } |
---|
296 | return rc |
---|
297 | |
---|
298 | # Return a list of cmd line args to the device models based on the |
---|
299 | # xm config file |
---|
300 | def parseDeviceModelArgs(self, vmConfig): |
---|
301 | dmargs = [ 'boot', 'fda', 'fdb', 'soundhw', |
---|
302 | 'localtime', 'serial', 'stdvga', 'isa', |
---|
303 | 'acpi', 'usb', 'usbdevice', 'keymap' ] |
---|
304 | |
---|
305 | ret = ['-vcpus', str(self.vm.getVCpuCount())] |
---|
306 | |
---|
307 | for a in dmargs: |
---|
308 | v = vmConfig['platform'].get(a) |
---|
309 | |
---|
310 | # python doesn't allow '-' in variable names |
---|
311 | if a == 'stdvga': a = 'std-vga' |
---|
312 | if a == 'keymap': a = 'k' |
---|
313 | |
---|
314 | # Handle booleans gracefully |
---|
315 | if a in ['localtime', 'std-vga', 'isa', 'usb', 'acpi']: |
---|
316 | try: |
---|
317 | if v != None: v = int(v) |
---|
318 | if v: ret.append("-%s" % a) |
---|
319 | except (ValueError, TypeError): |
---|
320 | pass # if we can't convert it to a sane type, ignore it |
---|
321 | else: |
---|
322 | if v: |
---|
323 | ret.append("-%s" % a) |
---|
324 | ret.append("%s" % v) |
---|
325 | |
---|
326 | if a in ['fda', 'fdb']: |
---|
327 | if v: |
---|
328 | if not os.path.isabs(v): |
---|
329 | raise VmError("Floppy file %s does not exist." % v) |
---|
330 | log.debug("args: %s, val: %s" % (a,v)) |
---|
331 | |
---|
332 | # Handle disk/network related options |
---|
333 | mac = None |
---|
334 | ret = ret + ["-domain-name", str(self.vm.info['name_label'])] |
---|
335 | nics = 0 |
---|
336 | |
---|
337 | for devuuid in vmConfig['vbd_refs']: |
---|
338 | devinfo = vmConfig['devices'][devuuid][1] |
---|
339 | uname = devinfo.get('uname') |
---|
340 | if uname is not None and 'file:' in uname: |
---|
341 | (_, vbdparam) = string.split(uname, ':', 1) |
---|
342 | if not os.path.isfile(vbdparam): |
---|
343 | raise VmError('Disk image does not exist: %s' % |
---|
344 | vbdparam) |
---|
345 | |
---|
346 | for devuuid in vmConfig['vif_refs']: |
---|
347 | devinfo = vmConfig['devices'][devuuid][1] |
---|
348 | dtype = devinfo.get('type', 'ioemu') |
---|
349 | if dtype != 'ioemu': |
---|
350 | continue |
---|
351 | nics += 1 |
---|
352 | mac = devinfo.get('mac') |
---|
353 | if mac is None: |
---|
354 | mac = randomMAC() |
---|
355 | bridge = devinfo.get('bridge', 'xenbr0') |
---|
356 | model = devinfo.get('model', 'rtl8139') |
---|
357 | ret.append("-net") |
---|
358 | ret.append("nic,vlan=%d,macaddr=%s,model=%s" % |
---|
359 | (nics, mac, model)) |
---|
360 | ret.append("-net") |
---|
361 | ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge)) |
---|
362 | |
---|
363 | |
---|
364 | # |
---|
365 | # Find RFB console device, and if it exists, make QEMU enable |
---|
366 | # the VNC console. |
---|
367 | # |
---|
368 | if int(vmConfig['platform'].get('nographic', 0)) != 0: |
---|
369 | # skip vnc init if nographic is set |
---|
370 | ret.append('-nographic') |
---|
371 | return ret |
---|
372 | |
---|
373 | vnc_config = {} |
---|
374 | has_vnc = int(vmConfig['platform'].get('vnc', 0)) != 0 |
---|
375 | has_sdl = int(vmConfig['platform'].get('sdl', 0)) != 0 |
---|
376 | for dev_uuid in vmConfig['console_refs']: |
---|
377 | dev_type, dev_info = vmConfig['devices'][dev_uuid] |
---|
378 | if dev_type == 'vfb': |
---|
379 | vnc_config = dev_info.get('other_config', {}) |
---|
380 | has_vnc = True |
---|
381 | break |
---|
382 | |
---|
383 | if has_vnc: |
---|
384 | if not vnc_config: |
---|
385 | for key in ('vncunused', 'vnclisten', 'vncdisplay', |
---|
386 | 'vncpasswd'): |
---|
387 | if key in vmConfig['platform']: |
---|
388 | vnc_config[key] = vmConfig['platform'][key] |
---|
389 | |
---|
390 | if not vnc_config.get('vncunused', 0) and \ |
---|
391 | vnc_config.get('vncdisplay', 0): |
---|
392 | vncdisplay = vnc_config.get('vncdisplay') |
---|
393 | ret.append('-vnc') |
---|
394 | ret.append(str(vncdisplay)) |
---|
395 | else: |
---|
396 | ret.append('-vncunused') |
---|
397 | |
---|
398 | vnclisten = vnc_config.get('vnclisten', |
---|
399 | xenopts().get_vnclisten_address()) |
---|
400 | ret.append('-vnclisten') |
---|
401 | ret.append(str(vnclisten)) |
---|
402 | |
---|
403 | # Store vncpassword in xenstore |
---|
404 | vncpasswd = vnc_config.get('vncpasswd') |
---|
405 | if not vncpasswd: |
---|
406 | vncpasswd = xenopts().get_vncpasswd_default() |
---|
407 | |
---|
408 | if vncpasswd is None: |
---|
409 | raise VmError('vncpasswd is not setup in vmconfig or ' |
---|
410 | 'xend-config.sxp') |
---|
411 | |
---|
412 | if vncpasswd != '': |
---|
413 | self.vm.storeVm('vncpasswd', vncpasswd) |
---|
414 | elif has_sdl: |
---|
415 | # SDL is default in QEMU. |
---|
416 | pass |
---|
417 | else: |
---|
418 | ret.append('-nographic') |
---|
419 | |
---|
420 | if int(vmConfig['platform'].get('monitor', 0)) != 0: |
---|
421 | ret = ret + ['-monitor', 'vc'] |
---|
422 | return ret |
---|
423 | |
---|
424 | def createDeviceModel(self, restore = False): |
---|
425 | if self.pid: |
---|
426 | return |
---|
427 | # Execute device model. |
---|
428 | #todo: Error handling |
---|
429 | args = [self.device_model] |
---|
430 | args = args + ([ "-d", "%d" % self.vm.getDomid() ]) |
---|
431 | if arch.type == "ia64": |
---|
432 | args = args + ([ "-m", "%s" % |
---|
433 | (self.getRequiredInitialReservation() / 1024) ]) |
---|
434 | args = args + self.dmargs |
---|
435 | if restore: |
---|
436 | args = args + ([ "-loadvm", "/tmp/xen.qemu-dm.%d" % |
---|
437 | self.vm.getDomid() ]) |
---|
438 | env = dict(os.environ) |
---|
439 | if self.display: |
---|
440 | env['DISPLAY'] = self.display |
---|
441 | if self.xauthority: |
---|
442 | env['XAUTHORITY'] = self.xauthority |
---|
443 | if self.vncconsole: |
---|
444 | args = args + ([ "-vncviewer" ]) |
---|
445 | log.info("spawning device models: %s %s", self.device_model, args) |
---|
446 | # keep track of pid and spawned options to kill it later |
---|
447 | self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env) |
---|
448 | self.vm.storeDom("image/device-model-pid", self.pid) |
---|
449 | log.info("device model pid: %d", self.pid) |
---|
450 | |
---|
451 | def recreate(self): |
---|
452 | self.pid = self.vm.gatherDom(('image/device-model-pid', int)) |
---|
453 | |
---|
454 | def destroy(self, suspend = False): |
---|
455 | if self.pid: |
---|
456 | try: |
---|
457 | sig = signal.SIGKILL |
---|
458 | if suspend: |
---|
459 | log.info("use sigusr1 to signal qemu %d", self.pid) |
---|
460 | sig = signal.SIGUSR1 |
---|
461 | os.kill(self.pid, sig) |
---|
462 | except OSError, exn: |
---|
463 | log.exception(exn) |
---|
464 | try: |
---|
465 | os.waitpid(self.pid, 0) |
---|
466 | except OSError, exn: |
---|
467 | # This is expected if Xend has been restarted within the |
---|
468 | # life of this domain. In this case, we can kill the process, |
---|
469 | # but we can't wait for it because it's not our child. |
---|
470 | pass |
---|
471 | self.pid = None |
---|
472 | |
---|
473 | |
---|
474 | class IA64_HVM_ImageHandler(HVMImageHandler): |
---|
475 | |
---|
476 | def getRequiredAvailableMemory(self, mem_kb): |
---|
477 | page_kb = 16 |
---|
478 | # ROM size for guest firmware, ioreq page, pio page and xenstore page |
---|
479 | extra_pages = 1024 + 4 |
---|
480 | return mem_kb + extra_pages * page_kb |
---|
481 | |
---|
482 | def getRequiredInitialReservation(self): |
---|
483 | return self.vm.getMemoryTarget() |
---|
484 | |
---|
485 | def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb): |
---|
486 | # Explicit shadow memory is not a concept |
---|
487 | return 0 |
---|
488 | |
---|
489 | class X86_HVM_ImageHandler(HVMImageHandler): |
---|
490 | |
---|
491 | def getRequiredAvailableMemory(self, mem_kb): |
---|
492 | # Add 8 MiB overhead for QEMU's video RAM. |
---|
493 | return mem_kb + 8192 |
---|
494 | |
---|
495 | def getRequiredInitialReservation(self): |
---|
496 | return self.vm.getMemoryTarget() |
---|
497 | |
---|
498 | def getRequiredMaximumReservation(self): |
---|
499 | return self.vm.getMemoryMaximum() |
---|
500 | |
---|
501 | def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb): |
---|
502 | # 256 pages (1MB) per vcpu, |
---|
503 | # plus 1 page per MiB of RAM for the P2M map, |
---|
504 | # plus 1 page per MiB of RAM to shadow the resident processes. |
---|
505 | # This is higher than the minimum that Xen would allocate if no value |
---|
506 | # were given (but the Xen minimum is for safety, not performance). |
---|
507 | return max(4 * (256 * self.vm.getVCpuCount() + 2 * (maxmem_kb / 1024)), |
---|
508 | shadow_mem_kb) |
---|
509 | |
---|
510 | class X86_Linux_ImageHandler(LinuxImageHandler): |
---|
511 | |
---|
512 | def buildDomain(self): |
---|
513 | # set physical mapping limit |
---|
514 | # add an 8MB slack to balance backend allocations. |
---|
515 | mem_kb = self.getRequiredMaximumReservation() + (8 * 1024) |
---|
516 | xc.domain_set_memmap_limit(self.vm.getDomid(), mem_kb) |
---|
517 | return LinuxImageHandler.buildDomain(self) |
---|
518 | |
---|
519 | _handlers = { |
---|
520 | "powerpc": { |
---|
521 | "linux": PPC_LinuxImageHandler, |
---|
522 | }, |
---|
523 | "ia64": { |
---|
524 | "linux": LinuxImageHandler, |
---|
525 | "hvm": IA64_HVM_ImageHandler, |
---|
526 | }, |
---|
527 | "x86": { |
---|
528 | "linux": X86_Linux_ImageHandler, |
---|
529 | "hvm": X86_HVM_ImageHandler, |
---|
530 | }, |
---|
531 | } |
---|
532 | |
---|
533 | def findImageHandlerClass(image): |
---|
534 | """Find the image handler class for an image config. |
---|
535 | |
---|
536 | @param image config |
---|
537 | @return ImageHandler subclass or None |
---|
538 | """ |
---|
539 | image_type = image.image_type() |
---|
540 | try: |
---|
541 | return _handlers[arch.type][image_type] |
---|
542 | except KeyError: |
---|
543 | raise VmError('unknown image type: ' + image_type) |
---|