@@ -198,29 +198,30 @@ func (fs *filesystem) revalidateStep(ctx context.Context, rp resolvingPath, d *d
198
198
// Precondition: fs.renameMu must be locked.
199
199
func (d * dentry ) invalidate (ctx context.Context , vfsObj * vfs.VirtualFilesystem , ds * * []* dentry ) {
200
200
// Remove d from its parent.
201
- func () {
201
+ removed := func () bool {
202
202
parent := d .parent .Load ()
203
203
parent .opMu .RLock ()
204
204
defer parent .opMu .RUnlock ()
205
205
parent .childrenMu .Lock ()
206
206
defer parent .childrenMu .Unlock ()
207
207
208
- if d .isSynthetic () {
209
- // Normally we don't mark invalidated dentries as deleted since
210
- // they may still exist (but at a different path), and also for
211
- // consistency with Linux. However, synthetic files are guaranteed
212
- // to become unreachable if their dentries are invalidated, so
213
- // treat their invalidation as deletion.
214
- d .deleteSynthetic (parent , ds )
215
- }
216
-
217
208
// Since the opMu was just reacquired above, re-check that the
218
209
// parent's child with this name is still the same. Do not touch it if
219
210
// it has been replaced with a different one.
220
211
if child := parent .children [d .name ]; child == d {
221
212
// Invalidate dentry so it gets reloaded next time it's accessed.
222
213
delete (parent .children , d .name )
214
+ if d .isSynthetic () {
215
+ // Normally we don't mark invalidated dentries as deleted since
216
+ // they may still exist (but at a different path), and also for
217
+ // consistency with Linux. However, synthetic files are
218
+ // guaranteed to become unreachable if their dentries are
219
+ // invalidated, so treat their invalidation as deletion.
220
+ d .deleteSynthetic (parent , ds )
221
+ }
222
+ return true
223
223
}
224
+ return false
224
225
}()
225
226
226
227
// Invalidate d and its descendants.
@@ -239,7 +240,14 @@ func (d *dentry) invalidate(ctx context.Context, vfsObj *vfs.VirtualFilesystem,
239
240
rc .DecRef (ctx )
240
241
}
241
242
d .decRefNoCaching ()
242
- if d .isSynthetic () || d .endpoint != nil {
243
+
244
+ // If an extra reference is held on d as described by the comment for
245
+ // dentry.refs, and d hasn't been racily removed by
246
+ // filesystem.unlinkAt() or another revalidation, drop that reference
247
+ // now. (The same would apply to racy replacement by
248
+ // filesystem.RenameAt(), but we can't race with rename since renameMu
249
+ // has been locked since entering filesystem.revalidatePath().)
250
+ if removed && (d .isSynthetic () || d .endpoint != nil ) {
243
251
d .decRefNoCaching ()
244
252
}
245
253
0 commit comments