You encrypted a data partition with LUKS and now the volume is too small—or you reclaimed space and need to shrink it. LUKS does not bake the partition size into the header, so resizing is possible when you follow the right order:
- Extend (outside → inside): partition/disk → LUKS mapper → filesystem
- Shrink (inside → outside): filesystem → LUKS mapper → partition
This walkthrough uses LUKS2 with ext4:
- Inspect a real secondary disk (
/dev/sdc1, mappersecure_data) to read the stack - Run extend and shrink on a loop-file lab where growing and shrinking are safe to repeat
Related guides:
- Encrypt a disk partition with LUKS — create a new volume
- Mount LUKS with crypttab — unlock at boot
- Open LUKS on another Linux machine — rescue or migration host
Tested on: Ubuntu 26.04 LTS (Resolute Raccoon); kernel 7.0.0-27-generic; cryptsetup 2.8.4.
cryptsetup open—extend when free space follows the partition on the disk, or shrink with an offline filesystem check. It does not cover resizing the encrypted root volume your system boots from (initramfs, bootloader, and partition layout are a migration project) or removing encryption without restoring data elsewhere.
Quick reference: extend vs shrink order
| Goal | Order (outside → inside) | Key commands |
|---|---|---|
| Extend | Partition/disk → LUKS mapper → filesystem | growpart or parted resizepart → cryptsetup resize → resize2fs |
| Shrink | Filesystem → LUKS mapper → partition | umount → e2fsck -f → resize2fs SIZE → cryptsetup resize --size SECTORS → parted resizepart |
LUKS sits between the partition and the filesystem. Wrong order causes:
- Filesystem larger than the encrypted area (extend mistakes)
- Truncated data (shrink mistakes)
What you need
- Root or
sudoon the host cryptsetup,e2fsprogs, andparted(orgrowpartfromcloud-guest-utilson Ubuntu)- A current data backup and a LUKS header backup before any shrink
- The LUKS volume unmounted for shrink; extend can grow ext4 online only after the mapper and LUKS payload are already larger
- Free unallocated space after the partition when you extend a physical disk (or a larger loop/image file in a lab)
On Fedora and other distributions:
- Install the same packages locally
- The
cryptsetup resizeworkflow is not Ubuntu-specific
Inspect the LUKS stack before you resize
Before you resize, confirm:
- Which block device is the LUKS container
- Which mapper name is open
- The
size:field in 512-byte sectors
On the lab host, /dev/sdc1 holds the cluster demo volume secure_data. Open it and print the block layout:
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT /dev/sdc
sudo cryptsetup open /dev/sdc1 secure_dataThen read the LUKS payload size in 512-byte sectors:
sudo cryptsetup status secure_dataSample output:
NAME SIZE TYPE FSTYPE MOUNTPOINT
sdc 5G disk
└─sdc1 5G part crypto_LUKS
└─secure_data 5G crypt ext4
/dev/mapper/secure_data is active.
type: LUKS2
cipher: aes-xts-plain64
keysize: 512 bits
device: /dev/sdc1
sector size: 512
offset: 32768 sectors
size: 10448896 sectors
mode: read/writeFrom cryptsetup status:
device:— LUKS container (/dev/sdc1)offset:— payload offset inside the LUKS container, shown in sectors/512-byte units incryptsetup status; add this to the partition start when calculating the absolute disk end sectorsize:— encrypted payload in 512-byte sectors (use withcryptsetup resize --sizewhen shrinking)- For
parted resizepart, the end sector is absolute on the disk:partition_start + offset + size - 1
Close the mapper when you finish inspecting: sudo cryptsetup close secure_data.
If LUKS sits on an LVM logical volume inside the mapper, see LVM on LUKS — the order includes pvresize, not just lvextend / lvreduce.
Extend a LUKS partition
Extending needs free space after the partition on the same disk (or a larger backing image).
- Loop lab: 2 GiB image → 3 GiB (safe to repeat)
- Physical disk:
sudo growpart /dev/sdc 1when unallocated space followssdc1
Step 1: Grow the partition or backing image
For a loop-file lab, grow the file, refresh the kernel’s view of the loop size, fix the GPT if needed, then grow partition 1:
IMG=/var/tmp/luks-resize-lab.img
LOOP=/dev/loop24
truncate -s 3G "$IMG"
sudo losetup -c "$LOOP"
sudo sgdisk -e "$LOOP"
sudo partprobe "$LOOP"
sudo parted -s "$LOOP" resizepart 1 100%Loop-file gotchas after truncate:
losetup -c— refresh kernel loop size (without it,cryptsetup resizehas nothing to grow into)sgdisk -e— move backup GPT to the end of a grown image filepartprobe— pick up the resized partition table
On a real disk with space after partition 1:
sudo growpart /dev/sdc 1Check that the partition picked up the new space:
lsblk -o NAME,SIZE,TYPE,FSTYPE "$LOOP"Sample output:
NAME SIZE TYPE FSTYPE
loop24 3G loop
└─loop24p1 3G part crypto_LUKS
└─resize_demo 2G crypt ext4loop24p1 is 3 G but the mapper is still 2 G—the next step grows the LUKS payload.
Step 2: Resize the LUKS mapper
With the mapper already open (resize_demo in the lab), grow the LUKS encrypted area to fill the partition. Omit --size so cryptsetup uses the maximum allowed by the backing device:
sudo cryptsetup resize resize_demoA successful grow prints nothing. Confirm the new sector count:
sudo cryptsetup status resize_demo | grep -E 'size:|offset:'Sample output:
offset: 32768 [512-byte units] (16777216 [bytes])
size: 6256607 [512-byte units] (3203382784 [bytes])6256607 sectors × 512 bytes ≈ 2.98 GiB — the LUKS payload now matches the grown 3 G partition (minus header offset).
cryptsetup resize expects --size in 512-byte sectors when you pass a value. Suffixes like 512M are not valid for --size: cryptsetup: invalid numeric value is the error you get. Do not confuse --size with --device-size — the latter accepts unit suffixes (M, G, MiB), but this guide uses --size because it matches the cryptsetup status sector output. Omit --size to grow to the backing device maximum, or pass an explicit sector count when shrinking.
Step 3: Grow ext4 on the mapper
With the mapper still open, grow the filesystem. ext4 can expand online while mounted:
sudo resize2fs /dev/mapper/resize_demoSample output:
resize2fs 1.47.2 (1-Jan-2025)
Filesystem at /dev/mapper/resize_demo is mounted on /mnt/resize-demo; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 1
The filesystem on /dev/mapper/resize_demo is now 782075 (4k) blocks long.Check usable space at the mount point:
df -h /mnt/resize-demoSample output:
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/resize_demo 2.9G 532K 2.8G 1% /mnt/resize-demoExtend order in one line: partition → cryptsetup resize → resize2fs. For related flags and operations, see the cryptsetup command cheatsheet.
Shrink a LUKS partition
Shrinking is offline work:
umount- Shrink filesystem (
resize2fs) - Shrink LUKS payload (
cryptsetup resize --size) - Shrink partition (
parted resizepart)
Target sizes:
- Loop lab: 1800 M on the ~2.9 G filesystem after the extend demo
- 5 G
secure_data: pick a target smaller than the current filesystem size, but larger than the data currently used, with a safety margin
Step 1: Unmount and run a full fsck
Take the filesystem offline, then force a full check before shrinking. On production disks, answer repair prompts yourself:
sudo umount /mnt/resize-demo
sudo e2fsck -f /dev/mapper/resize_demoIn a disposable lab (or a script where you accept automatic repairs), add -y:
sudo e2fsck -fy /dev/mapper/resize_demoSample output:
e2fsck 1.47.2 (1-Jan-2025)
Pass 1: Checking inodes, blocks, and sizes
...
/dev/mapper/resize_demo: 13/195072 files (0.0% non-contiguous), 22095/782075 blocksDo not use -y on real data unless you are sure every automatic repair is acceptable.
Step 2: Shrink ext4 to the target size
Shrink the filesystem offline to 1800 M (smaller than the current ~2.9 G lab size):
sudo resize2fs /dev/mapper/resize_demo 1800MSample output:
resize2fs 1.47.2 (1-Jan-2025)
Resizing the filesystem on /dev/mapper/resize_demo to 460800 (4k) blocks.
The filesystem on /dev/mapper/resize_demo is now 460800 (4k) blocks long.If the filesystem is still mounted, ext4 stops you. Remount and try shrinking again to see the error:
sudo mount /dev/mapper/resize_demo /mnt/resize-demo
sudo resize2fs /dev/mapper/resize_demo 1500MSample output:
resize2fs 1.47.2 (1-Jan-2025)
resize2fs: On-line shrinking not supported
Filesystem at /dev/mapper/resize_demo is mounted on /mnt/resize-demo; on-line resizing requiredUnmount first, then rerun resize2fs.
Step 3: Shrink the LUKS mapper with --size in sectors
Pass a sector count slightly larger than the shrunk filesystem:
- Lab value:
3775000sectors (512-byte units) - Read
cryptsetup statusafterresize2fsif you are unsure
Unmount (if needed), then shrink the LUKS payload:
sudo umount /mnt/resize-demo
sudo cryptsetup resize resize_demo --size 3775000Suffixes like 512M are not valid for --size. This fails immediately:
sudo cryptsetup resize resize_demo --size 512MSample output:
cryptsetup: invalid numeric valueAlways use a plain integer sector count with --size. Verify the LUKS payload shrank:
sudo cryptsetup status resize_demo | grep 'size:'Sample output:
size: 3775000 [512-byte units] (1932800000 [bytes])Step 4: Shrink the partition
parted resizepart expects an absolute end sector on the disk—not a value relative to the partition start. Read the partition start sector first:
sudo parted /dev/loop24 unit s printSample output:
Number Start End Size File system Name
1 2048s 6291422s 6289375s primaryCalculate the new absolute end sector:
new_partition_end = partition_start + LUKS_offset + LUKS_size - 1For this lab (partition_start 2048, LUKS_offset 32768, LUKS_size 3775000):
2048 + 32768 + 3775000 - 1 = 3809815Shrink partition 1 to that absolute sector:
sudo parted /dev/loop24 unit s resizepart 1 3809815sparted asks Yes/No? when shrinking — answer Yes. Then verify the partition is still large enough for the LUKS header and payload:
lsblk -o NAME,SIZE,TYPE,FSTYPE /dev/loop24
sudo cryptsetup status resize_demo | grep -E 'size:|offset:'Check:
partition_length(in sectors) ≥LUKS_offset + LUKS_size- Equivalently, the partition end sector you passed is ≥
partition_start + LUKS_offset + LUKS_size - 1
LVM on LUKS extend and shrink order
Stack: partition → LUKS → LVM → filesystem
The LUKS mapper is the LVM physical volume. You must resize the PV with pvresize whenever the mapper size changes.
| Goal | Correct order for partition → LUKS → LVM → filesystem |
|---|---|
| Extend | Grow partition (if needed) → cryptsetup resize → pvresize /dev/mapper/name → lvextend → grow filesystem (resize2fs, xfs_growfs, etc.) |
| Shrink | Shrink filesystem → lvreduce → pvresize --setphysicalvolumesize SIZE /dev/mapper/name → cryptsetup resize --size SECTORS → shrink partition |
cryptsetup resize --size before reducing the LVM PV. That can truncate the physical volume while logical volumes still expect extents near the end of the mapper.
LVM cautions:
- Shrink the filesystem before
lvreduce— reducing the LV first can destroy data - If
pvresize --setphysicalvolumesizerefuses because extents sit near the end of the PV, move or remove those extents first; do not force the LUKS or partition layer smaller until LVM reports the PV fits the target size - On another host, open and unlock LUKS before resizing LVM or the filesystem
Order-of-operations pitfalls
| Mistake | What goes wrong | Fix |
|---|---|---|
resize2fs before growing partition/LUKS |
Filesystem has no room to grow | Extend partition/image first, then cryptsetup resize, then resize2fs |
cryptsetup resize before shrinking filesystem |
LUKS area smaller than ext4 superblock | Shrink ext4 offline first, then cryptsetup resize --size |
| Shrink partition before LUKS/filesystem | Truncates encrypted data | Shrink filesystem and LUKS, then partition last |
Wrong parted end sector (LUKS offset only) |
Partition ends inside the LUKS area | Use absolute end: partition_start + LUKS_offset + LUKS_size - 1 |
cryptsetup resize --size before lvreduce/pvresize |
Truncates LVM PV while LVs still use extents | Shrink filesystem → lvreduce → pvresize --setphysicalvolumesize → then LUKS and partition |
Extend LUKS without pvresize |
lvextend has no free PV space |
Run pvresize /dev/mapper/name after cryptsetup resize |
cryptsetup resize --size 512M |
invalid numeric value for --size |
Use --size SECTORS (512-byte sectors), not --device-size syntax on --size |
| Shrink ext4 while mounted | On-line shrinking not supported |
umount, then resize2fs |
Skip e2fsck -f before shrink |
resize2fs may refuse or corrupt |
Always force-check offline before shrinking |
Filesystem larger than LUKS size |
I/O errors, mount failures | Grow LUKS with cryptsetup resize before resize2fs when extending |
truncate on loop image without losetup -c |
Partition grows but LUKS cannot extend | Run losetup -c (or detach and reattach) after growing the image file |
btrfs and XFS notes
This guide focuses on ext4 (offline shrink is supported). Other filesystems:
| Filesystem | Grow | Shrink |
|---|---|---|
| ext4 | resize2fs (online after LUKS grow) |
resize2fs SIZE offline only |
| btrfs | btrfs filesystem resize |
btrfs filesystem resize with negative size (online shrink possible) |
| XFS | xfs_growfs mountpoint |
No shrink—backup, recreate smaller LUKS, restore |
Non-ext4 notes:
- XFS on LUKS — no in-place shrink; migrate data, recreate smaller LUKS, restore
- btrfs on LUKS — shrink btrfs first, then
cryptsetup resize --size, then the partition
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
On-line shrinking not supported |
ext4 shrink attempted on a mounted filesystem | Unmount (or boot rescue media for root), run e2fsck -f, then resize2fs /dev/mapper/name TARGET |
invalid numeric value from cryptsetup resize |
Suffix (512M, 3G) passed to --size (sectors only) |
Read size: from cryptsetup status, or use --device-size with units—not on --size |
| Filesystem bigger than LUKS after extend | resize2fs ran before cryptsetup resize |
Grow the mapper first: sudo cryptsetup resize resize_demo, then sudo resize2fs /dev/mapper/resize_demo |
cryptsetup resize fails or hangs with no output |
Backing partition still at old size (common on loop images after truncate) |
losetup -c, sgdisk -e, partprobe, then parted resizepart before cryptsetup resize |
resize2fs: requested size larger than containing partition |
Target shrink size exceeds current filesystem | Pick a target smaller than current filesystem size but larger than used data, with margin |
| Data past the new end after shrink | Partition shortened before filesystem and LUKS payload shrank | Restore from backup or LUKS header backup if available; do not mount and write |
References
- pvresize(8) man page
- cryptsetup FAQ — resizing (official)
- cryptsetup(8) man page
- resize2fs(8) man page
Summary
- Extend (plain partition): grow partition/image →
cryptsetup resize→resize2fs /dev/mapper/name - Shrink (plain partition): umount →
e2fsck -f→resize2fs TARGET→cryptsetup resize --size SECTORS→parted resizepartwith absolute endpartition_start + LUKS_offset + LUKS_size - 1 - LVM inside LUKS: add
pvresizeon extend andlvreduce+pvresize --setphysicalvolumesizebefore shrinking LUKS - Back up data and the LUKS header before any shrink; wrong ordering causes permanent loss

