Skip to content

StorPool: resize of an encrypted volume does not account for the LUKS header (live resize fails with "Cannot grow device files", guest ends up 2 MiB short) #14695

Open

Description

@vishesh92

problem

When a LUKS-encrypted volume on StorPool primary storage is resized, the
plugin resizes the StorPool volume to exactly the requested size. At creation
the plugin adds 2 MiB (2097152 bytes) for the LUKS header, but the resize path
does not.

Effects:

  1. Live resize fails inside QEMU. The agent runs virsh blockresize with the
    new size; QEMU needs new size + LUKS payload offset on the underlying block
    device, which is larger than the device, and returns:

    internal error: unable to execute QEMU command 'block_resize': Cannot grow device files
    

    The failure is not surfaced. notifyqemu() in resizevolume.sh only logs
    "failed to live resize", the script exits 0, the agent returns success and
    the resizeVolume job succeeds. The guest keeps seeing the old size.

  2. Size mismatch. CloudStack records the requested size, but once QEMU
    re-reads the device (VM stop/start, or a manual blockresize) the guest sees
    the requested size minus the LUKS header. The same shortfall applies to
    offline resize, without any error (from code reading, not tested).

  3. Rollback uses the same unadjusted size (from code reading, not tested).
    If the StorPool API call or the agent command fails, resizeVolume() calls
    StorPoolUtil.volumeUpdate(name, oldSize, true, ...), i.e. shrinkOk=true
    with the CloudStack size. For an encrypted volume that has never been
    resized the device is oldSize + 2097152, so this requests a 2 MiB shrink of
    a LUKS device.

Code references (main at cc30155):

The header allowance was introduced with StorPool encryption support in #7539.

versions

on all versions

The steps to reproduce the bug

  1. KVM zone with StorPool primary storage and a host that supports volume
    encryption. Create a custom-size disk offering with encrypt=true, tagged
    to the StorPool pool.
  2. Create a 10 GiB data volume from that offering and attach it to a running
    VM. On the host, blockdev --getsize64 on the StorPool device shows
    10739515392 (10 GiB + 2097152); the guest sees 10737418240.
  3. Resize the volume while the VM is running:
    cmk resize volume id= size=20
  4. Observe:
    • the resizeVolume job succeeds and CloudStack reports 20 GiB
    • blockdev --getsize64 shows 21474836480 (exactly 20 GiB, no allowance)
    • libvirtd logs the block_resize "Cannot grow device files" error
    • the guest still sees 10 GiB

Expected: the StorPool volume is resized to 20 GiB + 2097152, blockresize
succeeds, and the guest sees 20 GiB, matching what CloudStack reports.

What to do about it?

Apply the same allowance on resize as on create, for encrypted volumes only:

  • In updateVolumeByOffering and updateVolumeByStorPoolQoS, send
    payload.newSize + 2097152 to the StorPool API when the volume has a
    passphrase (or KMS key on main). updateVolumeByStorPoolQoS needs the
    volume passed in.
  • Use the same adjusted size for the rollback in resizeVolume().
  • Keep payload.newSize for the agent command and for the size stored in
    the database.

Sketch:

private static long getStorPoolVolumeSize(VolumeObject vol, long size) {
    boolean encrypted = vol.getPassphraseId() != null || vol.getKmsKeyId() != null;
    return encrypted ? size + 2097152 : size;
}

Volumes already resized under this bug have no allowance; the next resize
after the fix would correct them.

Separately, it may be worth surfacing the blockresize failure instead of
returning success, so a failed live resize is visible in the job result.

Activity

  1. vishesh92 commented on Nov 13, 2026

    @vishesh92
    MemberAuthor

    @slavkap please take a look

  2. slavkap commented on Nov 13, 2026

    @slavkap
    Contributor

    thank you, @vishesh92, for the report! I'll check it

  3. weizhouapache commented on Nov 13, 2026

    @weizhouapache
    Member

    RBD-encrypted volumes use a 16 MiB LUKS2 header.

    The behaviour is slightly different: RBD allocates the full volume size passed by CloudStack, while only volume_size - 16 MiB is visible inside the guest VM.

  4. added a commit that references this issue on Nov 13, 2026
    0148241
  5. slavkap commented on Nov 13, 2026

    @slavkap
    Contributor

    Thanks @weizhouapache! For StorPool we use LUKS1 at the moment, and for it 2 MiB looks to be enough. I will look into LUKS2.

    Thanks @vishesh92 for the report! If you have the time and opportunity, I'd be glad if you could review/test the fix in #14698

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions