Check List
Describe the bug
DokanEventRelease (sys/notification.c) has a non-atomic re-entry guard, leaving a race window between passing the guard and setting the unmount flags. If two threads enter concurrently for the same VCB, this leads to either a double ExDeleteLookasideListEx on the same list (0xA IRQL_NOT_LESS_OR_EQUAL), or a store into a VCB already freed by the thread that got ahead (0x50 PAGE_FAULT_IN_NONPAGED_AREA).
Observed under a workload where a user-mode FS process repeatedly mounts/unmounts (up to 8 concurrent mounts, 60 s request timeout): multiple BSODs, three times 0xA at dokan2+0x13cbc and once 0x50 at dokan2+0x144da, all in the same process on the same code path. Present in both v2.3.1.1000 and master (as of 2026-07-22).
To Reproduce
- Mount a volume (mirror is fine) with a short request timeout.
- Issue
DokanRemoveMountPoint concurrently from two threads against the same mount point — or race one DokanRemoveMountPoint against the timeout-triggered unmount (timeout.c DokanUnmount).
- Repeat in a loop. Enabling Driver Verifier (special pool, force IRQL checking) on dokan2.sys makes the race easier to catch.
Expected behavior
Concurrent unmount/release requests for the same VCB are serialized: one performs the teardown, the others return cleanly. No BSOD.
Logs
BSOD minidump analysis. The 0xA dumps are identical (FAILURE_BUCKET_ID: AV_dokan2!unknown_function):
nt!KeBugCheckEx
nt!KiBugCheckDispatch
nt!KiPageFault
nt!ExpRemoveGeneralLookaside+0x21
nt!ExDeleteLookasideListEx+0x28
dokan2+0x13cbc
Symbol resolution with dokan2.pdb (private PDB) from the release asset dokan.zip — the installed dokan2.sys is SHA256-identical to x64/Release/Driver/dokan2.sys:
dokan2+0x13cbc = dokan2!DokanEventRelease+0x198 (notification.c:380) — return address right after the ExDeleteLookasideListEx(&vcb->FCBAvlNodeLookasideList) call at line 378
dokan2+0x144da = dokan2!DokanStopFcbGarbageCollectorThread+0x36 (notification.c:309) — the Vcb->FcbGarbageCollectorThread = NULL; store, i.e. the 0x50 is a write to an already-freed VCB
DokanStopFcbGarbageCollectorThread is called from DokanEventRelease (line 374), so both crashes are inside the unmount path. Minidumps can be provided if needed.
Environment:
- Windows version: Windows 11 Pro build 26200
- Processor architecture: x64
- Dokany version: 2.3.1.1000 (dokan2.sys built 2025-09-28)
- Library type (Dokany/FUSE): Dokany
Additional context
Root cause in v2.3.1.1000's DokanEventRelease (sys/notification.c):
- The re-entry guards (line 336
IsDeletePending, line 341 IsUnmountPendingVcb) are plain flag reads with no locking; check and set are not atomic.
- The flags are only set at lines 358–359 (
SetLongFlag: VCB_DISMOUNT_PENDING / DCB_DELETE_PENDING), after DokanDeleteMountPoint (line 355, which involves mount manager I/O). Two threads entering at about the same time both pass the guard and execute the whole teardown twice.
FCBAvlNodeLookasideListInit is never cleared after ExDeleteLookasideListEx (lines 377–379; same at 385–387 on master), so nothing prevents re-entering the deleted list.
The 0xA is two threads running ExDeleteLookasideListEx on the same list concurrently — ExpRemoveGeneralLookaside then walks a corrupted list (ExDeleteLookasideListEx does not tolerate concurrent calls on the same list). The 0x50 is the trailing thread executing the line-309 store after the leading thread had already freed the VCB.
Entry points that can race for the same VCB:
DokanRemoveMountPoint → SendGlobalReleaseIRP → FSCTL_EVENT_RELEASE → DokanGlobalEventRelease (fscontrol.c:430). Every call reaches the driver; no idempotency on the user-mode side.
- Volume FSCTL (fscontrol.c:575)
- Timeout watcher thread →
DokanUnmount (timeout.c:32). The driver unmounts on its own when the request timeout fires.
- MountManager link deletion (device.c:469/480)
- EventStart failure (event.c:1162)
For example, while a DokanRemoveMountPoint unmount is inside DokanDeleteMountPoint, the timeout thread (or a second DokanRemoveMountPoint) can pass the guard.
Suggested fix:
- Make the re-entry guard an interlocked test-and-set, and set the flags at the top of the function (before
IoAcquireRemoveLock)
- Set
FCBAvlNodeLookasideListInit = FALSE before ExDeleteLookasideListEx
- Make teardown steps such as
DokanStopFcbGarbageCollectorThread idempotent and order them against VCB freeing
Check List
Describe the bug
DokanEventRelease(sys/notification.c) has a non-atomic re-entry guard, leaving a race window between passing the guard and setting the unmount flags. If two threads enter concurrently for the same VCB, this leads to either a doubleExDeleteLookasideListExon the same list (0xA IRQL_NOT_LESS_OR_EQUAL), or a store into a VCB already freed by the thread that got ahead (0x50 PAGE_FAULT_IN_NONPAGED_AREA).Observed under a workload where a user-mode FS process repeatedly mounts/unmounts (up to 8 concurrent mounts, 60 s request timeout): multiple BSODs, three times 0xA at dokan2+0x13cbc and once 0x50 at dokan2+0x144da, all in the same process on the same code path. Present in both v2.3.1.1000 and master (as of 2026-07-22).
To Reproduce
DokanRemoveMountPointconcurrently from two threads against the same mount point — or race oneDokanRemoveMountPointagainst the timeout-triggered unmount (timeout.cDokanUnmount).Expected behavior
Concurrent unmount/release requests for the same VCB are serialized: one performs the teardown, the others return cleanly. No BSOD.
Logs
BSOD minidump analysis. The 0xA dumps are identical (
FAILURE_BUCKET_ID: AV_dokan2!unknown_function):Symbol resolution with dokan2.pdb (private PDB) from the release asset dokan.zip — the installed dokan2.sys is SHA256-identical to
x64/Release/Driver/dokan2.sys:dokan2+0x13cbc=dokan2!DokanEventRelease+0x198(notification.c:380) — return address right after theExDeleteLookasideListEx(&vcb->FCBAvlNodeLookasideList)call at line 378dokan2+0x144da=dokan2!DokanStopFcbGarbageCollectorThread+0x36(notification.c:309) — theVcb->FcbGarbageCollectorThread = NULL;store, i.e. the 0x50 is a write to an already-freed VCBDokanStopFcbGarbageCollectorThreadis called fromDokanEventRelease(line 374), so both crashes are inside the unmount path. Minidumps can be provided if needed.Environment:
Additional context
Root cause in v2.3.1.1000's
DokanEventRelease(sys/notification.c):IsDeletePending, line 341IsUnmountPendingVcb) are plain flag reads with no locking; check and set are not atomic.SetLongFlag:VCB_DISMOUNT_PENDING/DCB_DELETE_PENDING), afterDokanDeleteMountPoint(line 355, which involves mount manager I/O). Two threads entering at about the same time both pass the guard and execute the whole teardown twice.FCBAvlNodeLookasideListInitis never cleared afterExDeleteLookasideListEx(lines 377–379; same at 385–387 on master), so nothing prevents re-entering the deleted list.The 0xA is two threads running
ExDeleteLookasideListExon the same list concurrently —ExpRemoveGeneralLookasidethen walks a corrupted list (ExDeleteLookasideListExdoes not tolerate concurrent calls on the same list). The 0x50 is the trailing thread executing the line-309 store after the leading thread had already freed the VCB.Entry points that can race for the same VCB:
DokanRemoveMountPoint→SendGlobalReleaseIRP→ FSCTL_EVENT_RELEASE →DokanGlobalEventRelease(fscontrol.c:430). Every call reaches the driver; no idempotency on the user-mode side.DokanUnmount(timeout.c:32). The driver unmounts on its own when the request timeout fires.For example, while a
DokanRemoveMountPointunmount is insideDokanDeleteMountPoint, the timeout thread (or a secondDokanRemoveMountPoint) can pass the guard.Suggested fix:
IoAcquireRemoveLock)FCBAvlNodeLookasideListInit = FALSEbeforeExDeleteLookasideListExDokanStopFcbGarbageCollectorThreadidempotent and order them against VCB freeing