Aadeshveer's Blog

A summer with QEMU

Day 1

7 March 2026 (~2hr)

Today's Target: My first target will not be diving into code but understanding migration


Day 2

8 March 2026 (~3hrs)

Today's Target: Today we will read documentation of mapped-ram migration and if time permits move to reading actual code


Day 3

9 March 2026 (~45 mins)

Today's Target: First step will be reading the code actually using userfaultfd, then if time remains we shall see what happens


Day 4

10 March 2026(~3 hrs)

Today's Target: Analyse the qemu thread API and look into use of concurrency


Days in between

I spent a few days in between to write a formal proposal and sent it to mentor for review. Sorry I did not write anything in the log but my proposal more or less has it so I will just put that here

Abstract

The present implementation of snapshot load, loads all the guest data on QEMU instance before beginning the process. This is not necessary and can be improved on using the ideas from postcopy and mapped-ram migration. Loading the device data and letting the guest run instantly is a feasible option, given we keep supplying it with the pages it needs. This will be achieved using userfaultfd in Linux to detect page fault by the guest, which tells us what page to supply. Coupling it with another eager loading thread this project aims to substantially speed up the snapshot loading process in QEMU.

About me

I am a sophomore in the Computer Science and Engineering Department at IIT Bombay (GPA 9.47). This semester, I took the core Operating Systems course and found the concepts of emulation and virtualization quite interesting. I am interested in systems and low-level optimization, and find fun in navigating through massive C/C++ codebases. One of my recent experiences was with llama.cpp, a high-performance LLM inference engine, where I first got introduced to open source. I worked on optimizing CUDA kernels for SSM scan and cum sum, successfully getting a 2-3x speedup in each(If you want to read more about my wrestle with it do look up my blog where I posted my logs) On the crossection of my newfound urge to contribute to open source and curiosity to learn more about virtualization, exists this project. I would love the opportunity to learn more about virtualization hands on and work with the great community of QEMU, from where I can learn a lot as a student. GitHub github.com/Aadeshveer Blog aadeshveer.bearblog.dev

The problem

Current implementation of snapshot load, uses the simple method of loading in all VM data into the QEMU instance for it to start. Though it is usually acceptable considering the case when the user wants to quickly open multiple snapshots it can be quite slow. This load is not necessary and by loading in only the required data at t = 0 and loading in rest of data later we can improve on speed of loading. This essentially will require use of userfaultfd provided by linux to get to know when the guest hits in a page fault and needs some data with high priority.

Existing Infrastructure

Current infrastructure has post-copy and pre-copy migration implemented(along with mapped ram feature). The logic used in this process will be very useful for correctly implementing what can be said as the inverse of migration. Most of the implementation regarding mapped ram and postcopy exist in the migration directory of source code. There already exist wrappers on userfaultfd in the file include/qemu/userfaultfd.h which can be used readily. Initial loading verification is already done in the qemu_loadvm_state_main (in migration/savevm.c), there needs to be a code divergence from here if fast snapshot load is enabled. Atomic wrappers like qatomic_and exist in include/qemu/atomic.h to implement bit maps

Proposed solution

Basic Idea

The basic idea to solve the problem which has partly been directed to in the project idea is the following:

Eagerness and multithreading

This needs to be conducted eagerly, loading pages even when the guest doesn’t need them, to be finished with the load procedure as soon as possible. The loading will have to be done by two threads, one that will eagerly keep loading in pages and other loads in the on demand pages. This architectural decision is based on the following points:

Bitmaps vs queues

Another design choice I spent time on was to use bitmap or linked list for managing memory.

How many bitmaps

On further exploration about how to keep thread 2 waiting till thread 1 uploads the pages it claims, it turns out using one bitmap is not enough. We need three states of a page, WAITING, UPLOADING, and UPLOADED. So we need atleast 2 bits for each datapoint and so 2 bitmaps. One bitmap will be 1 if the page needs to be loaded and the second will have 1 for pages that have been loaded.

Pseudocode solution

Set up the userfaultfd fill in bitmap_loaded for data with all zeros fill in bitmap_waiting for data with all ones load in the device data of the guest make the thread for on demand loading let the guest run

thread 1: ctr = 0 while (ctr < maxRAM) { if (atomic read and clear at ctr on bitmap_waiting) { // we need to load this page load the page(ctr); add 1 at ctr on bitmap_loaded } else { // page was already loaded continue; } } cleanup kill thread 2 exit()

thread 2: while (1) { fault_info = read(uffd); if (atomic read and clear at fault_info.address) { // we need to load this page load the page(fault_info.address) add 1 at fault_info.address on bitmap_loaded } else { // page is being loaded by thread 1 while (bitmap_loaded 0 at fault_info.address) yield(); } wake up the guest }

Projected timeline

Considering that my university exams will be conducted by end of April, I will begin actively working on the project right in May. As the next semester will start in mid July, I plan to be done with core programming and debugging by end of July. Thus, I might start working earlier in May on the coding tasks and keep a buffer over the timeline. Time commitment: 40 hours per week for first 6 weeks followed by 20 hours per week in last 6 weeks.

Community engagement(3 weeks)

I will try to participate in the mailing list, and contribute a few patches regarding documentation. During this period I plan on studying the internals of postcopy-ram.c and finalize the design with mentor before coding begins.

Core programming(6 weeks)

This period will be marked by major code implementation and raw coding, architecting the bare bones of the project

Week 1 (25th May - 31st May)

Begin with changes in migration/savevm.c to direct the code when fast snapshot load is activated. Mostly skeletal changes with declaration of functions, followed by implementation of few.

Week 2 (1st June - 7th June)

Continue with the simplistic implementation to get a running prototype for a very simple case. Error handling and other features can be added iteratively.

Week 3 (8th June - 14th June)

Get a toy VM actually loaded in controlled environment, for proof of concept. Get started with error handling

Week 4 (15th June - 21st June)

Continue adding error handling code for various unexpected run time exceptions

Week 5 (22nd June - 28th June)

Work on adding support for other features like huge pages etc.

Week 6 (29th June - 5th July)

Get the loading working on most of the cases

Mid term evaluation

Midterm deliverable will be a semi functional fast snapshot load

Testing, benchmarking and documentation

This period involves, building on the surrounding necessities of a good project and confirms it’s readiness to be used by masses

Week 7 (6th July - 12th July)

Week for polishing the code and begin testing.

Week 8 (13th July - 19th July)

Continue with extensive testing and patching any exceptions left along the coding process. Testing will revolve around disk faults, corrupted data and multi signal handling

Week 9 (20th July - 26th July)

Begin with benchmarking the new implementation over the old one to test for substantiality of improvements.

Week 10 (27th July - 2nd August)

Write up proper documentation for official docs, and try to add more in code comments for functions

Week 11 (3rd August - 9th August)

Continue with adding documentation and engaging with community for more reviews

Week 12 (10th August - 16th August)

Buffer week


Day 5

15 March 2026(~1hr)

Today's Target: Work on the reply/feedback by mentor to improve the proposal


Day 6

16 March 2026(~30mins)

Today's Target: Work on getting a first patch in qemu mailing list


Day 7

11 May 2026(~8 hrs)

Today's Target: Get qemu working and play with migration


Day 8

12 May 2026(~6 hrs)

Today's Target: Get used to qemu tracepoints and set up patches


Day 9

13 May 2026(~7hrs)

Today's Target: Continue toying with postcopy and mapped ram and look into postcopy-blocktime


Day 10

14 May 2026(~6hrs)

Today's Target: Continue the postcopy exploration and look into postcopy-blocktime


Day 11

15 May 2026(~5hrs)

Today's Target: Look into postcopy block time and try to migrate in a file from file uri and see how postcopy behaves


Day 12

16 May 2026(~4 hrs)

Today's Target: Decide point of divergence for fast snapshot load and again look into mapped ram support


Day 13

17 May 2026(~6hrs)

Today's Target: Finalise the divergence point and start thinking about week1


Day 14

18 May 2026(~7hrs)

Today's Target: Look deeply into mapped RAM


WORK PLAN

Points I think I miss

postcopy handle run HMP "info ramblock" Guest RAM, a few ROMs, vGPU vRAM (sometimes)


Day 15

23 May 2026(~9 hrs)

Target: Start some coding, trying to add stubs that will be filled later


Day 16

24 May 2026(~6hrs)

Target: Continue with filling in bmap and potentially move to step 2


Day 17

30 May 2026(~3hrs)

Target: Understand maped ram some more deeply starting trying to understand device states


Day 18

8 June 2026(~9hrs)

Target: Revise the logs to get back in field


Day 19

9 June 2026(~8hrs)

Target: Get done with step 1 and move to step 2


Day 20

10 June 2026(~5hrs)

Target: Complete step 2 basic implementation and try moving to step 3


Day 21

11 June 2026(~8hrs)

Target: Try completing step 2 and try having a definitive solution to the channel copy problem


Day 22

12 June 2026(~9hrs)

Target: Complete step 2 and step 3 so that we have a running VM


Day 23

13 June 2026(~8hrs)

Target: Resolve the reading 0 value bug and get the basic VM running


Day 24

14 June 2026(~8hrs)

Target: Read more about how postcopy manages cleanup and go on with step 5 so we have a proper cleanup


Day 25

15 June 2026(~7hrs)

Target: Add tracepoints and maybe look into how to separate the patches


Day 26

16 June 2026(~8hrs)

Target: Update the page offset calculations and add proper state management


Day 27

17 June 2026(~8hrs)

Target: Add proper state management and work on RFC cover letter


Day 28

18 June 2026(~5hrs)

Target: Look into adding postcopy blocktime support


Day 29

19 June 2026(~4hrs)

Target: Verify blocktime support


Day 30

22 June 2026(~2hrs)

Target: Look into huge pages


Day 31

23 June 2026(~5hrs)

Target: Work on RFC feedback


Day 32

24 June 2026(~5hrs)

Target: Work on RFC feedback


Day 33

25 June 2026(~6hrs)

Target: Continue working on RFC feedback and move to the TODOs


Day 34

26 June 2026(~6hrs)

Target: Work on RFC, proper error handling


Day 35

27 June 2026(~2hrs)

Target: Keep working on RFC v2 and look into hugepages support


Day 36

28 June 2026(~6hrs)

Target: Keep working on RFC v2 and look into hugepages support


Day 37

29 June 2026(~7hrs)

Target: Complete minor style points on the v2 and look into tests


Day 38

30 June 2026(~6hrs)

Target: We can go deeper into tests


Day 39

1 July 2026(~4hrs)

Target: Work on hugepages support


Day 40

5 July 2026(~3hrs)

Target: Working on documentation

Fast Snapshot Load

Overview

Fast snapshot load is an extension of the postcopy migration feature to disk loads.

Unlike a usual snapshot load, which requires all VM data (RAM as well as device states) to be loaded into host RAM from the snapshot file for the guest to run, fast snapshot load uses postcopy infrastructure to load in only the required device states and load RAM pages on demand. The idea is to start the guest and serve its page faults on the go, reducing the perceived resume time for large snapshots.

Architecture

This feature combines postcopy migration and mapped-ram capabilities to load RAM pages on demand. It is done by catching guest faults using Linux userfaultfd and loading the page by calculating the offset of its location in the snapshot file using mapped-ram capabilities.

Fault Thread

The fault thread uses Linux userfaultfd to catch page faults caused by guest and directly load the page from the snapshot file. It is very similar to network postcopy fault thread, with primary difference being it loads pages directly by reading from the snapshot file.

Eager Thread

Eager thread iterates over all pages in RAM and loads each page not yet loaded by fault thread. It is required as unlike network postcopy where majority of RAM has already been loaded via precopy, here entire RAM is waiting to be loaded. If there is no eager loading thread each page will only be loaded when it is required by guest. In case there are some background pages that are never/rarely accessed by guest, the system will be locked in migration state indefinitely.

Synchronization

In order to make sure both of these threads do not load the same page twice potentially overwriting and corrupting user RAM, a bitmap is used (RAMBlock->pending_bmap) which tracks the pages claimed to be loaded by threads. This prevents race condition when one thread is loading the page and other one tries to do the same.

Usage

Simply enable mapped-ram and postcopy-ram capabilities on the destination:

migrate_set_capability mapped-ram on
migrate_set_capability postcopy-ram on

Use a file: URI for migration:

migrate_incoming file:/path/to/snapshot/file

Day 41

6 July 2026(~3hrs)

Target: Start looking into multifd support


Day 42

7 July 2026(~5hrs)

Target: Work on reading about multifd and network postcopy


Day 43

8 July 2026(~3hrs)

Target: Work comments about RFC v2


Day 44

9 July 2026(~4hrs)

Target: Implement changes as suggested in RFC v2 comments


Day 45

10 July 2026(~2hrs)

Target: Implement changes as suggested in RFC v2 comments


Day 46

11 July 2026(~4hrs)

Target: Decide on unexpected features

CAPABILITY What to do
MIGRATION_CAPABILITY_XBZRLE Blocked by mapped ram
MIGRATION_CAPABILITY_RDMA_PIN_ALL Reading about RDMA seems network specific, so most likely will not be allowed cause of mapped ram
MIGRATION_CAPABILITY_AUTO_CONVERGE Strictly network thing, docs say it just throttles down guest not affecting us
MIGRATION_CAPABILITY_EVENTS Why is this a capability? and I think most stuff wont work without it? Should be covered
MIGRATION_CAPABILITY_POSTCOPY_RAM NULL
MIGRATION_CAPABILITY_X_COLO Reading about it, this is about running two VMs identically in case one fails, again network thing should not affect us. Docs say migration never fails etc, but we dont have a source and it should automatically fail for file incoming URI
MIGRATION_CAPABILITY_RELEASE_RAM Not affecting file migration so no need to stop it
MIGRATION_CAPABILITY_RETURN_PATH Here too I think return path should itself throw error for file migration
MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER I think this can be supported and might even be supported so we wont need to disable it
MIGRATION_CAPABILITY_MULTIFD This is one we need to disable, we can work on supporting it later
MIGRATION_CAPABILITY_DIRTY_BITMAPS I am sure we currently wont support dirty bitmaps as this should be block migration but the question is it allowed on file migration, maybe we can even check, I tried running it and it was successful, that is surprising, let's try if our code works and it does, so I dont think we should do anything about it
MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME Explicitly allowed
MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE I think this should not be explicityly disallowed too
MIGRATION_CAPABILITY_X_IGNORE_SHARED Should not be explicitly allowed/disallowed, looks fine as active
MIGRATION_CAPABILITY_VALIDATE_UUID Not something that should break in our case
MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT This seems for outgoing migration, should not affect incoming
MIGRATION_CAPABILITY_ZERO_COPY_SEND Looks like something enabled by default
MIGRATION_CAPABILITY_POSTCOPY_PREEMPT Disallow I guess, because otherwise extra thread is launched, in a way this already exists
MIGRATION_CAPABILITY_SWITCHOVER_ACK For switching from precopy to postcopy which we are anyway not doing
MIGRATION_CAPABILITY_DIRTY_LIMIT Doesnt seem to really affect us
MIGRATION_CAPABILITY_MAPPED_RAM NULL
MIGRATION_CAPABILITY__MAX Just the end

Day 47

13 July 2026(~4hrs)

Target: Continue on running network postcopy and use of multifd


Day 48

14 July 2026(~5hrs)

Target: Send out formal patch set


Day 49

15 July 2026(~6hrs)

Target: Back to reading about network postcopy


Day 50

17 July 2026(~5hrs)

Target: Network postcopy and potentially think more about ram_save_host_page


Day 51

22 July 2026(~2hrs)

Target: work on the v3 review


Day 52

24 July 2026(~2hrs)

Target: work on the v3 review


Day 53

25 July 2026(~2hrs)

Target: work on the v3 review


Day 54

26 July 2026(~3hrs)


Day 55

27 July 2026(~3hrs)


Day 56

28 July 2026(~3hrs)

Target: Complete v3 review points and prep for v4


Day 57 & 58

29 & 30 July 2026(~3hrs)

Target: Testing v4


Day 59

8 August 2026(~1hr)

Target: Improve on v4


Day 60

12 August 2026(~2hrs)

Target: Improve on v4


Day 61

16 August 2026(~3hrs)

Target: Finalize a v5

Running TODOS

Questions

All resolved

Resolved questions