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
,
69 Irp
= DataQueueEntry
->Irp
;
71 if ((DataQueueEntry
->DataEntryType
== Buffered
) && (Irp
))
73 DataLeft
= DataQueueEntry
->DataSize
- ByteOffset
;
75 if (DataQueueEntry
->QuotaInEntry
< DataLeft
)
77 NewQuotaLeft
= DataLeft
- DataQueueEntry
->QuotaInEntry
;
78 if (NewQuotaLeft
> QuotaLeft
) NewQuotaLeft
= QuotaLeft
;
80 QuotaLeft
-= NewQuotaLeft
;
81 DataQueueEntry
->QuotaInEntry
+= NewQuotaLeft
;
83 if (DataQueueEntry
->QuotaInEntry
== DataLeft
&&
84 IoSetCancelRoutine(Irp
, NULL
))
86 DataQueueEntry
->Irp
= NULL
;
88 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
89 Irp
->IoStatus
.Information
= DataQueueEntry
->DataSize
;
91 InsertTailList(List
, &Irp
->Tail
.Overlay
.ListEntry
);
96 NextEntry
= NextEntry
->Flink
;
100 DataQueue
->QuotaUsed
= DataQueue
->Quota
- QuotaLeft
;
105 NpRemoveDataQueueEntry(IN PNP_DATA_QUEUE DataQueue
,
110 PNP_DATA_QUEUE_ENTRY QueueEntry
;
113 if (DataQueue
->QueueState
== Empty
)
116 ASSERT(IsListEmpty(&DataQueue
->Queue
));
117 ASSERT(DataQueue
->EntriesInQueue
== 0);
118 ASSERT(DataQueue
->BytesInQueue
== 0);
119 ASSERT(DataQueue
->QuotaUsed
== 0);
123 QueueEntry
= CONTAINING_RECORD(RemoveHeadList(&DataQueue
->Queue
),
127 DataQueue
->BytesInQueue
-= QueueEntry
->DataSize
;
128 --DataQueue
->EntriesInQueue
;
131 if (DataQueue
->QueueState
!= WriteEntries
||
132 DataQueue
->QuotaUsed
< DataQueue
->Quota
||
133 !QueueEntry
->QuotaInEntry
)
138 DataQueue
->QuotaUsed
-= QueueEntry
->QuotaInEntry
;
140 if (IsListEmpty(&DataQueue
->Queue
))
142 DataQueue
->QueueState
= Empty
;
146 Irp
= QueueEntry
->Irp
;
147 NpFreeClientSecurityContext(QueueEntry
->ClientSecurityContext
);
149 if (Irp
&& !IoSetCancelRoutine(Irp
, NULL
))
151 Irp
->Tail
.Overlay
.DriverContext
[3] = NULL
;
155 ExFreePool(QueueEntry
);
159 NpGetNextRealDataQueueEntry(DataQueue
, List
);
164 NpCompleteStalledWrites(DataQueue
, List
);
168 DataQueue
->ByteOffset
= 0;
174 NpGetNextRealDataQueueEntry(IN PNP_DATA_QUEUE DataQueue
,
177 PNP_DATA_QUEUE_ENTRY DataEntry
;
180 PLIST_ENTRY NextEntry
;
183 for (NextEntry
= DataQueue
->Queue
.Flink
;
184 NextEntry
!= &DataQueue
->Queue
;
185 NextEntry
= DataQueue
->Queue
.Flink
)
187 DataEntry
= CONTAINING_RECORD(NextEntry
,
191 Type
= DataEntry
->DataEntryType
;
192 if (Type
== Buffered
|| Type
== Unbuffered
) break;
194 Irp
= NpRemoveDataQueueEntry(DataQueue
, FALSE
, List
);
197 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
198 InsertTailList(List
, &Irp
->Tail
.Overlay
.ListEntry
);
207 NpCancelDataQueueIrp(IN PDEVICE_OBJECT DeviceObject
,
210 PNP_DATA_QUEUE DataQueue
;
211 PNP_DATA_QUEUE_ENTRY DataEntry
;
212 LIST_ENTRY DeferredList
;
213 PSECURITY_CLIENT_CONTEXT ClientSecurityContext
;
214 BOOLEAN CompleteWrites
, FirstEntry
;
216 if (DeviceObject
) IoReleaseCancelSpinLock(Irp
->CancelIrql
);
218 InitializeListHead(&DeferredList
);
220 DataQueue
= Irp
->Tail
.Overlay
.DriverContext
[2];
221 ClientSecurityContext
= NULL
;
225 FsRtlEnterFileSystem();
226 NpAcquireExclusiveVcb();
229 DataEntry
= Irp
->Tail
.Overlay
.DriverContext
[3];
232 if (DataEntry
->QueueEntry
.Blink
== &DataQueue
->Queue
)
234 DataQueue
->ByteOffset
= 0;
242 RemoveEntryList(&DataEntry
->QueueEntry
);
244 ClientSecurityContext
= DataEntry
->ClientSecurityContext
;
246 CompleteWrites
= TRUE
;
247 if (DataQueue
->QueueState
!= WriteEntries
||
248 DataQueue
->QuotaUsed
< DataQueue
->Quota
||
249 !DataEntry
->QuotaInEntry
)
251 CompleteWrites
= FALSE
;
254 DataQueue
->BytesInQueue
-= DataEntry
->DataSize
;
255 DataQueue
->QuotaUsed
-= DataEntry
->QuotaInEntry
;
256 --DataQueue
->EntriesInQueue
;
258 if (IsListEmpty(&DataQueue
->Queue
))
260 DataQueue
->QueueState
= Empty
;
261 ASSERT(DataQueue
->BytesInQueue
== 0);
262 ASSERT(DataQueue
->EntriesInQueue
== 0);
263 ASSERT(DataQueue
->QuotaUsed
== 0);
269 NpGetNextRealDataQueueEntry(DataQueue
, &DeferredList
);
273 NpCompleteStalledWrites(DataQueue
, &DeferredList
);
281 FsRtlExitFileSystem();
284 if (DataEntry
) ExFreePool(DataEntry
);
286 NpFreeClientSecurityContext(ClientSecurityContext
);
287 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
288 IoCompleteRequest(Irp
, IO_NAMED_PIPE_INCREMENT
);
290 NpCompleteDeferredIrps(&DeferredList
);
295 NpAddDataQueueEntry(IN ULONG NamedPipeEnd
,
297 IN PNP_DATA_QUEUE DataQueue
,
306 PNP_DATA_QUEUE_ENTRY DataEntry
;
309 PSECURITY_CLIENT_CONTEXT ClientContext
;
312 ClientContext
= NULL
;
313 ASSERT((DataQueue
->QueueState
== Empty
) || (DataQueue
->QueueState
== Who
));
315 Status
= STATUS_SUCCESS
;
317 if ((Type
!= 2) && (Who
== WriteEntries
))
319 Status
= NpGetClientSecurityContext(NamedPipeEnd
,
321 Irp
? Irp
->Tail
.Overlay
.Thread
:
322 PsGetCurrentThread(),
324 if (!NT_SUCCESS(Status
))
337 DataEntry
= ExAllocatePoolWithQuotaTag(NonPagedPool
| POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
339 NPFS_DATA_ENTRY_TAG
);
342 NpFreeClientSecurityContext(ClientContext
);
343 return STATUS_INSUFFICIENT_RESOURCES
;
346 DataEntry
->DataEntryType
= Type
;
347 DataEntry
->QuotaInEntry
= 0;
348 DataEntry
->Irp
= Irp
;
349 DataEntry
->DataSize
= DataSize
;
350 DataEntry
->ClientSecurityContext
= ClientContext
;
351 ASSERT((DataQueue
->QueueState
== Empty
) || (DataQueue
->QueueState
== Who
));
352 Status
= STATUS_PENDING
;
357 EntrySize
= sizeof(*DataEntry
);
358 if (Who
!= ReadEntries
)
360 EntrySize
+= DataSize
;
361 if (EntrySize
< DataSize
)
363 NpFreeClientSecurityContext(ClientContext
);
364 return STATUS_INVALID_PARAMETER
;
368 QuotaInEntry
= DataSize
- ByteOffset
;
369 if (DataQueue
->Quota
- DataQueue
->QuotaUsed
< QuotaInEntry
)
371 QuotaInEntry
= DataQueue
->Quota
- DataQueue
->QuotaUsed
;
379 DataEntry
= ExAllocatePoolWithQuotaTag(NonPagedPool
| POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
381 NPFS_DATA_ENTRY_TAG
);
384 NpFreeClientSecurityContext(ClientContext
);
385 return STATUS_INSUFFICIENT_RESOURCES
;
388 DataEntry
->QuotaInEntry
= QuotaInEntry
;
389 DataEntry
->Irp
= Irp
;
390 DataEntry
->DataEntryType
= Buffered
;
391 DataEntry
->ClientSecurityContext
= ClientContext
;
392 DataEntry
->DataSize
= DataSize
;
394 if (Who
== ReadEntries
)
398 Status
= STATUS_PENDING
;
399 ASSERT((DataQueue
->QueueState
== Empty
) ||
400 (DataQueue
->QueueState
== Who
));
406 RtlCopyMemory(DataEntry
+ 1,
407 Irp
? Irp
->UserBuffer
: Buffer
,
410 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
412 NpFreeClientSecurityContext(ClientContext
);
413 _SEH2_YIELD(return _SEH2_GetExceptionCode());
419 Status
= STATUS_PENDING
;
423 DataEntry
->Irp
= NULL
;
424 Status
= STATUS_SUCCESS
;
427 ASSERT((DataQueue
->QueueState
== Empty
) ||
428 (DataQueue
->QueueState
== Who
));
434 NpFreeClientSecurityContext(ClientContext
);
435 return STATUS_INVALID_PARAMETER
;
438 ASSERT((DataQueue
->QueueState
== Empty
) || (DataQueue
->QueueState
== Who
));
439 if (DataQueue
->QueueState
== Empty
)
441 ASSERT(DataQueue
->BytesInQueue
== 0);
442 ASSERT(DataQueue
->EntriesInQueue
== 0);
443 ASSERT(IsListEmpty(&DataQueue
->Queue
));
447 ASSERT(DataQueue
->QueueState
== Who
);
448 ASSERT(DataQueue
->QueueState
!= Empty
);
449 ASSERT(DataQueue
->EntriesInQueue
!= 0);
452 DataQueue
->QuotaUsed
+= DataEntry
->QuotaInEntry
;
453 DataQueue
->QueueState
= Who
;
454 DataQueue
->BytesInQueue
+= DataEntry
->DataSize
;
455 DataQueue
->EntriesInQueue
++;
459 DataQueue
->ByteOffset
= ByteOffset
;
460 ASSERT(Who
== WriteEntries
);
461 ASSERT(ByteOffset
< DataEntry
->DataSize
);
462 ASSERT(DataQueue
->EntriesInQueue
== 1);
465 InsertTailList(&DataQueue
->Queue
, &DataEntry
->QueueEntry
);
467 if (Status
== STATUS_PENDING
)
469 IoMarkIrpPending(Irp
);
470 Irp
->Tail
.Overlay
.DriverContext
[2] = DataQueue
;
471 Irp
->Tail
.Overlay
.DriverContext
[3] = DataEntry
;
473 IoSetCancelRoutine(Irp
, NpCancelDataQueueIrp
);
475 if ((Irp
->Cancel
) && (IoSetCancelRoutine(Irp
, NULL
)))
477 NpCancelDataQueueIrp(NULL
, Irp
);