Converting a root filesystem from EXT4 to XFS while the system is running presents unique technical constraints. The primary obstacle is that the root partition contains:
- Running OS processes
- Active mount points
- Essential system daemons
Here's the step-by-step approach I've successfully used in production environments:
# 1. Create new EBS volume in the same AZ
aws ec2 create-volume --availability-zone us-east-1a --size 20 --volume-type gp3
# 2. Attach to your instance
aws ec2 attach-volume --volume-id vol-123456 --instance-id i-abcdef --device /dev/sdf
After attaching the new volume:
# Verify the disk is detected
lsblk
# Create partition table
sudo parted /dev/xvdf mklabel gpt
# Create primary partition
sudo parted -a opt /dev/xvdf mkpart primary 0% 100%
# Format as XFS
sudo mkfs.xfs /dev/xvdf1
# Create mount point and mount
sudo mkdir -p /mnt/xfs_volume
sudo mount /dev/xvdf1 /mnt/xfs_volume
For critical directories like /var/www and /var/lib/mysql:
# Use rsync for initial copy (run during low traffic)
sudo rsync -avz /var/www/ /mnt/xfs_volume/www/
# For MySQL, stop service first
sudo systemctl stop mysql
sudo rsync -avz /var/lib/mysql/ /mnt/xfs_volume/mysql/
Modify /etc/fstab to persist the mount:
# Add this line to /etc/fstab
UUID=(xfs_volume_uuid) /var/www xfs defaults,nofail 0 2
For database directories, consider symlink approach:
sudo mv /var/lib/mysql /var/lib/mysql.old
sudo ln -s /mnt/xfs_volume/mysql /var/lib/mysql
Key advantages for your backup workflow:
# Freeze filesystem before snapshot
sudo xfs_freeze -f /mnt/xfs_volume
# Create snapshot (via AWS CLI)
aws ec2 create-snapshot --volume-id vol-123456
# Unfreeze
sudo xfs_freeze -u /mnt/xfs_volume
Always test the new configuration before deleting old data:
# Create validation script
#!/bin/bash
if [ -f /var/www/index.php ]; then
echo "Web content verified"
else
echo "ERROR: Content missing" >&2
exit 1
fi
When your production server runs everything on a single ext4-formatted EBS volume, converting to XFS for better snapshot consistency becomes tricky. The main obstacle is that you can't modify the root filesystem while the system is running. Here's what we're dealing with:
# Current disk layout example
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda 202:0 0 50G 0 disk
└─xvda1 202:1 0 50G 0 part /
Instead of attempting a risky in-place conversion, we'll implement a safer migration path:
- Create new EBS volumes with XFS
- Migrate data partitions incrementally
- Maintain service availability throughout
1. Preparing New XFS Volumes
First, create and attach additional EBS volumes through AWS Console or CLI:
aws ec2 create-volume --availability-zone us-east-1a \
--volume-type gp2 --size 100 --tag-specifications \
'ResourceType=volume,Tags=[{Key=Name,Value=xfs-data}]'
After attaching to your instance, initialize them:
# List available disks
lsblk
# Format as XFS (example for /dev/xvdf)
mkfs.xfs /dev/xvdf
2. Migrating /var/www
For web content that needs snapshot consistency:
# Create temporary mount point
mkdir /mnt/xfs-www
# Mount new XFS volume
mount /dev/xvdf /mnt/xfs-www
# Sync data (using rsync for integrity)
rsync -avz /var/www/ /mnt/xfs-www/
# Update fstab
echo "/dev/xvdf /var/www xfs defaults,noatime 0 2" >> /etc/fstab
# Remount to final location
umount /mnt/xfs-www
mount /var/www
3. Handling Database Migration
For MySQL data in /var/lib/mysql:
# Stop MySQL service first
service mysql stop
# Create XFS volume for database
mkfs.xfs /dev/xvdg
# Mount and transfer data
mount /dev/xvdg /mnt/xfs-mysql
rsync -avz /var/lib/mysql/ /mnt/xfs-mysql/
# Update ownership
chown -R mysql:mysql /mnt/xfs-mysql
# Update fstab and remount
echo "/dev/xvdg /var/lib/mysql xfs defaults,noatime 0 2" >> /etc/fstab
umount /mnt/xfs-mysql
mount /var/lib/mysql
# Restart MySQL
service mysql start
After completing all migrations, verify filesystem types:
df -Th | grep -E 'Filesystem|/var/www|/var/lib'
Expected output should show XFS for migrated partitions while keeping ext4 for the root filesystem.
Now with XFS volumes, you can use AWS's native snapshot capability or implement pre/post snapshot scripts:
# Example pre-snapshot script for MySQL
FLUSH TABLES WITH READ LOCK;
FLUSH LOGS;
SHOW MASTER STATUS;
\! xfs_freeze -f /var/lib/mysql
# Post-snapshot
\! xfs_freeze -u /var/lib/mysql
UNLOCK TABLES;
For larger deployments, consider automating with AWS Systems Manager:
aws ssm send-command \
--instance-ids i-1234567890abcdef0 \
--document-name "AWS-RunShellScript" \
--parameters 'commands=["mkfs.xfs /dev/xvdf"]'
Remember to test the entire procedure in a staging environment before applying to production.