EVMS Architecture OverviewTerminologyDifferent volume management implementations use different terms for their components. Sometimes a term used in one volume management scheme can mean something different in another volume management scheme. For example, consider the Multi-Disk (MD) driver, which implements RAID devices, and the Logical Volume Manager (LVM). MD takes in "disks" or "devices" and exports "volumes." A disk can be any block device, such as a physical disk, a partition, or a volume exported by MD. LVM takes in "physical volumes" (PVs) and exports "groups" and from groups it exports "logical volumes" (LVs). A PV can be any block device, such as a physical disk, a partition, a volume exported by MD, or an LV. Because of the different terms used to describe the components in different volume management schemes, we developed a set of terms specific to EVMS. The terms are intended to describe the various components of EVMS and not conflict with terms used by other volume management schemes.The following list defines general terms used with EVMS.
Sector The lowest level of addressability on a block device. This definition is in keeping with the standard meaning found in other management systems. Logical Disk (or Disk)The ordered set of contiguous sectors that comprises or represents a physical device.Disk Segment (or Segment) An ordered set of physically contiguous sectors residing on a logical disk or other disk segment. The general analogy is to traditional disk partitions, such as DOS or OS/2®.Storage Region (or Region) An ordered set of logically contiguous sectors that might be physically contiguous. The underlying mapping can be to logical disks, disk segments, or other storage regions. For example, the "volumes" exported by MD and LVM are considered regions in the EVMS architecture. Storage ObjectAny memory structure in EVMS that is capable of being a block device. Feature ObjectA logically contiguous address space created from one or more disks, segments, regions, or other feature objects through the use of an EVMS feature. Storage Container (or Container)A collection of storage objects. Storage containers provide a re-mapping of the collection into a new set of storage objects that the storage container exports. The appropriate analogy is to other volume groups, such as in AIX®, and Linux LVM. Logical Volume (or Volume)A mountable storage object. EVMS Logical Volume (or EVMS Volume)A mountable storage object that is comprised of one or more EVMS feature objects. Compatibility Logical Volume (or Compatibility Volume)A mountable storage object that does not contain any EVMS feature objects. Many plug-ins in EVMS provide support for the capabilities of other volume management schemes. Volumes that are designated as "compatibility" are insured to be backwards compatible to that particular scheme because they do not contain any EVMS native metadata. EVMS LayersEVMS defines a layered architecture where plug-ins in each layer create abstractions of the layer(s) below. EVMS also allows plug-ins to create abstractions of objects within the same layer. The following list defines these layers from the bottom up. Logical Device ManagersThe first layer is the logical device managers. These plug-ins communicate with the hardware device drivers to create the first EVMS objects. Currently, all local devices (most IDE and SCSI disks) are handled by a single plug-in. Future releases of EVMS might have additional device managers to do network device management, such as for disks on a SAN (storage area network). Segment ManagersThe second layer is the segment managers. In general, these plug-ins handle the segmenting, or partitioning, of disk drives. These engine components can replace programs, such as fdisk and diskdruid, and the kernel component can replace the in-kernel disk partitioning code. Segment managers can also be "stacked," meaning that one segment manager can take input from another segment manager. Currently, the only plug-in in this layer is the Default Segment Manager. This plug-in handles the DOS partitioning scheme (the MBR (Master Boot Records) and the (EBR) Extended Boot Records). This scheme is traditionally used by Linux™. The plug-in also handles some special cases that arise with OS/2 partitions. In the future additional segment managers might handle additional partitioning schemes. Region ManagersThe third layer is the region managers. This layer is intended to provide a place for plug-ins that ensures compatibility with existing volume management schemes in Linux or other operating systems. Region managers are intended to model systems that provide a logical abstraction above disks or partitions.Like the segment managers, region managers can also be stacked. Therefore, the input object to a region manager can be a disk, a segment, or another region. There are currently four region manager plug-ins in EVMS. The first is the LVM plug-in that provides compatibility with the Linux LVM and allows the creation of volume groups or containers and logical volumes or regions. Two more plug-ins are the AIX and OS/2 region managers. The AIX LVM is very similar in functionality to the Linux LVM because it uses volume groups and logical volumes. Currently there is only kernel support for the AIX plug-in. The OS/2 plug-in provides compatibility with volumes created under OS/2. Unlike the Linux and AIX LVMs, the OS/2 LVM is based on the linear linking of disk partitions. The fourth region manager plug-in is the Multi-Disk (MD) plug-in for RAID. This plug-in provides RAID levels linear, 0, 1, 1+0, 4, and 5 in software. The ability to stack region managers allows combinations of RAID and LVM. For instance, a stripe set (RAID 0) could be used as a PV in LVM, or two LVM LVs could be mirrored using RAID 1. EVMS FeaturesThe fourth layer is the EVMS features. EVMS features add functionality to objects in the lower layers. For example, the Drive Linking feature can take in objects from the lower layers and export them as a single, large object. Like segment managers and region managers, EVMS features can also be stacked. Therefore, the input object to a feature can be a disk, a segment, a region, or another feature object. The following diagram illustrates the layers in the EVMS architecture.EVMS Engine Architecture OverviewThe Engine is a shared object with external APIs that user interfaces call. The Engine also has an interface for communicating with the user-space plug-ins. The Engine converts the initiating call of the external APIs into the appropriate calls to the plug-ins.Engine LayersThe Engine supports the EVMS architecture layers by using File System Interface Modules (FSIM). An FSIM provides an interface to the file system's utilities, such as mkfs, fsck, expanding the file system, and shrinking the file system. FSIMs only operate on volumes.Data StructuresThe Engine models uses various data structures to model the configuration of the system. Plug-ins create, view, and modify the data structures. No changes are committed to the disk(s) until the user selects to commit changes. This implementation allows the user to play "What if?" without actually changing the configuration of the system. It is important that plug-ins adhere to this principle. A plug-in should not write any data to disk except on the call to the plug-in's commit_changes() function. The Engine uses a variety of data structures to accomplish its work. The three major data structures (storage_object_t, storage_container_t, and logical_volume_t) are described below. The remaining data structures are described within their contexts later this guide. storage_object_tThe main structure used in the Engine is the storage_object_t. The storage_object_t contains information about a storage object.
typedef struct storage_object_s {
object_handle_t app_handle; /* External API handle for this structure; */
/* used only by the Engine */
object_type_t object_type; /* SEGMENT, REGION, DISK ,... */
data_type_t data_type; /* DATA_TYPE, META_DATA_TYPE, FREE_SPACE_TYPE */
plugin_record_t * plugin; /* Plug-in record of plug-in that manages this object */
struct storage_container_s * producing_container; /* storage_container that produced this object */
struct storage_container_s * consuming_container; /* storage_container that consumed this object */
dlist_t parent_objects; /* List of parent objects, filled in by parent */
dlist_t child_objects; /* List of child objects, filled in by owner */
struct storage_object_s * associated_object; /* Object to which this object is associated */
u_int32_t flags; /* Defined by SOFLAG_???? in common.h */
lba_t start; /* Relative starting block of this object */
sector_count_t size; /* Size of object in sectors */
struct logical_volume_s * volume; /* Volume which comprises this object */
evms_feature_header_t * feature_header; /* Copy of EVMS storage object's top feature header */
/* read in by Engine */
/* NULL if it does not exist */
geometry_t geometry; /* Optional geometry of the object */
void * private_data; /* Optional plug-in's data for the object */
void * consuming_private_data;/* Optional consuming plug-in's data for the object */
char name[EVMS_NAME_SIZE+1];/* Object's name, filled in by owner */
} storage_object_t;Disks, segments, regions, and EVMS objects (Feature objects) are all storage objects. Each is represented with a storage_object_t .storage_container_tA storage container is represented by a storage_container_t. Storage containers consume storage objects and produce storage objects. For example, the EVMS implementation of LVM uses a storage container to represent an LVM group. The storage container takes in storage objects that represent the LVM physical volumes (PVs) that comprise the group and exports storage objects that represent the LVM logical volumes (LVs) that are exported from the group. typedef struct storage_container_s {
object_handle_t app_handle; /* External API handle for this structure; */
/* used only by the Engine */
plugin_record_t * plugin; /* Plug-in record of the plug-in that manages */
/* this container */
/* Filled in by the plug-in during discover */
/* or create_container() */
uint flags; /* Defined by SCFLAG_???? in common.h */
dlist_t objects_consumed; /* List of objects in this container */
/* The Engine allocate_container API will create the */
/* dlist_t anchor for this list. */
/* The plug-in inserts storage_object_t structures */
/* into this list when it assigns objects to this */
/* container. */
dlist_t objects_produced; /* List of objects produced from this container, */
/* including free space objects */
/* The Engine allocate_container API will create the */
/* dlist_t anchor for this list. */
/* The plug-in inserts storage_object_t structures */
/* into this list when it produces objects from this */
/* container. */
sector_count_t size; /* Total size of all objects on the objects_produced list */
void * private_data; /* Optional plug-in data for the container */
char name[EVMS_NAME_SIZE+1]; /* Container name, filled in by the plug-in */
} storage_container_t;logical_volume_tThe logical_volume_t contains information about a logical volume.
typedef struct logical_volume_s {
object_handle_t app_handle; /* External API handle for this structure; */
/* used only by the Engine */
plugin_record_t * file_system_manager; /* Plug-in record of the File System Interface */
/* Module that handles this volume */
plugin_record_t * original_fsim; /* Plug-in record of the File System Interface */
/* Module that was initially discovered for this volume */
char * mount_point; /* Dir where the volume is mounted, NULL if not mounted */
sector_count_t fs_size; /* Size of the file system */
sector_count_t min_fs_size; /* Minimum size for the file system */
sector_count_t max_fs_size; /* Maximum size for the file system */
sector_count_t original_vol_size; /* Size of the file system before expand or shrink */
sector_count_t vol_size; /* Size of the volume */
sector_count_t max_vol_size; /* Maximum size for the volume */
struct logical_volume_s * associated_volume; /* Volume to which this volume is associated */
/* by an associative feature */
option_array_t * mkfs_options; /* Options for mkfs */
option_array_t * fsck_options; /* Options for fsck */
option_array_t * defrag_options; /* Options for defrag */
storage_object_t * object; /* Top level storage_object_t for the volume */
uint minor_number; /* Volume's minor number */
u_int64_t serial_number; /* Volume's serial number */
u_int32_t flags; /* Defined by VOLFLAG_???? defines */
void * private_data; /* Private data pointer for FSIMs. */
char name[EVMS_VOLUME_NAME_SIZE+1];
/* Volume name, filled in by the Engine */
} logical_volume_t;The DLIST Library[Add description of the DLIST library and how it is used by the Engine.]Data Structure Example[Add a description of the diagram.]Source CodeAll of the source code for the Engine, user space plug-ins, and user interfaces is in the engine directory.
Contents of Engine DirectoryDirectoryContentsengine/dlist/ Source code for the DLIST list handling library engine/Engine/ Source code for the Engine engine/include/Include files for the Engine, plug-ins, and user interfaces engine/libNot used engine/man/ Man pagesengine/Plugins/ Source for user space plug-ins Each plug-in is in its own directory. engine/UserInterface/ Source for the user interfaces Each user interface is in its own directory.
The current content of the Plugins directory is:
Contents of Plugin DirectoryDirectory ContentsaixregmgrAIX Region Manager plug-in bbrBad Block Relocation Feature plug-indefsegmgrDefault Segment Manager plug-indrivelinkDrive Link Feature plug-inlocaldskmgrLocal Device Manager plug-inlvmregmgr LVM Region Manager plug-inlvmsegmgrNot usedmdregmgrMD Region Manager plug-ins (linear, RAID0, RAID1, RAID4/5) os2regmgrOS/2 Region Manager plug-inos2segmgrNot useds390segmgrSystem 390 Segment Manager plug-insnapshotSnapshot Feature plug-in
When you create your new plug-in, you can make a new directory in the Plugins directory for your new plug-in, or you can build your plug-in in another directory. If you decide to build your plug-in outside of the Plugins directory, be sure you include the engine header files when you build. If you have previously built and installed the engine code, the header files were installed in $(prefix)/evms. $(prefix) is set with the option to engine/configure. The default setting for $(prefix) is /usr/local. Loading Plug-ins When the engine code is installed, the plug-ins are installed in $(prefix)/lib/evms. $(prefix) is set with the option to engine/configure. The default setting for $(prefix) is /usr/local. When the Engine is opened, it attempts to load each of the files in $(prefix)/lib/evms. A user space plug-in is built into a shared object. The shared object must export a variable named evms_plugin_records. evms_plugin_records is the address of a NULL terminated array of pointers to plugin_record_t structures.
typedef struct plugin_record_s {
object_handle_t app_handle; /* External API handle for this structure; */
/* used only by the Engine */
plugin_id_t id; /* Plug-in's ID */
evms_version_t version; /* Plug-in's version */
evms_version_t required_api_version; /* Version of the Engine plug-in API */
/* that the plug-in requires */
so_record_t * so_record; /* Record for the shared object from */
/* which the plug-in was loaded */
char * short_name;
char * long_name;
char * oem_name;
union {
struct plugin_functions_s * plugin;
struct fsim_functions_s * fsim;
} functions;
struct container_functions_s * container_functions; /* Optional container functions if the */
/* plug-in supports containers */
} plugin_record_t;The shared object can contain more than one plug-in. The Engine will walk the array of pointers to plugin_record_t structures and attempt to load the plug-in specified in each plugin_record_t. The MD Region Manager is an example. libmdregmgr-0.1.0.so contains the plug-ins to handle various personalities of MD: linear, RAID0, RAID1, and RAID4/5.The Engine first validates the plugin_record_t. It must have an ID. Part of the ID contains the plug-in type. The macros for setting and getting plug-in ID fields, as well as the valid types are defined in linux/include/linux/evms/evms_common.h. The Engine validates that the ID has a valid type. The plugin_record_t must have pointers filled in for the short_name, long_name, and oem_name. The plugin_record_t must have a pointer to its function table, either a plugin_functions_t table or a fsim_functions_t table if the plug-in is an FSIM. If a plug-in manages storage objects, meaning that it is not an FSIM, the plugin_functions_t table must contain entries for the following functions: setup_evms_plugin(), discover(), add_sectors_to_kill_list(), commit_changes(), read(), and write(). If a plug-in manages logical volumes, meaning that it is an FSIM, the fsim_functions_t table must contain entries for the functions setup_evms_plugin(), and is_this_yours(). The Engine will provide default functions for the remaining entries in the function table if a plug-in does not supply them. Most default entries return ENOSYS. Once the Engine knows it has a valid plugin_record_t, it calls the plug-in's setup_evms_plugin() function. The Engine passes the mode in which the Engine was opened and a pointer to an engine_functions_t, a table of the Engine's service functions. On setup_evms_plugin(), the plug-in does any initialization, including saving the pointer to the engine_functions_t, and returns an error code to the Engine. If the plug-in returns a non-zero value, that means the plug-in failed setup, and the Engine will abort loading the plug-in. For the definitive process of how plug-ins are loaded, see the source in engine/Engine/dload.c.