When /home Is Full: Why LVM Makes Storage Expansion Easier
· 15 min read
Most storage expansion problems I run into start with something simple:
df -h
Imagine I see this:
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-root--lv 50G 20G 30G 40% /
/dev/sda2 2G 250M 1.7G 13% /boot
/dev/mapper/ubuntu--vg-home--lv 100G 95G 5G 95% /home
/home is almost full.
Maybe it contains application files, deployment directories, uploads, source code, user files, or other data that has grown over time.
The path is already in use. Everything is working. I just need more space.
What I want is simple:
/home
100 GB
becomes:
/home
300 GB
without changing /home into another path.
That is the problem this article is about.
Sometimes this is easy without LVM.
Sometimes the partition layout gets in the way.
And sometimes the easiest solution is to attach another disk or iSCSI LUN and let LVM add that capacity underneath the same /home filesystem.
First: what does df -h actually show?
df means disk free.
The -h option means human-readable.
So:
df -h
shows filesystem capacity in values such as:
100G
95G
5G
The important part is this:
/home
is only the mount point.
It is not necessarily the physical disk.
There may be several storage layers underneath it.
For example, this:
/dev/mapper/ubuntu--vg-home--lv → /home
already tells me /home is backed by an LVM Logical Volume.
Disk, partition, filesystem, and mount point are different
A simple non-LVM storage stack might look like:
Disk
↓
Partition
↓
Filesystem
↓
Mount point
For example:
/dev/sda
↓
/dev/sda3
↓
ext4
↓
/home
These are different things:
/dev/sda
→ whole disk
/dev/sda3
→ one partition on that disk
ext4
→ filesystem
/home
→ directory where the filesystem is mounted
The user or application normally only cares about:
/home
What is /dev?
Linux exposes devices through special device nodes under:
/dev
For example:
/dev/sda
/dev/sdb
/dev/sdc
are block-device names.
/dev/sda usually represents a whole disk-like device.
A number after it normally means a partition:
/dev/sda
├── /dev/sda1
├── /dev/sda2
├── /dev/sda3
└── /dev/sda4
NVMe devices look different:
/dev/nvme0n1
/dev/nvme0n1p1
Virtio disks may appear as:
/dev/vda
/dev/vdb
So I never assume the new disk will definitely be /dev/sdb.
I check:
lsblk
The real problem: /home is full
Suppose I do not use LVM.
My server might look like this:
/dev/sda
├── /dev/sda1 → EFI
├── /dev/sda2 → /boot
├── /dev/sda3 → /
└── /dev/sda4 → /home
And:
df -h /home
shows:
Filesystem Size Used Avail Use% Mounted on
/dev/sda4 100G 95G 5G 95% /home
The requirement is not:
Give me another directory.
It is:
Make the existing
/homelarger.
Non-LVM: when growing /home is easy
Suppose /home is the final partition on the disk:
/dev/sda
├── sda1 → EFI
├── sda2 → /boot
├── sda3 → /
└── sda4 → /home 100 GB
The virtual disk is 200 GB.
I increase it in Proxmox to 400 GB.
Linux may now see:
/dev/sda = 400 GB
while /dev/sda4 is still only 100 GB.
The layout is now conceptually:
[/ EFI ][ /boot ][ / ][ /home 100G ][ free 200G ]
This is the easy case.
The free space is directly after /home.
So /home can expand into it.
For an ext4 filesystem, a common flow is conceptually:
lsblk
growpart /dev/sda 4
resize2fs /dev/sda4
df -h /home
For XFS, after the partition is enlarged, the filesystem is normally grown from the mount point:
xfs_growfs /home
In this situation, non-LVM is perfectly fine.
LVM is not required just for the sake of using LVM.
Why a normal partition needs free space next to it
A normal partition represents one continuous range of sectors on one disk.
Think of the disk as a row of rooms:
[ room 1 ][ room 2 ][ room 3 ][ empty ]
If /home is the last room before the empty space:
[/home][free]
it can simply grow to the right:
[/home................]
But this is different:
[/home][another partition][free]
/home cannot jump over that other partition.
The free capacity exists, but it is in the wrong place.
A real non-LVM case where adding disk capacity does not immediately help /home
Suppose the original disk is:
/dev/sda 200 GB
├── sda1 1 GB → EFI
├── sda2 2 GB → /boot
├── sda3 80 GB → /
├── sda4 100 GB → /home
└── sda5 10 GB → swap
Ignore the exact totals here; the important part is the order:
[ EFI ][ /boot ][ / ][ /home ][ swap ]
Now /home is almost full.
I enlarge the virtual disk by 200 GB.
The disk becomes larger, but the layout becomes:
[ EFI ][ /boot ][ / ][ /home ][ swap ][ free 200G ]
The new space exists.
But /home cannot directly use it.
Why?
Because swap is sitting between /home and the free space.
The partition that can naturally grow into the new free space is actually the last partition, which in this example is swap:
[ /home ][ swap ][ free ]
could become:
[ /home ][ swap............. ]
But that does not solve the problem because the thing that is full is /home, not swap.
Can I just make swap smaller and give that space to /home?
Not quite.
Suppose I start with:
[/home 100G][swap 10G][free 200G]
If I only shrink swap from its right side:
[/home 100G][swap 5G][free 205G]
swap is still in the middle.
/home still cannot reach the free space.
What I really need is to move swap out of the way.
Because swap does not contain permanent files, this particular case is relatively manageable.
Conceptually:
Before:
[/home 100G][swap 10G][free 200G]
Temporarily remove/recreate swap:
[/home 100G][free 210G]
Grow /home:
[/home 300G][free 10G]
Create swap again at the end:
[/home 300G][swap 10G]
So non-LVM is not impossible here.
It simply requires changing the partition layout.
If this is urgent, what do I do?
Before touching partitions, I first identify exactly what is mounted where:
lsblk -f
findmnt /home
swapon --show
free -h
That matters because deleting the wrong partition is obviously much worse than running out of disk space.
If the only thing blocking /home is swap, the high-level emergency procedure is:
verify the layout
↓
make sure RAM can survive without the current swap
↓
disable the old swap
↓
remove/recreate the swap partition layout
↓
grow the /home partition
↓
grow the filesystem
↓
create swap again at the end
↓
enable swap again
If swap is heavily used and RAM is tight, I would not blindly run swapoff.
A temporary swap file can be useful before changing the old swap partition.
The important lesson is that an urgent non-LVM fix may be possible, but it can involve more moving parts than simply adding capacity.
What if the blocking partition is /home, ordinary data, or system data?
The answer depends on what that partition contains.
If the blocking partition is swap
This is usually the easiest case because swap can be recreated.
[target][swap][free]
can often be rearranged into:
[target........][swap]
If the blocking partition contains movable data
Suppose the layout is:
[/home][/archive][free]
or:
[/home][/srv][free]
If the blocking filesystem contains ordinary data, I can move that data somewhere else first.
Conceptually:
1. copy the blocking filesystem to another disk
2. verify the copy
3. unmount the old filesystem
4. remove or recreate its old partition
5. grow /home
6. recreate the other filesystem if needed
7. restore the data
When moving Linux files, I care about more than file contents.
I also want to preserve ownership, permissions, timestamps, symlinks, ACLs, and extended attributes.
A command such as:
rsync -aHAX /source/ /mnt/temporary-disk/
is often more appropriate than a simple file copy.
I still verify the result before removing the original filesystem.
Sometimes the cleaner design is to leave that data permanently on the new disk instead of putting it back.
If the blocking partition contains system data
Now the risk is much higher.
For example:
[/home][/var][free]
or:
[/home][/usr][free]
or a layout involving the root filesystem:
[/home][/][free]
/var, /usr, and / are not just ordinary folders that I casually move while Linux is running.
They may contain or be actively used by:
system services
logs
package-manager data
Docker
libraries
databases
application state
boot-time files
For a case like that, I usually prefer one of these approaches:
attach another disk and migrate /home there
or, if the partition table really must be rearranged:
use a maintenance or rescue environment
The more important the blocking filesystem is to the running OS, the less attractive live partition surgery becomes.
A simple way to think about it is:
| Blocking partition | Relative difficulty |
|---|---|
| swap | easiest to recreate |
| archive / backup data | usually easy to move |
/home or another user-data filesystem | usually movable with planning |
| application data | movable, but may require downtime |
/var | sensitive |
/usr | very sensitive |
/ | very sensitive |
| boot / EFI | avoid touching unless necessary |
Another non-LVM problem: the new capacity arrives as another disk
There is another common situation.
Instead of enlarging the existing disk, Proxmox or the storage platform gives me another disk:
/dev/sda = existing disk
/dev/sdb = new 200 GB disk
My /home filesystem may still live on:
/dev/sda4
↓
ext4
↓
/home
A normal ext4 or XFS filesystem on /dev/sda4 cannot simply say:
use the old blocks from /dev/sda4
plus 200 GB from /dev/sdb
They are separate block devices.
Without another storage layer, I normally need to migrate /home to the new disk, create another mount layout, or otherwise redesign the storage.
This is one of the reasons LVM exists.
Why LVM exists
Traditional partitions are closely tied to where storage physically sits.
LVM adds an abstraction layer so I can manage storage based more on how much capacity I need than on exactly where that capacity happens to be located.
The simplest summary is:
Partitions manage pieces of disks. LVM manages pools of storage.
Without LVM, I think about things such as:
Which partition is last?
Where is the free space?
What partition is in the way?
Can I enlarge this exact disk?
Do I need to move another filesystem first?
With LVM, I can create a storage pool and allocate logical volumes from it.
The main terms are:
PV
Physical Volume
VG
Volume Group
LV
Logical Volume
I think of them like this:
PV
→ storage given to LVM
VG
→ a pool containing that storage
LV
→ a logical block device allocated from the pool
The stack becomes:
Disk or LUN
↓
PV
↓
VG
↓
LV
↓
Filesystem
↓
/home
A simple /home example with LVM
Suppose /home starts with 100 GB:
/dev/sda → PV
↓
ubuntu-vg
↓
home-lv 100 GB
↓
ext4
↓
/home
Now /home reaches 95 GB used.
I need another 200 GB.
Instead of rearranging old partitions, I attach another 200 GB disk:
/dev/sdb = 200 GB
I can give that disk to LVM:
old PV 100 GB ─┐
├── ubuntu-vg = 300 GB total capacity
new PV 200 GB ─┘
Then the Logical Volume backing /home can grow:
home-lv
100 GB → 300 GB
The filesystem grows too:
filesystem
100 GB → 300 GB
And the user still sees:
/home
Nothing about the application path needs to change.
How can two different disks look like one storage device?
This is the part that can feel strange at first.
Suppose I have:
/dev/sda = 100 GB
/dev/sdb = 200 GB
They are still physically two separate block devices.
LVM does not magically weld them into one physical disk.
Instead, LVM creates a mapping layer.
LVM divides Physical Volumes into chunks called Physical Extents (PEs).
Logical Volumes are built from corresponding Logical Extents (LEs).
Conceptually:
Physical storage:
Disk A
[ PE1 ][ PE2 ][ PE3 ]
Disk B
[ PE4 ][ PE5 ][ PE6 ]
LVM can map them into one logical sequence:
Logical Volume:
[ LE1 ][ LE2 ][ LE3 ][ LE4 ][ LE5 ][ LE6 ]
For example:
LE1 → PE on Disk A
LE2 → PE on Disk A
LE3 → PE on Disk A
LE4 → PE on Disk B
LE5 → PE on Disk B
LE6 → PE on Disk B
The filesystem above LVM sees one logical block device:
/dev/ubuntu-vg/home-lv
It does not need to care that some blocks ultimately live on one PV and some on another.
That is the trick.
LVM does not physically insert one disk into another
LVM is not doing this:
Disk A
[ old data ][ Disk B somehow inserted here ][ more data ]
The physical devices remain separate.
LVM simply maintains a logical map above them:
Disk A ─┐
├── VG → LV → filesystem → /home
Disk B ─┘
This is why the physical space does not need to be adjacent in the same way a normal partition does.
LVM does not magically fix a blocked partition
There is an important limitation.
Suppose the PV itself is a partition:
/dev/sda
├── /dev/sda3 → PV
└── /dev/sda4 → another filesystem
and free space exists after /dev/sda4.
LVM cannot make /dev/sda3 jump over /dev/sda4.
The normal partition rule still applies.
The advantage is that I may not need to grow /dev/sda3 at all.
I can attach another disk:
/dev/sdb → new PV
and add it to the existing VG:
/dev/sda3 → old PV ─┐
├── VG → LV → /home
/dev/sdb → new PV ─┘
So LVM does not remove the physical partition limitation.
It gives me another way around it.
A real LVM expansion flow
Suppose:
df -h /home
shows:
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-home--lv 100G 95G 5G 95% /home
I inspect the storage layers:
lsblk -f
pvs
vgs
lvs
Suppose the VG has no free capacity and I attach a new empty 200 GB disk that Linux identifies as /dev/sdb.
After carefully verifying that /dev/sdb is the intended empty disk, the LVM part is conceptually:
pvcreate /dev/sdb
vgextend ubuntu-vg /dev/sdb
lvextend -l +100%FREE /dev/ubuntu-vg/home-lv
Then I grow the filesystem.
For ext4:
resize2fs /dev/ubuntu-vg/home-lv
For XFS:
xfs_growfs /home
Afterward:
df -h /home
may show something like:
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-home--lv 300G 95G 205G 32% /home
The mount point is still exactly the same:
/home
Only the storage layers underneath it changed.
What if I enlarge the existing LVM disk instead?
LVM also works when I enlarge an existing virtual disk.
If the whole device is already a PV:
/dev/sdb
↓
PV
and Proxmox changes it from:
100 GB
to:
300 GB
then, after Linux sees the larger device, LVM can discover the new capacity with:
pvresize /dev/sdb
Then the flow is:
larger PV
↓
VG gains free capacity
↓
LV grows
↓
filesystem grows
↓
/home grows
If the PV is inside a partition such as /dev/sdb1, that partition may still need to grow first.
Again, LVM does not make partition geometry disappear.
Why df -h can stay unchanged after I add storage
Adding capacity at one layer does not automatically resize every layer above it.
For example:
Proxmox disk
300 GB
can still have:
partition
100 GB
or:
PV
100 GB
or:
LV
100 GB
or:
filesystem
100 GB
df -h reports the filesystem’s usable capacity.
So I think from bottom to top:
Proxmox / iSCSI
↓
block device
↓
partition, if used
↓
PV, if LVM is used
↓
VG
↓
LV
↓
filesystem
↓
/home
Then I ask:
Which layer has not grown yet?
My usual troubleshooting flow
I start with:
df -h
Then:
lsblk -f
For /home specifically:
findmnt /home
df -T /home
If LVM is involved:
pvs
vgs
lvs
Those commands answer different questions:
df -h
→ which filesystem is running out of space?
lsblk -f
→ what disks, partitions, filesystems, and mounts exist?
findmnt /home
→ what device actually backs /home?
pvs
→ which devices are LVM Physical Volumes?
vgs
→ how much total and free capacity exists in the Volume Group?
lvs
→ how large is the Logical Volume?
Non-LVM versus LVM
| Non-LVM | LVM | |
|---|---|---|
Keep /home as the same path | Yes | Yes |
| Grow an existing disk | Easy when the layout permits | Easy when the layout permits |
| Partition needs adjacent free space | Yes | Yes, if growing that same PV partition |
| Add another disk to the same logical storage | Not directly | Yes |
| Combine capacity from multiple disks/LUNs | Not directly | Yes, through PVs and a VG |
| Avoid moving an unrelated blocking partition | Often requires migration or rearrangement | Often possible by adding another PV |
| Number of storage layers | Fewer | More |
| Troubleshooting | Simpler | Requires PV/VG/LV knowledge |
| Simple fixed-purpose server | Excellent | Sometimes unnecessary |
| Long-lived server that keeps growing | Can become layout-dependent | Usually more flexible |
When I am happy with non-LVM
Non-LVM is perfectly reasonable when the layout is simple.
For example:
/dev/sda4
↓
ext4
↓
/home
If /dev/sda4 is the final partition and the virtual disk can be enlarged, growing /home can be very straightforward.
That is a good design.
When I prefer LVM
I prefer LVM when I expect storage requirements to change over the lifetime of the server.
A server may start with:
/home = 100 GB
then need:
/home = 300 GB
and later:
/home = 500 GB
The next capacity increase may come from:
a larger Proxmox virtual disk
another Proxmox virtual disk
an iSCSI LUN
another iSCSI LUN
LVM gives me a layer where those physical storage changes do not have to map directly to changes in the path the application or user sees.
LVM is not RAID
Combining capacity through LVM does not automatically make the data redundant.
If I have:
/dev/sda ─┐
├── VG
/dev/sdb ─┘
that does not mean every block exists on both devices.
It only means both devices can contribute storage capacity.
In simple terms:
LVM
→ flexible storage management
RAID
→ disk layout and possible redundancy
Backup
→ recovery from data loss
They solve different problems.
The point
The problem I care about is not simply:
How do I attach another disk?
It is:
/homeis almost full. How do I make the same/homelarger with the least disruptive change?
Without LVM, that may be very easy when /home is the last partition and the free space is directly after it.
But if the layout is:
[/home][swap][free]
or:
[/home][another filesystem][free]
then the partition in the middle has to be dealt with first.
If it is swap, it can usually be recreated.
If it contains movable data, I can migrate that data first.
If it contains important system data, I may prefer migration, maintenance mode, or a different disk instead of live partition surgery.
LVM exists to reduce how much storage management depends on that physical partition layout.
It lets me think in terms of a pool:
Disk / LUN 1 → PV ─┐
├── VG → LV → filesystem → /home
Disk / LUN 2 → PV ─┘
The underlying devices can change while /home remains /home.
That is the practical reason I usually prefer LVM for Linux servers that I expect to keep growing.
Comments
Comments are welcome — please read the comment policy first. Powered by giscus and GitHub Discussions.