Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the goroutine inside traversePluginDir also makes order of events non-deterministic, especially if changes are occurring at the same time the initial scan is being done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does the handleCreateEvent function verify the created path still exists?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
goroutine
intraversePluginDir
is used to place items on a non-buffered channel,ws.fsWatcher.Events
. If must be present to avoid deadlocks.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handleCreateEvent
does not explicitly re-check existence of the dir right before the Driver is delegated to handle the registration:kubernetes/pkg/kubelet/util/pluginwatcher/plugin_watcher.go
Line 250 in e86bdc7
With the changes in this PR, the fsnotify CREATE/DELETE operations should not occur out of sync. If a dir existed right before Registration, it should not go away until a DELETE event comes right after it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is the expectation from the underlying library. Just to be safe, it will be worth catching any potential issue around delete after create operations and logging it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nothing guarantees that, correct?
traversePluginDir is called
traversePluginDir adds a filesystem watch to a particular directory
kubernetes/pkg/kubelet/util/pluginwatcher/plugin_watcher.go
Lines 205 to 212 in fad2399
traversePluginDir descends into the directory and adds synthetic Create events for the files found in the dir via a goroutine
kubernetes/pkg/kubelet/util/pluginwatcher/plugin_watcher.go
Lines 215 to 221 in fad2399
because there is an active watcher registered in step 2 that can immediately start delivering events, and the synthetic create events in step 3 are delivered via a goroutine, they can interleave with actual observed filesystem events in non-deterministic ways. For example, if a driver is being deleted while this runs:
because the delete is handled, then the synthetic create event, could we end up with a registered driver that doesn't actually exist any more?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To guarantee consistency, shouldn't you be enqueuing existing sockets first prior to accepting fsnotify events from the kernel? Imagine a situation where a socket was identified by path traversal, but before
traversePluginDir
can enqueue a create event, the socket get's deleted and that event gets processed first before the creation event?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's what I expected as well. registering watches on the dirs, processing the contents and enqueuing synthetic create events, then starting processing of the events from the registered watchers
yes, that's exactly the scenario described above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@liggitt @vishh I think the code already has
HappensBefore
andHappensAfter
serial properties that you are alluding to. The code seems to have 1to1 parity between observed filesystem event and synthetic queued events. To explain, let's further unpack the scenario that Jordan presented earlier:So let's look at some scenarios
a. But, socket file is
immediately deleted
from filesystemb. According to fswatcher, if the file is removed before it is observed, the Walk will generate an error
Scenario 2
a. queues synthetic create event
a. enqueues the observed delete event
Because there is a sequentiality between the creation and immediate deletion of the socket files, the observed events will have before/after relationships. Therefore, the synthetic events are generated and placed on the internal event queue (fsWatcher.Events) should also inherit that sequentiality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the scenario described in #71440 (comment) is still racy
The synthetic create events traversePluginDir sends to the channel (for socket files encountered by filepath.Walk) are independent of (and can race with) create/delete events sent to the channel by the registered filesystem watchers.
That said, if a synthetic create event was processed after an actual observed delete event, handleCreateEvent does verify the created path still exists:
kubernetes/pkg/kubelet/util/pluginwatcher/plugin_watcher.go
Lines 240 to 243 in fad2399
I still think the raciness should be fixed in a follow up because it makes the event flow hard to understand and relies on compensation in the event handler, but in the context of this PR, it is not unsafe.