二、根本原因
开机挂载竞态(boot mount race)。
fnOS 的共享由 share_service(systemd: share_service.service)在开机时"重建"。它从「持久的共享清单 + 实时挂载状态」动态生成 SMB 配置:
- 内部盘
/vol1 永远在 → 内部共享每次都正常。
- 外接 USB 盘挂载较慢(实测开机后约 3~14 秒才挂上
/vol00/*)。
开机时 share_service 抢在 USB 盘挂载完成之前就重建共享,发现 /vol00/* 路径不存在,于是:
[smb] Rebuild external shares for 1000
[smb] append namin**ap with path /vol00/ST1000LM035-1RK172 ... not exist skip
[smb] append namin**ap with path /vol00/WDC WD20NMVW-11EDZS7 ... not exist skip
[smb] append namin**ap with path /vol00/WDC WD20NMVW-11EDZS7_1 ... not exist skip
[smb] User 1000 has 8 shares ← 少了 3 个外接共享
关键点:这次"跳过"不仅当次不生效,还会把外接存储从 fnOS 的「可见文件夹范围」里剔除(清成"无")。等几秒后盘挂上来(OnMountEvent),这版 fnOS(1.1.30)的自愈逻辑没有把它们补回去。于是:
- 网页「外接存储」= 无 → 页面不显示、前端报
semi-modal-content undefined;
- SMB 上外接共享消失,必须手动重新勾选才能恢复——直到下次重启再次丢失。
顺带澄清(避免误判)
- postgres
trim 库的 share / fileshare 表为空是正常的:内部/团队是「全部允许」(无需逐项记录)、外接是「无」(没有勾选记录),所以表本就为空,不是数据库损坏。
- 早期一度怀疑"数据库被清空的定时炸弹",经核实不成立。
三、诊断过程(关键证据)
| 步骤 |
命令 / 操作 |
结论 |
| 看 Samba 配置 |
cat /etc/samba/smb.conf、/etc/samba/users/1000.share.conf |
共享走动态 include users/%Y.share.conf |
| 看挂载 |
findmnt、lsblk、mount |
三块外接盘通过 systemd 动态 .mount 单元挂载,不在 fstab |
| 看数据库 |
sudo -u postgres psql -d trim |
share 表空(属正常,见上) |
| 看开机日志 |
/usr/trim/logs/share_service.log |
实锤竞态:开机时 /vol00/* ... not exist skip,3~5 秒后才 OnMountEvent |
| 网页复现 |
系统设置→文件共享协议→SMB→设置可见文件夹范围 |
「外接存储 = 无」,三块盘能识别但全未勾选 |
四、最终解决方案(原生,已两次真机重启验证)
分两部分:① 恢复显示(网页勾选)+ ② 根因修复(开机等挂载,防止再被剔除)。
① 在网页里勾选外接盘(恢复 fnOS 原生外接共享)
路径:系统设置 → 文件共享协议 → SMB → 设置可见文件夹范围 → 外接存储,勾选三块盘 → 确定。
效果:fnOS 原生把外接共享写回 /etc/samba/users/1000.share.conf,网页「外接存储」显示为「3 项」。
② 给 share_service 加「开机等挂载」延迟(根因修复)
让 share_service 等 /vol00 挂载稳定后再启动,从根上避免"路径不存在→剔除"。
脚本 /usr/local/bin/wait-vol00-mounts.sh:
#!/bin/bash
# Block share_service start until external USB (/vol00) mounts settle, so fnOS
# does NOT prune external shares due to the boot mount race (fnOS v1.1.30).
count(){ findmnt -rn -o TARGET 2>/dev/null | grep -c '^/vol00/'; }
prev=-1; stable=0; c=0
for i in $(seq 1 30); do # 最多 ~60s
c=$(count)
if [ "$c" -ge 1 ] && [ "$c" -eq "$prev" ]; then
stable=$((stable+1)); [ "$stable" -ge 2 ] && break # 连续 2 次稳定即放行
else stable=0; fi
prev=$c; sleep 2
done
logger -t share-wait-vol00 "proceeding; /vol00 mounts=$c after ~$((i*2))s"
exit 0
chmod +x /usr/local/bin/wait-vol00-mounts.sh
systemd drop-in /etc/systemd/system/share_service.service.d/wait-vol00.conf:
[Service]
TimeoutStartSec=180
ExecStartPre=/usr/local/bin/wait-vol00-mounts.sh
systemctl daemon-reload
说明:drop-in 放在 *.service.d/ 下,与 fnOS 自带的 unit 文件分离,fnOS 升级替换 unit 不会删掉它。TimeoutStartSec=180 给等待留足余量(默认 90s 可能不够)。若哪天拔掉所有外接盘,脚本会等满 ~60s 后放行,仅延长开机时间,不影响功能。
五、验证结果
重启后(/usr/trim/logs/share_service.log + journalctl):
# 开机延迟生效:
share-wait-vol00: proceeding; /vol00 mounts=3 after ~14s
# share_service 重建:无任何 not exist skip
[smb] User 1000 has 10 shares ← 6 内部 + 3 外接 + 1 远程挂载,正确