Skip to content

fix(device-plugin): re-check lock file state to prevent vGPUmonitor hang - #2451

Closed
AyushSrivastava1818 wants to merge 3 commits into
Project-HAMi:masterfrom
AyushSrivastava1818:fix/watch-lockfile-concurrency-bug
Closed

fix(device-plugin): re-check lock file state to prevent vGPUmonitor hang#2451
AyushSrivastava1818 wants to merge 3 commits into
Project-HAMi:masterfrom
AyushSrivastava1818:fix/watch-lockfile-concurrency-bug

Conversation

@AyushSrivastava1818

@AyushSrivastava1818 AyushSrivastava1818 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

WatchLockFile() previously reported MIG apply lock file transitions over a single buffered chan bool, using non-blocking sends for both lock creation and removal events. During a rapid create/remove sequence, the "lock removed" notification could be dropped if the channel buffer was already occupied. The consumer would then wait indefinitely for a notification that had already been discarded, permanently stalling the vGPU monitor feedback loop until the process was restarted.

This PR changes the notification mechanism from event-based state propagation to state-based synchronization. The notification channel is now used only to signal that the lock state may have changed, while the filesystem (os.Stat) becomes the single source of truth for determining whether the MIG apply lock currently exists.

  • pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock.go: replaced chan bool with a notification-only chan struct{}, added IsMigApplyLockExist(), and closed the notification channel on watcher shutdown.
  • cmd/vGPUmonitor/feedback.go: added an initial lock-state check and re-evaluates the filesystem after receiving notifications instead of relying on queued channel values.
  • cmd/vGPUmonitor/main.go: replaced the direct <-lockChannel wait with a state-check loop that waits until the lock file is actually removed before restarting watchAndFeedback().
  • pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go: updated existing tests for the new notification API and added a RapidCreateAndRemove regression test covering rapid lock file transitions.

Which issue(s) this PR fixes:

Fixes #2450

Special notes for your reviewer:

The notification channel is no longer treated as the source of truth. It acts only as a wake-up signal, while IsMigApplyLockExist() determines the current lock state from the filesystem. Even if notifications are coalesced or dropped due to non-blocking sends, consumers always re-check the filesystem before proceeding, preventing the feedback loop from blocking indefinitely because of a lost notification.

Testing

  • Updated existing WatchLockFile unit tests.
  • Added RapidCreateAndRemove regression coverage.
  • go test ./pkg/device-plugin/nvidiadevice/nvinternal/plugin/... -count=1
  • Verified the modified packages build successfully (GOOS=linux).
  • Ran go vet on the modified packages with no new issues reported.

Does this PR introduce a user-facing change?

Yes. The vGPU monitor no longer risks becoming permanently stalled due to a lost lock-file notification during rapid MIG apply operations. Metrics collection and utilization feedback now recover correctly even when intermediate filesystem notifications are coalesced or dropped.

AI Disclosure:

AI assistance was used for code inspection, concurrency analysis, and drafting the regression tests and PR description. The implementation, testing, and final changes were reviewed before submission.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of MIG apply locks during startup and runtime.
    • Monitoring now waits for locks to be removed instead of stopping prematurely.
    • Added safer behavior when lock notifications close, are unavailable, or arrive after the lock is removed.
    • Improved responsiveness to rapid lock creation and removal events.
    • Monitoring now exits cleanly when its operating context is canceled.
    • Added fail-closed handling for lock-state detection errors.

Redesign WatchLockFile to return an event notification channel (chan struct{}) instead of a boolean payload channel, and have consumers determine lock state by inspecting the filesystem via os.Stat (IsMigApplyLockExist).

This prevents dropped or reordered fsnotify events from causing watchAndFeedback in vGPUmonitor to block indefinitely on lock release. Also handles initial lock file presence at startup and watcher shutdown.

Signed-off-by: AyushSrivastava1818 <ayush.sri0705@gmail.com>
@hami-robot

hami-robot Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: AyushSrivastava1818
Once this PR has been reviewed and has the lgtm label, please assign shouren for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@github-actions github-actions Bot added the kind/bug Something isn't working label Aug 7, 2026
@hami-robot hami-robot Bot added the size/L label Aug 7, 2026
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e21fe460-ee42-4e8b-a93e-169ee362a314

📥 Commits

Reviewing files that changed from the base of the PR and between 65fb96b and 807e611.

📒 Files selected for processing (2)
  • cmd/vGPUmonitor/feedback_test.go
  • pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go
  • cmd/vGPUmonitor/feedback_test.go

📝 Walkthrough

Walkthrough

The MIG lock watcher now sends state-change notifications through a chan struct{} and closes the channel when watching ends. Consumers re-check lock-file existence, handle startup and removal states, and avoid blocking when create and remove events occur rapidly.

Changes

MIG lock flow

Layer / File(s) Summary
State-based lock watcher
pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock.go, pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go
Adds IsMigApplyLockExist, changes watcher signals to chan struct{}, closes the channel on exit, handles overflow wake-ups, and tests rapid lock transitions.
Lock-aware feedback control
cmd/vGPUmonitor/feedback.go, cmd/vGPUmonitor/main.go
Handles existing MIG locks, re-checks lock state after notifications, and waits for lock removal, cancellation, or channel closure.
Feedback and wait-loop tests
cmd/vGPUmonitor/feedback_test.go, cmd/vGPUmonitor/main_test.go
Tests startup locks, notification handling, channel closure, NVML errors, cancellation, lock removal, and errTemporaryClosed matching.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant fsnotify
  participant watchLockFile
  participant watchAndFeedback
  participant monitorLoop
  participant MIGLockFile
  fsnotify->>watchLockFile: Create or remove event
  watchLockFile->>watchAndFeedback: struct{} notification
  watchAndFeedback->>MIGLockFile: IsMigApplyLockExist()
  MIGLockFile-->>watchAndFeedback: lock state
  watchAndFeedback->>monitorLoop: errTemporaryClosed when locked
  monitorLoop->>MIGLockFile: re-check until lock removal
  MIGLockFile-->>monitorLoop: lock removed
Loading

Possibly related PRs

Suggested reviewers: chaunceyjiang

Poem

A rabbit checks the lock-state sign,
Then hops when removal is clear.
Coalesced signals keep the line,
Closed channels end without fear.
Fast lock changes no longer stall.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main fix: preventing vGPUmonitor hangs by re-checking the MIG lock file state.
Linked Issues check ✅ Passed The changes address issue #2450 by using state-based lock checks, notification-only signals, shutdown handling, and race-focused tests.
Out of Scope Changes check ✅ Passed The implementation and tests remain within the linked issue scope of preventing vGPUmonitor hangs caused by dropped lock-file notifications.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai
coderabbitai Bot requested a review from peachest August 7, 2026 14:09
@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.38776% with 15 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...vice-plugin/nvidiadevice/nvinternal/plugin/lock.go 62.50% 9 Missing ⚠️
cmd/vGPUmonitor/feedback.go 71.42% 3 Missing and 1 partial ⚠️
cmd/vGPUmonitor/main.go 81.81% 2 Missing ⚠️
Flag Coverage Δ
unittests 64.35% <69.38%> (+0.96%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cmd/vGPUmonitor/main.go 19.51% <81.81%> (+9.78%) ⬆️
cmd/vGPUmonitor/feedback.go 40.21% <71.42%> (+18.78%) ⬆️
...vice-plugin/nvidiadevice/nvinternal/plugin/lock.go 55.00% <62.50%> (-4.43%) ⬇️

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go`:
- Around line 78-87: Update both signal receive cases in
pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go at lines 78-87 and
116-125 to capture the receive-success boolean from sigChan and fail the test
when the channel is closed before a notification arrives; retain the existing
filesystem assertions and timeout behavior for valid notifications.
- Around line 162-199: Update the RapidCreateAndRemove test so its consumer
goroutine starts and observes the lock file’s existence before
os.Remove(testFile) is called. Coordinate the test with a readiness signal, then
remove the file and retain the assertion that the consumer exits through the
notification or filesystem re-check path.

In `@pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock.go`:
- Around line 91-94: Update isLockFileExist to return true when os.Stat
succeeds, return false only when os.IsNotExist(err) is true, and treat all other
stat errors as locked by returning true.
- Around line 114-125: Update the watcher loop around watcher.Events and
watcher.Errors to handle fsnotify overflow errors, including ErrEventOverflow.
When overflow occurs, either stop and close the unusable watcher or send a
coalesced sigChan wake-up so vGPUmonitor and feedback.go re-evaluate the lock
state; preserve the existing event signaling and shutdown behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6de6e78c-d228-44ee-9cde-e5e9a51538fa

📥 Commits

Reviewing files that changed from the base of the PR and between 3616313 and d677f69.

📒 Files selected for processing (4)
  • cmd/vGPUmonitor/feedback.go
  • cmd/vGPUmonitor/main.go
  • pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock.go
  • pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go

Comment thread pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go
Comment thread pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go
Comment thread pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock.go
Comment thread pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock.go
…t tests

Address review comments on PR Project-HAMi#2451:
- Fail closed in isLockFileExist on unknown stat errors
- Handle fsnotify.ErrEventOverflow in WatchLockFile with non-blocking wake-up
- Add channel receive ok-checks in lock_test.go and restructure RapidCreateAndRemove subtest
- Extract waitForLockRemoval in main.go and add unit tests for feedback.go and main.go

Signed-off-by: AyushSrivastava1818 <ayush.sri0705@gmail.com>
@hami-robot hami-robot Bot added size/XL and removed size/L labels Aug 8, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/vGPUmonitor/feedback_test.go`:
- Around line 329-354: The coalesced-burst test must avoid scheduling-dependent
signal processing. Update the producer and setup around watchAndFeedback so a
stale notification is queued while the state is locked, then set the final state
to unlocked before invoking watchAndFeedback; cancel the context only after the
function consumes that notification. Preserve the assertion that
watchAndFeedback returns nil, and ensure the revised synchronization is safe
under the race detector.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a4664da5-e5ff-4276-b991-e9716a158441

📥 Commits

Reviewing files that changed from the base of the PR and between d677f69 and 65fb96b.

📒 Files selected for processing (6)
  • cmd/vGPUmonitor/feedback.go
  • cmd/vGPUmonitor/feedback_test.go
  • cmd/vGPUmonitor/main.go
  • cmd/vGPUmonitor/main_test.go
  • pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock.go
  • pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/device-plugin/nvidiadevice/nvinternal/plugin/lock_test.go
  • cmd/vGPUmonitor/feedback.go

Comment thread cmd/vGPUmonitor/feedback_test.go
Signed-off-by: AyushSrivastava1818 <ayush.sri0705@gmail.com>
@AyushSrivastava1818

Copy link
Copy Markdown
Contributor Author

Hi @archlitchi @chaunceyjiang @peachest,

PR #2451 (fix/watch-lockfile-concurrency-bug) is ready for maintainer review:

  • CI Status: All checks are green (Compile, Lint, Unit Test, e2e, CodeQL, DCO, Dependency Quality, License Compliance, Security Analysis).
  • Review Threads: Both CodeRabbit review threads (RapidCreateAndRemove test coordination in lock_test.go and CoalescedBurst_FinalStateConverges test stability in feedback_test.go) were addressed in commit 807e611 and marked resolved.

Could you please review and apply /lgtm / /approve when you have a moment? Thank you!

@FouoF

FouoF commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Why not use a blocking send or expand the buffer size?

@AyushSrivastava1818

Copy link
Copy Markdown
Contributor Author

@FouoF Considered both, went with neither — here's the reasoning:

Blocking send — ties the watcher goroutine to the consumer's readiness. Worse, the channel is explicitly closed on watcher shutdown (defer close(sigChan)), so any blocking send racing that close either panics (send on a closed channel) or, if it lands just before the close, blocks forever with nothing left to read it. A blocking send here isn't just slower, it's a crash/deadlock risk built into the shutdown path.

Bigger buffer — only raises the burst size needed to reproduce #2450, it doesn't remove the failure mode, and it doesn't fix staleness: even with zero drops, a queued event can be read after the real state has already moved past it. You can see the same tension even in fsnotify's own error channel — when watcher.Errors overflows, we don't try to force every error through either; we just fire a non-blocking coalesced wake-up and let the consumer re-check state (lines 138–151). Same principle, applied consistently everywhere in this file.

So the channel is now purely a wake-up signal (chan struct{}, buffered 1, always non-blocking send/default), and IsMigApplyLockExist() is the single source of truth on every wake. However many notifications coalesce, drop, or race the shutdown close, the consumer converges to the actual current filesystem state — so correctness doesn't depend on the channel being lossless or ordered at all, which neither a bigger buffer nor a blocking send can guarantee.

RapidCreateAndRemove in lock_test.go covers the burst case #2450 was actually failing on.

@mesutoezdil

Copy link
Copy Markdown
Contributor

You can view the relevant rule here.
https://github.com/Project-HAMi/HAMi/blob/master/CONTRIBUTING.md#contribution-gates
"4. Review replies. The reply you post must be written by you and must address the specific point raised. Verbatim or canned AI replies, or replies that do not engage the comment, lead to the PR being closed."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vGPUmonitor: MIG lock file create/remove events can race through a saturating channel, permanently hanging watchAndFeedback

3 participants