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 /home larger.

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 partitionRelative difficulty
swapeasiest to recreate
archive / backup datausually easy to move
/home or another user-data filesystemusually movable with planning
application datamovable, but may require downtime
/varsensitive
/usrvery sensitive
/very sensitive
boot / EFIavoid 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-LVMLVM
Keep /home as the same pathYesYes
Grow an existing diskEasy when the layout permitsEasy when the layout permits
Partition needs adjacent free spaceYesYes, if growing that same PV partition
Add another disk to the same logical storageNot directlyYes
Combine capacity from multiple disks/LUNsNot directlyYes, through PVs and a VG
Avoid moving an unrelated blocking partitionOften requires migration or rearrangementOften possible by adding another PV
Number of storage layersFewerMore
TroubleshootingSimplerRequires PV/VG/LV knowledge
Simple fixed-purpose serverExcellentSometimes unnecessary
Long-lived server that keeps growingCan become layout-dependentUsually 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:

/home is almost full. How do I make the same /home larger 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.