本页目录

存储操作手册

LVM、文件系统、挂载、swap 等存储层操作。磁盘查看/SMART 见 disk-ops.md

LVM (逻辑卷管理)

LVM 三层: PV (物理卷, 磁盘/分区) → VG (卷组, PV 池) → LV (逻辑卷, 可格式化的块设备)。

# === PV 层 ===
pvdisplay                                 # 所有 PV 详情
pvs                                       # 简洁
pvcreate /dev/sdb1                        # 创建 PV
pvremove /dev/sdb1                        # 移除 (先确保 VG 中已移除)
pvresize /dev/sdb1                        # 分区扩容后刷新 PV 大小

# === VG 层 ===
vgdisplay                                 # 所有 VG 详情
vgs                                       # 简洁
vgcreate vg0 /dev/sdb1                    # 创建 VG, 加入一个 PV
vgextend vg0 /dev/sdc1                    # 往 VG 加新 PV (扩容池)
vgreduce vg0 /dev/sdc1                    # 从 VG 移除 PV (需先 pvmove 数据)
vgremove vg0                              # 删除 VG (!危险)

# === LV 层 ===
lvdisplay                                 # 所有 LV 详情
lvs                                       # 简洁
lvcreate -L 50G -n data vg0               # 创建 50G LV
lvcreate -l 100%FREE -n data vg0          # 用尽所有剩余空间
lvcreate -L 50G -n data vg0 --type raid1  # 镜像 LV (需 2 PV)
lvremove vg0/data                         # 删除 LV (!危险)
lvextend -L +10G vg0/data                 # 扩容 +10G
lvextend -l +100%FREE vg0/data            # 扩展到全部空闲空间
lvreduce -L -10G vg0/data                 # 缩容 (!慎用, XFS 不支持缩)

# 扩容后需扩展文件系统:
resize2fs /dev/vg0/data                   # ext4
xfs_growfs /mnt/data                      # XFS (需已挂载)

# 重命名
lvrename vg0 oldname newname

# 快照 (LVM thin 推荐)
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                                    # 查看快照 (含隐藏 LV)

# 扫描/激活
vgscan --mknodes                          # 重新扫描 VG 并创建设备节点
vgchange -ay vg0                          # 激活 VG 中所有 LV
vgchange -an vg0                          # 停用 VG

文件系统

# 创建
mkfs.ext4 -L mylabel /dev/sdb1            # ext4 带标签
mkfs.ext4 -L mylabel -m 0 /dev/sdb1       # -m 0 = 不预留 root 空间
mkfs.xfs -L mylabel /dev/vg0/data         # XFS
mkfs.btrfs -L mylabel /dev/sdb1           # btrfs
mkfs.vfat -F32 /dev/sdb1                  # FAT32 (EFI/U盘)
mkfs.exfat /dev/sdb1                      # exFAT (大文件 U 盘)
mkswap -L swap /dev/vg0/swap              # swap

# 标签
e2label /dev/sdb1 mylabel                 # ext 改标签
xfs_admin -L mylabel /dev/vg0/data        # XFS 改标签
btrfs filesystem label /dev/sdb1 mylabel  # btrfs 改标签

# 查看
blkid                                      # UUID + FS 类型
findfs UUID=abc123                         # UUID → 设备路径
dumpe2fs /dev/sdb1 | head -40             # ext 超级块信息
xfs_info /mnt/data                         # XFS 信息
btrfs filesystem show                      # btrfs 概览
btrfs filesystem df /mnt                   # btrfs 空间使用

# 修复 (必须先 umount)
fsck /dev/sdb1                             # ext (自动修复非严重问题)
fsck -y /dev/sdb1                          # 全部自动 yes
fsck -n /dev/sdb1                          # 只检查不修复
xfs_repair /dev/vg0/data                   # XFS 修复 (比 fsck 快)
xfs_repair -n /dev/vg0/data                # XFS 只检查
btrfs check /dev/sdb1                      # btrfs 检查 (只读)
btrfs check --repair /dev/sdb1             # btrfs 修复 (!慎用)

# 强制检查 (下次重启)
tune2fs -c 1 /dev/sdb1                     # 下次 mount 时 fsck
touch /forcefsck                           # 根分区强制检查 (systemd)

挂载 (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                        # lazy umount (等没人用了再卸)
umount -f /mnt/data                        # 强制卸载 (NFS 等无响应时)
fuser -mv /mnt/data                        # 谁在用这个挂载点

# 持久化: /etc/fstab
# UUID=abc123    /mnt/data    ext4    defaults,noatime    0 2
# /dev/vg0/swap  none         swap    sw                  0 0
# //server/share /mnt/smb    cifs    credentials=/etc/smb.cred,uid=1000  0 0

# 列含义: device  mountpoint  type  options  dump  fsck_order
# dump: 0=不备份, 1=备份
# fsck_order: 0=不检查, 1=根(最先), 2=其他

# fstab 常用 options:
# defaults = rw,suid,dev,exec,auto,nouser,async
# noatime     不更新访问时间 (SSD 推荐, 减少写入)
# relatime    仅当 atime < mtime 时更新 (折中)
# nodiratime  不更新目录访问时间
# discard     TRIM (NVMe 用内核内置 discard 更好)
# x-systemd.automount  访问时才挂载 (延迟挂载)
# x-systemd.device-timeout=10  等设备出现最多 10s

# 测试 fstab
mount -a                                   # 挂载 fstab 中所有未挂载项
findmnt --verify                           # 检查 fstab 语法

# 查看挂载
findmnt                                    # 挂载树
findmnt -t ext4,xfs                        # 按类型过滤
findmnt /home                              # 看 /home 的挂载源和选项

swap

# 查看
swapon --show                              # 当前 swap 状态 (设备/大小/使用量)
free -h                                    # 含 swap 使用
cat /proc/swaps                            # 内核视角

# 管理
swapon /dev/vg0/swap                       # 启用
swapoff /dev/vg0/swap                      # 禁用
mkswap -L swap /dev/vg0/swap               # 创建 swap 签名
swapon -a                                  # 启用 fstab 中所有 swap

# swap 文件 (备选方案)
dd if=/dev/zero of=/swapfile bs=1M count=4096  # 创建 4G
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
# fstab: /swapfile none swap sw 0 0

# swap 优先级 (多个 swap 时)
# swapon -p 10 /dev/sda1       # 0-32767, 越高越优先
# fstab: ... sw pri=10 0 0

# 调优
sysctl vm.swappiness                        # 当前 swappiness (0-100, 低=少用swap)
# 桌面推荐 1-10, 服务器视情况

btrfs 常用

# 子卷
btrfs subvolume list /                      # 列出子卷
btrfs subvolume create /mnt/@data           # 创建子卷
btrfs subvolume delete /mnt/@data           # 删除子卷
btrfs subvolume snapshot /mnt/@data /mnt/@data-snap  # 快照

# 压缩 (挂载选项)
# mount -o compress=zstd /dev/sdb1 /mnt
# fstab: UUID=... /mnt btrfs compress=zstd,noatime 0 0

# scrub (数据完整性校验)
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                    # 重新平衡数据分布

# RAID (btrfs 原生, 不要叠加 mdadm)
# mkfs.btrfs -m raid1 -d raid1 /dev/sdb1 /dev/sdc1

分区操作

# 查看
fdisk -l                                    # MBR
gdisk -l                                    # GPT (推荐)
parted -l                                   # 两种都支持

# 交互式分区
gdisk /dev/sdb                              # GPT
# n → 新建, d → 删除, w → 写入, q → 退出不保存

# 非交互
parted /dev/sdb mklabel gpt                 # 创建 GPT 分区表
parted /dev/sdb mkpart primary ext4 0% 100% # 一个分区占满
parted /dev/sdb mkpart primary ext4 1MiB 51201MiB  # 精确大小

# 分区扩容 (分区后有未分配空间)
growpart /dev/sdb 1                         # 扩展分区 1 到最大 (cloud-init 常用)
# 之后: resize2fs /dev/sdb1 或 xfs_growfs /mnt

# 分区表备份/恢复
sgdisk --backup=table.bak /dev/sdb          # 备份 GPT
sgdisk --load-backup=table.bak /dev/sdb     # 恢复

ZFS (Zettabyte File System)

Pool: tank

属性
类型Mirror (2-way)
WDC WD40EFZZ 4TB ×2 (D4-320 USB3)
ashift12 (4K)
ARC 上限32GB (/etc/modprobe.d/zfs.conf)
挂载点/tank
创建2026-07-02
# 设备标识 (by-id, 稳定)
/dev/disk/by-id/ata-WDC_WD40EFZZ-68CPAN0_WD-WX12DA5H2PCN  → sda
/dev/disk/by-id/ata-WDC_WD40EFZZ-68CPAN0_WD-WX12DA5H234S  → sdb

Dataset 布局

Datasetrecordsizecompression用途共享
tank128Klz4-
tank/media1Mlz4家庭电影库SMB + NFS
tank/photos128Klz4家庭相册SMB + NFS
tank/data128Klz4额外存储SMB + NFS
tank/backup128Klz4备份容器不共享
tank/backup/system1Mlz4系统盘备份 (restic)不共享

常用操作

# 状态与健康
zpool status tank                         # 池 + VDEV 状态
zpool list -v tank                        # 池大小/用量
zfs list -r tank                          # dataset 树
zpool events tank -v                      # 事件历史

# Scrub (数据完整性校验, 每月自动执行)
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       # 删除快照

# 磁盘替换 (mirror 降级时)
zpool offline tank <故障盘ID>
# 物理换盘后:
zpool replace tank <旧盘ID> <新盘ID>
zpool status -v tank                      # 监控 resilver

# 导入/导出
zpool export tank                         # 安全卸载 (迁移前)
zpool import -d /dev/disk/by-id/ tank     # 导入

# 性能监控
arc_summary                               # ARC 缓存详细统计
zpool iostat -v 1                         # 实时 IO (每秒)

服务清单

服务systemd unit说明
Sambasmb.serviceguest 共享 /tank/{media,photos,data}
NFSnfs-server.service导出到 192.168.31.0/24
ZFS 挂载zfs-mount.service开机自动挂载 dataset
ZFS 事件zfs-zed.service磁盘故障邮件通知 (root)
ZFS 指标zfs-prometheus.timer每 5 分钟采集 → Prometheus
月 scrubzfs-scrub-monthly@tank.timer数据完整性月检

Grafana 监控

  • Dashboard: 主机状态 / li-home-0 · ZFS Pool (uid: host-li-home-0-zfs)
  • 告警规则: /etc/grafana/provisioning/alerting/zfs-storage.yaml
    • pool DEGRADED/FAULTED → critical
    • 容量 >80% → warning, >90% → critical
    • 单 VDEV 故障 → critical
    • ARC 命中率 <50% → warning

恢复流程

单盘故障 (mirror 存活)

  1. zpool status tank 确认故障盘 ID
  2. 物理更换故障盘
  3. zpool replace tank <旧> <新>
  4. zpool status -v tank 监控 resilver 完成

池无法导入

  1. ls /dev/disk/by-id/ata-* 确认盘可见
  2. zpool import -f -d /dev/disk/by-id/ tank 强制导入
  3. 若已 export: zpool import -d /dev/disk/by-id/ -a

Samba 不可用

  1. systemctl status smb
  2. zfs mount 确认 /tank 挂载
  3. testparm && systemctl restart smb

NFS 不可用

  1. systemctl status nfs-server
  2. showmount -e localhost
  3. exportfs -ra

USB 盘掉线 (D4-320)

  1. 检查 USB 线缆是否松动
  2. dmesg | tail -30 查看是否有 USB disconnect
  3. echo "0224" | sudo -S modprobe -r usb-storage uas && echo "0224" | sudo -S modprobe uas usb-storage
  4. zpool online tank <盘> (如果自动 offline 了)