Skip to content

VDO

Virtual Data Optimizer — block-level inline deduplication and compression. Available as LVM-managed VDO logical volumes (the modern path) or as standalone device-mapper targets.

LVM VDO (VdoVolume)

sts.vdo

VDO (Virtual Data Optimizer) volume management -- deduplication, compression, and thin provisioning.

VdoCalculateSize pydantic-model

Bases: StsBaseModel

VDO space and memory usage calculator via vdocalculatesize.

Attributes:

Name Type Description
slab_bits int | None

Slab size as power of 2 (mutually exclusive with slab_size)

slab_size str | None

Slab size in MB (mutually exclusive with slab_bits)

Show JSON schema:
{
  "additionalProperties": false,
  "description": "VDO space and memory usage calculator via vdocalculatesize.\n\nAttributes:\n    slab_bits: Slab size as power of 2 (mutually exclusive with slab_size)\n    slab_size: Slab size in MB (mutually exclusive with slab_bits)",
  "properties": {
    "logical_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Logical Size"
    },
    "physical_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Physical Size"
    },
    "slab_bits": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Slab Bits"
    },
    "slab_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Slab Size"
    },
    "block_map_cache_size": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Block Map Cache Size"
    },
    "index_memory_size": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Index Memory Size"
    },
    "sparse_index": {
      "default": false,
      "title": "Sparse Index",
      "type": "boolean"
    }
  },
  "title": "VdoCalculateSize",
  "type": "object"
}

Fields:

  • logical_size (str | None)
  • physical_size (str | None)
  • slab_bits (int | None)
  • slab_size (str | None)
  • block_map_cache_size (int | None)
  • index_memory_size (float | None)
  • sparse_index (bool)
Source code in sts_libs/src/sts/vdo.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
class VdoCalculateSize(StsBaseModel):
    """VDO space and memory usage calculator via vdocalculatesize.

    Attributes:
        slab_bits: Slab size as power of 2 (mutually exclusive with slab_size)
        slab_size: Slab size in MB (mutually exclusive with slab_bits)
    """

    # Valid slab bits range (13-23 inclusive)
    MIN_SLAB_BITS: ClassVar[int] = 13  # 32 MB slab size
    MAX_SLAB_BITS: ClassVar[int] = 23  # 32 GB slab size
    DEFAULT_SLAB_BITS: ClassVar[int] = 19  # 2 GB slab size (default)

    # Valid index memory sizes in gigabytes
    VALID_INDEX_MEMORY_SIZES: ClassVar[tuple[float, ...]] = (0.25, 0.5, 0.75)

    logical_size: str | None = None
    physical_size: str | None = None
    slab_bits: int | None = None
    slab_size: str | None = None
    block_map_cache_size: int | None = None
    index_memory_size: float | None = None
    sparse_index: bool = False

    def _build_command(self) -> list[str]:
        """Build vdocalculatesize command with options."""
        cmd = ['vdocalculatesize']

        if self.logical_size:
            cmd.append(f'--logical-size={self.logical_size}')

        if self.physical_size:
            cmd.append(f'--physical-size={self.physical_size}')

        if self.slab_bits is not None:
            cmd.append(f'--slab-bits={self.slab_bits}')

        if self.slab_size:
            cmd.append(f'--slab-size={self.slab_size}')

        if self.block_map_cache_size is not None:
            cmd.append(f'--block-map-cache-size={self.block_map_cache_size}')

        if self.index_memory_size is not None:
            # :g strips trailing zeros — vdocalculatesize rejects '1.0' but accepts '1'
            cmd.append(f'--index-memory-size={self.index_memory_size:g}')

        if self.sparse_index:
            cmd.append('--sparse-index')

        return cmd

    def calculate(self) -> CommandResult:
        """Run vdocalculatesize with the configured options."""
        cmd = self._build_command()
        return run(' '.join(cmd))

calculate()

Run vdocalculatesize with the configured options.

Source code in sts_libs/src/sts/vdo.py
189
190
191
192
def calculate(self) -> CommandResult:
    """Run vdocalculatesize with the configured options."""
    cmd = self._build_command()
    return run(' '.join(cmd))

VdoFormat pydantic-model

Bases: StsBaseModel

Low-level VDO device formatting via vdoformat.

Attributes:

Name Type Description
slab_bits int | None

Slab size as power of 2 (13=32MB .. 19=2GB default .. 23=32GB). Max 8192 slabs per volume, so slab size determines max physical volume size.

Show JSON schema:
{
  "additionalProperties": false,
  "description": "Low-level VDO device formatting via vdoformat.\n\nAttributes:\n    slab_bits: Slab size as power of 2 (13=32MB .. 19=2GB default .. 23=32GB).\n        Max 8192 slabs per volume, so slab size determines max physical volume size.",
  "properties": {
    "device": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "format": "path",
          "type": "string"
        }
      ],
      "title": "Device"
    },
    "logical_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Logical Size"
    },
    "slab_bits": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Slab Bits"
    },
    "uds_memory_size": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Uds Memory Size"
    },
    "uds_sparse": {
      "default": false,
      "title": "Uds Sparse",
      "type": "boolean"
    },
    "force": {
      "default": false,
      "title": "Force",
      "type": "boolean"
    },
    "verbose": {
      "default": false,
      "title": "Verbose",
      "type": "boolean"
    }
  },
  "required": [
    "device"
  ],
  "title": "VdoFormat",
  "type": "object"
}

Fields:

  • device (PathOrStr)
  • logical_size (str | None)
  • slab_bits (int | None)
  • uds_memory_size (float | None)
  • uds_sparse (bool)
  • force (bool)
  • verbose (bool)
Source code in sts_libs/src/sts/vdo.py
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
class VdoFormat(StsBaseModel):
    """Low-level VDO device formatting via vdoformat.

    Attributes:
        slab_bits: Slab size as power of 2 (13=32MB .. 19=2GB default .. 23=32GB).
            Max 8192 slabs per volume, so slab size determines max physical volume size.
    """

    # Valid slab bits range (13-23 inclusive)
    MIN_SLAB_BITS: ClassVar[int] = 13  # 32 MB slab size
    MAX_SLAB_BITS: ClassVar[int] = 23  # 32 GB slab size
    DEFAULT_SLAB_BITS: ClassVar[int] = 19  # 2 GB slab size (default)

    # Valid UDS memory sizes in gigabytes
    VALID_UDS_MEMORY_SIZES: ClassVar[tuple[float, ...]] = (0.25, 0.5, 0.75)

    device: PathOrStr
    logical_size: str | None = None
    slab_bits: int | None = None
    uds_memory_size: float | None = None
    uds_sparse: bool = False
    force: bool = False
    verbose: bool = False

    def _build_command(self) -> list[str]:
        """Build vdoformat command with options."""
        cmd = ['vdoformat']

        if self.force:
            cmd.append('--force')

        if self.logical_size:
            cmd.append(f'--logical-size={self.logical_size}')

        if self.slab_bits is not None:
            cmd.append(f'--slab-bits={self.slab_bits}')

        if self.uds_memory_size is not None:
            cmd.append(f'--uds-memory-size={self.uds_memory_size}')

        if self.uds_sparse:
            cmd.append('--uds-sparse')

        if self.verbose:
            cmd.append('--verbose')

        cmd.append(str(self.device))
        return cmd

    def format(self) -> bool:
        """Format device as VDO volume.

        Skips formatting if the device already contains a VDO,
        unless force=True was set.
        """
        cmd = self._build_command()
        result = run(' '.join(cmd))

        if result.failed:
            logger.error(f'Failed to format VDO device: {result.stderr}')
            return False

        logger.info(f'Successfully formatted {self.device} as VDO')
        return True

    @staticmethod
    def get_version() -> str | None:
        """Get vdoformat version."""
        result = run('vdoformat --version')
        if result.failed:
            logger.error(f'Failed to get vdoformat version: {result.stderr}')
            return None
        return result.stdout.strip()

    @property
    def slab_size_mb(self) -> int:
        """Slab size in megabytes, calculated as ``2^slab_bits * 4KB``."""
        bits = self.slab_bits if self.slab_bits is not None else self.DEFAULT_SLAB_BITS
        # Each slab is 2^bits blocks of 4KB
        return (2**bits * 4) // 1024

slab_size_mb property

Slab size in megabytes, calculated as 2^slab_bits * 4KB.

format()

Format device as VDO volume.

Skips formatting if the device already contains a VDO, unless force=True was set.

Source code in sts_libs/src/sts/vdo.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def format(self) -> bool:
    """Format device as VDO volume.

    Skips formatting if the device already contains a VDO,
    unless force=True was set.
    """
    cmd = self._build_command()
    result = run(' '.join(cmd))

    if result.failed:
        logger.error(f'Failed to format VDO device: {result.stderr}')
        return False

    logger.info(f'Successfully formatted {self.device} as VDO')
    return True

get_version() staticmethod

Get vdoformat version.

Source code in sts_libs/src/sts/vdo.py
120
121
122
123
124
125
126
127
@staticmethod
def get_version() -> str | None:
    """Get vdoformat version."""
    result = run('vdoformat --version')
    if result.failed:
        logger.error(f'Failed to get vdoformat version: {result.stderr}')
        return None
    return result.stdout.strip()

VdoState

Bases: StrEnum

VDO feature state.

Used to enable/disable features like compression and deduplication.

Source code in sts_libs/src/sts/vdo.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class VdoState(StrEnum):
    """VDO feature state.

    Used to enable/disable features like compression and deduplication.
    """

    def __str__(self) -> str:
        """Return the string value of the state."""
        return self.value

    def __format__(self, format_spec: str) -> str:
        """Format the state using its string value."""
        return self.value.__format__(format_spec)

    ENABLED = 'y'
    DISABLED = 'n'

__format__(format_spec)

Format the state using its string value.

Source code in sts_libs/src/sts/vdo.py
47
48
49
def __format__(self, format_spec: str) -> str:
    """Format the state using its string value."""
    return self.value.__format__(format_spec)

__str__()

Return the string value of the state.

Source code in sts_libs/src/sts/vdo.py
43
44
45
def __str__(self) -> str:
    """Return the string value of the state."""
    return self.value

VdoVolume pydantic-model

Bases: LogicalVolume

LVM VDO logical volume with deduplication, compression, and write policy control.

Example
device = VdoVolume(name='vdo0', vg='vg0')
device.create(size='1G')
Show JSON schema:
{
  "$defs": {
    "LVReport": {
      "description": "Parsed LV data from 'lvs -o lv_all,seg_all --reportformat json'.\n\nFrozen (immutable) snapshot of one logical volume's report fields.\nUnknown JSON keys are silently ignored (extra='ignore').\nAll fields match lvs JSON key names and retain str | None typing,\nexcept for a handful of numeric fields (see below) that are coerced.",
      "properties": {
        "lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Uuid"
        },
        "lv_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Name"
        },
        "lv_full_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Full Name"
        },
        "lv_path": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Path"
        },
        "lv_dm_path": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Dm Path"
        },
        "vg_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Name"
        },
        "lv_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Size"
        },
        "lv_metadata_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Metadata Size"
        },
        "seg_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Count"
        },
        "lv_layout": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Layout"
        },
        "lv_role": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Role"
        },
        "lv_attr": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Attr"
        },
        "lv_active": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active"
        },
        "lv_active_locally": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active Locally"
        },
        "lv_active_remotely": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active Remotely"
        },
        "lv_active_exclusively": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active Exclusively"
        },
        "lv_permissions": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Permissions"
        },
        "lv_suspended": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Suspended"
        },
        "lv_major": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Major"
        },
        "lv_minor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Minor"
        },
        "lv_kernel_major": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Kernel Major"
        },
        "lv_kernel_minor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Kernel Minor"
        },
        "lv_read_ahead": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Read Ahead"
        },
        "lv_kernel_read_ahead": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Kernel Read Ahead"
        },
        "pool_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pool Lv"
        },
        "pool_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pool Lv Uuid"
        },
        "data_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Lv"
        },
        "data_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Lv Uuid"
        },
        "metadata_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Lv"
        },
        "metadata_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Lv Uuid"
        },
        "data_percent": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Percent"
        },
        "metadata_percent": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Percent"
        },
        "origin": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Origin"
        },
        "origin_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Origin Uuid"
        },
        "origin_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Origin Size"
        },
        "snap_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Snap Percent"
        },
        "raid_mismatch_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Mismatch Count"
        },
        "raid_sync_action": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Sync Action"
        },
        "raid_write_behind": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Write Behind"
        },
        "raid_min_recovery_rate": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Min Recovery Rate"
        },
        "raid_max_recovery_rate": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Max Recovery Rate"
        },
        "cache_total_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Total Blocks"
        },
        "cache_used_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Used Blocks"
        },
        "cache_dirty_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Dirty Blocks"
        },
        "cache_read_hits": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Read Hits"
        },
        "cache_read_misses": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Read Misses"
        },
        "cache_write_hits": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Write Hits"
        },
        "cache_write_misses": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Write Misses"
        },
        "kernel_cache_settings": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Cache Settings"
        },
        "kernel_cache_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Cache Policy"
        },
        "vdo_operating_mode": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Operating Mode"
        },
        "vdo_compression_state": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Compression State"
        },
        "vdo_index_state": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Index State"
        },
        "vdo_used_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Used Size"
        },
        "vdo_saving_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Saving Percent"
        },
        "writecache_block_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Block Size"
        },
        "writecache_total_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Total Blocks"
        },
        "writecache_free_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Free Blocks"
        },
        "writecache_writeback_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Writeback Blocks"
        },
        "writecache_error": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Error"
        },
        "lv_allocation_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Allocation Policy"
        },
        "lv_allocation_locked": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Allocation Locked"
        },
        "lv_autoactivation": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Autoactivation"
        },
        "lv_when_full": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv When Full"
        },
        "lv_skip_activation": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Skip Activation"
        },
        "lv_fixed_minor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Fixed Minor"
        },
        "lv_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Time"
        },
        "lv_time_removed": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Time Removed"
        },
        "lv_host": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Host"
        },
        "lv_health_status": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Health Status"
        },
        "lv_check_needed": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Check Needed"
        },
        "lv_merge_failed": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Merge Failed"
        },
        "lv_snapshot_invalid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Snapshot Invalid"
        },
        "lv_tags": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Tags"
        },
        "lv_profile": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Profile"
        },
        "lv_lockargs": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Lockargs"
        },
        "lv_modules": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Modules"
        },
        "lv_historical": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Historical"
        },
        "kernel_discards": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Discards"
        },
        "copy_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Copy Percent"
        },
        "sync_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Sync Percent"
        },
        "lv_live_table": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Live Table"
        },
        "lv_inactive_table": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Inactive Table"
        },
        "lv_device_open": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Device Open"
        },
        "lv_parent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Parent"
        },
        "lv_ancestors": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Ancestors"
        },
        "lv_full_ancestors": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Full Ancestors"
        },
        "lv_descendants": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Descendants"
        },
        "lv_full_descendants": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Full Descendants"
        },
        "lv_converting": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Converting"
        },
        "lv_merging": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Merging"
        },
        "move_pv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Move Pv"
        },
        "move_pv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Move Pv Uuid"
        },
        "convert_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Convert Lv"
        },
        "convert_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Convert Lv Uuid"
        },
        "mirror_log": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Mirror Log"
        },
        "mirror_log_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Mirror Log Uuid"
        },
        "lv_initial_image_sync": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Initial Image Sync"
        },
        "lv_image_synced": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Image Synced"
        },
        "raidintegritymode": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raidintegritymode"
        },
        "raidintegrityblocksize": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raidintegrityblocksize"
        },
        "integritymismatches": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Integritymismatches"
        },
        "kernel_metadata_format": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Metadata Format"
        },
        "segtype": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Segtype"
        },
        "stripes": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Stripes"
        },
        "data_stripes": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Stripes"
        },
        "stripe_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Stripe Size"
        },
        "region_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Region Size"
        },
        "chunk_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Chunk Size"
        },
        "seg_start": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Start"
        },
        "seg_start_pe": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Start Pe"
        },
        "seg_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Size"
        },
        "seg_size_pe": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Size Pe"
        },
        "seg_tags": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Tags"
        },
        "seg_pe_ranges": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Pe Ranges"
        },
        "seg_le_ranges": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Le Ranges"
        },
        "seg_metadata_le_ranges": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Metadata Le Ranges"
        },
        "devices": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Devices"
        },
        "metadata_devices": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Devices"
        },
        "seg_monitor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Monitor"
        },
        "reshape_len": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Reshape Len"
        },
        "reshape_len_le": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Reshape Len Le"
        },
        "data_copies": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Copies"
        },
        "data_offset": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Offset"
        },
        "new_data_offset": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "New Data Offset"
        },
        "parity_chunks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Parity Chunks"
        },
        "thin_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Thin Count"
        },
        "discards": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Discards"
        },
        "cache_metadata_format": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Metadata Format"
        },
        "cache_mode": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Mode"
        },
        "zero": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Zero"
        },
        "transaction_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Transaction Id"
        },
        "thin_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Thin Id"
        },
        "cache_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Policy"
        },
        "cache_settings": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Settings"
        },
        "integrity_settings": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Integrity Settings"
        },
        "vdo_compression": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Compression"
        },
        "vdo_deduplication": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Deduplication"
        },
        "vdo_minimum_io_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Minimum Io Size"
        },
        "vdo_block_map_cache_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Block Map Cache Size"
        },
        "vdo_block_map_era_length": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Block Map Era Length"
        },
        "vdo_use_sparse_index": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Use Sparse Index"
        },
        "vdo_index_memory_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Index Memory Size"
        },
        "vdo_slab_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Slab Size"
        },
        "vdo_ack_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Ack Threads"
        },
        "vdo_bio_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Bio Threads"
        },
        "vdo_bio_rotation": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Bio Rotation"
        },
        "vdo_cpu_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Cpu Threads"
        },
        "vdo_hash_zone_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Hash Zone Threads"
        },
        "vdo_logical_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Logical Threads"
        },
        "vdo_physical_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Physical Threads"
        },
        "vdo_max_discard": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Max Discard"
        },
        "vdo_header_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Header Size"
        },
        "vdo_use_metadata_hints": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Use Metadata Hints"
        },
        "vdo_write_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Write Policy"
        }
      },
      "title": "LVReport",
      "type": "object"
    }
  },
  "additionalProperties": false,
  "description": "LVM VDO logical volume with deduplication, compression, and write policy control.\n\nExample:\n    ```python\n    device = VdoVolume(name='vdo0', vg='vg0')\n    device.create(size='1G')\n    ```",
  "properties": {
    "path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "format": "path",
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Path"
    },
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Name"
    },
    "size": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Size"
    },
    "model": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Model"
    },
    "vg": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg"
    },
    "pool_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pool Name"
    },
    "report": {
      "anyOf": [
        {
          "$ref": "#/$defs/LVReport"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "prevent_report_updates": {
      "default": false,
      "title": "Prevent Report Updates",
      "type": "boolean"
    },
    "deduplication": {
      "default": true,
      "title": "Deduplication",
      "type": "boolean"
    },
    "compression": {
      "default": true,
      "title": "Compression",
      "type": "boolean"
    },
    "write_policy": {
      "default": "sync",
      "enum": [
        "sync",
        "async"
      ],
      "title": "Write Policy",
      "type": "string"
    },
    "slab_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Slab Size"
    }
  },
  "title": "VdoVolume",
  "type": "object"
}

Fields:

  • path (PathOrStr | None)
  • name (str | None)
  • size (int | None)
  • model (str | None)
  • vg (str | None)
  • pool_name (str | None)
  • report (LVReport | None)
  • prevent_report_updates (bool)
  • deduplication (bool)
  • compression (bool)
  • write_policy (WritePolicy)
  • slab_size (str | None)
Source code in sts_libs/src/sts/vdo.py
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
class VdoVolume(LogicalVolume):
    """LVM VDO logical volume with deduplication, compression, and write policy control.

    Example:
        ```python
        device = VdoVolume(name='vdo0', vg='vg0')
        device.create(size='1G')
        ```
    """

    # VDO-specific options
    deduplication: bool = True
    compression: bool = True
    write_policy: WritePolicy = 'sync'
    slab_size: str | None = None

    # Class-level paths
    CONFIG_PATH: ClassVar[Path] = Path('/etc/vdoconf.yml')

    def create(
        self,
        *args: str,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[LvCreateOptions],
    ) -> CommandResult:
        """Create VDO volume with compression, deduplication, and write policy."""
        # Build VDO-specific options (WITHOUT --type, which goes in options dict)
        vdo_opts = [
            '--compression',
            VdoState.ENABLED if self.compression else VdoState.DISABLED,
            '--deduplication',
            VdoState.ENABLED if self.deduplication else VdoState.DISABLED,
            '--vdowritepolicy',
            self.write_policy,
        ]
        if self.slab_size:
            vdo_opts.extend(['--vdoslabsize', self.slab_size])

        # Pass type via options dict so LogicalVolume.create() can route pool_name to --vdopool
        options = dict(options)  # type: ignore[assignment]
        options.setdefault('type', 'vdo')

        # Create VDO volume using LVM
        return super().create(*args, *vdo_opts, force=force, yes=yes, **options)

    def get_stats(self, *, human_readable: bool = True) -> dict[str, str] | None:
        """Get VDO statistics via vdostats.

        Returns a dict keyed by lowercased, underscore-joined stat names
        (e.g., 'physical_blocks', 'data_blocks'), or None on error.
        """
        cmd = ['vdostats']
        if human_readable:
            cmd.append('--human-readable')
        cmd.append(str(self.path))

        result = run(' '.join(cmd))
        if result.failed:
            logger.error(f'Failed to get VDO stats: {result.stderr}')
            return None

        # Parse statistics output
        stats: dict[str, str] = {}
        for line in result.stdout.splitlines():
            if ':' not in line:
                continue
            key, value = line.split(':', 1)
            stats[key.strip().lower().replace(' ', '_')] = value.strip()

        return stats

    def set_deduplication(self, *, enabled: bool = True) -> bool:
        """Enable or disable inline deduplication."""
        cmd = 'enableDeduplication' if enabled else 'disableDeduplication'
        result = run(f'vdo {cmd} --name={self.name}')
        if result.failed:
            logger.error(f'Failed to set deduplication: {result.stderr}')
            return False

        self.deduplication = enabled
        return True

    def set_compression(self, *, enabled: bool = True) -> bool:
        """Enable or disable inline LZ4 compression."""
        cmd = 'enableCompression' if enabled else 'disableCompression'
        result = run(f'vdo {cmd} --name={self.name}')
        if result.failed:
            logger.error(f'Failed to set compression: {result.stderr}')
            return False

        self.compression = enabled
        return True

    def set_write_policy(self, policy: WritePolicy) -> bool:
        """Set write policy (sync = wait for physical write, async = acknowledge from memory)."""
        result = run(f'vdo changeWritePolicy --name={self.name} --writePolicy={policy}')
        if result.failed:
            logger.error(f'Failed to set write policy: {result.stderr}')
            return False

        self.write_policy = policy
        return True

create(*args, force=False, yes=True, **options)

Create VDO volume with compression, deduplication, and write policy.

Source code in sts_libs/src/sts/vdo.py
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
def create(
    self,
    *args: str,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[LvCreateOptions],
) -> CommandResult:
    """Create VDO volume with compression, deduplication, and write policy."""
    # Build VDO-specific options (WITHOUT --type, which goes in options dict)
    vdo_opts = [
        '--compression',
        VdoState.ENABLED if self.compression else VdoState.DISABLED,
        '--deduplication',
        VdoState.ENABLED if self.deduplication else VdoState.DISABLED,
        '--vdowritepolicy',
        self.write_policy,
    ]
    if self.slab_size:
        vdo_opts.extend(['--vdoslabsize', self.slab_size])

    # Pass type via options dict so LogicalVolume.create() can route pool_name to --vdopool
    options = dict(options)  # type: ignore[assignment]
    options.setdefault('type', 'vdo')

    # Create VDO volume using LVM
    return super().create(*args, *vdo_opts, force=force, yes=yes, **options)

get_stats(*, human_readable=True)

Get VDO statistics via vdostats.

Returns a dict keyed by lowercased, underscore-joined stat names (e.g., 'physical_blocks', 'data_blocks'), or None on error.

Source code in sts_libs/src/sts/vdo.py
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
def get_stats(self, *, human_readable: bool = True) -> dict[str, str] | None:
    """Get VDO statistics via vdostats.

    Returns a dict keyed by lowercased, underscore-joined stat names
    (e.g., 'physical_blocks', 'data_blocks'), or None on error.
    """
    cmd = ['vdostats']
    if human_readable:
        cmd.append('--human-readable')
    cmd.append(str(self.path))

    result = run(' '.join(cmd))
    if result.failed:
        logger.error(f'Failed to get VDO stats: {result.stderr}')
        return None

    # Parse statistics output
    stats: dict[str, str] = {}
    for line in result.stdout.splitlines():
        if ':' not in line:
            continue
        key, value = line.split(':', 1)
        stats[key.strip().lower().replace(' ', '_')] = value.strip()

    return stats

set_compression(*, enabled=True)

Enable or disable inline LZ4 compression.

Source code in sts_libs/src/sts/vdo.py
323
324
325
326
327
328
329
330
331
332
def set_compression(self, *, enabled: bool = True) -> bool:
    """Enable or disable inline LZ4 compression."""
    cmd = 'enableCompression' if enabled else 'disableCompression'
    result = run(f'vdo {cmd} --name={self.name}')
    if result.failed:
        logger.error(f'Failed to set compression: {result.stderr}')
        return False

    self.compression = enabled
    return True

set_deduplication(*, enabled=True)

Enable or disable inline deduplication.

Source code in sts_libs/src/sts/vdo.py
312
313
314
315
316
317
318
319
320
321
def set_deduplication(self, *, enabled: bool = True) -> bool:
    """Enable or disable inline deduplication."""
    cmd = 'enableDeduplication' if enabled else 'disableDeduplication'
    result = run(f'vdo {cmd} --name={self.name}')
    if result.failed:
        logger.error(f'Failed to set deduplication: {result.stderr}')
        return False

    self.deduplication = enabled
    return True

set_write_policy(policy)

Set write policy (sync = wait for physical write, async = acknowledge from memory).

Source code in sts_libs/src/sts/vdo.py
334
335
336
337
338
339
340
341
342
def set_write_policy(self, policy: WritePolicy) -> bool:
    """Set write policy (sync = wait for physical write, async = acknowledge from memory)."""
    result = run(f'vdo changeWritePolicy --name={self.name} --writePolicy={policy}')
    if result.failed:
        logger.error(f'Failed to set write policy: {result.stderr}')
        return False

    self.write_policy = policy
    return True

get_minimum_slab_size(device, *, use_default=True)

Get minimum slab size for a device based on its physical size.

Calculates the smallest slab size that stays within MAX_SLABS (8192), clamped to at least MIN_SLAB_SIZE_MB.

Parameters:

Name Type Description Default
device str | Path

Device path

required
use_default bool

Return DEFAULT_SLAB_SIZE ('2G') when calculated size is smaller

True
Source code in sts_libs/src/sts/vdo.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
def get_minimum_slab_size(device: str | Path, *, use_default: bool = True) -> str:
    """Get minimum slab size for a device based on its physical size.

    Calculates the smallest slab size that stays within MAX_SLABS (8192),
    clamped to at least MIN_SLAB_SIZE_MB.

    Args:
        device: Device path
        use_default: Return DEFAULT_SLAB_SIZE ('2G') when calculated size is smaller
    """
    device = Path(device)

    # Get device name - handle MD devices specially
    if str(device).startswith('/dev/md'):
        # For MD (RAID) devices, resolve the actual device name
        result = run(f'ls -al /dev/md | grep {device.name}')
        if result.failed:
            logger.warning(f'Device {device.name} not found in /dev/md')
            return DEFAULT_SLAB_SIZE
        device = Path(result.stdout.split('../')[-1])

    # Get device size from lsblk output
    result = run(f"lsblk | grep '{device.name} '")
    if result.failed:
        logger.warning(f'Device {device.name} not found using lsblk')
        return DEFAULT_SLAB_SIZE

    # Parse size (e.g. '1G', '2T') and convert to MB
    size = result.stdout.split()[3]
    multiplier = SIZE_MULTIPLIERS.index(size[-1:])
    device_size = int(float(size[:-1]) * (1024**multiplier))

    # Calculate minimum size:
    # 1. Divide device size by MAX_SLABS
    # 2. Round up to next power of 2
    # 3. Ensure at least MIN_SLAB_SIZE_MB
    minimum_size = 2 ** int(device_size / MAX_SLABS).bit_length()
    minimum_size = max(minimum_size, MIN_SLAB_SIZE_MB)

    # Use default size if calculated size is smaller
    if use_default and minimum_size < DEFAULT_SLAB_SIZE_MB:
        return DEFAULT_SLAB_SIZE
    return f'{minimum_size}M'

Device Mapper VDO (VdoDevice)

Low-level device mapper VDO target for direct dm-based VDO management.

sts.dm.vdo

Device Mapper VDO (Virtual Data Optimizer) target.

VdoDevice pydantic-model

Bases: DmDevice

VDO (Virtual Data Optimizer) target -- deduplication, compression, thin provisioning.

VDO volumes can be pre-formatted with vdoformat, or on kernels >= 6.12.0-241.el10 the kernel can auto-format during dmsetup create (controlled by indexMemory, indexSparse, and slabSize table parameters).

Args format: V4 <storage device> <storage size> <min IO size> <cache size> <era length> [opts]

Parsed fields use dmsetup parameter names (e.g. ack, bioRotationInterval, maxDiscard). Sizes in 4096-byte blocks unless noted otherwise.

Show JSON schema:
{
  "$defs": {
    "BlockdevInfo": {
      "description": "Parsed ``blockdev --report`` output.",
      "properties": {
        "ro": {
          "default": false,
          "title": "Ro",
          "type": "boolean"
        },
        "ra": {
          "default": 0,
          "title": "Ra",
          "type": "integer"
        },
        "log-sec": {
          "default": 0,
          "title": "Log-Sec",
          "type": "integer"
        },
        "phy-sec": {
          "default": 0,
          "title": "Phy-Sec",
          "type": "integer"
        },
        "start": {
          "default": 0,
          "title": "Start",
          "type": "integer"
        },
        "size": {
          "default": 0,
          "title": "Size",
          "type": "integer"
        }
      },
      "title": "BlockdevInfo",
      "type": "object"
    },
    "LsblkInfo": {
      "description": "Parsed ``lsblk -JOb`` output.",
      "properties": {
        "model": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Model"
        },
        "rm": {
          "default": false,
          "title": "Rm",
          "type": "boolean"
        },
        "hctl": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Hctl"
        },
        "state": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "State"
        },
        "pttype": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pttype"
        },
        "wwn": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Wwn"
        },
        "fstype": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Fstype"
        },
        "mountpoint": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Mountpoint"
        },
        "type": {
          "default": "disk",
          "title": "Type",
          "type": "string"
        },
        "tran": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Tran"
        },
        "maj:min": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Maj:Min"
        },
        "pkname": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pkname"
        },
        "start": {
          "default": 0,
          "title": "Start",
          "type": "integer"
        }
      },
      "title": "LsblkInfo",
      "type": "object"
    }
  },
  "additionalProperties": false,
  "description": "VDO (Virtual Data Optimizer) target -- deduplication, compression, thin provisioning.\n\nVDO volumes can be pre-formatted with ``vdoformat``, or on kernels >= 6.12.0-241.el10\nthe kernel can auto-format during ``dmsetup create`` (controlled by indexMemory,\nindexSparse, and slabSize table parameters).\n\nArgs format: ``V4 <storage device> <storage size> <min IO size> <cache size> <era length> [opts]``\n\nParsed fields use dmsetup parameter names (e.g. ``ack``, ``bioRotationInterval``,\n``maxDiscard``). Sizes in 4096-byte blocks unless noted otherwise.",
  "properties": {
    "path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "format": "path",
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Path"
    },
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Name"
    },
    "size": {
      "anyOf": [
        {
          "minimum": 0,
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Size"
    },
    "model": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Model"
    },
    "blockdev_info": {
      "anyOf": [
        {
          "$ref": "#/$defs/BlockdevInfo"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "lsblk_info": {
      "anyOf": [
        {
          "$ref": "#/$defs/LsblkInfo"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "start": {
      "default": 0,
      "title": "Start",
      "type": "integer"
    },
    "size_sectors": {
      "default": 0,
      "title": "Size Sectors",
      "type": "integer"
    },
    "args": {
      "default": "",
      "title": "Args",
      "type": "string"
    },
    "dm_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Dm Name"
    },
    "target_type": {
      "default": "vdo",
      "title": "Target Type",
      "type": "string"
    },
    "table": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Table"
    },
    "is_created": {
      "default": false,
      "title": "Is Created",
      "type": "boolean"
    },
    "vdo_version": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Version"
    },
    "storage_device": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Storage Device"
    },
    "storage_size_blocks": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Storage Size Blocks"
    },
    "minimum_io_size": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Minimum Io Size"
    },
    "block_map_cache_blocks": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Block Map Cache Blocks"
    },
    "block_map_period": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Block Map Period"
    },
    "ack": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Ack"
    },
    "bio": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Bio"
    },
    "bioRotationInterval": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Biorotationinterval"
    },
    "cpu": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cpu"
    },
    "hash": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Hash"
    },
    "logical": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Logical"
    },
    "physical": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Physical"
    },
    "maxDiscard": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Maxdiscard"
    },
    "deduplication": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Deduplication"
    },
    "compression": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Compression"
    }
  },
  "title": "VdoDevice",
  "type": "object"
}

Fields:

  • path (PathOrStr | None)
  • name (str | None)
  • size (int | None)
  • model (str | None)
  • blockdev_info (BlockdevInfo | None)
  • lsblk_info (LsblkInfo | None)
  • start (int)
  • size_sectors (int)
  • args (str)
  • dm_name (str | None)
  • table (str | None)
  • is_created (bool)
  • vdo_version (str | None)
  • storage_device (str | None)
  • storage_size_blocks (int | None)
  • minimum_io_size (int | None)
  • block_map_cache_blocks (int | None)
  • block_map_period (int | None)
  • ack (int | None)
  • bio (int | None)
  • bio_rotation_interval (int | None)
  • cpu (int | None)
  • hash (int | None)
  • logical (int | None)
  • physical (int | None)
  • max_discard (int | None)
  • deduplication (bool | None)
  • compression (bool | None)
  • target_type (str)
Source code in sts_libs/src/sts/dm/vdo.py
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
class VdoDevice(DmDevice):
    """VDO (Virtual Data Optimizer) target -- deduplication, compression, thin provisioning.

    VDO volumes can be pre-formatted with ``vdoformat``, or on kernels >= 6.12.0-241.el10
    the kernel can auto-format during ``dmsetup create`` (controlled by indexMemory,
    indexSparse, and slabSize table parameters).

    Args format: ``V4 <storage device> <storage size> <min IO size> <cache size> <era length> [opts]``

    Parsed fields use dmsetup parameter names (e.g. ``ack``, ``bioRotationInterval``,
    ``maxDiscard``). Sizes in 4096-byte blocks unless noted otherwise.
    """

    # Parsed attributes (populated by refresh)
    # Names match dmsetup parameter names
    vdo_version: str | None = Field(default=None, init=False)
    storage_device: str | None = Field(default=None, init=False)
    storage_size_blocks: int | None = Field(default=None, init=False)
    minimum_io_size: int | None = Field(default=None, init=False)
    block_map_cache_blocks: int | None = Field(default=None, init=False)
    block_map_period: int | None = Field(default=None, init=False)
    ack: int | None = Field(default=None, init=False)
    bio: int | None = Field(default=None, init=False)
    bio_rotation_interval: int | None = Field(default=None, init=False, validation_alias='bioRotationInterval')
    cpu: int | None = Field(default=None, init=False)
    hash: int | None = Field(default=None, init=False)
    logical: int | None = Field(default=None, init=False)
    physical: int | None = Field(default=None, init=False)
    max_discard: int | None = Field(default=None, init=False, validation_alias='maxDiscard')
    deduplication: bool | None = None
    compression: bool | None = None

    target_type: str = Field(default='vdo', init=False)

    @classmethod
    def from_block_device(
        cls,
        device: BlockDevice,
        logical_size_sectors: int,
        *,
        start: int = 0,
        minimum_io_size: int = 4096,
        block_map_cache_size_mb: int = 128,
        block_map_period: int = 16380,
        **kwargs: int | bool | str | None,
    ) -> VdoDevice:
        """Create VdoDevice from BlockDevice.

        Args:
            device: Storage block device
            logical_size_sectors: Logical device size in 512-byte sectors
            start: Start sector in virtual device
            minimum_io_size: Minimum I/O size in bytes, 512 or 4096 (default: 4096)
            block_map_cache_size_mb: Block map cache size in MB (default: 128, min: 128)
            block_map_period: Block map era length (default: 16380, range: 1-16380)
            **kwargs: Optional VDO parameters using dmsetup names (ack, bio,
                bioRotationInterval, cpu, hash, logical, physical, maxDiscard,
                deduplication, compression, indexMemory, indexSparse, slabSize)
        """
        # Get device identifier
        device_id = cls._get_device_identifier(device)

        # Calculate storage device size in 4096-byte blocks
        if device.size is None:
            raise ValueError('Cannot determine size: device size is unknown')
        storage_size_blocks = device.size // 4096

        # Convert block map cache size from MB to 4096-byte blocks
        block_map_cache_blocks = (block_map_cache_size_mb * 1024 * 1024) // 4096

        # Build required arguments
        # NOTE: dm-vdo kernel constraint: if any of hash/logical/physical threads is
        # non-zero, all three must be specified and non-zero. This is NOT validated here
        # to allow testing negative cases - the kernel will reject invalid configurations.
        args_parts = [
            'V4',
            device_id,
            str(storage_size_blocks),
            str(minimum_io_size),
            str(block_map_cache_blocks),
            str(block_map_period),
        ]

        optional_params = ('ack', 'bio', 'bioRotationInterval', 'cpu', 'hash', 'logical', 'physical', 'maxDiscard')
        optional_args: list[str] = []

        for param_name in optional_params:
            value = kwargs.get(param_name)
            if value is not None:
                optional_args.extend([param_name, str(value)])

        # Handle deduplication (only add if False, as True is default)
        dedup_val = kwargs.get('deduplication', True)
        deduplication_enabled = bool(dedup_val) if dedup_val is not None else True
        if not deduplication_enabled:
            optional_args.extend(['deduplication', 'off'])

        # Handle compression (only add if True, as False is default)
        comp_val = kwargs.get('compression', False)
        compression_enabled = bool(comp_val) if comp_val is not None else False
        if compression_enabled:
            optional_args.extend(['compression', 'on'])

        # Kernel-side format parameters (indexMemory, indexSparse, slabSize)
        for fmt_key in ('indexMemory', 'slabSize'):
            fmt_val = kwargs.get(fmt_key)
            if fmt_val is not None:
                optional_args.extend([fmt_key, str(fmt_val)])

        index_sparse_val = kwargs.get('indexSparse')
        if index_sparse_val is not None:
            optional_args.extend(['indexSparse', 'on' if index_sparse_val else 'off'])

        if optional_args:
            args_parts.extend(optional_args)

        args = ' '.join(args_parts)

        # deduplication/compression are only added to args when non-default,
        # so _parse_table won't see them for default values - pass explicitly instead
        return cls(
            start=start,
            size_sectors=logical_size_sectors,
            args=args,
            deduplication=deduplication_enabled,
            compression=compression_enabled,
        )

    def _parse_table(self) -> None:
        """Parse VDO-specific attributes from the args string."""
        super()._parse_table()
        if not self.args:
            return

        parts = self.args.split()

        if len(parts) < 6:
            return

        # Parse required positional arguments
        self.vdo_version = parts[0]  # V4
        self.storage_device = parts[1]
        self.storage_size_blocks = int(parts[2])
        self.minimum_io_size = int(parts[3])
        self.block_map_cache_blocks = int(parts[4])
        self.block_map_period = int(parts[5])

        # Parse optional key-value arguments
        i = 6
        while i < len(parts) - 1:
            key = parts[i]
            value = parts[i + 1]

            # dmsetup parameter names used directly as attribute names
            if key == 'ack':
                self.ack = int(value)
            elif key == 'bio':
                self.bio = int(value)
            elif key == 'bioRotationInterval':
                self.bio_rotation_interval = int(value)
            elif key == 'cpu':
                self.cpu = int(value)
            elif key == 'hash':
                self.hash = int(value)
            elif key == 'logical':
                self.logical = int(value)
            elif key == 'physical':
                self.physical = int(value)
            elif key == 'maxDiscard':
                self.max_discard = int(value)
            elif key == 'deduplication':
                self.deduplication = value == 'on'
            elif key == 'compression':
                self.compression = value == 'on'

            i += 2

    @classmethod
    def from_table_line(cls, table_line: str) -> VdoDevice | None:
        """Create VdoDevice from a ``dmsetup table`` output line."""
        parts = table_line.strip().split(None, 3)
        if len(parts) < 4:
            logger.warning(f'Invalid table line: {table_line}')
            return None

        start = int(parts[0])
        size = int(parts[1])
        target_type = parts[2]
        args = parts[3]

        if target_type != 'vdo':
            logger.warning(f'Not a VDO target: {target_type}')
            return None

        target = cls(start=start, size_sectors=size, args=args)
        target._parse_table()  # parse args to populate attributes
        return target

    @staticmethod
    def parse_status(status_line: str) -> VdoStatus:
        """Parse VDO status output into a VdoStatus.

        Status format::

            <start> <size> vdo <device> <operating mode> <in recovery>
            <index state> <compression state> <used blocks> <total blocks>
        """
        parts = status_line.strip().split()
        result: dict[str, str | int] = {}

        # Format: <start> <size> vdo <device> <mode> <recovery> <index> <compression> <used> <total>
        # Minimum 10 parts expected
        if len(parts) < 10:
            logger.warning(f'Invalid VDO status line (expected 10+ parts, got {len(parts)}): {status_line}')
            return VdoStatus.model_validate(result)

        try:
            result['start'] = int(parts[0])
            result['size'] = int(parts[1])
        except ValueError:
            logger.warning(f'Failed to parse start/size from status: {status_line}')
            return VdoStatus.model_validate(result)

        # parts[2] is 'vdo' (target type)
        result['device'] = parts[3]
        result['operating_mode'] = parts[4]
        result['in_recovery'] = parts[5]
        result['index_state'] = parts[6]
        result['compression_state'] = parts[7]

        try:
            result['physical_blocks_used'] = int(parts[8])
            result['total_physical_blocks'] = int(parts[9])
        except ValueError:
            logger.warning(f'Failed to parse block counts from status: {status_line}')

        return VdoStatus.model_validate(result)

    @classmethod
    def create_positional(
        cls,
        device_path: str,
        storage_size_blocks: int,
        logical_size_sectors: int,
        *,
        start: int = 0,
        minimum_io_size: int = 4096,
        block_map_cache_blocks: int = 32768,
        block_map_period: int = 16380,
        **kwargs: int | str | bool,
    ) -> VdoDevice:
        """Create VdoDevice with positional arguments matching dmsetup table format.

        Args:
            device_path: Device path or major:minor identifier
            storage_size_blocks: Storage device size in 4096-byte blocks
            logical_size_sectors: Logical device size in 512-byte sectors
            start: Start sector in virtual device
            minimum_io_size: Minimum I/O size in bytes (512 or 4096)
            block_map_cache_blocks: Block map cache in 4096-byte blocks (min: 32768)
            block_map_period: Block map era length (range: 1-16380)
            **kwargs: Optional VDO key-value arguments (bool values serialized as on/off)
        """
        # Build required arguments
        args_parts = [
            'V4',
            device_path,
            str(storage_size_blocks),
            str(minimum_io_size),
            str(block_map_cache_blocks),
            str(block_map_period),
        ]

        # Process optional arguments
        for key, value in kwargs.items():
            if isinstance(value, bool):
                args_parts.extend([key, 'on' if value else 'off'])
            else:
                args_parts.extend([key, str(value)])

        args = ' '.join(args_parts)
        return cls(start=start, size_sectors=logical_size_sectors, args=args)

create_positional(device_path, storage_size_blocks, logical_size_sectors, *, start=0, minimum_io_size=4096, block_map_cache_blocks=32768, block_map_period=16380, **kwargs) classmethod

Create VdoDevice with positional arguments matching dmsetup table format.

Parameters:

Name Type Description Default
device_path str

Device path or major:minor identifier

required
storage_size_blocks int

Storage device size in 4096-byte blocks

required
logical_size_sectors int

Logical device size in 512-byte sectors

required
start int

Start sector in virtual device

0
minimum_io_size int

Minimum I/O size in bytes (512 or 4096)

4096
block_map_cache_blocks int

Block map cache in 4096-byte blocks (min: 32768)

32768
block_map_period int

Block map era length (range: 1-16380)

16380
**kwargs int | str | bool

Optional VDO key-value arguments (bool values serialized as on/off)

{}
Source code in sts_libs/src/sts/dm/vdo.py
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
@classmethod
def create_positional(
    cls,
    device_path: str,
    storage_size_blocks: int,
    logical_size_sectors: int,
    *,
    start: int = 0,
    minimum_io_size: int = 4096,
    block_map_cache_blocks: int = 32768,
    block_map_period: int = 16380,
    **kwargs: int | str | bool,
) -> VdoDevice:
    """Create VdoDevice with positional arguments matching dmsetup table format.

    Args:
        device_path: Device path or major:minor identifier
        storage_size_blocks: Storage device size in 4096-byte blocks
        logical_size_sectors: Logical device size in 512-byte sectors
        start: Start sector in virtual device
        minimum_io_size: Minimum I/O size in bytes (512 or 4096)
        block_map_cache_blocks: Block map cache in 4096-byte blocks (min: 32768)
        block_map_period: Block map era length (range: 1-16380)
        **kwargs: Optional VDO key-value arguments (bool values serialized as on/off)
    """
    # Build required arguments
    args_parts = [
        'V4',
        device_path,
        str(storage_size_blocks),
        str(minimum_io_size),
        str(block_map_cache_blocks),
        str(block_map_period),
    ]

    # Process optional arguments
    for key, value in kwargs.items():
        if isinstance(value, bool):
            args_parts.extend([key, 'on' if value else 'off'])
        else:
            args_parts.extend([key, str(value)])

    args = ' '.join(args_parts)
    return cls(start=start, size_sectors=logical_size_sectors, args=args)

from_block_device(device, logical_size_sectors, *, start=0, minimum_io_size=4096, block_map_cache_size_mb=128, block_map_period=16380, **kwargs) classmethod

Create VdoDevice from BlockDevice.

Parameters:

Name Type Description Default
device BlockDevice

Storage block device

required
logical_size_sectors int

Logical device size in 512-byte sectors

required
start int

Start sector in virtual device

0
minimum_io_size int

Minimum I/O size in bytes, 512 or 4096 (default: 4096)

4096
block_map_cache_size_mb int

Block map cache size in MB (default: 128, min: 128)

128
block_map_period int

Block map era length (default: 16380, range: 1-16380)

16380
**kwargs int | bool | str | None

Optional VDO parameters using dmsetup names (ack, bio, bioRotationInterval, cpu, hash, logical, physical, maxDiscard, deduplication, compression, indexMemory, indexSparse, slabSize)

{}
Source code in sts_libs/src/sts/dm/vdo.py
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
@classmethod
def from_block_device(
    cls,
    device: BlockDevice,
    logical_size_sectors: int,
    *,
    start: int = 0,
    minimum_io_size: int = 4096,
    block_map_cache_size_mb: int = 128,
    block_map_period: int = 16380,
    **kwargs: int | bool | str | None,
) -> VdoDevice:
    """Create VdoDevice from BlockDevice.

    Args:
        device: Storage block device
        logical_size_sectors: Logical device size in 512-byte sectors
        start: Start sector in virtual device
        minimum_io_size: Minimum I/O size in bytes, 512 or 4096 (default: 4096)
        block_map_cache_size_mb: Block map cache size in MB (default: 128, min: 128)
        block_map_period: Block map era length (default: 16380, range: 1-16380)
        **kwargs: Optional VDO parameters using dmsetup names (ack, bio,
            bioRotationInterval, cpu, hash, logical, physical, maxDiscard,
            deduplication, compression, indexMemory, indexSparse, slabSize)
    """
    # Get device identifier
    device_id = cls._get_device_identifier(device)

    # Calculate storage device size in 4096-byte blocks
    if device.size is None:
        raise ValueError('Cannot determine size: device size is unknown')
    storage_size_blocks = device.size // 4096

    # Convert block map cache size from MB to 4096-byte blocks
    block_map_cache_blocks = (block_map_cache_size_mb * 1024 * 1024) // 4096

    # Build required arguments
    # NOTE: dm-vdo kernel constraint: if any of hash/logical/physical threads is
    # non-zero, all three must be specified and non-zero. This is NOT validated here
    # to allow testing negative cases - the kernel will reject invalid configurations.
    args_parts = [
        'V4',
        device_id,
        str(storage_size_blocks),
        str(minimum_io_size),
        str(block_map_cache_blocks),
        str(block_map_period),
    ]

    optional_params = ('ack', 'bio', 'bioRotationInterval', 'cpu', 'hash', 'logical', 'physical', 'maxDiscard')
    optional_args: list[str] = []

    for param_name in optional_params:
        value = kwargs.get(param_name)
        if value is not None:
            optional_args.extend([param_name, str(value)])

    # Handle deduplication (only add if False, as True is default)
    dedup_val = kwargs.get('deduplication', True)
    deduplication_enabled = bool(dedup_val) if dedup_val is not None else True
    if not deduplication_enabled:
        optional_args.extend(['deduplication', 'off'])

    # Handle compression (only add if True, as False is default)
    comp_val = kwargs.get('compression', False)
    compression_enabled = bool(comp_val) if comp_val is not None else False
    if compression_enabled:
        optional_args.extend(['compression', 'on'])

    # Kernel-side format parameters (indexMemory, indexSparse, slabSize)
    for fmt_key in ('indexMemory', 'slabSize'):
        fmt_val = kwargs.get(fmt_key)
        if fmt_val is not None:
            optional_args.extend([fmt_key, str(fmt_val)])

    index_sparse_val = kwargs.get('indexSparse')
    if index_sparse_val is not None:
        optional_args.extend(['indexSparse', 'on' if index_sparse_val else 'off'])

    if optional_args:
        args_parts.extend(optional_args)

    args = ' '.join(args_parts)

    # deduplication/compression are only added to args when non-default,
    # so _parse_table won't see them for default values - pass explicitly instead
    return cls(
        start=start,
        size_sectors=logical_size_sectors,
        args=args,
        deduplication=deduplication_enabled,
        compression=compression_enabled,
    )

from_table_line(table_line) classmethod

Create VdoDevice from a dmsetup table output line.

Source code in sts_libs/src/sts/dm/vdo.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
@classmethod
def from_table_line(cls, table_line: str) -> VdoDevice | None:
    """Create VdoDevice from a ``dmsetup table`` output line."""
    parts = table_line.strip().split(None, 3)
    if len(parts) < 4:
        logger.warning(f'Invalid table line: {table_line}')
        return None

    start = int(parts[0])
    size = int(parts[1])
    target_type = parts[2]
    args = parts[3]

    if target_type != 'vdo':
        logger.warning(f'Not a VDO target: {target_type}')
        return None

    target = cls(start=start, size_sectors=size, args=args)
    target._parse_table()  # parse args to populate attributes
    return target

parse_status(status_line) staticmethod

Parse VDO status output into a VdoStatus.

Status format::

<start> <size> vdo <device> <operating mode> <in recovery>
<index state> <compression state> <used blocks> <total blocks>
Source code in sts_libs/src/sts/dm/vdo.py
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
@staticmethod
def parse_status(status_line: str) -> VdoStatus:
    """Parse VDO status output into a VdoStatus.

    Status format::

        <start> <size> vdo <device> <operating mode> <in recovery>
        <index state> <compression state> <used blocks> <total blocks>
    """
    parts = status_line.strip().split()
    result: dict[str, str | int] = {}

    # Format: <start> <size> vdo <device> <mode> <recovery> <index> <compression> <used> <total>
    # Minimum 10 parts expected
    if len(parts) < 10:
        logger.warning(f'Invalid VDO status line (expected 10+ parts, got {len(parts)}): {status_line}')
        return VdoStatus.model_validate(result)

    try:
        result['start'] = int(parts[0])
        result['size'] = int(parts[1])
    except ValueError:
        logger.warning(f'Failed to parse start/size from status: {status_line}')
        return VdoStatus.model_validate(result)

    # parts[2] is 'vdo' (target type)
    result['device'] = parts[3]
    result['operating_mode'] = parts[4]
    result['in_recovery'] = parts[5]
    result['index_state'] = parts[6]
    result['compression_state'] = parts[7]

    try:
        result['physical_blocks_used'] = int(parts[8])
        result['total_physical_blocks'] = int(parts[9])
    except ValueError:
        logger.warning(f'Failed to parse block counts from status: {status_line}')

    return VdoStatus.model_validate(result)

VdoStatus pydantic-model

Bases: ReportModel

Parsed 'dmsetup status' output for a VDO target.

See VdoDevice.parse_status for the raw status line format.

Show JSON schema:
{
  "description": "Parsed 'dmsetup status' output for a VDO target.\n\nSee `VdoDevice.parse_status` for the raw status line format.",
  "properties": {
    "start": {
      "default": 0,
      "title": "Start",
      "type": "integer"
    },
    "size": {
      "default": 0,
      "title": "Size",
      "type": "integer"
    },
    "device": {
      "default": "",
      "title": "Device",
      "type": "string"
    },
    "operating_mode": {
      "default": "",
      "title": "Operating Mode",
      "type": "string"
    },
    "in_recovery": {
      "default": "",
      "title": "In Recovery",
      "type": "string"
    },
    "index_state": {
      "default": "",
      "title": "Index State",
      "type": "string"
    },
    "compression_state": {
      "default": "",
      "title": "Compression State",
      "type": "string"
    },
    "physical_blocks_used": {
      "default": 0,
      "title": "Physical Blocks Used",
      "type": "integer"
    },
    "total_physical_blocks": {
      "default": 0,
      "title": "Total Physical Blocks",
      "type": "integer"
    }
  },
  "title": "VdoStatus",
  "type": "object"
}

Fields:

  • start (int)
  • size (int)
  • device (str)
  • operating_mode (str)
  • in_recovery (str)
  • index_state (str)
  • compression_state (str)
  • physical_blocks_used (int)
  • total_physical_blocks (int)
Source code in sts_libs/src/sts/dm/vdo.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class VdoStatus(ReportModel):
    """Parsed 'dmsetup status' output for a VDO target.

    See `VdoDevice.parse_status` for the raw status line format.
    """

    start: int = 0
    size: int = 0
    device: str = ''
    operating_mode: str = ''
    in_recovery: str = ''
    index_state: str = ''
    compression_state: str = ''
    physical_blocks_used: int = 0
    total_physical_blocks: int = 0