Hey everyone,
I finally upgraded my server with a dedicated SSD for /var. The goal was simple: production databases need room to breathe, and I wanted the magic of Btrfs snapshots without the performance hit on my root drive.
However, as with all "simple" Linux maintenance tasks, muscle memory and "Device Busy" errors had other plans. Here is the full story of how I migrated /var, accidentally used a 1990s partition table, locked myself out of the filesystem, and used a raw-disk mount trick to fix it all.
Step 1: The "Old Habit" Mistake
I installed the new drive (/dev/sdc) and immediately went into autopilot. I fired up fdisk, hit n for new, p for primary... and without thinking, I created a DOS (MBR) partition table.

I didn't notice. I happily formatted it as Btrfs, synced my data, and rebooted. It worked fine. Linux doesn't technically care if your 2TB drive uses a partition table from the DOS era.
But when I ran sudo fdisk -l /dev/sdc later to check my work, I saw Disklabel type: dos.
For a modern server, I wanted GPT. It supports larger drives, it’s more robust, and frankly, it bothered me to have a legacy setup on brand new hardware. So, I decided to fix it.
Step 2: The "Device Busy" Trap
I figured I would just unmount the drive, wipe it, and start over.
sudo umount /var
# Error: target is busy.
Of course it's busy. It's /var. It holds logs, databases, and cached data that the OS is constantly writing to.
"No problem," I thought. "I'll use a bind mount to move the folders out of the way and revert to the internal drive."
sudo mount --bind / /mnt
sudo mv /mnt/var /mnt/var.mountpoint
# Error: Device or resource busy
The Catch: When you run mount --bind / /mnt, you are creating a mirror of the active filesystem tree. This means /mnt/var in the mirror was also showing the mounted SSD. The kernel locked it there too. I was stuck.
Step 3: The "Inception" Fix (Mounting the Raw Disk)
To fix this, I had to bypass the running operating system and mount the underlying physical disk directly. This allowed me to manipulate the folders "underneath" the active SSD mount.
- Find the root partition:
findmnt -n -o SOURCE /
# Output: /dev/sda2
- Mount the raw partition (The Secret Sauce):
Instead of binding/, I mounted the physical device.
sudo mount /dev/sda2 /mnt
- Find the real folder:
Since I use Btrfs on root, I had to dig into the subvolume.
cd /mnt/@rootfs
- The Swap:
Now I was looking at the raw files on the disk, ignoring the fact that the OS was running on them. I moved the empty mount point folder out of the way and restored my backup data.
# Move the empty folder used for the SSD mount
sudo mv var var.mountpoint
# Restore the backup data to be the active /var again
sudo mv var.old var
I commented out the SSD line in /etc/fstab and rebooted. The system came back up running on the internal drive. Freedom.
Step 4: Doing It Right (GPT & Btrfs)
Now that the drive was unmounted, I did the setup again—correctly this time.
1. Partitioning (GPT Style)
I ran fdisk /dev/sdc but forced myself to break the habit:
g: Create a new GPT partition table.n: New partition (Accept defaults).w: Write.
2. Formatting & Subvolumes

sudo mkfs.btrfs -L "var_data" -f /dev/sdc1
sudo mount /dev/sdc1 /mnt
sudo btrfs subvolume create /mnt/@var
3. The "No-CoW" Secret Sauce (Critical!)
Btrfs "Copy-on-Write" kills database performance. You must disable it on empty folders before filling them.
# Create structure
sudo mkdir -p /mnt/@var/lib/mongodb
sudo mkdir -p /mnt/@var/lib/postgresql
# Disable CoW (+C attribute)
sudo chattr +C /mnt/@var/lib/mongodb
sudo chattr +C /mnt/@var/lib/postgresql
4. Migration & Fstab
I synced the data from the internal drive to the new SSD structure.
sudo rsync -avXAHS /var/ /mnt/@var/
Then I updated /etc/fstab with the new UUID (since I reformatted) and the optimized flags:

UUID=... /var btrfs defaults,noatime,compress=zstd:3,discard=async,space_cache=v2,subvol=@var 0 0
Step 5: The Final Switch
I repeated the "Inception" move one last time to swap the folders back, rebooted, and verified everything.
df -h /var: Shows the new 2TB size.fdisk -l /dev/sdc: ShowsDisklabel type: gpt.lsattr -d /var/lib/mongodb: Shows theC(No-CoW) flag.
The final touch was enabling btrbk to snapshot the new /var volume every night. Now I have a high-speed database drive with instant snapshots, and I finally broke my MBR muscle memory.

As always,
Michael Garcia a.k.a. TheCrazyGM