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