Home > Uncategorized > Reduce a filesystem, a logical volume and even a physical disk

Reduce a filesystem, a logical volume and even a physical disk

Imagine that your linux system is running on a 1To drive. At one point you needed 1To but nowaday you only use 70Go on it. You may want to transfer your system to a smaller drive either to :

  • Reuse this 1To physical drive in another system
  • Free up some space on your host if this 1To drive is a thick provisioned virtual hard drive

As a reminder, if this 1To drive is a virtual thin provisioned hard drive, you can reclaim the space by ensuring that your hypervisor is correctly configured to support discard on this drive, then run the fstrim command in the linux VM. The discard option in fstab would trim automatically

In the following example, the system is a debian VM using LVM and the hard drive will be changed from 32G to 10G.
My filesystem type on the root partition I’ll shrink is ext4 and I boot using UEFI

Before starting be sure you have a backup of your data. You could loose all your data if something goes wrong.
To be able to perform this operation, your filesystem should not be mounted.
In my case I’m shrinking the root filesystem so I’ll boot on a debian system installed on a second disk.
Another option would be to boot in the debian installation media and choose Advanced -> Rescue mode in the installer to get a shell and perform the commands. If you do so, ensure to answer “do not use a root file system” when the installer will ask what partition to use a the root filesystem.

Let’s start by identifying the drives and filesystem to reduce

root@debian:~# lsblk 
NAME                  MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda                     8:0    0    7G  0 disk 
├─sda1                  8:1    0  512M  0 part /boot/efi
├─sda2                  8:2    0  5.5G  0 part /
└─sda3                  8:3    0  976M  0 part [SWAP]
sdb                     8:16   0   32G  0 disk 
├─sdb1                  8:17   0  512M  0 part 
├─sdb2                  8:18   0  488M  0 part 
└─sdb3                  8:19   0   31G  0 part 
  ├─debian--vg-root   254:0    0 30.1G  0 lvm  
  └─debian--vg-swap_1 254:1    0  976M  0 lvm  
sdc                     8:32   0   10G  0 disk 
root@debian:~# fdisk -l /dev/sdb
Disk /dev/sdb: 32 GiB, 34359738368 bytes, 67108864 sectors
Disk model: QEMU HARDDISK   
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 0C445618-2828-451C-BBD8-3105C88F2D06

Device       Start      End  Sectors  Size Type
/dev/sdb1     2048  1050623  1048576  512M EFI System
/dev/sdb2  1050624  2050047   999424  488M Linux filesystem
/dev/sdb3  2050048 67106815 65056768   31G Linux LVM  

In my case the original hard drive is sdb and target is sdc.
sdb have 3 parition, sdb1 is the EFI parition, sdb2 is the boot partition and sdb3 is the LVM partition where my root and swap partition is located.

We will shrink “debian–vg-root” and move everything from sdb to sdc

Let’s see/confirm the current root filesystem size.

root@debian:~# mount /dev/debian-vg/root /mnt
root@debian:~# df -h | grep root
/dev/mapper/debian--vg-root   30G  1.7G   27G   6% /mnt
root@debian:~# umount /dev/debian-vg/root

To be able to reduce the logical volume root of the debian-vg volume group we must start be reducing the filesystem size.

We start by a forced fsck check on the filesystem

root@debian:~# e2fsck -f /dev/debian-vg/root 
e2fsck 1.47.0 (5-Feb-2023)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/debian-vg/root: 38223/1970416 files (0.2% non-contiguous), 590657/7879680 blocks

Then reduce your filesystem with the resize2fs command. The -M option will reduce as much as possible. This command could be very long to execute depending to the size of the filesystem

root@debian:~# resize2fs -M /dev/debian-vg/root 
resize2fs 1.47.0 (5-Feb-2023)
resize2fs 1.47.0 (5-Feb-2023)
Resizing the filesystem on /dev/debian-vg/root to 784869 (4k) blocks.
The filesystem on /dev/debian-vg/root is now 784869 (4k) blocks long.

Check the result

root@debian:~# mount /dev/debian-vg/root /mnt
root@debian:~# df -h | grep root
/dev/mapper/debian--vg-root  2.8G  1.7G  1.1G  62% /mnt
root@debian:~# umount /dev/debian-vg/root

Now let’s resize the LVM logical volume. Stay safe between the filesystem size and the lv size. A lv smaller than the filesystem will destroy it. Add at least ~1G to be safe. Here I resize to 6G as i want to keep enough free space on the root filesystem

root@debian:~# lvresize -L 6G /dev/debian-vg/root 
  WARNING: Reducing active logical volume to 6.00 GiB.
  THIS MAY DESTROY YOUR DATA (filesystem etc.)
Do you really want to reduce debian-vg/root? [y/n]: y
  Size of logical volume debian-vg/root changed from <30.06 GiB (7695 extents) to 6.00 GiB (1536 extents).
  Logical volume debian-vg/root successfully resized.

You can extend the filesystem to 100% of the logical volume if you want


root@debian:~# e2fsck -f /dev/debian-vg/root
e2fsck 1.47.0 (5-Feb-2023)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/debian-vg/root: 38223/196224 files (0.2% non-contiguous), 474182/784869 blocks
root@debian:~# resize2fs /dev/debian-vg/root 
resize2fs 1.47.0 (5-Feb-2023)
Resizing the filesystem on /dev/debian-vg/root to 1572864 (4k) blocks.
The filesystem on /dev/debian-vg/root is now 1572864 (4k) blocks long.

root@debian:~# mount /dev/debian-vg/root /mnt
root@debian:~# df -h | grep root
/dev/mapper/debian--vg-root  5.8G  1.7G  3.9G  30% /mnt
root@debian:~# umount /mnt 

Let’s run lsblk again

root@debian:~# lsblk 
NAME                  MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda                     8:0    0    7G  0 disk 
├─sda1                  8:1    0  512M  0 part /boot/efi
├─sda2                  8:2    0  5.5G  0 part /
└─sda3                  8:3    0  976M  0 part [SWAP]
sdb                     8:16   0   32G  0 disk 
├─sdb1                  8:17   0  512M  0 part 
├─sdb2                  8:18   0  488M  0 part 
└─sdb3                  8:19   0   31G  0 part 
  ├─debian--vg-root   254:0    0    6G  0 lvm  
  └─debian--vg-swap_1 254:1    0  976M  0 lvm  
sdc                     8:32   0   10G  0 disk 

The sdb3 parition is still 31G but it’s content is only 6G+976M + 512M of sdb1 + 488M of sdb2 = ~8G. It will fit in sdc. We can start to move our data to the new disk.

Let’s see again the partition table of sdb

root@debian:~# fdisk -l /dev/sdb
Disk /dev/sdb: 32 GiB, 34359738368 bytes, 67108864 sectors
Disk model: QEMU HARDDISK   
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 0C445618-2828-451C-BBD8-3105C88F2D06

Device       Start      End  Sectors  Size Type
/dev/sdb1     2048  1050623  1048576  512M EFI System
/dev/sdb2  1050624  2050047   999424  488M Linux filesystem
/dev/sdb3  2050048 67106815 65056768   31G Linux LVM

Then we need to replicate this on sdc. Of course the LVM partition will be smaller.
I start by creating a GPT disklabel (as I’m using EFI boot. If you are using “Legacy bios” you need to create a MBR disklabel with o instead of g and making the new system bootable will require extra step not explained here)

root@debian:~# fdisk /dev/sdc

Welcome to fdisk (util-linux 2.38.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS (MBR) disklabel with disk identifier 0x9cf3f81a.

Command (m for help): g
Created a new GPT disklabel (GUID: 3D38E71C-613D-5345-AA1B-8979A377E738).

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Now we will replicate the partition table of sdb to sdc.

root@debian:~# fdisk /dev/sdc

Welcome to fdisk (util-linux 2.38.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): n
Partition number (1-128, default 1): 
First sector (2048-20971486, default 2048): 2048
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-20971486, default 20969471): +1048576

Created a new partition 1 of type 'Linux filesystem' and of size 512 MiB.

Command (m for help): t
Selected partition 1
Partition type or alias (type L to list all): 1
Changed type of partition 'Linux filesystem' to 'EFI System'.

Command (m for help): n
Partition number (2-128, default 2): 2
First sector (1050625-20971486, default 1052672): 1052672
Last sector, +/-sectors or +/-size{K,M,G,T,P} (1052672-20971486, default 20969471): +999424

Created a new partition 2 of type 'Linux filesystem' and of size 488 MiB.

Command (m for help): n
Partition number (3-128, default 3): 3
First sector (1050625-20971486, default 2054144): 2054144
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2054144-20971486, default 20969471): 

Created a new partition 3 of type 'Linux filesystem' and of size 9 GiB.

Command (m for help): t
Partition number (1-3, default 3): 3
Partition type or alias (type L to list all): lvm

Changed type of partition 'Linux filesystem' to 'Linux LVM'.

Command (m for help): p
Disk /dev/sdc: 10 GiB, 10737418240 bytes, 20971520 sectors
Disk model: QEMU HARDDISK   
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3D38E71C-613D-5345-AA1B-8979A377E738

Device       Start      End  Sectors  Size Type
/dev/sdc1     2048  1050624  1048577  512M EFI System
/dev/sdc2  1052672  2052096   999425  488M Linux filesystem
/dev/sdc3  2054144 20969471 18915328    9G Linux LVM

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

Let’s copy sdb1 to sdc1 and sdb2 to sdc2 (EFI and boot partition)

root@debian:~# dd if=/dev/sdb1 of=/dev/sdc1 bs=4k
131072+0 records in
131072+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 3.80218 s, 141 MB/s
root@debian:~# dd if=/dev/sdb2 of=/dev/sdc2 bs=4k
124928+0 records in
124928+0 records out
511705088 bytes (512 MB, 488 MiB) copied, 4.3996 s, 116 MB/s

We will now extend the lvm physical volume

root@debian:~# vgextend debian-vg /dev/sdc3 
  Physical volume "/dev/sdc3" successfully created.
  Volume group "debian-vg" successfully extended

Then move the volume group from sdb3 to sdc3.

root@debian:~# pvmove -v /dev/sdb3 /dev/sdc3
  Executing: /sbin/modprobe dm-mirror
  Creating logical volume pvmove0
  activation/volume_list configuration setting not defined: Checking only host tags for debian-vg/root.
  Moving 1536 extents of logical volume debian-vg/root.
  activation/volume_list configuration setting not defined: Checking only host tags for debian-vg/swap_1.
  Moving 244 extents of logical volume debian-vg/swap_1.
  activation/volume_list configuration setting not defined: Checking only host tags for debian-vg/root.
  activation/volume_list configuration setting not defined: Checking only host tags for debian-vg/swap_1.
  Archiving volume group "debian-vg" metadata (seqno 5).
  Creating debian--vg-pvmove0
  Loading table for debian--vg-pvmove0 (254:2).
  Loading table for debian--vg-root (254:0).
  Loading table for debian--vg-swap_1 (254:1).
  Suspending debian--vg-root (254:0) with device flush
  Suspending debian--vg-swap_1 (254:1) with device flush
  Resuming debian--vg-pvmove0 (254:2).
  Resuming debian--vg-root (254:0).
  Resuming debian--vg-swap_1 (254:1).
  activation/volume_list configuration setting not defined: Checking only host tags for debian-vg/pvmove0.
  Creating volume group backup "/etc/lvm/backup/debian-vg" (seqno 6).
  Checking progress before waiting every 15 seconds.
  /dev/sdb3: Moved: 0.39%
  /dev/sdb3: Moved: 52.36%
  /dev/sdb3: Moved: 86.29%
  /dev/sdb3: Moved: 100.00%
  Polling finished successfully.

The last step is to remove sdb3 from the volume group

root@debian:~# pvs
  PV         VG        Fmt  Attr PSize   PFree  
  /dev/sdb3  debian-vg lvm2 a--  <31.02g <31.02g
  /dev/sdc3  debian-vg lvm2 a--   <9.02g   2.06g
root@debian:~# vgreduce debian-vg /dev/sdb3
  Removed "/dev/sdb3" from volume group "debian-vg"
root@debian:~# pvs
  PV         VG        Fmt  Attr PSize  PFree 
  /dev/sdb3            lvm2 ---  31.02g 31.02g
  /dev/sdc3  debian-vg lvm2 a--  <9.02g  2.06g

You can now halt the system, remove the sdb disk and boot on the new disk.
Depending on your OS and the UEFI, you may need to tell the EFI to boot on the right file on the new disk. For example, you use debian and proxmox, you will need to create a new boot entry

Categories: Uncategorized Tags:
  1. No comments yet.
  1. No trackbacks yet.