Below is an overview of the lifecycleof a vdev, from initialization to termination.
For examples of source code that look after each stage of a vdev's lifecycle, see the next chapter: The Basics: vdev trace.
The life of a vdev can be divided into two stages:
The figure below presents the lifecycle of a vdev. Notice the Startup/Running demarcation, identified by the VDEV_CTRL_GUEST_CONFIGURED callback.
When you write a vdev, you must include code to identify the demarcation between your vdev's startup stage and its running stage, because some functions may be called only during the startup stage, when the qvm process instance is assembling the VM, including the vdevs. Others may be called only after the startup stage has completed, when the system is running.
When the qvm process is completing the vdev and VM configuration, it will issue callbacks that your vdev can use to identify when the startup stage ends and the running stage has begun:
When a qvm process instance is in its startup stage (i.e., assembling and configuring a VM), it is single-threaded: it runs with only a main thread executing code. This means that your vdev can skip some tasks that are required after the VM machine is ready and the guest has started executing. For example, your vdev doesn't need to call gasp_lock() and gasp_unlock() around other calls to gasp_*() functions (see Guest memory regions and the Virtual Device Developer's API Reference gasp.h chapter).
When the guest starts executing, it requires at least one vCPU, which adds a vCPU thread, so the qvm process instance must run at least two threads: the main thread and the vCPU thread. This means that your vdev is running in a multi-threaded environment and must use lock functions such as gasp_lock() to ensure that no other entity in your VM (e.g., another vdev) interferes with your vdev's resources.