1 /* 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 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "npfs.h" 12 13 // File ID number for NPFS bugchecking support 14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_DATASUP) 15 16 /* FUNCTIONS ******************************************************************/ 17 18 NTSTATUS 19 NTAPI 20 NpUninitializeDataQueue(IN PNP_DATA_QUEUE DataQueue) 21 { 22 PAGED_CODE(); 23 24 ASSERT(DataQueue->QueueState == Empty); 25 26 RtlZeroMemory(DataQueue, sizeof(*DataQueue)); 27 return STATUS_SUCCESS; 28 } 29 30 NTSTATUS 31 NTAPI 32 NpInitializeDataQueue(IN PNP_DATA_QUEUE DataQueue, 33 IN ULONG Quota) 34 { 35 PAGED_CODE(); 36 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; 45 } 46 47 VOID 48 NTAPI 49 NpCompleteStalledWrites(IN PNP_DATA_QUEUE DataQueue, 50 IN PLIST_ENTRY List) 51 { 52 ULONG QuotaLeft, ByteOffset, DataLeft, NewQuotaLeft; 53 PNP_DATA_QUEUE_ENTRY DataQueueEntry; 54 PIRP Irp; 55 PLIST_ENTRY NextEntry; 56 57 QuotaLeft = DataQueue->Quota - DataQueue->QuotaUsed; 58 ByteOffset = DataQueue->ByteOffset; 59 60 NextEntry = DataQueue->Queue.Flink; 61 while (NextEntry != &DataQueue->Queue) 62 { 63 if (!QuotaLeft) break; 64 65 DataQueueEntry = CONTAINING_RECORD(NextEntry, 66 NP_DATA_QUEUE_ENTRY, 67 QueueEntry); 68 69 Irp = DataQueueEntry->Irp; 70 71 if ((DataQueueEntry->DataEntryType == Buffered) && (Irp)) 72 { 73 DataLeft = DataQueueEntry->DataSize - ByteOffset; 74 75 if (DataQueueEntry->QuotaInEntry < DataLeft) 76 { 77 NewQuotaLeft = DataLeft - DataQueueEntry->QuotaInEntry; 78 if (NewQuotaLeft > QuotaLeft) NewQuotaLeft = QuotaLeft; 79 80 QuotaLeft -= NewQuotaLeft; 81 DataQueueEntry->QuotaInEntry += NewQuotaLeft; 82 83 if (DataQueueEntry->QuotaInEntry == DataLeft && 84 IoSetCancelRoutine(Irp, NULL)) 85 { 86 DataQueueEntry->Irp = NULL; 87 88 Irp->IoStatus.Status = STATUS_SUCCESS; 89 Irp->IoStatus.Information = DataQueueEntry->DataSize; 90 91 InsertTailList(List, &Irp->Tail.Overlay.ListEntry); 92 } 93 } 94 } 95 96 NextEntry = NextEntry->Flink; 97 ByteOffset = 0; 98 } 99 100 DataQueue->QuotaUsed = DataQueue->Quota - QuotaLeft; 101 } 102 103 PIRP 104 NTAPI 105 NpRemoveDataQueueEntry(IN PNP_DATA_QUEUE DataQueue, 106 IN BOOLEAN Flag, 107 IN PLIST_ENTRY List) 108 { 109 PIRP Irp; 110 PNP_DATA_QUEUE_ENTRY QueueEntry; 111 BOOLEAN HasWrites; 112 113 if (DataQueue->QueueState == Empty) 114 { 115 Irp = NULL; 116 ASSERT(IsListEmpty(&DataQueue->Queue)); 117 ASSERT(DataQueue->EntriesInQueue == 0); 118 ASSERT(DataQueue->BytesInQueue == 0); 119 ASSERT(DataQueue->QuotaUsed == 0); 120 } 121 else 122 { 123 QueueEntry = CONTAINING_RECORD(RemoveHeadList(&DataQueue->Queue), 124 NP_DATA_QUEUE_ENTRY, 125 QueueEntry); 126 127 DataQueue->BytesInQueue -= QueueEntry->DataSize; 128 --DataQueue->EntriesInQueue; 129 130 HasWrites = TRUE; 131 if (DataQueue->QueueState != WriteEntries || 132 DataQueue->QuotaUsed < DataQueue->Quota || 133 !QueueEntry->QuotaInEntry) 134 { 135 HasWrites = FALSE; 136 } 137 138 DataQueue->QuotaUsed -= QueueEntry->QuotaInEntry; 139 140 if (IsListEmpty(&DataQueue->Queue)) 141 { 142 DataQueue->QueueState = Empty; 143 HasWrites = FALSE; 144 } 145 146 Irp = QueueEntry->Irp; 147 NpFreeClientSecurityContext(QueueEntry->ClientSecurityContext); 148 149 if (Irp && !IoSetCancelRoutine(Irp, NULL)) 150 { 151 Irp->Tail.Overlay.DriverContext[3] = NULL; 152 Irp = NULL; 153 } 154 155 ExFreePool(QueueEntry); 156 157 if (Flag) 158 { 159 NpGetNextRealDataQueueEntry(DataQueue, List); 160 } 161 162 if (HasWrites) 163 { 164 NpCompleteStalledWrites(DataQueue, List); 165 } 166 } 167 168 DataQueue->ByteOffset = 0; 169 return Irp; 170 } 171 172 PLIST_ENTRY 173 NTAPI 174 NpGetNextRealDataQueueEntry(IN PNP_DATA_QUEUE DataQueue, 175 IN PLIST_ENTRY List) 176 { 177 PNP_DATA_QUEUE_ENTRY DataEntry; 178 ULONG Type; 179 PIRP Irp; 180 PLIST_ENTRY NextEntry; 181 PAGED_CODE(); 182 183 for (NextEntry = DataQueue->Queue.Flink; 184 NextEntry != &DataQueue->Queue; 185 NextEntry = DataQueue->Queue.Flink) 186 { 187 DataEntry = CONTAINING_RECORD(NextEntry, 188 NP_DATA_QUEUE_ENTRY, 189 QueueEntry); 190 191 Type = DataEntry->DataEntryType; 192 if (Type == Buffered || Type == Unbuffered) break; 193 194 Irp = NpRemoveDataQueueEntry(DataQueue, FALSE, List); 195 if (Irp) 196 { 197 Irp->IoStatus.Status = STATUS_SUCCESS; 198 InsertTailList(List, &Irp->Tail.Overlay.ListEntry); 199 } 200 } 201 202 return NextEntry; 203 } 204 205 VOID 206 NTAPI 207 NpCancelDataQueueIrp(IN PDEVICE_OBJECT DeviceObject, 208 IN PIRP Irp) 209 { 210 PNP_DATA_QUEUE DataQueue; 211 PNP_DATA_QUEUE_ENTRY DataEntry; 212 LIST_ENTRY DeferredList; 213 PSECURITY_CLIENT_CONTEXT ClientSecurityContext; 214 BOOLEAN CompleteWrites, FirstEntry; 215 216 if (DeviceObject) IoReleaseCancelSpinLock(Irp->CancelIrql); 217 218 InitializeListHead(&DeferredList); 219 220 DataQueue = Irp->Tail.Overlay.DriverContext[2]; 221 ClientSecurityContext = NULL; 222 223 if (DeviceObject) 224 { 225 FsRtlEnterFileSystem(); 226 NpAcquireExclusiveVcb(); 227 } 228 229 DataEntry = Irp->Tail.Overlay.DriverContext[3]; 230 if (DataEntry) 231 { 232 if (DataEntry->QueueEntry.Blink == &DataQueue->Queue) 233 { 234 DataQueue->ByteOffset = 0; 235 FirstEntry = TRUE; 236 } 237 else 238 { 239 FirstEntry = FALSE; 240 } 241 242 RemoveEntryList(&DataEntry->QueueEntry); 243 244 ClientSecurityContext = DataEntry->ClientSecurityContext; 245 246 CompleteWrites = TRUE; 247 if (DataQueue->QueueState != WriteEntries || 248 DataQueue->QuotaUsed < DataQueue->Quota || 249 !DataEntry->QuotaInEntry) 250 { 251 CompleteWrites = FALSE; 252 } 253 254 DataQueue->BytesInQueue -= DataEntry->DataSize; 255 DataQueue->QuotaUsed -= DataEntry->QuotaInEntry; 256 --DataQueue->EntriesInQueue; 257 258 if (IsListEmpty(&DataQueue->Queue)) 259 { 260 DataQueue->QueueState = Empty; 261 ASSERT(DataQueue->BytesInQueue == 0); 262 ASSERT(DataQueue->EntriesInQueue == 0); 263 ASSERT(DataQueue->QuotaUsed == 0); 264 } 265 else 266 { 267 if (FirstEntry) 268 { 269 NpGetNextRealDataQueueEntry(DataQueue, &DeferredList); 270 } 271 if (CompleteWrites) 272 { 273 NpCompleteStalledWrites(DataQueue, &DeferredList); 274 } 275 } 276 } 277 278 if (DeviceObject) 279 { 280 NpReleaseVcb(); 281 FsRtlExitFileSystem(); 282 } 283 284 if (DataEntry) ExFreePool(DataEntry); 285 286 NpFreeClientSecurityContext(ClientSecurityContext); 287 Irp->IoStatus.Status = STATUS_CANCELLED; 288 IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT); 289 290 NpCompleteDeferredIrps(&DeferredList); 291 } 292 293 NTSTATUS 294 NTAPI 295 NpAddDataQueueEntry(IN ULONG NamedPipeEnd, 296 IN PNP_CCB Ccb, 297 IN PNP_DATA_QUEUE DataQueue, 298 IN ULONG Who, 299 IN ULONG Type, 300 IN ULONG DataSize, 301 IN PIRP Irp, 302 IN PVOID Buffer, 303 IN ULONG ByteOffset) 304 { 305 NTSTATUS Status; 306 PNP_DATA_QUEUE_ENTRY DataEntry; 307 SIZE_T EntrySize; 308 ULONG QuotaInEntry; 309 PSECURITY_CLIENT_CONTEXT ClientContext; 310 BOOLEAN HasSpace; 311 312 ClientContext = NULL; 313 ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who)); 314 315 Status = STATUS_SUCCESS; 316 317 if ((Type != 2) && (Who == WriteEntries)) 318 { 319 Status = NpGetClientSecurityContext(NamedPipeEnd, 320 Ccb, 321 Irp ? Irp->Tail.Overlay.Thread : 322 PsGetCurrentThread(), 323 &ClientContext); 324 if (!NT_SUCCESS(Status)) 325 { 326 return Status; 327 } 328 } 329 330 switch (Type) 331 { 332 case Unbuffered: 333 case 2: 334 case 3: 335 336 ASSERT(Irp != NULL); 337 DataEntry = ExAllocatePoolWithQuotaTag(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, 338 sizeof(*DataEntry), 339 NPFS_DATA_ENTRY_TAG); 340 if (!DataEntry) 341 { 342 NpFreeClientSecurityContext(ClientContext); 343 return STATUS_INSUFFICIENT_RESOURCES; 344 } 345 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; 353 break; 354 355 case Buffered: 356 357 EntrySize = sizeof(*DataEntry); 358 if (Who != ReadEntries) 359 { 360 EntrySize += DataSize; 361 if (EntrySize < DataSize) 362 { 363 NpFreeClientSecurityContext(ClientContext); 364 return STATUS_INVALID_PARAMETER; 365 } 366 } 367 368 QuotaInEntry = DataSize - ByteOffset; 369 if (DataQueue->Quota - DataQueue->QuotaUsed < QuotaInEntry) 370 { 371 QuotaInEntry = DataQueue->Quota - DataQueue->QuotaUsed; 372 HasSpace = TRUE; 373 } 374 else 375 { 376 HasSpace = FALSE; 377 } 378 379 DataEntry = ExAllocatePoolWithQuotaTag(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, 380 EntrySize, 381 NPFS_DATA_ENTRY_TAG); 382 if (!DataEntry) 383 { 384 NpFreeClientSecurityContext(ClientContext); 385 return STATUS_INSUFFICIENT_RESOURCES; 386 } 387 388 DataEntry->QuotaInEntry = QuotaInEntry; 389 DataEntry->Irp = Irp; 390 DataEntry->DataEntryType = Buffered; 391 DataEntry->ClientSecurityContext = ClientContext; 392 DataEntry->DataSize = DataSize; 393 394 if (Who == ReadEntries) 395 { 396 ASSERT(Irp); 397 398 Status = STATUS_PENDING; 399 ASSERT((DataQueue->QueueState == Empty) || 400 (DataQueue->QueueState == Who)); 401 } 402 else 403 { 404 _SEH2_TRY 405 { 406 RtlCopyMemory(DataEntry + 1, 407 Irp ? Irp->UserBuffer: Buffer, 408 DataSize); 409 } 410 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 411 { 412 NpFreeClientSecurityContext(ClientContext); 413 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 414 } 415 _SEH2_END; 416 417 if (HasSpace && Irp) 418 { 419 Status = STATUS_PENDING; 420 } 421 else 422 { 423 DataEntry->Irp = NULL; 424 Status = STATUS_SUCCESS; 425 } 426 427 ASSERT((DataQueue->QueueState == Empty) || 428 (DataQueue->QueueState == Who)); 429 } 430 break; 431 432 default: 433 ASSERT(FALSE); 434 NpFreeClientSecurityContext(ClientContext); 435 return STATUS_INVALID_PARAMETER; 436 } 437 438 ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who)); 439 if (DataQueue->QueueState == Empty) 440 { 441 ASSERT(DataQueue->BytesInQueue == 0); 442 ASSERT(DataQueue->EntriesInQueue == 0); 443 ASSERT(IsListEmpty(&DataQueue->Queue)); 444 } 445 else 446 { 447 ASSERT(DataQueue->QueueState == Who); 448 ASSERT(DataQueue->QueueState != Empty); 449 ASSERT(DataQueue->EntriesInQueue != 0); 450 } 451 452 DataQueue->QuotaUsed += DataEntry->QuotaInEntry; 453 DataQueue->QueueState = Who; 454 DataQueue->BytesInQueue += DataEntry->DataSize; 455 DataQueue->EntriesInQueue++; 456 457 if (ByteOffset) 458 { 459 DataQueue->ByteOffset = ByteOffset; 460 ASSERT(Who == WriteEntries); 461 ASSERT(ByteOffset < DataEntry->DataSize); 462 ASSERT(DataQueue->EntriesInQueue == 1); 463 } 464 465 InsertTailList(&DataQueue->Queue, &DataEntry->QueueEntry); 466 467 if (Status == STATUS_PENDING) 468 { 469 IoMarkIrpPending(Irp); 470 Irp->Tail.Overlay.DriverContext[2] = DataQueue; 471 Irp->Tail.Overlay.DriverContext[3] = DataEntry; 472 473 IoSetCancelRoutine(Irp, NpCancelDataQueueIrp); 474 475 if ((Irp->Cancel) && (IoSetCancelRoutine(Irp, NULL))) 476 { 477 NpCancelDataQueueIrp(NULL, Irp); 478 } 479 } 480 481 return Status; 482 } 483 484 /* EOF */ 485