Storage Operations Manual
Storage layer operations including LVM, file systems, mounting, and swap. For disk viewing/SMART, see disk-ops.md.
LVM (Logical Volume Management)
LVM three layers: PV (Physical Volume, disk/partition) → VG (Volume Group, PV pool) → LV (Logical Volume, block device that can be formatted).
pvdisplay pvs pvcreate /dev/sdb1 pvremove /dev/sdb1 pvresize /dev/sdb1
vgdisplay vgs vgcreate vg0 /dev/sdb1 vgextend vg0 /dev/sdc1 vgreduce vg0 /dev/sdc1 vgremove vg0
lvdisplay lvs lvcreate -L 50G -n data vg0 lvcreate -l 100%FREE -n data vg0 lvcreate -L 50G -n data vg0 --type raid1 lvremove vg0/data lvextend -L +10G vg0/data lvextend -l +100%FREE vg0/data lvreduce -L -10G vg0/data
resize2fs /dev/vg0/data xfs_growfs /mnt/data
lvrename vg0 oldname newname
lvcreate -L 5G -s -n snap_data vg0/data lvcreate -L 5G -s -n snap_data vg0/data --permission r lvconvert --merge vg0/snap_data lvs -a
vgscan --mknodes vgchange -ay vg0 vgchange -an vg0
File Systems
mkfs.ext4 -L mylabel /dev/sdb1 mkfs.ext4 -L mylabel -m 0 /dev/sdb1 mkfs.xfs -L mylabel /dev/vg0/data mkfs.btrfs -L mylabel /dev/sdb1 mkfs.vfat -F32 /dev/sdb1 mkfs.exfat /dev/sdb1 mkswap -L swap /dev/vg0/swap
e2label /dev/sdb1 mylabel xfs_admin -L mylabel /dev/vg0/data btrfs filesystem label /dev/sdb1 mylabel
blkid findfs UUID=abc123 dumpe2fs /dev/sdb1 | head -40 xfs_info /mnt/data btrfs filesystem show btrfs filesystem df /mnt
fsck /dev/sdb1 fsck -y /dev/sdb1 fsck -n /dev/sdb1 xfs_repair /dev/vg0/data xfs_repair -n /dev/vg0/data btrfs check /dev/sdb1 btrfs check --repair /dev/sdb1
tune2fs -c 1 /dev/sdb1 touch /forcefsck
Mounting (mount / fstab)
mount /dev/sdb1 /mnt/data
mount -t ext4 /dev/sdb1 /mnt/data mount -o ro,noexec /dev/sdb1 /mnt/data mount -o remount,rw / mount -o remount,ro / umount /mnt/data umount -l /mnt/data umount -f /mnt/data fuser -mv /mnt/data
mount -a findmnt --verify
findmnt findmnt -t ext4,xfs findmnt /home
Swap
swapon --show free -h cat /proc/swaps
swapon /dev/vg0/swap swapoff /dev/vg0/swap mkswap -L swap /dev/vg0/swap swapon -a
dd if=/dev/zero of=/swapfile bs=1M count=4096 chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
sysctl vm.swappiness
Common btrfs Operations
btrfs subvolume list / btrfs subvolume create /mnt/@data btrfs subvolume delete /mnt/@data btrfs subvolume snapshot /mnt/@data /mnt/@data-snap
btrfs scrub start /mnt
btrfs scrub status /mnt
btrfs scrub cancel /mnt
btrfs device add /dev/sdc1 /mnt btrfs device delete /dev/sdc1 /mnt btrfs balance start /mnt
Partition Operations
fdisk -l gdisk -l parted -l
gdisk /dev/sdb
parted /dev/sdb mklabel gpt parted /dev/sdb mkpart primary ext4 0% 100% parted /dev/sdb mkpart primary ext4 1MiB 51201MiB
growpart /dev/sdb 1
sgdisk --backup=table.bak /dev/sdb sgdisk --load-backup=table.bak /dev/sdb
ZFS (Zettabyte File System)
Pool: tank
| Property | Value |
| Type | Mirror (2-way) |
| Disks | WDC WD40EFZZ 4TB ×2 (D4-320 USB3) |
| ashift | 12 (4K) |
| ARC Limit | 32GB (/etc/modprobe.d/zfs.conf) |
| Mount Point | /tank |
| Created | 2026-07-02 |
/dev/disk/by-id/ata-WDC_WD40EFZZ-68CPAN0_WD-WX12DA5H2PCN → sda
/dev/disk/by-id/ata-WDC_WD40EFZZ-68CPAN0_WD-WX12DA5H234S → sdb
Dataset Layout
| Dataset | recordsize | compression | Purpose | Shared |
| tank | 128K | lz4 | Root | - |
| tank/media | 1M | lz4 | Home movie library | SMB + NFS |
| tank/photos | 128K | lz4 | Home photo album | SMB + NFS |
| tank/data | 128K | lz4 | Additional storage | SMB + NFS |
| tank/backup | 128K | lz4 | Backup container | Not shared |
| tank/backup/system | 1M | lz4 | System disk backup (restic) | Not shared |
Common Operations
zpool status tank zpool list -v tank zfs list -r tank zpool events tank -v
zpool scrub tank zpool scrub -s tank zpool status tank | grep scan
zfs snapshot tank/documents@before-reorg zfs list -t snapshot zfs rollback tank/documents@before-reorg zfs destroy tank/documents@old-snap
zpool offline tank <faulty_disk_ID>
zpool replace tank <old_disk_ID> <new_disk_ID>
zpool status -v tank
zpool export tank zpool import -d /dev/disk/by-id/ tank
arc_summary zpool iostat -v 1
Service List
| Service | systemd unit | Description |
| Samba | smb.service | Guest share /tank/{media,photos,data} |
| NFS | nfs-server.service | Export to 192.168.31.0/24 |
| ZFS Mount | zfs-mount.service | Auto-mount datasets on boot |
| ZFS Events | zfs-zed.service | Disk failure email notification (root) |
| ZFS Metrics | zfs-prometheus.timer | Collect every 5 minutes → Prometheus |
| Monthly Scrub | zfs-scrub-monthly@tank.timer | Monthly data integrity check |
Grafana Monitoring
- Dashboard: Host Status / li-home-0 · ZFS Pool (uid: host-li-home-0-zfs)
- Alert Rules:
/etc/grafana/provisioning/alerting/zfs-storage.yaml
- pool DEGRADED/FAULTED → critical
- Capacity >80% → warning, >90% → critical
- Single VDEV failure → critical
- ARC hit rate <50% → warning
Recovery Procedures
Single Disk Failure (mirror survives)
zpool status tank to confirm faulty disk ID
- Physically replace the faulty disk
zpool replace tank <old> <new>
zpool status -v tank to monitor resilver completion
Pool Cannot Be Imported
ls /dev/disk/by-id/ata-* to confirm disks are visible
zpool import -f -d /dev/disk/by-id/ tank to force import
- If already exported:
zpool import -d /dev/disk/by-id/ -a
Samba Unavailable
systemctl status smb
zfs mount to confirm /tank is mounted
testparm && systemctl restart smb
NFS Unavailable
systemctl status nfs-server
showmount -e localhost
exportfs -ra
USB Disk Disconnection (D4-320)
- Check if USB cable is loose
dmesg | tail -30 to check for USB disconnect
echo "0224" | sudo -S modprobe -r usb-storage uas && echo "0224" | sudo -S modprobe uas usb-storage
zpool online tank <disk> (if it went offline automatically)