飞牛NAS CLI手动创建EXT4存储空间及逆向研究报告

飞牛NAS手动创建EXT4硬盘分区及逆向研究报告

不同于常见的’修改 fstab 手动挂载’方案,本文通过逆向飞牛存储栈的完整抽象层,实现了新卷在 Web UI 中的原生识别与全功能管理。

为什么要逆向研究实现手动创建存储空间?

官方 Web UI 采用高度封装的向导式交互,虽降低了入门门槛,但严格限制了底层存储拓扑的灵活性。在实际场景中,手动创建存储空间具有不可替代的价值:

  1. 单盘多池划分:将一块大容量硬盘拆分为多个独立存储池,分别用于冷数据归档、Docker 持久化卷或虚拟机镜像,实现物理隔离与独立配额。
  2. 系统崩溃救援:当 Web UI 无法访问、数据库损坏或遭遇异常断电时,手动重建存储栈是抢救数据的唯一可靠途径。
  3. 规避自动装配干扰:NAS 后台守护进程可能误识别旧 RAID 签名导致卷状态异常。掌握底层逻辑可强制清理并精确对齐。
  4. 自动化运维基础:理解从裸盘到 /volX 的完整路径,是编写批量初始化脚本、集成 CI/CD 或进行深度性能调优的前提。

以下为经过完整验证的逐步骤操作实录。请严格按照顺序执行,并将 /dev/sdb 替换为您的实际目标磁盘。


前置检查:确认目标磁盘状态

在执行任何破坏性操作前,必须确认磁盘路径且未被系统占用。

1
2
# 查看当前块设备拓扑
lsblk

预期输出

1
2
3
4
5
6
7
8
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 20G 0 disk
├─sda1 8:1 0 94M 0 part
├─sda2 8:2 0 14.9G 0 part /
└─sda3 8:3 0 5G 0 part
└─md127 9:127 0 5G 0 raid1
└─trim_...-0 253:0 0 5G 0 lvm /vol1
sdb 8:16 0 3G 0 disk

说明:确认 /dev/sdb 无分区、无挂载点。若显示已挂载,请先执行 umount /dev/sdb*


步骤一:彻底清除磁盘残留签名

1
2
3
4
5
# 强制卸载可能残留的挂载点
umount /dev/sdb* 2>/dev/null || true

# 擦除所有旧分区表、文件系统与 RAID 超级块
wipefs -a /dev/sdb

预期输出

1
2
/dev/sdb: 8 bytes were erased at offset 0x00000200 (gpt): 45 46 49 20 50 41 52 54
/dev/sdb: 2 bytes were erased at offset 0x000001fe (PMBR): 55 aa

说明:此操作不可逆。确保未误选系统盘。


步骤二:创建 GPT 分区并设置 Linux RAID 类型

1
2
3
4
5
6
7
# 创建占满全盘的单一分区,类型设为 FD00
sgdisk -n 1:0:0 -t 1:FD00 -c 1:"FnOS_Data" /dev/sdb

# 通知内核刷新分区表并等待设备节点生成
partprobe /dev/sdb
udevadm settle
sleep 2

预期输出

1
2
Creating new GPT entries in memory.
The operation has completed successfully.

说明:类型 FD00 是底层 mdadm 识别的必要条件。udevadm settle 确保 /dev/sdb1 节点已就绪。


步骤三:构建单盘 RAID1 阵列

1
2
3
4
5
6
7
8
# 停止可能自动组装的冲突阵列
mdadm --stop /dev/md99 2>/dev/null || true

# 再次清理分区签名,防止 mdadm 拒绝创建
wipefs -a /dev/sdb1

# 创建单盘 RAID1
mdadm --create /dev/md99 --level=1 --raid-devices=1 --metadata=1.2 --name="test:0" --force /dev/sdb1

预期输出

1
mdadm: array /dev/md99 started.

说明:飞牛NAS使用单盘 RAID1 作为设备抽象层,以便后续无缝插入第二块硬盘扩容。--metadata=1.2--name="test:0" 是后端服务硬编码的识别特征。

1
2
# 验证阵列状态
cat /proc/mdstat

预期输出

1
2
3
Personalities : [raid1] 
md99 : active raid1 sdb1[0]
3141568 blocks super 1.2 [1/1] [U]

步骤四:初始化 LVM 物理卷与卷组

1
2
3
4
5
6
7
# 生成符合规范的 UUID(横杠转下划线)
RAW_UUID=$(cat /proc/sys/kernel/random/uuid)
VG_NAME="trim_$(echo $RAW_UUID | tr '-' '_')"
echo "生成的卷组名: $VG_NAME"

# 创建物理卷(将提示确认覆盖旧签名)
pvcreate -ff /dev/md99

预期输出

1
2
3
生成的卷组名: trim_e153b892_b7db_492f_916e_09e9ad5b7d83
Really INITIALIZE physical volume "/dev/md99" of volume group "..." [y/n]? y
Physical volume "/dev/md99" successfully created.

说明:此处需手动输入 y 并回车。VG 名称必须以 trim_ 开头,后接 UUID 格式,否则 Web 端扫描时将直接过滤。

1
2
# 创建卷组
vgcreate $VG_NAME /dev/md99

预期输出

1
Volume group "trim_e153b892_b7db_492f_916e_09e9ad5b7d83" successfully created

步骤五:创建逻辑卷 (LV)

1
2
# 创建逻辑卷,名称必须为 0
lvcreate -l 100%FREE -n 0 $VG_NAME

预期输出

1
2
3
WARNING: ext4 signature detected on /dev/.../0 at offset 1080. Wipe it? [y/n]: y
Wiping ext4 signature on /dev/.../0.
Logical volume "0" created.

说明:LV 名称固定为 0。系统将自动在 /dev/mapper/ 下生成 ${VG_NAME}-0 符号链接。


步骤六:格式化 ext4 并开启项目配额 (prjquota)

1
2
3
4
5
6
7
8
9
10
11
# 定义设备映射路径变量
DEV_MAP="/dev/mapper/${VG_NAME}-0"

# 格式化 ext4,块大小强制 4096
mkfs.ext4 -F -b 4096 $DEV_MAP

# 离线启用 project 特性
tune2fs -O project $DEV_MAP

# 重建文件系统元数据索引
e2fsck -f $DEV_MAP

预期输出

1
2
3
4
5
6
mke2fs 1.47.0 (5-Feb-2023)
Creating filesystem with 784384 4k blocks...
Setting project quota feature on the filesystem.
e2fsck 1.47.0 (5-Feb-2023)
...
/dev/mapper/...-0: 11/196224 files

说明tune2fs -O project 是核心步骤。缺失此特性会导致挂载参数无法加载 prjquota,进而触发 Web 端配额 API 拦截。


步骤七:挂载并严格同步系统权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建挂载点
mkdir -p /vol2

# 挂载,必须显式指定 prjquota 参数
mount -o rw,relatime,prjquota $DEV_MAP /vol2

# 获取系统卷 /vol1 的标准权限与所有者
VOL1_PERM=$(stat -c '%a' /vol1)
VOL1_OWNER=$(stat -c '%U:%G' /vol1)

# 同步至新卷
chown -R ${VOL1_OWNER} /vol2
chmod ${VOL1_PERM} /vol2

# 验证权限
ls -ld /vol2

预期输出

1
drwx------ 4 root root 4096 Apr  5 15:35 /vol2

说明:系统卷根目录权限为 700 root:root。若手动创建后为默认的 755,后端文件服务将拒绝读取。

此时可以在web端看到我们创建的存储空间(67b-0)

image-20260419145846134


步骤八:注入系统“指纹”目录

1
2
3
4
5
6
7
# 查看系统卷根目录结构
ls /vol1

# 递归复制指纹目录(-a 保留原始权限、时间戳与属性)
cp -a /vol1/lost+found /vol2/
cp -a /vol1/thumb /vol2/
cp -a /vol1/1000 /vol2/

预期输出

1
1000  lost+found  thumb

说明:Web 端文件管理器通过检查这三个目录判断卷是否完成初始化。

  • lost+found:ext4 标准目录,校验权限完整性。
  • thumb:缩略图缓存根目录。缺失时 API 判定卷未就绪。
  • 1000:默认管理员(UID 1000)空间映射,用于建立用户索引。

此时刷新 Web UI 存储池与文件管理器页面,新卷应完全可用,显示为存储空间X。

image-20260419145915257


关键技术约束对照表

层级 强制要求 偏离后果
分区表 GPT,类型 FD00 (Linux RAID) mdadm 拒绝组装或内核不识别
RAID元数据 mdadm v1.2,单盘 --force,名称 test:0 后端正则过滤失败,卷不可见
LVM命名 VG前缀 trim_+UUID转下划线;LV名必须为 0 filestor_service 扫描丢弃
文件系统 ext4,Block Size 4096,启用 project 特性 prjquota 挂载失败,配额API拦截
挂载参数 rw,relatime,prjquota Web端返回“内部错误”或拒绝访问
根目录指纹 必须存在 lost+foundthumb1000 且权限为 700 root:root 文件管理器初始化中断

安全与运维警告

  1. 路径二次确认:所有命令中的 /dev/sdb 必须与 lsblk 输出严格一致。误操作将导致系统盘或数据盘永久损毁。
  2. 无物理冗余--raid-devices=1 仅为统一设备抽象层,不提供硬盘级容灾。重要数据需定期冷备份。
  3. 数据库清理:若多次创建失败,内部 SQLite 可能残留错误状态。需定位 /var/lib/fnos/*.db 并清理 volumes 表中状态为 error 的记录。
  4. 版本差异:本流程基于当前版本逆向验证。大版本更新可能调整服务校验逻辑或引入 ZFS/Btrfs,生产环境请先在测试盘验证。

飞牛NAS CLI手动创建EXT4存储空间及逆向研究报告
https://blog.lecreate.asia/2026/04/30/2026041901/
作者
LECREATE
发布于
2026年4月30日
许可协议