Skip to content

Commit 1ffacd4

Browse files
committed
Library - Move UserContext under OpenCount lock
Close is called when all events are done and we get a kernel close request. The kernel can issue an event (GetFileInfo) but actually do not wait for its completion and directly send a close. We will have a race condition in ReleaseDokanOpenInfo where the DokanFileInfo might have the GetFileInfo UserContext and not the Cleanup UserContext that is expected to happen before Close. This change enforce to get the latest UserContext we can get from DokanOpenInfo. Yes, it does not prevent the GetFileInfo to be the latest to set UserContext in EventCompletion but that's the best we can do.
1 parent ed61a3e commit 1ffacd4

File tree

4 files changed

+39
-35
lines changed

4 files changed

+39
-35
lines changed

dokan/close.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,5 @@ VOID DispatchClose(PDOKAN_IO_EVENT IoEvent) {
3535
// Driver has simply notifying us of the Close request which he has
3636
// already completed at this stage. Driver is not expecting us
3737
// to reply from this so there is no need to send an EVENT_INFORMATION.
38-
39-
if (IoEvent->DokanOpenInfo) {
40-
EnterCriticalSection(&IoEvent->DokanOpenInfo->CriticalSection);
41-
IoEvent->DokanOpenInfo->FileName =
42-
_wcsdup(IoEvent->EventContext->Operation.Close.FileName);
43-
IoEvent->DokanOpenInfo->OpenCount--;
44-
LeaveCriticalSection(&IoEvent->DokanOpenInfo->CriticalSection);
45-
ReleaseDokanOpenInfo(IoEvent);
46-
}
38+
ReleaseDokanOpenInfo(IoEvent);
4739
}

dokan/dokan.c

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,8 @@ VOID SetupIOEventForProcessing(PDOKAN_IO_EVENT IoEvent) {
274274
if (IoEvent->DokanOpenInfo) {
275275
EnterCriticalSection(&IoEvent->DokanOpenInfo->CriticalSection);
276276
IoEvent->DokanOpenInfo->OpenCount++;
277+
IoEvent->DokanFileInfo.Context = IoEvent->DokanOpenInfo->UserContext;
277278
LeaveCriticalSection(&IoEvent->DokanOpenInfo->CriticalSection);
278-
IoEvent->DokanFileInfo.Context =
279-
InterlockedAdd64(&IoEvent->DokanOpenInfo->UserContext, 0);
280279
IoEvent->DokanFileInfo.IsDirectory =
281280
(UCHAR)IoEvent->DokanOpenInfo->IsDirectory;
282281

@@ -879,11 +878,7 @@ VOID ALIGN_ALLOCATION_SIZE(PLARGE_INTEGER size, PDOKAN_OPTIONS DokanOptions) {
879878

880879
VOID EventCompletion(PDOKAN_IO_EVENT IoEvent) {
881880
assert(IoEvent->EventResult);
882-
if (IoEvent->DokanOpenInfo) {
883-
InterlockedExchange64(&IoEvent->DokanOpenInfo->UserContext,
884-
IoEvent->DokanFileInfo.Context);
885-
ReleaseDokanOpenInfo(IoEvent);
886-
}
881+
ReleaseDokanOpenInfo(IoEvent);
887882
}
888883

889884
VOID CheckFileName(LPWSTR FileName) {
@@ -963,26 +958,38 @@ VOID CreateDispatchCommon(PDOKAN_IO_EVENT IoEvent, ULONG SizeOfEventInfo, BOOL U
963958
}
964959

965960
VOID ReleaseDokanOpenInfo(PDOKAN_IO_EVENT IoEvent) {
966-
LPWSTR fileNameForClose = NULL;
967-
961+
if (!IoEvent->DokanOpenInfo) {
962+
return;
963+
}
968964
EnterCriticalSection(&IoEvent->DokanOpenInfo->CriticalSection);
965+
IoEvent->DokanOpenInfo->UserContext = IoEvent->DokanFileInfo.Context;
969966
IoEvent->DokanOpenInfo->OpenCount--;
970-
if (IoEvent->DokanOpenInfo->OpenCount < 1) {
971-
if (IoEvent->DokanOpenInfo->FileName) {
972-
fileNameForClose = IoEvent->DokanOpenInfo->FileName;
973-
IoEvent->DokanOpenInfo->FileName = NULL;
974-
}
975-
LeaveCriticalSection(&IoEvent->DokanOpenInfo->CriticalSection);
976-
PushFileOpenInfo(IoEvent->DokanOpenInfo);
977-
IoEvent->DokanOpenInfo = NULL;
978-
if (IoEvent->EventResult) {
979-
// Reset the Kernel UserContext if we can. Close events do not have one.
980-
IoEvent->EventResult->Context = 0;
981-
}
982-
} else {
967+
if (IoEvent->EventContext->MajorFunction == IRP_MJ_CLOSE) {
968+
IoEvent->DokanOpenInfo->CloseFileName =
969+
_wcsdup(IoEvent->EventContext->Operation.Close.FileName);
970+
IoEvent->DokanOpenInfo->CloseUserContext = IoEvent->DokanFileInfo.Context;
971+
IoEvent->DokanOpenInfo->OpenCount--;
972+
}
973+
if (IoEvent->DokanOpenInfo->OpenCount > 0) {
974+
// We are still waiting for the Close event or there is another event running. We delay the Close event.
983975
LeaveCriticalSection(&IoEvent->DokanOpenInfo->CriticalSection);
976+
return;
984977
}
985978

979+
// Process close event as OpenCount is now 0
980+
LPWSTR fileNameForClose = NULL;
981+
if (IoEvent->DokanOpenInfo->CloseFileName) {
982+
fileNameForClose = IoEvent->DokanOpenInfo->CloseFileName;
983+
IoEvent->DokanOpenInfo->CloseFileName = NULL;
984+
}
985+
IoEvent->DokanFileInfo.Context = IoEvent->DokanOpenInfo->CloseUserContext;
986+
LeaveCriticalSection(&IoEvent->DokanOpenInfo->CriticalSection);
987+
PushFileOpenInfo(IoEvent->DokanOpenInfo);
988+
IoEvent->DokanOpenInfo = NULL;
989+
if (IoEvent->EventResult) {
990+
// Reset the Kernel UserContext if we can. Close events do not have one.
991+
IoEvent->EventResult->Context = 0;
992+
}
986993
if (fileNameForClose) {
987994
if (IoEvent->DokanInstance->DokanOperations->CloseFile) {
988995
IoEvent->DokanInstance->DokanOperations->CloseFile(

dokan/dokan_pool.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -560,13 +560,17 @@ PDOKAN_OPEN_INFO PopFileOpenInfo() {
560560
RtlZeroMemory(fileInfo, sizeof(DOKAN_OPEN_INFO));
561561
InitializeCriticalSection(&fileInfo->CriticalSection);
562562
}
563-
564563
if (fileInfo) {
565564
fileInfo->DokanInstance = NULL;
566565
fileInfo->DirList = NULL;
567-
InterlockedExchange64(&fileInfo->UserContext, 0);
566+
fileInfo->DirListSearchPattern= NULL;
567+
fileInfo->UserContext = 0;
568568
fileInfo->EventId = 0;
569569
fileInfo->IsDirectory = FALSE;
570+
fileInfo->OpenCount = 0;
571+
fileInfo->CloseFileName = NULL;
572+
fileInfo->CloseUserContext = 0;
573+
fileInfo->EventContext = NULL;
570574
}
571575
return fileInfo;
572576
}

dokan/dokani.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,16 @@ typedef struct _DOKAN_OPEN_INFO {
107107
PDOKAN_VECTOR DirList;
108108
PWCHAR DirListSearchPattern;
109109
/** User Context see DOKAN_FILE_INFO.Context */
110-
volatile LONG64 UserContext;
110+
LONG64 UserContext;
111111
/** Event Id */
112112
ULONG EventId;
113113
/** DOKAN_OPTIONS linked to the mount */
114114
BOOL IsDirectory;
115115
/** Open count on the file */
116116
ULONG OpenCount;
117117
/** Used when dispatching the close once the OpenCount drops to 0 **/
118-
LPWSTR FileName;
118+
LPWSTR CloseFileName;
119+
LONG64 CloseUserContext;
119120
/** Event context */
120121
PEVENT_CONTEXT EventContext;
121122
} DOKAN_OPEN_INFO, *PDOKAN_OPEN_INFO;

0 commit comments

Comments
 (0)