Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

969 lines
26 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. DataSup.c
  5. Abstract:
  6. This module implements the Named Pipe data queue support routines.
  7. Author:
  8. Gary Kimura [GaryKi] 30-Aug-1990
  9. Revision History:
  10. --*/
  11. #include "NpProcs.h"
  12. //
  13. // The debug trace level
  14. //
  15. #define Dbg (DEBUG_TRACE_DATASUP)
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, NpGetNextRealDataQueueEntry)
  18. #pragma alloc_text(PAGE, NpInitializeDataQueue)
  19. #pragma alloc_text(PAGE, NpUninitializeDataQueue)
  20. #pragma alloc_text(PAGE, NpAddDataQueueEntry)
  21. #pragma alloc_text(PAGE, NpCompleteStalledWrites)
  22. #pragma alloc_text(PAGE, NpRemoveDataQueueEntry)
  23. #endif
  24. //
  25. // The following macro is used to dump a data queue
  26. //
  27. #define DumpDataQueue(S,P) { \
  28. ULONG NpDumpDataQueue(IN PDATA_QUEUE Ptr); \
  29. DebugTrace(0,Dbg,S,0); \
  30. DebugTrace(0,Dbg,"", NpDumpDataQueue(P)); \
  31. }
  32. //
  33. // This is a debugging aid
  34. //
  35. _inline BOOLEAN
  36. NpfsVerifyDataQueue( IN ULONG Line, IN PDATA_QUEUE DataQueue ) {
  37. PDATA_ENTRY Entry;
  38. ULONG BytesInQueue = 0;
  39. ULONG EntriesInQueue = 0;
  40. for (Entry = (PDATA_ENTRY)DataQueue->Queue.Flink;
  41. Entry != (PDATA_ENTRY)&DataQueue->Queue;
  42. Entry = (PDATA_ENTRY)Entry->Queue.Flink) {
  43. BytesInQueue += Entry->DataSize;
  44. EntriesInQueue += 1;
  45. }
  46. if ((DataQueue->EntriesInQueue != EntriesInQueue) ||
  47. (DataQueue->BytesInQueue != BytesInQueue)) {
  48. DbgPrint("%d DataQueue is illformed %08lx %x %x\n", Line, DataQueue, BytesInQueue, EntriesInQueue);
  49. DbgBreakPoint();
  50. return FALSE;
  51. }
  52. return TRUE;
  53. }
  54. VOID
  55. NpCancelDataQueueIrp (
  56. IN PDEVICE_OBJECT DevictObject,
  57. IN PIRP Irp
  58. );
  59. NTSTATUS
  60. NpInitializeDataQueue (
  61. IN PDATA_QUEUE DataQueue,
  62. IN ULONG Quota
  63. )
  64. /*++
  65. Routine Description:
  66. This routine initializes a new data queue. The indicated quota is taken
  67. from the process and not returned until the data queue is uninitialized.
  68. Arguments:
  69. DataQueue - Supplies the data queue being initialized
  70. Process - Supplies a pointer to the process creating the named pipe
  71. Quota - Supplies the quota to assign to the data queue
  72. Return Value:
  73. None.
  74. --*/
  75. {
  76. PAGED_CODE();
  77. DebugTrace(+1, Dbg, "NpInitializeDataQueue, DataQueue = %08lx\n", DataQueue);
  78. //
  79. // Now we can initialize the data queue structure
  80. //
  81. DataQueue->QueueState = Empty;
  82. DataQueue->BytesInQueue = 0;
  83. DataQueue->EntriesInQueue = 0;
  84. DataQueue->Quota = Quota;
  85. DataQueue->QuotaUsed = 0;
  86. InitializeListHead (&DataQueue->Queue);
  87. DataQueue->NextByteOffset = 0;
  88. //
  89. // And return to our caller
  90. //
  91. DebugTrace(-1, Dbg, "NpInitializeDataQueue -> VOID\n", 0);
  92. return STATUS_SUCCESS;
  93. }
  94. VOID
  95. NpUninitializeDataQueue (
  96. IN PDATA_QUEUE DataQueue
  97. )
  98. /*++
  99. Routine Description:
  100. This routine uninitializes a data queue. The previously debited quota
  101. is returned to the process.
  102. Arguments:
  103. DataQueue - Supplies the data queue being uninitialized
  104. Process - Supplies a pointer to the process who created the named pipe
  105. Return Value:
  106. None.
  107. --*/
  108. {
  109. PAGED_CODE();
  110. DebugTrace(+1, Dbg, "NpUninitializeDataQueue, DataQueue = %08lx\n", DataQueue);
  111. //
  112. // Assert that the queue is empty
  113. //
  114. ASSERT( DataQueue->QueueState == Empty );
  115. //
  116. // Then for safety sake we'll zero out the data queue structure
  117. //
  118. RtlZeroMemory( DataQueue, sizeof(DATA_QUEUE ) );
  119. //
  120. // And return to our caller
  121. //
  122. DebugTrace(-1, Dbg, "NpUnininializeDataQueue -> VOID\n", 0);
  123. return;
  124. }
  125. NTSTATUS
  126. NpAddDataQueueEntry (
  127. IN NAMED_PIPE_END NamedPipeEnd,
  128. IN PCCB Ccb,
  129. IN PDATA_QUEUE DataQueue,
  130. IN QUEUE_STATE Who,
  131. IN DATA_ENTRY_TYPE Type,
  132. IN ULONG DataSize,
  133. IN PIRP Irp OPTIONAL,
  134. IN PVOID DataPointer OPTIONAL,
  135. IN ULONG ByteOffset
  136. )
  137. /*++
  138. Routine Description:
  139. This routine adds a new data entry to the end of the data queue.
  140. If necessary it will allocate a data entry buffer, or use space in
  141. the IRP, and possibly complete the indicated IRP.
  142. The different actions we are perform are based on the type and who
  143. parameters and quota requirements.
  144. Type == Internal (i.e, Unbuffered)
  145. +------+ - Allocate Data Entry from Irp
  146. |Irp | +----------+
  147. | |<---|Unbuffered| - Reference Irp
  148. +------+ |InIrp |
  149. | +----------+ - Use system buffer from Irp
  150. v |
  151. +------+ |
  152. |System|<-----+
  153. |Buffer|
  154. +------+
  155. Type == Buffered && Who == ReadEntries
  156. +----------+ - Allocate Data Entry from Irp
  157. |Irp | +-----------+
  158. |BufferedIo|<----|Buffered | - Allocate New System buffer
  159. |DeallBu...| |EitherQuota|
  160. +----------+ +-----------+ - Reference and modify Irp to
  161. | | | do Buffered I/O, Deallocate
  162. v | v buffer, and have io completion
  163. +------+ +------>+------+ copy the buffer (Input operation)
  164. |User | |System|
  165. |Buffer| |Buffer|
  166. +------+ +------+
  167. Type == Buffered && Who == WriteEntries && PipeQuota Available
  168. +----------+ - Allocate Data Entry from Quota
  169. |Irp | +-----------+
  170. | | |Buffered | - Allocate New System buffer
  171. | | |PipeQuota |
  172. +----------+ +-----------+ - Copy data from User buffer to
  173. | | system buffer
  174. v v
  175. +------+ +------+ - Complete Irp
  176. |User |..copy..>|System|
  177. |Buffer| |Buffer|
  178. +------+ +------+
  179. Type == Buffered && Who == WriteEntries && PipeQuota Not Available
  180. +----------+ - Allocate Data Entry from Irp
  181. |Irp | +-----------+
  182. |BufferedIo|<----|Buffered | - Allocate New System buffer
  183. |DeallBuff | |UserQuota |
  184. +----------+ +-----------+ - Reference and modify Irp to use
  185. | | | the new system buffer, do Buffered
  186. v | v I/O, and Deallocate buffer
  187. +------+ +------>+------+
  188. |User | |System| - Copy data from User buffer to
  189. |Buffer|..copy..>|Buffer| system buffer
  190. +------+ +------+
  191. Type == Flush or Close
  192. +----------+ - Allocate Data Entry from Irp
  193. |Irp | +-----------+
  194. | |<----|Buffered | - Reference the Irp
  195. | | |UserQuota |
  196. +----------+ +-----------+
  197. Arguments:
  198. DataQueue - Supplies the Data queue being modified
  199. Who - Indicates if this is the reader or writer that is adding to the pipe
  200. Type - Indicates the type of entry to add to the data queue
  201. DataSize - Indicates the size of the data buffer needed to represent
  202. this entry
  203. Irp - Supplies a pointer to the Irp responsible for this entry
  204. The irp is only optional for buffered write with available pipe quota
  205. DataPointer - If the Irp is not supplied then this field points to the
  206. user's write buffer.
  207. ByteOffset - Part of this buffer satisfied a read. Use this as the initial offset
  208. Return Value:
  209. PDATA_ENTRY - Returns a pointer to the newly added data entry
  210. --*/
  211. {
  212. PDATA_ENTRY DataEntry;
  213. PVOID DataBuffer;
  214. ULONG TotalSize;
  215. ULONG QuotaCharged;
  216. NTSTATUS status;
  217. PSECURITY_CLIENT_CONTEXT SecurityContext = NULL;
  218. PETHREAD Thread;
  219. BOOLEAN PendIRP;
  220. ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
  221. DebugTrace(+1, Dbg, "NpAddDataQueueEntry, DataQueue = %08lx\n", DataQueue);
  222. status = STATUS_SUCCESS;
  223. //
  224. // Capture security context if we have to.
  225. //
  226. if (Type != Flush && Who == WriteEntries) {
  227. if (Irp != NULL) {
  228. Thread = Irp->Tail.Overlay.Thread;
  229. } else {
  230. Thread = PsGetCurrentThread ();
  231. }
  232. status = NpGetClientSecurityContext (NamedPipeEnd,
  233. Ccb,
  234. Thread,
  235. &SecurityContext);
  236. if (!NT_SUCCESS (status)) {
  237. return status;
  238. }
  239. }
  240. //
  241. // Case on the type of operation we are doing
  242. //
  243. switch (Type) {
  244. case Unbuffered:
  245. case Flush:
  246. case Close:
  247. ASSERT(ARGUMENT_PRESENT(Irp));
  248. //
  249. // Allocate a data entry for the Irp
  250. //
  251. DataEntry = NpAllocatePagedPoolWithQuotaCold( sizeof (DATA_ENTRY), 'rFpN' );
  252. if (DataEntry == NULL) {
  253. NpFreeClientSecurityContext (SecurityContext);
  254. return STATUS_INSUFFICIENT_RESOURCES;
  255. }
  256. DataEntry->DataEntryType = Type;
  257. DataEntry->QuotaCharged = 0;
  258. DataEntry->Irp = Irp;
  259. DataEntry->DataSize = DataSize;
  260. DataEntry->SecurityClientContext = SecurityContext;
  261. ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
  262. status = STATUS_PENDING;
  263. break;
  264. case Buffered:
  265. //
  266. // Allocate a buffer but put the DATA_ENTRY on the end. We do this
  267. // so we can free and copy back the data in one chunk in I/O post
  268. // processing.
  269. //
  270. TotalSize = sizeof(DATA_ENTRY);
  271. if (Who != ReadEntries) {
  272. TotalSize += DataSize;
  273. if (TotalSize < DataSize) {
  274. //
  275. // DataSize is so large that adding this extra structure and
  276. // alignment padding causes it to wrap.
  277. //
  278. NpFreeClientSecurityContext (SecurityContext);
  279. return STATUS_INVALID_PARAMETER;
  280. }
  281. }
  282. //
  283. // Charge the data portion against the named pipe quota if possible and
  284. // charge the rest against the process.
  285. //
  286. if ((DataQueue->Quota - DataQueue->QuotaUsed) >= DataSize - ByteOffset) {
  287. QuotaCharged = DataSize - ByteOffset;
  288. PendIRP = FALSE;
  289. } else {
  290. QuotaCharged = DataQueue->Quota - DataQueue->QuotaUsed;
  291. PendIRP = TRUE;
  292. }
  293. DataBuffer = NpAllocatePagedPoolWithQuotaCold (TotalSize, 'rFpN');
  294. if (DataBuffer == NULL) {
  295. NpFreeClientSecurityContext (SecurityContext);
  296. return STATUS_INSUFFICIENT_RESOURCES;
  297. }
  298. DataEntry = (PDATA_ENTRY) DataBuffer;
  299. DataEntry->QuotaCharged = QuotaCharged;
  300. DataEntry->Irp = Irp;
  301. DataEntry->DataEntryType = Buffered;
  302. DataEntry->SecurityClientContext = SecurityContext;
  303. DataEntry->DataSize = DataSize;
  304. //
  305. // Check if this is the reader or writer
  306. //
  307. if (Who == ReadEntries) {
  308. ASSERT(ARGUMENT_PRESENT(Irp));
  309. status = STATUS_PENDING;
  310. ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
  311. } else {
  312. //
  313. // This is a writer entry
  314. //
  315. //
  316. // Safely copy the user buffer to the new system buffer using either
  317. // the irp user buffer is supplied of the data pointer we were given
  318. //
  319. if (ARGUMENT_PRESENT(Irp)) {
  320. DataPointer = Irp->UserBuffer;
  321. }
  322. try {
  323. RtlCopyMemory( DataEntry->DataBuffer, (PUCHAR) DataPointer, DataSize );
  324. } except(EXCEPTION_EXECUTE_HANDLER) {
  325. NpFreePool (DataBuffer);
  326. NpFreeClientSecurityContext (SecurityContext);
  327. return GetExceptionCode ();
  328. }
  329. if (PendIRP == FALSE || Irp == NULL) {
  330. DataEntry->Irp = NULL;
  331. status = STATUS_SUCCESS;
  332. } else {
  333. status = STATUS_PENDING;
  334. }
  335. ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
  336. }
  337. break;
  338. }
  339. ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
  340. #if DBG
  341. if (DataQueue->QueueState == Empty) {
  342. ASSERT (DataQueue->BytesInQueue == 0);
  343. ASSERT (DataQueue->EntriesInQueue == 0);
  344. ASSERT (IsListEmpty (&DataQueue->Queue));
  345. } else {
  346. ASSERT( DataQueue->QueueState == Who );
  347. ASSERT( DataQueue->QueueState != Empty );
  348. ASSERT( DataQueue->EntriesInQueue != 0 );
  349. }
  350. #endif
  351. DataQueue->QuotaUsed += DataEntry->QuotaCharged;
  352. DataQueue->QueueState = Who;
  353. DataQueue->BytesInQueue += DataEntry->DataSize;
  354. DataQueue->EntriesInQueue += 1;
  355. //
  356. // This handles the case where this write was used to complete some reads already and so we have to start
  357. // part way into the buffer. Obviously to have been completing reads we must be at the head of the queue.
  358. // The two cases that did this where on the outside but we call cancel here and that will need to remove
  359. // this offset.
  360. //
  361. if (ByteOffset) {
  362. DataQueue->NextByteOffset = ByteOffset;
  363. ASSERT (Who == WriteEntries);
  364. ASSERT (ByteOffset < DataEntry->DataSize);
  365. ASSERT (DataQueue->EntriesInQueue == 1);
  366. }
  367. InsertTailList (&DataQueue->Queue, &DataEntry->Queue);
  368. if (status == STATUS_PENDING) {
  369. IoMarkIrpPending (Irp);
  370. //
  371. // Tie the IRP to the DataQueue and DataEntry. We can divorse this link on cancel etc.
  372. //
  373. NpIrpDataQueue(Irp) = DataQueue;
  374. NpIrpDataEntry(Irp) = DataEntry;
  375. IoSetCancelRoutine( Irp, NpCancelDataQueueIrp );
  376. if (Irp->Cancel && IoSetCancelRoutine( Irp, NULL ) != NULL) {
  377. //
  378. // Indicate in the first parameter that we're calling the
  379. // cancel routine and not the I/O system. Therefore
  380. // the routine won't take out the VCB exclusive.
  381. //
  382. NpCancelDataQueueIrp( NULL, Irp );
  383. }
  384. }
  385. //
  386. // And return to our caller
  387. //
  388. return status;
  389. }
  390. VOID
  391. NpCompleteStalledWrites (
  392. IN PDATA_QUEUE DataQueue,
  393. IN PLIST_ENTRY DeferredList
  394. )
  395. /*++
  396. Routine Description:
  397. This routine is used to return any quota added back to the pipe to any stalled writes.
  398. We stall writes becuase there was no room in the pipe for them. If there is now room we can complete them.
  399. Arguments:
  400. DataQueue - Supplies a pointer to the data queue being modifed
  401. Return Value:
  402. None
  403. --*/
  404. {
  405. PLIST_ENTRY Link;
  406. PDATA_ENTRY DataEntry;
  407. ULONG ExtraQuota, Needed, ByteOffset;
  408. PIRP Irp;
  409. ExtraQuota = DataQueue->Quota - DataQueue->QuotaUsed;
  410. ByteOffset = DataQueue->NextByteOffset;
  411. for (Link = DataQueue->Queue.Flink;
  412. (Link != &DataQueue->Queue) && (ExtraQuota != 0);
  413. Link = Link->Flink, ByteOffset = 0) {
  414. DataEntry = CONTAINING_RECORD (Link, DATA_ENTRY, Queue);
  415. Irp = DataEntry->Irp;
  416. if ((DataEntry->DataEntryType != Buffered) || (Irp == NULL)) {
  417. continue;
  418. }
  419. if (DataEntry->QuotaCharged < DataEntry->DataSize - ByteOffset) {
  420. Needed = DataEntry->DataSize - ByteOffset - DataEntry->QuotaCharged;
  421. if (Needed > ExtraQuota) {
  422. Needed = ExtraQuota;
  423. }
  424. ExtraQuota -= Needed;
  425. DataEntry->QuotaCharged += Needed;
  426. if (DataEntry->QuotaCharged == DataEntry->DataSize - ByteOffset) {
  427. //
  428. // Attempt to complete this IRP. If cancel is already running then leave it in
  429. // place for cancel to sort out.
  430. //
  431. if (IoSetCancelRoutine (Irp, NULL) != NULL) {
  432. DataEntry->Irp = NULL;
  433. Irp->IoStatus.Information = DataEntry->DataSize;
  434. NpDeferredCompleteRequest (Irp, STATUS_SUCCESS, DeferredList);
  435. }
  436. }
  437. }
  438. }
  439. DataQueue->QuotaUsed = DataQueue->Quota - ExtraQuota;
  440. }
  441. PIRP
  442. NpRemoveDataQueueEntry (
  443. IN PDATA_QUEUE DataQueue,
  444. IN BOOLEAN CompletedFlushes,
  445. IN PLIST_ENTRY DeferredList
  446. )
  447. /*++
  448. Routine Description:
  449. This routines remove the first entry from the front of the indicated
  450. data queue, and possibly returns the Irp associated with the entry if
  451. it wasn't already completed when we did the insert.
  452. If the data entry we are removing indicates buffered I/O then we also
  453. need to deallocate the data buffer besides the data entry but only
  454. if the Irp is null. Note that the data entry might be stored in an IRP.
  455. If it is then we are going to return the IRP it is stored in.
  456. Arguments:
  457. DataQueue - Supplies a pointer to the data queue being modifed
  458. CompleteFlushes - Specifies if this routine should look to complete pended flushes
  459. DeferredList - List of IRPs to complete later after we drop the locks
  460. Return Value:
  461. PIRP - Possibly returns a pointer to an IRP.
  462. --*/
  463. {
  464. PDATA_ENTRY DataEntry;
  465. DATA_ENTRY_TYPE DataEntryType;
  466. PIRP Irp;
  467. ULONG DataSize;
  468. PVOID DataPointer;
  469. PLIST_ENTRY Links;
  470. PSECURITY_CLIENT_CONTEXT ClientContext;
  471. QUEUE_STATE Who;
  472. BOOLEAN DoScan;
  473. DebugTrace(+1, Dbg, "NpRemoveDataQueueEntry, DataQueue = %08lx\n", DataQueue);
  474. //
  475. // Check if the queue is empty, and if so then we simply return null
  476. //
  477. if (DataQueue->QueueState == Empty) {
  478. ASSERT (IsListEmpty (&DataQueue->Queue));
  479. ASSERT (DataQueue->EntriesInQueue == 0);
  480. ASSERT (DataQueue->BytesInQueue == 0);
  481. ASSERT (DataQueue->QuotaUsed == 0);
  482. Irp = NULL;
  483. } else {
  484. //
  485. // Reference the front of the data queue, and remove the entry
  486. // from the queue itself.
  487. //
  488. Links = (PLIST_ENTRY) RemoveHeadList (&DataQueue->Queue);
  489. DataEntry = CONTAINING_RECORD (Links, DATA_ENTRY, Queue);
  490. DataQueue->BytesInQueue -= DataEntry->DataSize;
  491. DataQueue->EntriesInQueue -= 1;
  492. Who = DataQueue->QueueState;
  493. //
  494. // If quota was completely used until now and we are adding some back in then we need to look for write
  495. // IRPs that were blocked becuase of pipe quota.
  496. //
  497. if (Who != WriteEntries || DataQueue->QuotaUsed < DataQueue->Quota || DataEntry->QuotaCharged == 0) {
  498. DoScan = FALSE;
  499. } else {
  500. DoScan = TRUE;
  501. }
  502. DataQueue->QuotaUsed -= DataEntry->QuotaCharged;
  503. //
  504. // Now if the queue is empty we need to reset the end of queue and
  505. // queue state
  506. //
  507. if (IsListEmpty (&DataQueue->Queue)) {
  508. DataQueue->QueueState = Empty;
  509. DoScan = FALSE;
  510. }
  511. //
  512. // Capture some of the fields from the data entry to make our
  513. // other references a little easier
  514. //
  515. DataEntryType = DataEntry->DataEntryType;
  516. Irp = DataEntry->Irp;
  517. DataSize = DataEntry->DataSize;
  518. ClientContext = DataEntry->SecurityClientContext;
  519. NpFreeClientSecurityContext (ClientContext);
  520. if (Irp != NULL) {
  521. //
  522. // Cancel is alreayd active. Let it complete this IRP.
  523. //
  524. if (IoSetCancelRoutine( Irp, NULL ) == NULL) {
  525. //
  526. // Divorce this IRP from the data entry so it doesn't clean up
  527. //
  528. NpIrpDataEntry(Irp) = NULL;
  529. Irp = NULL;
  530. }
  531. }
  532. NpFreePool( DataEntry );
  533. //
  534. //
  535. //
  536. if (CompletedFlushes) {
  537. NpGetNextRealDataQueueEntry (DataQueue, DeferredList);
  538. }
  539. if (DoScan) {
  540. NpCompleteStalledWrites (DataQueue, DeferredList);
  541. }
  542. }
  543. //
  544. // In all cases we'll also zero out the next byte offset.
  545. //
  546. DataQueue->NextByteOffset = 0;
  547. //
  548. // And return to our caller
  549. //
  550. DumpDataQueue( "After RemoveDataQueueEntry\n", DataQueue );
  551. DebugTrace(-1, Dbg, "NpRemoveDataQueueEntry -> %08lx\n", Irp);
  552. return Irp;
  553. }
  554. PDATA_ENTRY
  555. NpGetNextRealDataQueueEntry (
  556. IN PDATA_QUEUE DataQueue,
  557. IN PLIST_ENTRY DeferredList
  558. )
  559. /*++
  560. Routine Description:
  561. This routine will returns a pointer to the next real data queue entry
  562. in the indicated data queue. A real entry is either a read or write
  563. entry (i.e., buffered or unbuffered). It will complete (as necessary)
  564. any flush and close Irps that are in the queue until either the queue
  565. is empty or a real data queue entry is at the front of the queue.
  566. Arguments:
  567. DataQueue - Supplies a pointer to the data queue being modified
  568. Return Value:
  569. PDATA_ENTRY - Returns a pointer to the next data queue entry or NULL
  570. if there isn't any.
  571. --*/
  572. {
  573. PDATA_ENTRY DataEntry;
  574. PIRP Irp;
  575. PAGED_CODE();
  576. DebugTrace(+1, Dbg, "NpGetNextRealDataQueueEntry, DataQueue = %08lx\n", DataQueue);
  577. //
  578. // While the next data queue entry at the head of the data queue is not
  579. // a real data queue entry we'll dequeue that entry and complete
  580. // its corresponding IRP.
  581. //
  582. for (DataEntry = NpGetNextDataQueueEntry( DataQueue, NULL);
  583. (DataEntry != (PDATA_ENTRY) &DataQueue->Queue) &&
  584. ((DataEntry->DataEntryType != Buffered) &&
  585. (DataEntry->DataEntryType != Unbuffered));
  586. DataEntry = NpGetNextDataQueueEntry( DataQueue, NULL)) {
  587. //
  588. // We have a non real data queue entry that needs to be removed
  589. // and completed.
  590. //
  591. Irp = NpRemoveDataQueueEntry( DataQueue, FALSE, DeferredList );
  592. if (Irp != NULL) {
  593. NpDeferredCompleteRequest( Irp, STATUS_SUCCESS, DeferredList );
  594. }
  595. }
  596. //
  597. // At this point we either have an empty data queue and data entry is
  598. // null, or we have a real data queue entry. In either case it
  599. // is time to return to our caller
  600. //
  601. DebugTrace(-1, Dbg, "NpGetNextRealDataQueueEntry -> %08lx\n", DataEntry);
  602. return DataEntry;
  603. }
  604. //
  605. // Local support routine
  606. //
  607. VOID
  608. NpCancelDataQueueIrp (
  609. IN PDEVICE_OBJECT DeviceObject,
  610. IN PIRP Irp
  611. )
  612. /*++
  613. Routine Description:
  614. This routine implements the cancel function for an IRP saved in a
  615. data queue
  616. Arguments:
  617. DeviceObject - Generally ignored but the low order bit is a flag indicating
  618. if we are being called locally (i.e., not from the I/O system) and
  619. therefore don't need to take out the VCB.
  620. Irp - Supplies the Irp being cancelled. A pointer to the data queue
  621. structure is stored in the information field of the Irp Iosb
  622. field.
  623. Return Value:
  624. None.
  625. --*/
  626. {
  627. PDATA_QUEUE DataQueue;
  628. PDATA_ENTRY DataEntry;
  629. PCCB Ccb;
  630. PIO_STACK_LOCATION IrpSp;
  631. PFILE_OBJECT FileObject;
  632. ULONG DataSize;
  633. PSECURITY_CLIENT_CONTEXT ClientContext;
  634. QUEUE_STATE Who;
  635. BOOLEAN AtHead;
  636. BOOLEAN DoScan;
  637. LIST_ENTRY DeferredList;
  638. if (DeviceObject != NULL) {
  639. IoReleaseCancelSpinLock (Irp->CancelIrql);
  640. }
  641. //
  642. // The status field is used to store a pointer to the data queue
  643. // containing this irp
  644. //
  645. InitializeListHead (&DeferredList);
  646. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  647. FileObject = IrpSp->FileObject;
  648. DataQueue = NpIrpDataQueue (Irp);
  649. ClientContext = NULL;
  650. if (DeviceObject != NULL) {
  651. FsRtlEnterFileSystem ();
  652. NpAcquireExclusiveVcb ();
  653. }
  654. DataEntry = NpIrpDataEntry (Irp);
  655. if (DataEntry != NULL) {
  656. //
  657. // If what we are about to removed is in the front of the queue then we must
  658. // reset the next byte offset
  659. //
  660. if (DataEntry->Queue.Blink == &DataQueue->Queue) {
  661. DataQueue->NextByteOffset = 0;
  662. AtHead = TRUE;
  663. } else {
  664. AtHead = FALSE;
  665. }
  666. RemoveEntryList (&DataEntry->Queue);
  667. Who = DataQueue->QueueState;
  668. //
  669. // Capture some of the fields from the data entry to make our
  670. // other references a little easier
  671. //
  672. DataSize = DataEntry->DataSize;
  673. ClientContext = DataEntry->SecurityClientContext;
  674. //
  675. // If quota was completely used until now and we are adding some back in then we need to look for write
  676. // IRPs that were blocked because of pipe quota.
  677. //
  678. if (Who != WriteEntries || DataQueue->QuotaUsed < DataQueue->Quota || DataEntry->QuotaCharged == 0) {
  679. DoScan = FALSE;
  680. } else {
  681. DoScan = TRUE;
  682. }
  683. //
  684. // Return pipe quota for the entry.
  685. //
  686. DataQueue->QuotaUsed -= DataEntry->QuotaCharged;
  687. //
  688. // Update the data queue header information
  689. //
  690. DataQueue->BytesInQueue -= DataSize;
  691. DataQueue->EntriesInQueue -= 1;
  692. //
  693. // If the list is now empty then mark it as such. Complete any flushes at queue head as all the
  694. // requests a head of them have been completed.
  695. //
  696. if (IsListEmpty (&DataQueue->Queue)) {
  697. DataQueue->QueueState = Empty;
  698. ASSERT (DataQueue->BytesInQueue == 0);
  699. ASSERT (DataQueue->EntriesInQueue == 0);
  700. ASSERT (DataQueue->QuotaUsed == 0);
  701. } else {
  702. if (AtHead) {
  703. NpGetNextRealDataQueueEntry (DataQueue, &DeferredList);
  704. }
  705. if (DoScan) {
  706. NpCompleteStalledWrites (DataQueue, &DeferredList);
  707. }
  708. }
  709. }
  710. if (DeviceObject != NULL) {
  711. NpReleaseVcb ();
  712. FsRtlExitFileSystem ();
  713. }
  714. //
  715. // Finally complete the request saying that it has been cancelled.
  716. //
  717. if (DataEntry != NULL) {
  718. NpFreePool (DataEntry);
  719. }
  720. NpFreeClientSecurityContext (ClientContext);
  721. NpCompleteRequest (Irp, STATUS_CANCELLED);
  722. NpCompleteDeferredIrps (&DeferredList);
  723. //
  724. // And return to our caller
  725. //
  726. return;
  727. }