The problem you're addressing (if any)
Disposable vms are very useful for the intent they're made, however one drawback they have is that usage is not instant as other appvms, and one need to wait for it to load before using it (varying from 7-20s depending on hardware)
Describe the solution you'd like
It would be great if there was an option to "preload" the dispvm (quantity to preload would be defined by the user and limited by hardware dspecs) so whenever you need to use a dispvm the target program launches automatically.
Where is the value to a user, and who might that user be?
It would be a great benefit in terms of speed and convenience depending on how much the user relies on dispvms
Additional context
Currently behaviour would be preserved, if you launch a program for a dispvm using the qubes menu, each call would use a different preloaded dispvm, no reuse would be made. Also when one dispvm is "used", another one would be preloaded to keep the defined amount always ready.
Original description
Starting disposable VMs is faster than normal VMs, but it can often still take several seconds and be a noticeable delay in the user experience.
This proposes to solve this issue by keeping one or more disposable VMs always around runnning, but without qubes-guid started and thus "invisible".
When the user requests a disposable VMs, the system takes one of those cached disposable VMs, adjusts them if necessary and starts qubes-guid, and then starts another cached disposable VMs for the next request.
This allows instantaneously started DispVMs at the cost of losing 1.5-6 GB of RAM, which can be a good tradeoff at least for machines with >= 16GB RAM.
There are two ways of doing this: the most flexible way would be to support any DispVM usage by starting the appropriate service on the cached DVM, and there is an inflexible but faster way that pre-starts the application as well, but only supports a limited number of DispVM applications started from dom0 (typically a web browser and a terminal).
My code implements the "inflexible" way and offers two modes: a faster "separate" mode that keeps around a DispVM for each configured application, and a slower but less RAM hungry "unified" mode that keeps a DispVM with all the applications running, and kills the ones not needed at user request.
You can find the implementation at: https://github.com/qubesuser/qubes-core-admin/tree/insta_dvm
You'll need to create a configuration file in /etc/qubes/dvms like the one provided in the branch. The mode is chosen automatically depending on available RAM, but can be configured in /etc/qubes/cached-dvm-mode
The branch is missing packaging for qubes-start-cached-dvm and the dvms config file, systemd integration for starting it at boot, and making dom0 start menu entries use it.
It's also somewhat hackish overall and might need a rewrite in Python and adjustment to the new core code if shipped after that.
Initial implementation details
So, this task appeared much simpler than it really it, here is a breakdown of what must be discussed/defined (see QA), and what must be done to complete this task. I mixed some comments made by @marmarek and myself to attempt to create the scope of this issue, which is not yet finished and I will keep updating this comment.
Describe the solution you'd like
It would be great if there was an option to "preload" the dispvm (quantity to preload would be defined by the user and limited by hardware specs) so whenever you need to use a dispvm the target program launches automatically.
Relevant functions:
- API method:
qubes.api.admin.create_disposable()
- Validation:
qubes.vm.dispvm.DispVM.from_appvm()
- Storage:
qubes.vm.qubesvm.QubesVM.create_on_disk()
- Autostart:
qubes.vm.qubesvm.QubesVM.on_create_on_disk()
qubes.vm.dispvm.DispVM.from_appvm() seems to be the place to handle checks for the preloaded DispVM preference, in case it is bigger than 0, it should return one of the already preloaded DispVMs.
Preloaded DispVM management:
-
Preload DispVM per DispVM template:
- A process to control the creation of preloaded DispVMs (QA)
- On
qubes.vm.dispvm.DispVM.from_appvm() create the logic for returning the preloaded DispVM or let it return a new name.
- Add the preloaded qubes to a list, to not query every running DispVM that was created by that template that is already in use by the user for anything they want.
- Qubesd can be restarted during system runtime and it needs to rebuild the list.
- Qubes in the list should be marked somehow to be included in the list.
- Set the feature
internal=1
- The process controlling the preloaded DispVMs then calls
admin.vm.Start.
- Handle the event
domain-started with admin.vm.Pause.
-
When a Qrexec call targets a DispVM template or a preloaded domain has the event domain-unpaused emitted:
- Return one of the preloaded DispVMs from an available list.
- Remove the returned qube from the available list.
- Preload another DispVM for later use.
- Define when the nest DispVM should be preloaded, should it have a delay to not interfere with starting of the application of the preloaded DispVM user just got? Configurable delay is interesting, a value from 0-10 seconds seems appropriate. Check if this is a concern, maybe check available memory, total CPU cores or per qube vcpu (QA)
- Cleanup with
dispvm.cleanup() after the user closes the first application they started.
Trigger start of preloaded DispVMs:
- First batch should be triggered on boot, after qubes that have the
autostart=True preference (normal qubes should have higher precedence) to avoid memory hiccups of starting preloaded DispVMs but not being able to assign memory to sys-usb.
- Systemd service that doesn't start when kernel command-line has
qubes.skip_autostart (see systemctl cat qubes-vm@.service and /proc/cmdline)
- Internal API (see
internal. in qubes-core-admin/qubes/api/internal.py)
- Some qubes that require preloaded DispVMs only when powered on such as
qubes-builder can have startup/shutdown scripts to set the property on its DispVM template with admin.vm.property.Set. It is the simplest solution that doesn't involve creating dependencies on client qubes being running or not.
Resource management:
- If there is not enough memory to start the qube (qmemman would fail starting the qube), retry at a later time when more memory is available.
- For a later version, dynamically adjust number of pre-started disposables, which can also be 0, considering a system that has many qubes set to autostart.
Prevent incorrect user interaction with preloaded DispVM:
User needs to be prevented from interaction with "preloaded" disposables, so they really remain clean. This includes NOT showing them:
- In the menu
- As target in policy prompts (for example when user copies files)
- Possibly also some actions in domains widget should be inactive (hiding completely is probably a bad idea, as it skews view of the system memory)
- Not sure if qvm-run should also be prevented, I'm okay with not blocking it. And then, when it gets used, those things need to be undone.
For this, the feature internal=1 will be set. The domain will also be paused and when used, it will trigger domain-unpaused.
Tasks
Tasks:
With the information above, the following tasks seems appropriate:
Additional context
Currently behaviour would be preserved, if you launch a program for a dispvm using the qubes menu, each call would use a different preloaded dispvm, no reuse would be made. Also when one dispvm is "used", another one would be preloaded to keep the defined amount always ready.
In other words, every call to a DispVM template that would use it as a base to create a DispVM should consider if the DispVM template has the preference to preload set and use the preloaded DispVMs.
Pull requests
Details
Core:
GUI:
Global feature:
Late GUID:
Late GUID (don't wait):
Early GUID (wait):
Qmemman:
Memory threshold:
Installer:
Deferred netvm:
Dependency switch:
Backup:
Benchmark:
Site documentation:
Windows:
Autostart refill:
Speed optimization:
Misc:
Issues
Details
Done:
Important and sorted by priority:
Less important:
The problem you're addressing (if any)
Disposable vms are very useful for the intent they're made, however one drawback they have is that usage is not instant as other appvms, and one need to wait for it to load before using it (varying from 7-20s depending on hardware)
Describe the solution you'd like
It would be great if there was an option to "preload" the dispvm (quantity to preload would be defined by the user and limited by hardware dspecs) so whenever you need to use a dispvm the target program launches automatically.
Where is the value to a user, and who might that user be?
It would be a great benefit in terms of speed and convenience depending on how much the user relies on dispvms
Additional context
Currently behaviour would be preserved, if you launch a program for a dispvm using the qubes menu, each call would use a different preloaded dispvm, no reuse would be made. Also when one dispvm is "used", another one would be preloaded to keep the defined amount always ready.
Original description
Starting disposable VMs is faster than normal VMs, but it can often still take several seconds and be a noticeable delay in the user experience.
This proposes to solve this issue by keeping one or more disposable VMs always around runnning, but without qubes-guid started and thus "invisible".
When the user requests a disposable VMs, the system takes one of those cached disposable VMs, adjusts them if necessary and starts qubes-guid, and then starts another cached disposable VMs for the next request.
This allows instantaneously started DispVMs at the cost of losing 1.5-6 GB of RAM, which can be a good tradeoff at least for machines with >= 16GB RAM.
There are two ways of doing this: the most flexible way would be to support any DispVM usage by starting the appropriate service on the cached DVM, and there is an inflexible but faster way that pre-starts the application as well, but only supports a limited number of DispVM applications started from dom0 (typically a web browser and a terminal).
My code implements the "inflexible" way and offers two modes: a faster "separate" mode that keeps around a DispVM for each configured application, and a slower but less RAM hungry "unified" mode that keeps a DispVM with all the applications running, and kills the ones not needed at user request.
You can find the implementation at: https://github.com/qubesuser/qubes-core-admin/tree/insta_dvm
You'll need to create a configuration file in /etc/qubes/dvms like the one provided in the branch. The mode is chosen automatically depending on available RAM, but can be configured in /etc/qubes/cached-dvm-mode
The branch is missing packaging for qubes-start-cached-dvm and the dvms config file, systemd integration for starting it at boot, and making dom0 start menu entries use it.
It's also somewhat hackish overall and might need a rewrite in Python and adjustment to the new core code if shipped after that.
Initial implementation details
So, this task appeared much simpler than it really it, here is a breakdown of what must be discussed/defined (see QA), and what must be done to complete this task. I mixed some comments made by @marmarek and myself to attempt to create the scope of this issue, which is not yet finished and I will keep updating this comment.
Describe the solution you'd like
It would be great if there was an option to "preload" the dispvm (quantity to preload would be defined by the user and limited by hardware specs) so whenever you need to use a dispvm the target program launches automatically.
Relevant functions:
qubes.api.admin.create_disposable()qubes.vm.dispvm.DispVM.from_appvm()qubes.vm.qubesvm.QubesVM.create_on_disk()qubes.vm.qubesvm.QubesVM.on_create_on_disk()qubes.vm.dispvm.DispVM.from_appvm()seems to be the place to handle checks for the preloaded DispVM preference, in case it is bigger than 0, it should return one of the already preloaded DispVMs.Preloaded DispVM management:
Preload DispVM per DispVM template:
qubes.vm.dispvm.DispVM.from_appvm()create the logic for returning the preloaded DispVM or let it return a new name.internal=1admin.vm.Start.domain-startedwithadmin.vm.Pause.When a Qrexec call targets a DispVM template or a preloaded domain has the event
domain-unpausedemitted:dispvm.cleanup()after the user closes the first application they started.Trigger start of preloaded DispVMs:
autostart=Truepreference (normal qubes should have higher precedence) to avoid memory hiccups of starting preloaded DispVMs but not being able to assign memory tosys-usb.qubes.skip_autostart(seesystemctl cat qubes-vm@.serviceand/proc/cmdline)internal.inqubes-core-admin/qubes/api/internal.py)qubes-buildercan have startup/shutdown scripts to set the property on its DispVM template withadmin.vm.property.Set. It is the simplest solution that doesn't involve creating dependencies on client qubes being running or not.Resource management:
Prevent incorrect user interaction with preloaded DispVM:
User needs to be prevented from interaction with "preloaded" disposables, so they really remain clean. This includes NOT showing them:
For this, the feature
internal=1will be set. The domain will also be paused and when used, it will triggerdomain-unpaused.Tasks
Tasks:
With the information above, the following tasks seems appropriate:
dispvm-preloadanddispvm-preload-maxqubes.vm.dispvm.DispVM.from_appvm(), reply with a domain name that is preloaded when necessary.internaland pause qube)qvm-shutdownkills preloaded qubes, solving this)internalfeature and check if app-menus updateinternalfeature and check if qui-domains updatepreload-dispvm-maxfast and see if problems occurs, such as orphans (not in the feature list)preload-dispvm-maxfeature but not the other preload features.autostartevent)Additional context
Currently behaviour would be preserved, if you launch a program for a dispvm using the qubes menu, each call would use a different preloaded dispvm, no reuse would be made. Also when one dispvm is "used", another one would be preloaded to keep the defined amount always ready.
In other words, every call to a DispVM template that would use it as a base to create a DispVM should consider if the DispVM template has the preference to preload set and use the preloaded DispVMs.
Pull requests
Details
Core:
GUI:
Global feature:
Late GUID:
Late GUID (don't wait):
Early GUID (wait):
Qmemman:
Memory threshold:
Installer:
Deferred netvm:
Dependency switch:
Backup:
Benchmark:
Site documentation:
Windows:
Autostart refill:
Speed optimization:
Misc:
Issues
Details
Done:
qvm-run --allwill target preloaded disposables #10314Important and sorted by priority:
Less important: