Skip to content

fix(global/external): watchMounted 加锁读取 Mounted map#254

Open
pengpeng wants to merge 1 commit intomainfrom
cursor/fix-global-mounted-race
Open

fix(global/external): watchMounted 加锁读取 Mounted map#254
pengpeng wants to merge 1 commit intomainfrom
cursor/fix-global-mounted-race

Conversation

@pengpeng
Copy link
Copy Markdown
Member

@pengpeng pengpeng commented May 5, 2026

概要

`pkg/global/external.go` 的 `watchMounted` goroutine 在调用 `m.getMounted()`(内部已 `mu.Lock`)之后,立刻 不持锁 直接读 `m.Mounted[...]`,并把整个 `m.Mounted` 当作 `%+v` 打到日志。同一时刻 cron 每 5 分钟一次的 `Updated()` 也会进 `getMounted` 重建 map。

Go runtime 对并发 map 读写会直接 `fatal error: concurrent map read and map write`,进程会被打挂;即便不 fatal,日志里也可能拿到一个正在被替换的 map。

改动

新增两个辅助方法,全部在 RLock 下完成:

  • `hasMount(base string) bool`:替代 `_, exists := m.Mounted[base]` 的非锁化判断;
  • `snapshotMountedJSON() string`:在 RLock 下复制一份再做 `common.ToJson`,给日志使用。

`watchMounted` 中所有直接访问 `m.Mounted` 的地方都改用这两个方法。

验证方式

  • `go build ./pkg/global/` 通过。
  • 手工:起一个 goroutine 高频触发 `Updated()`,同时人为产生 `/data/External` 下的 fsnotify Create 事件;旧版本应当能跑出 "concurrent map read" fatal,新版本不再出现。
  • 正常流程:插拔外部存储设备,watchMounted 仍能正确发现/失败重试若干次。

Made with Cursor

The fsnotify watcher goroutine in watchMounted called m.getMounted()
(which takes m.mu.Lock) and then immediately read m.Mounted directly,
plus printed `m.Mounted` in several log statements. Concurrent
getMounted() / Updated() (cron, every 5min) writes the map at the
same time, which the Go runtime treats as a map race and can fatal
the process.

Add two helpers (hasMount, snapshotMountedJSON) that take
m.mu.RLock() and use them everywhere watchMounted previously
touched the map. The format-string log lines now print a stable
copy taken under the read lock, so we can no longer print a map
that's being modified.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant