2 * PROJECT: ReactOS Named Pipe FileSystem
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/filesystems/npfs/datasup.c
5 * PURPOSE: Data Queues Support
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
13 // File ID number for NPFS bugchecking support
14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_DATASUP)
16 /* FUNCTIONS ******************************************************************/
20 NpUninitializeDataQueue(IN PNP_DATA_QUEUE DataQueue
)
24 ASSERT(DataQueue
->QueueState
== Empty
);
26 RtlZeroMemory(DataQueue
, sizeof(*DataQueue
));
27 return STATUS_SUCCESS
;
32 NpInitializeDataQueue(IN PNP_DATA_QUEUE DataQueue
,
37 DataQueue
->BytesInQueue
= 0;
38 DataQueue
->EntriesInQueue
= 0;
39 DataQueue
->QuotaUsed
= 0;
40 DataQueue
->ByteOffset
= 0;
41 DataQueue
->QueueState
= Empty
;
42 DataQueue
->Quota
= Quota
;
43 InitializeListHead(&DataQueue
->Queue
);
44 return STATUS_SUCCESS
;
49 NpCompleteStalledWrites(IN PNP_DATA_QUEUE DataQueue
,
52 ULONG QuotaLeft
, ByteOffset
, DataLeft
, NewQuotaLeft
;
53 PNP_DATA_QUEUE_ENTRY DataQueueEntry
;
55 PLIST_ENTRY NextEntry
;
57 QuotaLeft
= DataQueue
->Quota
- DataQueue
->QuotaUsed
;
58 ByteOffset
= DataQueue
->ByteOffset
;
60 NextEntry
= DataQueue
->Queue
.Flink
;
61 while (NextEntry
!= &DataQueue
->Queue
)
63 if (!QuotaLeft
) break;
65 DataQueueEntry
= CONTAINING_RECORD(NextEntry
, NP_DATA_QUEUE_ENTRY
, Irp
);
67 Irp
= DataQueueEntry
->Irp
;
69 if ((DataQueueEntry
->DataEntryType
== 0) && (Irp
))
71 DataLeft
= DataQueueEntry
->DataSize
- ByteOffset
;
73 if (DataQueueEntry
->QuotaInEntry
< DataLeft
)
75 NewQuotaLeft
= DataLeft
- DataQueueEntry
->QuotaInEntry
;
76 if (NewQuotaLeft
> QuotaLeft
) NewQuotaLeft
= QuotaLeft
;
78 QuotaLeft
-= NewQuotaLeft
;
79 DataQueueEntry
->QuotaInEntry
+= NewQuotaLeft
;
81 if (DataQueueEntry
->QuotaInEntry
== DataLeft
&&
82 IoSetCancelRoutine(Irp
, NULL
))
84 DataQueueEntry
->Irp
= NULL
;
86 Irp
->IoStatus
.Status
= 0;
87 Irp
->IoStatus
.Information
= DataQueueEntry
->DataSize
;
89 InsertTailList(List
, &Irp
->Tail
.Overlay
.ListEntry
);
94 NextEntry
= NextEntry
->Flink
;
98 DataQueue
->QuotaUsed
= DataQueue
->Quota
- QuotaLeft
;
103 NpRemoveDataQueueEntry(IN PNP_DATA_QUEUE DataQueue
,
108 PNP_DATA_QUEUE_ENTRY QueueEntry
;
111 if (DataQueue
->QueueState
== Empty
)
114 ASSERT(IsListEmpty(&DataQueue
->Queue
));
115 ASSERT(DataQueue
->EntriesInQueue
== 0);
116 ASSERT(DataQueue
->BytesInQueue
== 0);
117 ASSERT(DataQueue
->QuotaUsed
== 0);
121 QueueEntry
= CONTAINING_RECORD(RemoveHeadList(&DataQueue
->Queue
),
125 DataQueue
->BytesInQueue
-= QueueEntry
->DataSize
;
126 --DataQueue
->EntriesInQueue
;
129 if (DataQueue
->QueueState
!= WriteEntries
||
130 DataQueue
->QuotaUsed
< DataQueue
->Quota
||
131 !QueueEntry
->QuotaInEntry
)
136 DataQueue
->QuotaUsed
-= QueueEntry
->QuotaInEntry
;
138 if (IsListEmpty(&DataQueue
->Queue
))
140 DataQueue
->QueueState
= Empty
;
144 Irp
= QueueEntry
->Irp
;
145 NpFreeClientSecurityContext(QueueEntry
->ClientSecurityContext
);
147 if (Irp
&& IoSetCancelRoutine(Irp
, NULL
))
149 Irp
->Tail
.Overlay
.DriverContext
[3] = NULL
;
152 ExFreePool(QueueEntry
);
156 NpGetNextRealDataQueueEntry(DataQueue
, List
);
161 NpCompleteStalledWrites(DataQueue
, List
);
165 DataQueue
->ByteOffset
= 0;
171 NpGetNextRealDataQueueEntry(IN PNP_DATA_QUEUE DataQueue
,
174 PNP_DATA_QUEUE_ENTRY DataEntry
;
177 PLIST_ENTRY NextEntry
;
180 for (NextEntry
= DataQueue
->Queue
.Flink
;
181 NextEntry
!= &DataQueue
->Queue
;
182 NextEntry
= DataQueue
->Queue
.Flink
)
184 DataEntry
= CONTAINING_RECORD(NextEntry
, NP_DATA_QUEUE_ENTRY
, QueueEntry
);
186 Type
= DataEntry
->DataEntryType
;
187 if (Type
== Buffered
|| Type
== Unbuffered
) break;
189 Irp
= NpRemoveDataQueueEntry(DataQueue
, FALSE
, List
);
192 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
193 InsertTailList(List
, &Irp
->Tail
.Overlay
.ListEntry
);
202 NpCancelDataQueueIrp(IN PDEVICE_OBJECT DeviceObject
,
205 PNP_DATA_QUEUE DataQueue
;
206 PNP_DATA_QUEUE_ENTRY DataEntry
;
207 LIST_ENTRY DeferredList
;
208 PSECURITY_CLIENT_CONTEXT ClientSecurityContext
;
209 BOOLEAN CompleteWrites
, FirstEntry
;
211 if (DeviceObject
) IoReleaseCancelSpinLock(Irp
->CancelIrql
);
213 InitializeListHead(&DeferredList
);
215 DataQueue
= (PNP_DATA_QUEUE
)Irp
->Tail
.Overlay
.DriverContext
[2];
216 ClientSecurityContext
= NULL
;
220 FsRtlEnterFileSystem();
221 NpAcquireExclusiveVcb();
224 DataEntry
= (PNP_DATA_QUEUE_ENTRY
)Irp
->Tail
.Overlay
.DriverContext
[3];
227 if (DataEntry
->QueueEntry
.Blink
== &DataQueue
->Queue
)
229 DataQueue
->ByteOffset
= 0;
237 RemoveEntryList(&DataEntry
->QueueEntry
);
239 ClientSecurityContext
= DataEntry
->ClientSecurityContext
;
242 if (DataQueue
->QueueState
!= WriteEntries
||
243 DataQueue
->QuotaUsed
< DataQueue
->Quota
||
244 !DataEntry
->QuotaInEntry
)
249 DataQueue
->BytesInQueue
-= DataEntry
->DataSize
;
250 DataQueue
->QuotaUsed
-= DataEntry
->QuotaInEntry
;
251 --DataQueue
->EntriesInQueue
;
253 if (IsListEmpty(&DataQueue
->Queue
))
255 DataQueue
->QueueState
= Empty
;
256 ASSERT(DataQueue
->BytesInQueue
== 0);
257 ASSERT(DataQueue
->EntriesInQueue
== 0);
258 ASSERT(DataQueue
->QuotaUsed
== 0);
264 NpGetNextRealDataQueueEntry(DataQueue
, &DeferredList
);
268 NpCompleteStalledWrites(DataQueue
, &DeferredList
);
276 FsRtlExitFileSystem();
279 if (DataEntry
) ExFreePool(DataEntry
);
281 NpFreeClientSecurityContext(ClientSecurityContext
);
282 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
283 IoCompleteRequest(Irp
, IO_NAMED_PIPE_INCREMENT
);
285 NpCompleteDeferredIrps(&DeferredList
);
290 NpAddDataQueueEntry(IN ULONG NamedPipeEnd
,
292 IN PNP_DATA_QUEUE DataQueue
,
301 PNP_DATA_QUEUE_ENTRY DataEntry
;
304 PSECURITY_CLIENT_CONTEXT ClientContext
;
307 ClientContext
= NULL
;
308 ASSERT((DataQueue
->QueueState
== Empty
) || (DataQueue
->QueueState
== Who
));
310 Status
= STATUS_SUCCESS
;
312 if ((Type
!= 2) && (Who
== WriteEntries
))
314 Status
= NpGetClientSecurityContext(NamedPipeEnd
,
316 Irp
? Irp
->Tail
.Overlay
.Thread
:
317 PsGetCurrentThread(),
319 if (!NT_SUCCESS(Status
))
332 DataEntry
= ExAllocatePoolWithQuotaTag(NonPagedPool
| POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
334 NPFS_DATA_ENTRY_TAG
);
337 NpFreeClientSecurityContext(ClientContext
);
338 return STATUS_INSUFFICIENT_RESOURCES
;
341 DataEntry
->DataEntryType
= Type
;
342 DataEntry
->QuotaInEntry
= 0;
343 DataEntry
->Irp
= Irp
;
344 DataEntry
->DataSize
= DataSize
;
345 DataEntry
->ClientSecurityContext
= ClientContext
;
346 ASSERT((DataQueue
->QueueState
== Empty
) || (DataQueue
->QueueState
== Who
));
347 Status
= STATUS_PENDING
;
352 EntrySize
= sizeof(*DataEntry
);
353 if (Who
!= ReadEntries
)
355 EntrySize
+= DataSize
;
356 if (EntrySize
< DataSize
)
358 NpFreeClientSecurityContext(ClientContext
);
359 return STATUS_INVALID_PARAMETER
;
363 QuotaInEntry
= DataSize
- ByteOffset
;
364 if (DataQueue
->Quota
- DataQueue
->QuotaUsed
< QuotaInEntry
)
366 QuotaInEntry
= DataQueue
->Quota
- DataQueue
->QuotaUsed
;
374 DataEntry
= ExAllocatePoolWithQuotaTag(NonPagedPool
| POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
376 NPFS_DATA_ENTRY_TAG
);
379 NpFreeClientSecurityContext(ClientContext
);
380 return STATUS_INSUFFICIENT_RESOURCES
;
383 DataEntry
->QuotaInEntry
= QuotaInEntry
;
384 DataEntry
->Irp
= Irp
;
385 DataEntry
->DataEntryType
= Buffered
;
386 DataEntry
->ClientSecurityContext
= ClientContext
;
387 DataEntry
->DataSize
= DataSize
;
389 if (Who
== ReadEntries
)
393 Status
= STATUS_PENDING
;
394 ASSERT((DataQueue
->QueueState
== Empty
) ||
395 (DataQueue
->QueueState
== Who
));
401 RtlCopyMemory(DataEntry
+ 1,
402 Irp
? Irp
->UserBuffer
: Buffer
,
405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
407 NpFreeClientSecurityContext(ClientContext
);
408 _SEH2_YIELD(return _SEH2_GetExceptionCode());
414 Status
= STATUS_PENDING
;
418 DataEntry
->Irp
= NULL
;
419 Status
= STATUS_SUCCESS
;
422 ASSERT((DataQueue
->QueueState
== Empty
) ||
423 (DataQueue
->QueueState
== Who
));
429 NpFreeClientSecurityContext(ClientContext
);
430 return STATUS_INVALID_PARAMETER
;
433 ASSERT((DataQueue
->QueueState
== Empty
) || (DataQueue
->QueueState
== Who
));
434 if (DataQueue
->QueueState
== Empty
)
436 ASSERT(DataQueue
->BytesInQueue
== 0);
437 ASSERT(DataQueue
->EntriesInQueue
== 0);
438 ASSERT(IsListEmpty(&DataQueue
->Queue
));
442 ASSERT(DataQueue
->QueueState
== Who
);
443 ASSERT(DataQueue
->QueueState
!= Empty
);
444 ASSERT(DataQueue
->EntriesInQueue
!= 0);
447 DataQueue
->QuotaUsed
+= DataEntry
->QuotaInEntry
;
448 DataQueue
->QueueState
= Who
;
449 DataQueue
->BytesInQueue
+= DataEntry
->DataSize
;
450 DataQueue
->EntriesInQueue
++;
454 DataQueue
->ByteOffset
= ByteOffset
;
455 ASSERT(Who
== WriteEntries
);
456 ASSERT(ByteOffset
< DataEntry
->DataSize
);
457 ASSERT(DataQueue
->EntriesInQueue
== 1);
460 InsertTailList(&DataQueue
->Queue
, &DataEntry
->QueueEntry
);
462 if (Status
== STATUS_PENDING
)
464 IoMarkIrpPending(Irp
);
465 Irp
->Tail
.Overlay
.DriverContext
[2] = DataQueue
;
466 Irp
->Tail
.Overlay
.DriverContext
[3] = DataEntry
;
468 IoSetCancelRoutine(Irp
, NpCancelDataQueueIrp
);
470 if ((Irp
->Cancel
) && (IoSetCancelRoutine(Irp
, NULL
)))
472 NpCancelDataQueueIrp(NULL
, Irp
);