xref: /reactos/drivers/filesystems/npfs/waitsup.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * PROJECT:     ReactOS Named Pipe FileSystem
3*c2c66affSColin Finck  * LICENSE:     BSD - See COPYING.ARM in the top level directory
4*c2c66affSColin Finck  * FILE:        drivers/filesystems/npfs/waitsup.c
5*c2c66affSColin Finck  * PURPOSE:     Pipes Waiting Support
6*c2c66affSColin Finck  * PROGRAMMERS: ReactOS Portable Systems Group
7*c2c66affSColin Finck  */
8*c2c66affSColin Finck 
9*c2c66affSColin Finck /* INCLUDES *******************************************************************/
10*c2c66affSColin Finck 
11*c2c66affSColin Finck #include "npfs.h"
12*c2c66affSColin Finck 
13*c2c66affSColin Finck // File ID number for NPFS bugchecking support
14*c2c66affSColin Finck #define NPFS_BUGCHECK_FILE_ID   (NPFS_BUGCHECK_WAITSUP)
15*c2c66affSColin Finck 
16*c2c66affSColin Finck /* FUNCTIONS ******************************************************************/
17*c2c66affSColin Finck 
18*c2c66affSColin Finck VOID
19*c2c66affSColin Finck NTAPI
NpCancelWaitQueueIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)20*c2c66affSColin Finck NpCancelWaitQueueIrp(IN PDEVICE_OBJECT DeviceObject,
21*c2c66affSColin Finck                      IN PIRP Irp)
22*c2c66affSColin Finck {
23*c2c66affSColin Finck     KIRQL OldIrql;
24*c2c66affSColin Finck     PNP_WAIT_QUEUE_ENTRY WaitEntry;
25*c2c66affSColin Finck     PNP_WAIT_QUEUE WaitQueue;
26*c2c66affSColin Finck 
27*c2c66affSColin Finck     IoReleaseCancelSpinLock(Irp->CancelIrql);
28*c2c66affSColin Finck 
29*c2c66affSColin Finck     WaitQueue = Irp->Tail.Overlay.DriverContext[0];
30*c2c66affSColin Finck 
31*c2c66affSColin Finck     KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
32*c2c66affSColin Finck 
33*c2c66affSColin Finck     WaitEntry = Irp->Tail.Overlay.DriverContext[1];
34*c2c66affSColin Finck     if (WaitEntry)
35*c2c66affSColin Finck     {
36*c2c66affSColin Finck         RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
37*c2c66affSColin Finck         if (!KeCancelTimer(&WaitEntry->Timer))
38*c2c66affSColin Finck         {
39*c2c66affSColin Finck             WaitEntry->Irp = NULL;
40*c2c66affSColin Finck             WaitEntry = NULL;
41*c2c66affSColin Finck         }
42*c2c66affSColin Finck     }
43*c2c66affSColin Finck 
44*c2c66affSColin Finck     KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
45*c2c66affSColin Finck 
46*c2c66affSColin Finck     if (WaitEntry)
47*c2c66affSColin Finck     {
48*c2c66affSColin Finck         ObDereferenceObject(WaitEntry->FileObject);
49*c2c66affSColin Finck         ExFreePool(WaitEntry);
50*c2c66affSColin Finck     }
51*c2c66affSColin Finck 
52*c2c66affSColin Finck     Irp->IoStatus.Information = 0;
53*c2c66affSColin Finck     Irp->IoStatus.Status = STATUS_CANCELLED;
54*c2c66affSColin Finck     IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
55*c2c66affSColin Finck }
56*c2c66affSColin Finck 
57*c2c66affSColin Finck VOID
58*c2c66affSColin Finck NTAPI
NpTimerDispatch(IN PKDPC Dpc,IN PVOID Context,IN PVOID Argument1,IN PVOID Argument2)59*c2c66affSColin Finck NpTimerDispatch(IN PKDPC Dpc,
60*c2c66affSColin Finck                 IN PVOID Context,
61*c2c66affSColin Finck                 IN PVOID Argument1,
62*c2c66affSColin Finck                 IN PVOID Argument2)
63*c2c66affSColin Finck {
64*c2c66affSColin Finck     PIRP Irp;
65*c2c66affSColin Finck     KIRQL OldIrql;
66*c2c66affSColin Finck     PNP_WAIT_QUEUE_ENTRY WaitEntry = Context;
67*c2c66affSColin Finck 
68*c2c66affSColin Finck     KeAcquireSpinLock(&WaitEntry->WaitQueue->WaitLock, &OldIrql);
69*c2c66affSColin Finck 
70*c2c66affSColin Finck     Irp = WaitEntry->Irp;
71*c2c66affSColin Finck     if (Irp)
72*c2c66affSColin Finck     {
73*c2c66affSColin Finck         RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
74*c2c66affSColin Finck 
75*c2c66affSColin Finck         if (!IoSetCancelRoutine(Irp, NULL))
76*c2c66affSColin Finck         {
77*c2c66affSColin Finck             Irp->Tail.Overlay.DriverContext[1] = NULL;
78*c2c66affSColin Finck             Irp = NULL;
79*c2c66affSColin Finck         }
80*c2c66affSColin Finck     }
81*c2c66affSColin Finck 
82*c2c66affSColin Finck     KeReleaseSpinLock(&WaitEntry->WaitQueue->WaitLock, OldIrql);
83*c2c66affSColin Finck 
84*c2c66affSColin Finck     if (Irp)
85*c2c66affSColin Finck     {
86*c2c66affSColin Finck         Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
87*c2c66affSColin Finck         IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
88*c2c66affSColin Finck     }
89*c2c66affSColin Finck 
90*c2c66affSColin Finck     ObDereferenceObject(WaitEntry->FileObject);
91*c2c66affSColin Finck     ExFreePool(WaitEntry);
92*c2c66affSColin Finck }
93*c2c66affSColin Finck 
94*c2c66affSColin Finck VOID
95*c2c66affSColin Finck NTAPI
NpInitializeWaitQueue(IN PNP_WAIT_QUEUE WaitQueue)96*c2c66affSColin Finck NpInitializeWaitQueue(IN PNP_WAIT_QUEUE WaitQueue)
97*c2c66affSColin Finck {
98*c2c66affSColin Finck     InitializeListHead(&WaitQueue->WaitList);
99*c2c66affSColin Finck     KeInitializeSpinLock(&WaitQueue->WaitLock);
100*c2c66affSColin Finck }
101*c2c66affSColin Finck 
102*c2c66affSColin Finck static
103*c2c66affSColin Finck BOOLEAN
NpEqualUnicodeString(IN PCUNICODE_STRING String1,IN PCUNICODE_STRING String2)104*c2c66affSColin Finck NpEqualUnicodeString(IN PCUNICODE_STRING String1,
105*c2c66affSColin Finck                      IN PCUNICODE_STRING String2)
106*c2c66affSColin Finck {
107*c2c66affSColin Finck     SIZE_T EqualLength;
108*c2c66affSColin Finck 
109*c2c66affSColin Finck     if (String1->Length != String2->Length)
110*c2c66affSColin Finck         return FALSE;
111*c2c66affSColin Finck 
112*c2c66affSColin Finck     EqualLength = RtlCompareMemory(String1->Buffer,
113*c2c66affSColin Finck                                    String2->Buffer,
114*c2c66affSColin Finck                                    String1->Length);
115*c2c66affSColin Finck     return EqualLength == String1->Length;
116*c2c66affSColin Finck }
117*c2c66affSColin Finck 
118*c2c66affSColin Finck NTSTATUS
119*c2c66affSColin Finck NTAPI
NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue,IN PUNICODE_STRING PipePath,IN NTSTATUS Status,IN PLIST_ENTRY List)120*c2c66affSColin Finck NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue,
121*c2c66affSColin Finck                IN PUNICODE_STRING PipePath,
122*c2c66affSColin Finck                IN NTSTATUS Status,
123*c2c66affSColin Finck                IN PLIST_ENTRY List)
124*c2c66affSColin Finck {
125*c2c66affSColin Finck     UNICODE_STRING PipePathUpper;
126*c2c66affSColin Finck     KIRQL OldIrql;
127*c2c66affSColin Finck     PWCHAR Buffer;
128*c2c66affSColin Finck     PLIST_ENTRY NextEntry;
129*c2c66affSColin Finck     PNP_WAIT_QUEUE_ENTRY WaitEntry, Linkage;
130*c2c66affSColin Finck     PIRP WaitIrp;
131*c2c66affSColin Finck     PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
132*c2c66affSColin Finck     UNICODE_STRING WaitName, PipeName;
133*c2c66affSColin Finck 
134*c2c66affSColin Finck     Linkage = NULL;
135*c2c66affSColin Finck 
136*c2c66affSColin Finck     Buffer = ExAllocatePoolWithTag(NonPagedPool,
137*c2c66affSColin Finck                                    PipePath->Length,
138*c2c66affSColin Finck                                    NPFS_WAIT_BLOCK_TAG);
139*c2c66affSColin Finck     if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
140*c2c66affSColin Finck 
141*c2c66affSColin Finck     RtlInitEmptyUnicodeString(&PipePathUpper, Buffer, PipePath->Length);
142*c2c66affSColin Finck     RtlUpcaseUnicodeString(&PipePathUpper, PipePath, FALSE);
143*c2c66affSColin Finck 
144*c2c66affSColin Finck     KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
145*c2c66affSColin Finck 
146*c2c66affSColin Finck     NextEntry = WaitQueue->WaitList.Flink;
147*c2c66affSColin Finck     while (NextEntry != &WaitQueue->WaitList)
148*c2c66affSColin Finck     {
149*c2c66affSColin Finck         WaitIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
150*c2c66affSColin Finck         NextEntry = NextEntry->Flink;
151*c2c66affSColin Finck         WaitEntry = WaitIrp->Tail.Overlay.DriverContext[1];
152*c2c66affSColin Finck 
153*c2c66affSColin Finck         if (WaitEntry->AliasName.Length)
154*c2c66affSColin Finck         {
155*c2c66affSColin Finck             ASSERT(FALSE);
156*c2c66affSColin Finck             /* We have an alias. Use that for comparison */
157*c2c66affSColin Finck             WaitName = WaitEntry->AliasName;
158*c2c66affSColin Finck             PipeName = PipePathUpper;
159*c2c66affSColin Finck         }
160*c2c66affSColin Finck         else
161*c2c66affSColin Finck         {
162*c2c66affSColin Finck             /* Use the name from the wait buffer to compare */
163*c2c66affSColin Finck             WaitBuffer = WaitIrp->AssociatedIrp.SystemBuffer;
164*c2c66affSColin Finck             WaitName.Buffer = WaitBuffer->Name;
165*c2c66affSColin Finck             WaitName.Length = WaitBuffer->NameLength;
166*c2c66affSColin Finck             WaitName.MaximumLength = WaitName.Length;
167*c2c66affSColin Finck 
168*c2c66affSColin Finck             /* WaitName doesn't have a leading backslash,
169*c2c66affSColin Finck              * so skip the one in PipePathUpper for the comparison */
170*c2c66affSColin Finck             PipeName.Buffer = PipePathUpper.Buffer + 1;
171*c2c66affSColin Finck             PipeName.Length = PipePathUpper.Length - sizeof(WCHAR);
172*c2c66affSColin Finck             PipeName.MaximumLength = PipeName.Length;
173*c2c66affSColin Finck         }
174*c2c66affSColin Finck 
175*c2c66affSColin Finck         /* Can't use RtlEqualUnicodeString with a spinlock held */
176*c2c66affSColin Finck         if (NpEqualUnicodeString(&WaitName, &PipeName))
177*c2c66affSColin Finck         {
178*c2c66affSColin Finck             /* Found a matching wait. Cancel it */
179*c2c66affSColin Finck             RemoveEntryList(&WaitIrp->Tail.Overlay.ListEntry);
180*c2c66affSColin Finck             if (KeCancelTimer(&WaitEntry->Timer))
181*c2c66affSColin Finck             {
182*c2c66affSColin Finck                 WaitEntry->WaitQueue = (PNP_WAIT_QUEUE)Linkage;
183*c2c66affSColin Finck                 Linkage = WaitEntry;
184*c2c66affSColin Finck             }
185*c2c66affSColin Finck             else
186*c2c66affSColin Finck             {
187*c2c66affSColin Finck                 WaitEntry->Irp = NULL;
188*c2c66affSColin Finck                 WaitIrp->Tail.Overlay.DriverContext[1] = NULL;
189*c2c66affSColin Finck             }
190*c2c66affSColin Finck 
191*c2c66affSColin Finck             if (IoSetCancelRoutine(WaitIrp, NULL))
192*c2c66affSColin Finck             {
193*c2c66affSColin Finck                 WaitIrp->IoStatus.Information = 0;
194*c2c66affSColin Finck                 WaitIrp->IoStatus.Status = Status;
195*c2c66affSColin Finck                 InsertTailList(List, &WaitIrp->Tail.Overlay.ListEntry);
196*c2c66affSColin Finck             }
197*c2c66affSColin Finck             else
198*c2c66affSColin Finck             {
199*c2c66affSColin Finck                 WaitIrp->Tail.Overlay.DriverContext[1] = NULL;
200*c2c66affSColin Finck             }
201*c2c66affSColin Finck         }
202*c2c66affSColin Finck     }
203*c2c66affSColin Finck 
204*c2c66affSColin Finck     KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
205*c2c66affSColin Finck 
206*c2c66affSColin Finck     ExFreePoolWithTag(Buffer, NPFS_WAIT_BLOCK_TAG);
207*c2c66affSColin Finck 
208*c2c66affSColin Finck     while (Linkage)
209*c2c66affSColin Finck     {
210*c2c66affSColin Finck         WaitEntry = Linkage;
211*c2c66affSColin Finck         Linkage = (PNP_WAIT_QUEUE_ENTRY)Linkage->WaitQueue;
212*c2c66affSColin Finck         ObDereferenceObject(WaitEntry->FileObject);
213*c2c66affSColin Finck         ExFreePool(WaitEntry);
214*c2c66affSColin Finck     }
215*c2c66affSColin Finck 
216*c2c66affSColin Finck     return STATUS_SUCCESS;
217*c2c66affSColin Finck }
218*c2c66affSColin Finck 
219*c2c66affSColin Finck NTSTATUS
220*c2c66affSColin Finck NTAPI
NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,IN LARGE_INTEGER WaitTime,IN PIRP Irp,IN PUNICODE_STRING AliasName)221*c2c66affSColin Finck NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
222*c2c66affSColin Finck             IN LARGE_INTEGER WaitTime,
223*c2c66affSColin Finck             IN PIRP Irp,
224*c2c66affSColin Finck             IN PUNICODE_STRING AliasName)
225*c2c66affSColin Finck {
226*c2c66affSColin Finck     PIO_STACK_LOCATION IoStack;
227*c2c66affSColin Finck     KIRQL OldIrql;
228*c2c66affSColin Finck     NTSTATUS Status;
229*c2c66affSColin Finck     PNP_WAIT_QUEUE_ENTRY WaitEntry;
230*c2c66affSColin Finck     PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
231*c2c66affSColin Finck     LARGE_INTEGER DueTime;
232*c2c66affSColin Finck     ULONG i;
233*c2c66affSColin Finck 
234*c2c66affSColin Finck     IoStack = IoGetCurrentIrpStackLocation(Irp);
235*c2c66affSColin Finck 
236*c2c66affSColin Finck     WaitEntry = ExAllocatePoolWithQuotaTag(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
237*c2c66affSColin Finck                                            sizeof(*WaitEntry),
238*c2c66affSColin Finck                                            NPFS_WRITE_BLOCK_TAG);
239*c2c66affSColin Finck     if (!WaitEntry)
240*c2c66affSColin Finck     {
241*c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
242*c2c66affSColin Finck     }
243*c2c66affSColin Finck 
244*c2c66affSColin Finck     KeInitializeDpc(&WaitEntry->Dpc, NpTimerDispatch, WaitEntry);
245*c2c66affSColin Finck     KeInitializeTimer(&WaitEntry->Timer);
246*c2c66affSColin Finck 
247*c2c66affSColin Finck     if (AliasName)
248*c2c66affSColin Finck     {
249*c2c66affSColin Finck         WaitEntry->AliasName = *AliasName;
250*c2c66affSColin Finck     }
251*c2c66affSColin Finck     else
252*c2c66affSColin Finck     {
253*c2c66affSColin Finck         WaitEntry->AliasName.Length = 0;
254*c2c66affSColin Finck         WaitEntry->AliasName.Buffer = NULL;
255*c2c66affSColin Finck     }
256*c2c66affSColin Finck 
257*c2c66affSColin Finck     WaitEntry->WaitQueue = WaitQueue;
258*c2c66affSColin Finck     WaitEntry->Irp = Irp;
259*c2c66affSColin Finck 
260*c2c66affSColin Finck     WaitBuffer = Irp->AssociatedIrp.SystemBuffer;
261*c2c66affSColin Finck     if (WaitBuffer->TimeoutSpecified)
262*c2c66affSColin Finck     {
263*c2c66affSColin Finck         DueTime = WaitBuffer->Timeout;
264*c2c66affSColin Finck     }
265*c2c66affSColin Finck     else
266*c2c66affSColin Finck     {
267*c2c66affSColin Finck         DueTime = WaitTime;
268*c2c66affSColin Finck     }
269*c2c66affSColin Finck 
270*c2c66affSColin Finck     for (i = 0; i < WaitBuffer->NameLength / sizeof(WCHAR); i++)
271*c2c66affSColin Finck     {
272*c2c66affSColin Finck         WaitBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitBuffer->Name[i]);
273*c2c66affSColin Finck     }
274*c2c66affSColin Finck 
275*c2c66affSColin Finck     Irp->Tail.Overlay.DriverContext[0] = WaitQueue;
276*c2c66affSColin Finck     Irp->Tail.Overlay.DriverContext[1] = WaitEntry;
277*c2c66affSColin Finck 
278*c2c66affSColin Finck     KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
279*c2c66affSColin Finck 
280*c2c66affSColin Finck     IoSetCancelRoutine(Irp, NpCancelWaitQueueIrp);
281*c2c66affSColin Finck 
282*c2c66affSColin Finck     if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
283*c2c66affSColin Finck     {
284*c2c66affSColin Finck         Status = STATUS_CANCELLED;
285*c2c66affSColin Finck     }
286*c2c66affSColin Finck     else
287*c2c66affSColin Finck     {
288*c2c66affSColin Finck         InsertTailList(&WaitQueue->WaitList, &Irp->Tail.Overlay.ListEntry);
289*c2c66affSColin Finck 
290*c2c66affSColin Finck         IoMarkIrpPending(Irp);
291*c2c66affSColin Finck         Status = STATUS_PENDING;
292*c2c66affSColin Finck 
293*c2c66affSColin Finck         WaitEntry->FileObject = IoStack->FileObject;
294*c2c66affSColin Finck         ObReferenceObject(WaitEntry->FileObject);
295*c2c66affSColin Finck 
296*c2c66affSColin Finck         KeSetTimer(&WaitEntry->Timer, DueTime, &WaitEntry->Dpc);
297*c2c66affSColin Finck         WaitEntry = NULL;
298*c2c66affSColin Finck     }
299*c2c66affSColin Finck 
300*c2c66affSColin Finck     KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
301*c2c66affSColin Finck     if (WaitEntry) ExFreePool(WaitEntry);
302*c2c66affSColin Finck 
303*c2c66affSColin Finck     return Status;
304*c2c66affSColin Finck }
305*c2c66affSColin Finck 
306*c2c66affSColin Finck /* EOF */
307