---
title: 存储操作手册
url: https://doc.liz6.com/devops/storage-ops
locale: zh
area: devops
tags:
- devops
date: 2026-06-30
modified: 2026-07-02
description: '存储操作手册 LVM、文件系统、挂载、swap 等存储层操作。磁盘查看/SMART 见 disk-ops.md。 LVM (逻辑卷管理) LVM 三层: PV (物理卷, 磁盘/分区) → VG (卷组, PV 池) → LV (逻辑卷, 可格式化的块设备)。 文件系统 挂载 (mount / fstab) swap …'
---

# 存储操作手册

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

## LVM (逻辑卷管理)

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

```bash
# === 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
```

## 文件系统

```bash
# 创建
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)

```bash
# 临时挂载
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

```bash
# 查看
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 常用

```bash
# 子卷
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
```

## 分区操作

```bash
# 查看
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) |
| ashift | 12 (4K) |
| ARC 上限 | 32GB (/etc/modprobe.d/zfs.conf) |
| 挂载点 | /tank |
| 创建 | 2026-07-02 |

```bash
# 设备标识 (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 布局

| Dataset | recordsize | compression | 用途 | 共享 |
|---------|------------|-------------|------|------|
| tank | 128K | lz4 | 根 | - |
| tank/media | 1M | lz4 | 家庭电影库 | SMB + NFS |
| tank/photos | 128K | lz4 | 家庭相册 | SMB + NFS |
| tank/data | 128K | lz4 | 额外存储 | SMB + NFS |
| tank/backup | 128K | lz4 | 备份容器 | 不共享 |
| tank/backup/system | 1M | lz4 | 系统盘备份 (restic) | 不共享 |

### 常用操作

```bash
# 状态与健康
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 | 说明 |
|------|-------------|------|
| Samba | smb.service | guest 共享 /tank/{media,photos,data} |
| NFS | nfs-server.service | 导出到 192.168.31.0/24 |
| ZFS 挂载 | zfs-mount.service | 开机自动挂载 dataset |
| ZFS 事件 | zfs-zed.service | 磁盘故障邮件通知 (root) |
| ZFS 指标 | zfs-prometheus.timer | 每 5 分钟采集 → Prometheus |
| 月 scrub | zfs-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 了)
