本篇文章已有2人收藏 | Loading收藏

1788156886 portcfg featured

各位旅行者,今天来唠一个我折腾黑群晖时踩的坑——群晖 NAS 盘位显示不全,外加一块 USB 外置硬盘凭空「消失」了

现象挺邪门的:存储空间管理器里的盘位对不上实际插盘数,插上去的 USB 移动硬盘也不在「外接设备」里露脸,反而神不知鬼不觉地钻进了「内置硬盘」的队伍。o(TヘTo) 折腾一圈才发现,根子不在硬盘、不在接口,而在群晖那四个神秘的 portcfg 参数上。

本教程适用于:DSM 7.x 系列,XPEnology(RR / ARPL / ARC 等引导)。本文以 RR 引导 + DS3617xs 为例,但原理对所有群晖机型通用。

遇到问题

  • 盘位显示不全:存储空间管理器里的内置盘数量和实际插盘对不上,看着就像「少了几块盘」。
  • USB 外置硬盘「消失」:插上的 USB 移动硬盘不出现在「外接设备 → 外接硬盘」里,反而被误判成了内置盘,差点混进存储池。😱

分析原因

一、四个参数决定一块盘的「身份」

DSM 启动时,需要知道每一块磁盘到底是「内置硬盘」「eSATA 外置」还是「USB 外置」。这个分类不是看物理接口自动判断的,而是靠四个配置值——写在 synoinfo.conf 里、由引导在编译时固化:

参数 含义
internalportcfg 位掩码:哪些磁盘索引是内置盘(进存储池、显示在「存储空间 → HDD」)
esataportcfg 位掩码:哪些磁盘索引是 eSATA 外置盘
usbportcfg 位掩码:哪些磁盘索引是 USB 外置盘(显示在「外接设备 → 外接硬盘」)
maxdisks 整数:DSM 最多识别多少块内置盘(上限)

一句话:前三个是「分类标签」,maxdisks 是「数量上限」。一块盘该归哪类,完全由它的索引落在哪个掩码里决定。

二、位掩码,而且是 1-based

每个 *portcfg 都是一个十六进制数,把它展开成二进制后,每一位对应一个磁盘索引。这里有个最容易踩的坑——它是 1-based 的:

关键规则(1-based):第 N 块盘对应第 (N−1) 位,即磁盘索引 N 的位 = 1 << (N-1)

举例:要让「磁盘索引 22」被标记为某类,操作的是 bit 21(因为 22−1=21)。常用对照如下:

磁盘索引 N 对应的 bit hex
1 bit 0 0x00000001
4 bit 3 0x00000008
21 bit 20 0x00100000
22 bit 21 0x00200000
29 bit 28 0x10000000
30 bit 29 0x20000000
32 bit 31 0x80000000

P.S. 至于怎么确认它确实是 1-based 而非 0-based,第七节的脚本会用一个巧妙的方法验证,先别急。

三、根因:USB 盘落进了内置索引区间

群晖给每块盘分配一个从 1 开始的整数编号(Disk 1、Disk 2……),叫「磁盘索引」:

  • 它由开机枚举顺序决定,不是你能直接指定的;
  • SATA 盘的索引通常 ≈ 它的 ata 端口号(ata4 → 索引4);
  • USB 盘没有固定的 ata 号,会被塞进当前空闲的索引槽(往往紧跟最后一块 SATA 盘)。

正因如此,USB 盘可能落到一个很小的索引——落在内置区间里,从而被误判成内置盘。这就是本次问题的根因。

解决办法

四、通用计算流程

照着下面三步,就能把每块盘归好类、算出掩码。
  1. 列出所有盘的「索引 + 通道」。SSH 进 DSM 执行:
    # 每块盘的 DSM 磁盘索引
    for d in /run/synostorage/disks/*; do
      dev=$(basename "$d")
      echo "$dev id=$(cat $d/id 2>/dev/null)"
    done
    
    # 每块盘走的是 SATA(ata) 还是 USB(usb) 通道
    for d in /sys/block/sd[a-z]; do
      [ -e "$d" ] || continue
      echo "$(basename $d) -> $(readlink -f $d/device)"
    done

    id 文件拿索引,看 sysfs 路径里含 ata 还是 usb 判断通道。

  2. 按物理通道给每个索引打标签:走 ata 且要内置 → internal;走 usb → usb;走 eSATA → esata。
  3. 把标签转成 hex 掩码:把同一类的所有索引 N 按位或起来即可。
    # 伪代码:把该类所有索引 N 的位 OR 起来
    mask = 0
    for N in 该类所有索引:
        mask |= (1 << (N-1))   # 最终写成 0x + 8 位十六进制

P.S. 算起来烦的话,直接用第六、七节的两个脚本,别手算。

五、完整实例:把一块 USB 盘从内置挪到外置

我这次的现场盘位长这样:

索引 通道 应归类
sdd 4 ata internal
sdp 16 ata internal
sds 19 ata internal
sdu 21 ata internal
sdv 22 usb → usb(当前被当内置)
sdaa 27 ata internal
sdab 28 ata internal
sdac 29 ata internal

目标:把索引 22(sdv,USB 盘)从 internal 挪到 usb。算位:索引 22 → bit 21 → 1<<21 = 0x00200000

# 改之前
internalportcfg = 0x1DFFFFFF
usbportcfg      = 0xE0000000   (bit29/30/31 = 索引30/31/32)

# 改之后(bit21 从 internal 清掉、在 usb 置位)
internalportcfg = 0x1DFFFFFF & ~0x00200000 = 0x1DDFFFFF
usbportcfg      = 0xE0000000 | 0x00200000 = 0xE0200000

手算复核一下 0x1DDFFFFF:把 0x1DFFFFFF 展开成二进制,把 bit21 那一位从 1 改成 0,就是 0x1DDFFFFF,对得上。✓

改在哪、怎么生效:这几个值是编译时固化的,不是改 /etc/synoinfo.conf 就能完事。以 RR 引导为例,得改引导盘第一分区 /dev/synoboot1 里的 user-config.yml,然后重新编译引导 + 重启。详见「坑与注意事项」。

附赠两个脚本

六、portcfg-autocalc.sh:诊断 + 自动算掩码

手动算位太费劲,我写了个脚本一把梭。它的逻辑是:对每块有索引的盘,比对「物理通道」和「当前 portcfg 分类」,把不一致的盘标出来,并给出修正后的掩码(只挪不一致盘的位,保留其余范围)。先诊断、再给修正建议,一目了然。

展开查看 portcfg-autocalc.sh 完整代码 展开 / 收起

下载 portcfg-autocalc.sh

用法:传到 NAS 直接 bash portcfg-autocalc.sh。如果你有 eSATA 盘,把脚本顶部的 ESATA_INDICES="" 填上它的索引(空格分隔),那些 ata 通道的盘会被归到 esataportcfg 而非 internal。

七、portcfg-base-check.sh:判定 1-based 还是 0-based

还有个隐藏坑:1-based 和 0-based 对大多数盘的分类是一样的(因为低位常全置位或全空),所以光看一块盘往往判不出来。只有「区分盘」——索引 N 使得 bit(N-1) 和 bitN 落在不同掩码的盘——才是判定关键。这个脚本就是自动找出区分盘、并给最终结论的。

展开查看 portcfg-base-check.sh 完整代码 展开 / 收起

下载 portcfg-base-check.sh

坑与注意事项

  1. USB 盘索引不稳定:增减 SATA 盘会改变 USB 盘的索引。本次把「索引22=USB」固化进掩码,只要不动 SATA 盘就稳定;动了就要重算。
  2. 编译时固化,别只改运行时:只改 /etc/synoinfo.conf 会被引导在每次启动时覆盖回去,必须改 user-config.yml + 重新编译。
  3. 编译时别重跑自动检测:RR 菜单里的「磁盘自动检测」可能用枚举结果重算 portcfg,覆盖你手改的值,只选「编译/Build」。
  4. 挂载引导盘要加 -o loop:直接挂会报 wrong fs type。
    # 挂载引导盘第一分区(必须 -o loop)
    mount -t vfat -o loop,rw /dev/synoboot1 /mnt
  5. maxdisks 可能被机型钳制:配置写了不一定生效(DS3617xs 实测写 32 → 实际 26)。
  6. 改之前先记索引:盘一旦被正确分类为外置,就会从 /run/synostorage/disks/ 消失,届时再查索引就难了。
  7. 1-based 别搞反:索引 N 操作 bit (N-1),搞反会把相邻盘误分类。
  8. 先备份:改 user-config.yml 前先 cp 一份(如 user-config.yml.bak)。

遗留问题

  • USB 盘的索引会随 SATA 盘增减而漂移,所以这套「固化索引到掩码」的方案只在盘位不变时稳定;哪天加盘、减盘了,记得重新跑一遍脚本、重算一次。
免责声明:本文涉及引导配置的修改与重新编译,操作有风险。动手前请务必先备份 user-config.yml 及重要数据,并确认自己理解每一步在干什么。黑群晖/引导相关操作请自行斟酌,出现数据丢失或系统异常,作者不承担责任。

🔗 相关阅读:同为群晖 NAS 折腾,修复黑群晖无法生成缩略图及无法转码视频 一篇记录了用第三方 ffmpeg 替换修复;远程访问家中的服务,Frp 穿透群晖 NAS 获取真实 IP 也值得一读。