diff --git a/common/fstab b/common/fstab index 968d9b77..45df7401 100644 --- a/common/fstab +++ b/common/fstab @@ -7,8 +7,8 @@ # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info # /dev/mapper/dmroot / ext4 defaults,noatime 1 1 -/dev/mapper/dmswap swap swap defaults 0 0 /dev/xvdb /rw ext4 noauto,defaults 0 0 +/dev/xvdc1 swap swap defaults 0 0 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index 3999d0a2..ed769d08 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -60,7 +60,8 @@ vm_default_netmask = "255.255.0.0" default_root_img = "root.img" default_rootcow_img = "root-cow.img" -default_swapcow_img = "swap-cow.img" +default_volatile_img = "volatile.img" +default_clean_volatile_img = "clean-volatile.img" default_private_img = "private.img" default_appvms_conf_file = "appvm-template.conf" default_netvms_conf_file = "netvm-template.conf" @@ -82,11 +83,6 @@ dom0_vm = None qubes_appmenu_create_cmd = "/usr/lib/qubes/create_apps_for_appvm.sh" qubes_appmenu_remove_cmd = "/usr/lib/qubes/remove_appvm_appmenus.sh" -# TODO: we should detect the actual size of the AppVM's swap partition -# rather than using this ugly hardcoded value, which was choosen here -# as "should be good for everyone" -swap_cow_sz = 1024*1024*1024 - class XendSession(object): def __init__(self): self.get_xend_session_old_api() @@ -213,7 +209,7 @@ class QubesVm(object): self.root_img = dir_path + "/" + ( root_img if root_img is not None else default_root_img) - self.rootcow_img = dir_path + "/" + default_rootcow_img + self.volatile_img = dir_path + "/" + default_volatile_img if private_img is not None and os.path.isabs(private_img): self.private_img = private_img @@ -647,7 +643,7 @@ class QubesVm(object): attrs["dir_path"] = self.dir_path attrs["conf_file"] = self.conf_file attrs["root_img"] = self.root_img - attrs["rootcow_img"] = self.rootcow_img + attrs["volatile_img"] = self.volatile_img attrs["private_img"] = self.private_img attrs["uses_default_netvm"] = str(self.uses_default_netvm) attrs["netvm_qid"] = str(self.netvm_vm.qid) if self.netvm_vm is not None else "none" @@ -691,6 +687,13 @@ class QubesTemplateVm(QubesVm): super(QubesTemplateVm, self).__init__(**kwargs) dir_path = kwargs["dir_path"] + + # Clean image for root-cow and swap (AppVM side) + self.clean_volatile_img = self.dir_path + "/" + default_clean_volatile_img + + # Image for template changes + self.rootcow_img = self.dir_path + "/" + default_rootcow_img + if appvms_conf_file is not None and os.path.isabs(appvms_conf_file): self.appvms_conf_file = appvms_conf_file else: @@ -799,13 +802,21 @@ class QubesTemplateVm(QubesVm): raise IOError ("Error while copying {0} to {1}".\ format(src_template_vm.root_img, self.root_img)) if verbose: - print "--> Copying the template's root COW image:\n{0} ==>\n{1}".\ - format(src_template_vm.rootcow_img, self.rootcow_img) + print "--> Copying the template's clean volatile image:\n{0} ==>\n{1}".\ + format(src_template_vm.clean_volatile_img, self.clean_volatile_img) # We prefer to use Linux's cp, because it nicely handles sparse files - retcode = subprocess.call (["cp", src_template_vm.rootcow_img, self.rootcow_img]) + retcode = subprocess.call (["cp", src_template_vm.clean_volatile_img, self.clean_volatile_img]) if retcode != 0: raise IOError ("Error while copying {0} to {1}".\ - format(src_template_vm.root_img, self.root_img)) + format(src_template_vm.clean_volatile_img, self.clean_volatile_img)) + if verbose: + print "--> Copying the template's volatile image:\n{0} ==>\n{1}".\ + format(self.clean_volatile_img, self.volatile_img) + # We prefer to use Linux's cp, because it nicely handles sparse files + retcode = subprocess.call (["cp", self.clean_volatile_img, self.volatile_img]) + if retcode != 0: + raise IOError ("Error while copying {0} to {1}".\ + format(self.clean_volatile_img, self.volatile_img)) if verbose: print "--> Copying the template's kernel dir:\n{0} ==>\n{1}".\ format(src_template_vm.kernels_dir, self.kernels_dir) @@ -816,6 +827,8 @@ class QubesTemplateVm(QubesVm): format(src_template_vm.appmenus_templates_dir, self.appmenus_templates_dir) shutil.copytree (src_template_vm.appmenus_templates_dir, self.appmenus_templates_dir) + # Create root-cow.img + self.commit_changes() def verify_files(self): if dry_run: @@ -847,6 +860,16 @@ class QubesTemplateVm(QubesVm): "VM private image file doesn't exist: {0}".\ format(self.private_img)) + if not os.path.exists (self.volatile_img): + raise QubesException ( + "VM volatile image file doesn't exist: {0}".\ + format(self.volatile_img)) + + if not os.path.exists (self.clean_volatile_img): + raise QubesException ( + "Clean VM volatile image file doesn't exist: {0}".\ + format(self.clean_volatile_img)) + if not os.path.exists (self.kernels_dir): raise QubesException ( "VM's kernels directory does not exist: {0}".\ @@ -858,6 +881,7 @@ class QubesTemplateVm(QubesVm): if dry_run: return + self.reset_volatile_storage() if not self.is_updateable(): raise QubesException ("Cannot start Template VM that is marked \"nonupdatable\"") @@ -866,6 +890,21 @@ class QubesTemplateVm(QubesVm): return super(QubesTemplateVm, self).start(debug_console=debug_console, verbose=verbose) + def reset_volatile_storage(): + assert not self.is_running(), "Attempt to clean volatile image of running Template VM!" + + print "--> Cleaning volatile image: {0}...".format (self.volatile_img) + if dry_run: + return + if os.path.exists (self.volatile_img): + os.remove (self.volatile_img) + + # We prefer to use Linux's cp, because it nicely handles sparse files + retcode = subprocess.call (["cp", self.clean_volatile_img, self.volatile_img]) + if retcode != 0: + raise IOError ("Error while copying {0} to {1}".\ + format(self.clean_volatile_img, self.volatile_img)) + def commit_changes (self): assert not self.is_running(), "Attempt to commit changes on running Template VM!" @@ -890,6 +929,8 @@ class QubesTemplateVm(QubesVm): attrs["appvms_conf_file"] = self.appvms_conf_file attrs["netvms_conf_file"] = self.netvms_conf_file attrs["standalonevms_conf_file"] = self.standalonevms_conf_file + attrs["clean_volatile_img"] = self.clean_volatile_img + attrs["rootcow_img"] = self.rootcow_img return attrs class QubesCowVm(QubesVm): @@ -927,8 +968,6 @@ class QubesCowVm(QubesVm): self.template_vm = template_vm - self.swapcow_img = dir_path + "/" + default_swapcow_img - def set_updateable(self): if self.is_updateable(): return @@ -1001,6 +1040,9 @@ class QubesCowVm(QubesVm): raise IOError ("Error while copying {0} to {1}".\ format(template_root, self.root_img)) + # Create volatile.img + self.reset_volatile_storage() + def verify_files(self): if dry_run: return @@ -1034,45 +1076,35 @@ class QubesCowVm(QubesVm): raise QubesException("VM is already running!") if not self.is_updateable(): - self.reset_cow_storage() + self.reset_volatile_storage() - self.reset_swap_cow_storage() + self.reset_volatile_storage() return super(QubesCowVm, self).start(debug_console=debug_console, verbose=verbose, preparing_dvm=preparing_dvm) - def reset_cow_storage (self): + def reset_volatile_storage(): + assert not self.is_running(), "Attempt to clean volatile image of running VM!" - print "--> Resetting the COW storage: {0}...".format (self.rootcow_img) + # Only makes sense on template based VM + if not self.template_vm: + return + print "--> Cleaning volatile image: {0}...".format (self.volatile_img) if dry_run: return - # this is probbaly not needed, as open (..., "w") should remove the previous file - if os.path.exists (self.rootcow_img): - os.remove (self.rootcow_img) - - - f_cow = open (self.rootcow_img, "w") - f_root = open (self.template_vm.root_img, "r") - f_root.seek(0, os.SEEK_END) - f_cow.truncate (f_root.tell()) # make empty sparse file of the same size as root.img - f_cow.close () - f_root.close() - - def reset_swap_cow_storage (self): - print "--> Resetting the swap COW storage: {0}...".format (self.swapcow_img) - if os.path.exists (self.swapcow_img): - os.remove (self.swapcow_img) - - f_swap_cow = open (self.swapcow_img, "w") - f_swap_cow.truncate (swap_cow_sz) - f_swap_cow.close() + if os.path.exists (self.volatile_img): + os.remove (self.volatile_img) + # We prefer to use Linux's cp, because it nicely handles sparse files + retcode = subprocess.call (["cp", self.template_vm.clean_volatile_img, self.volatile_img]) + if retcode != 0: + raise IOError ("Error while copying {0} to {1}".\ + format(self.template_vm.clean_volatile_img, self.volatile_img)) def remove_from_disk(self): if dry_run: return - subprocess.check_call ([qubes_appmenu_remove_cmd, self.name]) shutil.rmtree (self.dir_path) @@ -1536,14 +1568,6 @@ class QubesAppVm(QubesCowVm): return conf - def start(self, debug_console = False, verbose = False, preparing_dvm = False): - if dry_run: - return - - self.reset_swap_cow_storage() - - return super(QubesAppVm, self).start(debug_console=debug_console, verbose=verbose, preparing_dvm=preparing_dvm) - class QubesVmCollection(dict): """ A collection of Qubes VMs indexed by Qubes id (qid) diff --git a/dom0/qvm-tools/qvm-prefs b/dom0/qvm-tools/qvm-prefs index 743de112..8ee3abdf 100755 --- a/dom0/qvm-tools/qvm-prefs +++ b/dom0/qvm-tools/qvm-prefs @@ -46,7 +46,7 @@ def do_list(vm): print fmt.format ("root COW img", vm.rootcow_img) if vm.is_appvm(): print fmt.format ("root img", vm.template_vm.root_img) - print fmt.format ("root COW img", vm.rootcow_img) + print fmt.format ("root volatile img", vm.volatile_img) print fmt.format ("private img", vm.private_img) diff --git a/dom0/restore/qubes_prepare_saved_domain.sh b/dom0/restore/qubes_prepare_saved_domain.sh index 1d1bf0c3..a1bf0770 100755 --- a/dom0/restore/qubes_prepare_saved_domain.sh +++ b/dom0/restore/qubes_prepare_saved_domain.sh @@ -59,5 +59,5 @@ if ! xm save $1 $2 ; then fi rm -f $QMEMMAN_STOP cd $VMDIR -tar -Scvf saved_cows.tar root-cow.img swap-cow.img +tar -Scvf saved_cows.tar volatile.img echo "DVM savefile created successfully." diff --git a/dom0/restore/qubes_restore.c b/dom0/restore/qubes_restore.c index 3788fb66..3afd1472 100644 --- a/dom0/restore/qubes_restore.c +++ b/dom0/restore/qubes_restore.c @@ -239,10 +239,10 @@ char *build_dvm_ip(int netvm, int id) return buf; } -#define NAME_PATTERN "/root-cow.img" +#define NAME_PATTERN "/volatile.img" // replaces the unique portions of the savefile with per-dvm values // returns the name of VM the savefile was taken for -// by looking for /.../vmname/root-cow.img +// by looking for /.../vmname/volatile.img // normally, it should be "templatename-dvm" char *get_vmname_from_savefile(int fd) { @@ -258,7 +258,7 @@ char *get_vmname_from_savefile(int fd) name = strstr(buf + 20, NAME_PATTERN); if (!name) { fprintf(stderr, - "cannot find 'root-cow.img' in savefile\n"); + "cannot find 'volatile.img' in savefile\n"); exit(1); } *name = 0;