- Fix compile issues caused by previous patch.
[reactos.git] / reactos / ntoskrnl / io / irp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/irp.c
5 * PURPOSE: Handle IRPs
6 *
7 * PROGRAMMERS: Hartmut Birr
8 * Alex Ionescu (alex@relsoft.net)
9 * David Welch (welch@mcmail.com)
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* PRIVATE FUNCTIONS ********************************************************/
19
20 VOID
21 STDCALL
22 IopFreeIrpKernelApc(PKAPC Apc,
23 PKNORMAL_ROUTINE *NormalRoutine,
24 PVOID *NormalContext,
25 PVOID *SystemArgument1,
26 PVOID *SystemArgument2)
27 {
28 /* Free the IRP */
29 IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
30 }
31
32 VOID
33 STDCALL
34 IopAbortIrpKernelApc(PKAPC Apc)
35 {
36 /* Free the IRP */
37 IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
38 }
39
40 VOID
41 STDCALL
42 IopRemoveThreadIrp(VOID)
43 {
44 KIRQL OldIrql;
45 PIRP DeadIrp;
46 PETHREAD IrpThread;
47 PLIST_ENTRY IrpEntry;
48 PIO_ERROR_LOG_PACKET ErrorLogEntry;
49
50 /* First, raise to APC to protect IrpList */
51 KeRaiseIrql(APC_LEVEL, &OldIrql);
52
53 /* Get the Thread and check the list */
54 IrpThread = PsGetCurrentThread();
55 if (IsListEmpty(&IrpThread->IrpList))
56 {
57 /* It got completed now, so quit */
58 KeLowerIrql(OldIrql);
59 return;
60 }
61
62 /* Get the misbehaving IRP */
63 IrpEntry = IrpThread->IrpList.Flink;
64 DeadIrp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
65
66 /* Disown the IRP! */
67 DeadIrp->Tail.Overlay.Thread = NULL;
68 InitializeListHead(&DeadIrp->ThreadListEntry);
69 RemoveHeadList(&IrpThread->IrpList);
70
71 /* Lower IRQL now */
72 KeLowerIrql(OldIrql);
73
74 /* Check if we can send an Error Log Entry*/
75 if (DeadIrp->CurrentLocation <= DeadIrp->StackCount)
76 {
77 /* Allocate an entry */
78 ErrorLogEntry = IoAllocateErrorLogEntry(IoGetCurrentIrpStackLocation(DeadIrp)->DeviceObject,
79 sizeof(IO_ERROR_LOG_PACKET));
80
81 /* Write the entry */
82 ErrorLogEntry->ErrorCode = 0xBAADF00D; /* FIXME */
83 IoWriteErrorLogEntry(ErrorLogEntry);
84 }
85 }
86
87 VOID
88 STDCALL
89 IopCleanupIrp(PIRP Irp,
90 PFILE_OBJECT FileObject)
91 {
92 PMDL Mdl;
93
94 /* Check if there's an MDL */
95 while ((Mdl = Irp->MdlAddress))
96 {
97 /* Clear all of them */
98 Irp->MdlAddress = Mdl->Next;
99 IoFreeMdl(Mdl);
100 }
101
102 /* Free the buffer */
103 if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
104 {
105 ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
106 }
107
108 /* Derefernce the User Event */
109 if (Irp->UserEvent && !(Irp->Flags & IRP_SYNCHRONOUS_API) && FileObject)
110 {
111 ObDereferenceObject(Irp->UserEvent);
112 }
113
114 /* Dereference the File Object */
115 if (FileObject) ObDereferenceObject(FileObject);
116
117 /* Free the IRP */
118 IoFreeIrp(Irp);
119 }
120
121 /*
122 * FUNCTION: Performs the second stage of irp completion for read/write irps
123 *
124 * Called as a special kernel APC kernel-routine or directly from IofCompleteRequest()
125 *
126 * Note that we'll never see irp's flagged IRP_PAGING_IO (IRP_MOUNT_OPERATION)
127 * or IRP_CLOSE_OPERATION (IRP_MJ_CLOSE and IRP_MJ_CLEANUP) here since their
128 * cleanup/completion is fully taken care of in IoCompleteRequest.
129 * -Gunnar
130 */
131 VOID
132 STDCALL
133 IopCompleteRequest(PKAPC Apc,
134 PKNORMAL_ROUTINE* NormalRoutine,
135 PVOID* NormalContext,
136 PVOID* SystemArgument1,
137 PVOID* SystemArgument2)
138 {
139 PFILE_OBJECT FileObject;
140 PIRP Irp;
141 PMDL Mdl;
142 PKEVENT UserEvent;
143 BOOLEAN SyncIrp;
144
145 if (Apc) DPRINT("IoSecondStageCompletition with APC: 0x%p\n", Apc);
146
147 /* Get data from the APC */
148 FileObject = (PFILE_OBJECT)(*SystemArgument1);
149 Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc);
150 DPRINT("IoSecondStageCompletition, 0x%p\n", Irp);
151
152 /* Save the User Event */
153 UserEvent = Irp->UserEvent;
154
155 /* Remember if the IRP is Sync or not */
156 SyncIrp = Irp->Flags & IRP_SYNCHRONOUS_API ? TRUE : FALSE;
157
158 /* Handle Buffered case first */
159 if (Irp->Flags & IRP_BUFFERED_IO)
160 {
161 /* Check if we have an input buffer and if we suceeded */
162 if ((Irp->Flags & IRP_INPUT_OPERATION) &&
163 (Irp->IoStatus.Status != STATUS_VERIFY_REQUIRED) &&
164 !(NT_ERROR(Irp->IoStatus.Status)))
165 {
166 /* Copy the buffer back to the user */
167 RtlCopyMemory(Irp->UserBuffer,
168 Irp->AssociatedIrp.SystemBuffer,
169 Irp->IoStatus.Information);
170 }
171
172 /* Also check if we should de-allocate it */
173 if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
174 {
175 ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
176 }
177 }
178
179 /* Now we got rid of these two... */
180 Irp->Flags &= ~(IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
181
182 /* Check if there's an MDL */
183 while ((Mdl = Irp->MdlAddress))
184 {
185 /* Clear all of them */
186 Irp->MdlAddress = Mdl->Next;
187 IoFreeMdl(Mdl);
188 }
189
190 /* Remove the IRP from the list of Thread Pending IRPs */
191 RemoveEntryList(&Irp->ThreadListEntry);
192 InitializeListHead(&Irp->ThreadListEntry);
193
194 #if 1
195 /* Check for Success but allow failure for Async IRPs */
196 if (!(NT_ERROR(Irp->IoStatus.Status)) ||
197 ((NT_ERROR(Irp->IoStatus.Status)) &&
198 (Irp->PendingReturned) && !(SyncIrp) &&
199 ((FileObject == NULL) || (FileObject->Flags & FO_SYNCHRONOUS_IO))))
200 {
201 _SEH_TRY
202 {
203 /* Save the IOSB Information */
204 *Irp->UserIosb = Irp->IoStatus;
205 }
206 _SEH_HANDLE
207 {
208 /* Ignore any error */
209 }
210 _SEH_END;
211
212 /* Check if there's an event */
213 if (UserEvent)
214 {
215 /* Check if we should signal the File Object Event as well */
216 if (FileObject)
217 {
218 /* If the File Object is SYNC, then we need to signal its event too */
219 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
220 {
221 /* Set the Status */
222 FileObject->FinalStatus = Irp->IoStatus.Status;
223
224 /* Signal Event */
225 KeSetEvent(&FileObject->Event, 0, FALSE);
226 }
227 }
228 /* Signal the Event */
229 KeSetEvent(UserEvent, 0, FALSE);
230
231 /* Dereference the Event if this is an ASYNC IRP */
232 if (FileObject && !SyncIrp && UserEvent != &FileObject->Event)
233 {
234 ObDereferenceObject(UserEvent);
235 }
236 }
237 else if (FileObject)
238 {
239 /* Set the Status */
240 FileObject->FinalStatus = Irp->IoStatus.Status;
241
242 /* Signal the File Object Instead */
243 KeSetEvent(&FileObject->Event, 0, FALSE);
244
245 }
246
247 /* Now call the User APC if one was requested */
248 if (Irp->Overlay.AsynchronousParameters.UserApcRoutine != NULL)
249 {
250 KeInitializeApc(&Irp->Tail.Apc,
251 KeGetCurrentThread(),
252 CurrentApcEnvironment,
253 IopFreeIrpKernelApc,
254 IopAbortIrpKernelApc,
255 (PKNORMAL_ROUTINE)Irp->Overlay.AsynchronousParameters.UserApcRoutine,
256 Irp->RequestorMode,
257 Irp->Overlay.AsynchronousParameters.UserApcContext);
258
259 KeInsertQueueApc(&Irp->Tail.Apc,
260 Irp->UserIosb,
261 NULL,
262 2);
263 Irp = NULL;
264 }
265 else if (FileObject && FileObject->CompletionContext)
266 {
267 /* Call the IO Completion Port if we have one, instead */
268 Irp->Tail.CompletionKey = FileObject->CompletionContext->Key;
269 Irp->Tail.Overlay.PacketType = IrpCompletionPacket;
270 KeInsertQueue(FileObject->CompletionContext->Port,
271 &Irp->Tail.Overlay.ListEntry);
272 Irp = NULL;
273 }
274 }
275 else
276 {
277 /* Signal the Events only if PendingReturned and we have a File Object */
278 if (FileObject && Irp->PendingReturned)
279 {
280 /* Check for SYNC IRP */
281 if (SyncIrp)
282 {
283 /* Set the status in this case only */
284 _SEH_TRY
285 {
286 *Irp->UserIosb = Irp->IoStatus;
287 }
288 _SEH_HANDLE
289 {
290 /* Ignore any error */
291 }
292 _SEH_END;
293
294 /* Signal our event if we have one */
295 if (UserEvent)
296 {
297 KeSetEvent(UserEvent, 0, FALSE);
298 }
299 else
300 {
301 /* Signal the File's Event instead */
302 KeSetEvent(&FileObject->Event, 0, FALSE);
303 }
304 }
305 else
306 {
307 #if 1
308 /* FIXME: This is necessary to fix bug #609 */
309 _SEH_TRY
310 {
311 *Irp->UserIosb = Irp->IoStatus;
312 }
313 _SEH_HANDLE
314 {
315 /* Ignore any error */
316 }
317 _SEH_END;
318 #endif
319 /* We'll report the Status to the File Object, not the IRP */
320 FileObject->FinalStatus = Irp->IoStatus.Status;
321
322 /* Signal the File Object ONLY if this was Async */
323 KeSetEvent(&FileObject->Event, 0, FALSE);
324 }
325 }
326
327 /* Dereference the Event if it's an ASYNC IRP on a File Object */
328 if (UserEvent && !SyncIrp && FileObject)
329 {
330 if (UserEvent != &FileObject->Event)
331 {
332 ObDereferenceObject(UserEvent);
333 }
334 }
335 }
336
337 /* Dereference the File Object */
338 if (FileObject) ObDereferenceObject(FileObject);
339
340 /* Free the IRP */
341 if (Irp) IoFreeIrp(Irp);
342
343 #else
344
345 if (NT_SUCCESS(Irp->IoStatus.Status) || Irp->PendingReturned)
346 {
347 _SEH_TRY
348 {
349 /* Save the IOSB Information */
350 *Irp->UserIosb = Irp->IoStatus;
351 }
352 _SEH_HANDLE
353 {
354 /* Ignore any error */
355 }
356 _SEH_END;
357
358 if (FileObject)
359 {
360 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
361 {
362 /* Set the Status */
363 FileObject->FinalStatus = Irp->IoStatus.Status;
364
365 /* FIXME: Remove this check when I/O code is fixed */
366 if (UserEvent != &FileObject->Event)
367 {
368 /* Signal Event */
369 KeSetEvent(&FileObject->Event, 0, FALSE);
370 }
371 }
372 }
373
374 /* Signal the user event, if one exist */
375 if (UserEvent)
376 {
377 KeSetEvent(UserEvent, 0, FALSE);
378 }
379
380 /* Now call the User APC if one was requested */
381 if (Irp->Overlay.AsynchronousParameters.UserApcRoutine)
382 {
383 KeInitializeApc(&Irp->Tail.Apc,
384 KeGetCurrentThread(),
385 CurrentApcEnvironment,
386 IopFreeIrpKernelApc,
387 IopAbortIrpKernelApc,
388 (PKNORMAL_ROUTINE)Irp->Overlay.AsynchronousParameters.UserApcRoutine,
389 Irp->RequestorMode,
390 Irp->Overlay.AsynchronousParameters.UserApcContext);
391
392 KeInsertQueueApc(&Irp->Tail.Apc,
393 Irp->UserIosb,
394 NULL,
395 2);
396 Irp = NULL;
397 }
398 else if (FileObject && FileObject->CompletionContext)
399 {
400 /* Call the IO Completion Port if we have one, instead */
401 IoSetIoCompletion(FileObject->CompletionContext->Port,
402 FileObject->CompletionContext->Key,
403 Irp->Overlay.AsynchronousParameters.UserApcContext,
404 Irp->IoStatus.Status,
405 Irp->IoStatus.Information,
406 FALSE);
407 Irp = NULL;
408 }
409 }
410
411 /* Free the Irp if it hasn't already */
412 if (Irp) IoFreeIrp(Irp);
413
414 if (FileObject)
415 {
416 /* Dereference the user event, if it is an event object */
417 /* FIXME: Remove last check when I/O code is fixed */
418 if (UserEvent && !SyncIrp && UserEvent != &FileObject->Event)
419 {
420 ObDereferenceObject(UserEvent);
421 }
422
423 /* Dereference the File Object */
424 ObDereferenceObject(FileObject);
425 }
426 #endif
427 }
428
429 /* FUNCTIONS *****************************************************************/
430
431 /*
432 * @implemented
433 *
434 * FUNCTION: Allocates an IRP
435 * ARGUMENTS:
436 * StackSize = the size of the stack required for the irp
437 * ChargeQuota = Charge allocation to current threads quota
438 * RETURNS: Irp allocated
439 */
440 PIRP
441 STDCALL
442 IoAllocateIrp(CCHAR StackSize,
443 BOOLEAN ChargeQuota)
444 {
445 PIRP Irp = NULL;
446 USHORT Size = IoSizeOfIrp(StackSize);
447 PKPRCB Prcb;
448 UCHAR Flags = 0;
449 PNPAGED_LOOKASIDE_LIST List = NULL;
450 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
451
452 /* Figure out which Lookaside List to use */
453 if ((StackSize <= 8) && (ChargeQuota == FALSE))
454 {
455 DPRINT("Using lookaside, %d\n", StackSize);
456 /* Set Fixed Size Flag */
457 Flags = IRP_ALLOCATED_FIXED_SIZE;
458
459 /* See if we should use big list */
460 if (StackSize != 1)
461 {
462 DPRINT("Using large lookaside\n");
463 Size = IoSizeOfIrp(8);
464 ListType = LookasideLargeIrpList;
465 }
466
467 /* Get the PRCB */
468 Prcb = KeGetCurrentPrcb();
469
470 /* Get the P List First */
471 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
472
473 /* Attempt allocation */
474 List->L.TotalAllocates++;
475 DPRINT("Total allocates: %d\n", List->L.TotalAllocates);
476 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
477 DPRINT("Alloc attempt on CPU list: %p\n", Irp);
478
479 /* Check if the P List failed */
480 if (!Irp)
481 {
482 /* Let the balancer know */
483 List->L.AllocateMisses++;
484 DPRINT("Total misses: %d\n", List->L.AllocateMisses);
485
486 /* Try the L List */
487 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
488 List->L.TotalAllocates++;
489 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
490 DPRINT("Alloc attempt on SYS list: %p\n", Irp);
491 }
492 }
493
494 /* Check if we have to use the pool */
495 if (!Irp)
496 {
497 DPRINT("Using pool\n");
498 /* Did we try lookaside and fail? */
499 if (Flags & IRP_ALLOCATED_FIXED_SIZE) List->L.AllocateMisses++;
500
501 /* Check if we shoudl charge quota */
502 if (ChargeQuota)
503 {
504 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
505 /* FIXME */
506 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
507 }
508 else
509 {
510 /* Allocate the IRP With no Quota charge */
511 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
512 }
513
514 /* Make sure it was sucessful */
515 if (!Irp) return(NULL);
516 }
517 else
518 {
519 /* We have an IRP from Lookaside */
520 Flags |= IRP_LOOKASIDE_ALLOCATION;
521 }
522
523 /* Set Flag */
524 if (ChargeQuota) Flags |= IRP_QUOTA_CHARGED;
525
526 /* Now Initialize it */
527 DPRINT("irp allocated\n");
528 IoInitializeIrp(Irp, Size, StackSize);
529
530 /* Set the Allocation Flags */
531 Irp->AllocationFlags = Flags;
532
533 /* Return it */
534 return Irp;
535 }
536
537 /*
538 * @implemented
539 *
540 * FUNCTION: Allocates and sets up an IRP to be sent to lower level drivers
541 * ARGUMENTS:
542 * MajorFunction = One of IRP_MJ_READ, IRP_MJ_WRITE,
543 * IRP_MJ_FLUSH_BUFFERS or IRP_MJ_SHUTDOWN
544 * DeviceObject = Device object to send the irp to
545 * Buffer = Buffer into which data will be read or written
546 * Length = Length in bytes of the irp to be allocated
547 * StartingOffset = Starting offset on the device
548 * IoStatusBlock (OUT) = Storage for the result of the operation
549 * RETURNS: The IRP allocated on success, or
550 * NULL on failure
551 */
552 PIRP
553 STDCALL
554 IoBuildAsynchronousFsdRequest(ULONG MajorFunction,
555 PDEVICE_OBJECT DeviceObject,
556 PVOID Buffer,
557 ULONG Length,
558 PLARGE_INTEGER StartingOffset,
559 PIO_STATUS_BLOCK IoStatusBlock)
560 {
561 PIRP Irp;
562 PIO_STACK_LOCATION StackPtr;
563 LOCK_OPERATION AccessType;
564
565 DPRINT("IoBuildAsynchronousFsdRequest(MajorFunction %x, DeviceObject 0x%p, "
566 "Buffer 0x%p, Length %x, StartingOffset 0x%p, "
567 "IoStatusBlock 0x%p\n",MajorFunction,DeviceObject,Buffer,Length,
568 StartingOffset,IoStatusBlock);
569
570 /* Allocate IRP */
571 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE))) return Irp;
572
573 /* Get the Stack */
574 StackPtr = IoGetNextIrpStackLocation(Irp);
575
576 /* Write the Major function and then deal with it */
577 StackPtr->MajorFunction = (UCHAR)MajorFunction;
578
579 /* Do not handle the following here */
580 if (MajorFunction != IRP_MJ_FLUSH_BUFFERS &&
581 MajorFunction != IRP_MJ_SHUTDOWN &&
582 MajorFunction != IRP_MJ_PNP)
583 {
584 /* Check if this is Buffered IO */
585 if (DeviceObject->Flags & DO_BUFFERED_IO)
586 {
587 /* Allocate the System Buffer */
588 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
589 Length,
590 TAG_SYS_BUF);
591
592 /* Set flags */
593 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
594
595 /* Handle special IRP_MJ_WRITE Case */
596 if (MajorFunction == IRP_MJ_WRITE)
597 {
598 /* Copy the buffer data */
599 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
600 }
601 else
602 {
603 /* Set the Input Operation flag and set this as a User Buffer */
604 Irp->Flags |= IRP_INPUT_OPERATION;
605 Irp->UserBuffer = Buffer;
606 }
607 }
608 else if (DeviceObject->Flags & DO_DIRECT_IO)
609 {
610 /* Use an MDL for Direct I/O */
611 Irp->MdlAddress = MmCreateMdl(NULL, Buffer, Length);
612
613
614 if (MajorFunction == IRP_MJ_READ)
615 {
616 AccessType = IoWriteAccess;
617 }
618 else
619 {
620 AccessType = IoReadAccess;
621 }
622
623 /* Probe and Lock */
624 _SEH_TRY
625 {
626 /* Do the probe */
627 MmProbeAndLockPages(Irp->MdlAddress, KernelMode, AccessType);
628 }
629 _SEH_HANDLE
630 {
631 /* Free the IRP and its MDL */
632 IoFreeMdl(Irp->MdlAddress);
633 IoFreeIrp(Irp);
634 /* FIXME - pass the exception to the caller? */
635 Irp = NULL;
636 }
637 _SEH_END;
638
639 if (!Irp)
640 return NULL;
641 }
642 else
643 {
644 /* Neither, use the buffer */
645 Irp->UserBuffer = Buffer;
646 }
647
648 if (MajorFunction == IRP_MJ_READ)
649 {
650 StackPtr->Parameters.Read.Length = Length;
651 StackPtr->Parameters.Read.ByteOffset = *StartingOffset;
652 }
653 else if (MajorFunction == IRP_MJ_WRITE)
654 {
655 StackPtr->Parameters.Write.Length = Length;
656 StackPtr->Parameters.Write.ByteOffset = *StartingOffset;
657 }
658 }
659
660 /* Set the Current Thread and IOSB */
661 if (!IoStatusBlock) KEBUGCHECK(0); /* Temporary to catch illegal ROS Drivers */
662 Irp->UserIosb = IoStatusBlock;
663 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
664
665 /* Set the Status Block after all is done */
666 return Irp;
667 }
668
669
670 /*
671 * @implemented
672 *
673 * FUNCTION: Allocates and sets up an IRP to be sent to drivers
674 * ARGUMENTS:
675 * IoControlCode = Device io control code
676 * DeviceObject = Device object to send the irp to
677 * InputBuffer = Buffer from which data will be read by the driver
678 * InputBufferLength = Length in bytes of the input buffer
679 * OutputBuffer = Buffer into which data will be written by the driver
680 * OutputBufferLength = Length in bytes of the output buffer
681 * InternalDeviceIoControl = Determines weather
682 * IRP_MJ_INTERNAL_DEVICE_CONTROL or
683 * IRP_MJ_DEVICE_CONTROL will be used
684 * Event = Event used to notify the caller of completion
685 * IoStatusBlock (OUT) = Storage for the result of the operation
686 * RETURNS: The IRP allocated on success, or
687 * NULL on failure
688 */
689 PIRP
690 STDCALL
691 IoBuildDeviceIoControlRequest (ULONG IoControlCode,
692 PDEVICE_OBJECT DeviceObject,
693 PVOID InputBuffer,
694 ULONG InputBufferLength,
695 PVOID OutputBuffer,
696 ULONG OutputBufferLength,
697 BOOLEAN InternalDeviceIoControl,
698 PKEVENT Event,
699 PIO_STATUS_BLOCK IoStatusBlock)
700 {
701 PIRP Irp;
702 PIO_STACK_LOCATION StackPtr;
703 ULONG BufferLength;
704 LOCK_OPERATION AccessType;
705
706 DPRINT("IoBuildDeviceIoRequest(IoControlCode %x, DeviceObject 0x%p, "
707 "InputBuffer 0x%p, InputBufferLength %x, OutputBuffer 0x%p, "
708 "OutputBufferLength %x, InternalDeviceIoControl %x "
709 "Event 0x%p, IoStatusBlock 0x%p\n",IoControlCode,DeviceObject,
710 InputBuffer,InputBufferLength,OutputBuffer,OutputBufferLength,
711 InternalDeviceIoControl,Event,IoStatusBlock);
712
713 /* Allocate IRP */
714 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE))) return Irp;
715
716 /* Get the Stack */
717 StackPtr = IoGetNextIrpStackLocation(Irp);
718
719 /* Set the DevCtl Type */
720 StackPtr->MajorFunction = InternalDeviceIoControl ?
721 IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL;
722
723 /* Set the IOCTL Data */
724 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
725 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
726 StackPtr->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
727
728 /* Handle the Methods */
729 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
730 {
731 case METHOD_BUFFERED:
732 DPRINT("Using METHOD_BUFFERED!\n");
733
734 /* Select the right Buffer Length */
735 BufferLength = InputBufferLength > OutputBufferLength ? InputBufferLength : OutputBufferLength;
736
737 /* Make sure there is one */
738 if (BufferLength)
739 {
740 /* Allocate the System Buffer */
741 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
742 BufferLength,
743 TAG_SYS_BUF);
744
745 /* Fail if we couldn't */
746 if (Irp->AssociatedIrp.SystemBuffer == NULL)
747 {
748 IoFreeIrp(Irp);
749 return(NULL);
750 }
751
752 /* Check if we got a buffer */
753 if (InputBuffer)
754 {
755 /* Copy into the System Buffer */
756 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
757 InputBuffer,
758 InputBufferLength);
759 }
760
761 /* Write the flags */
762 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
763 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
764
765 /* Save the Buffer */
766 Irp->UserBuffer = OutputBuffer;
767 }
768 else
769 {
770 /* Clear the Flags and Buffer */
771 Irp->Flags = 0;
772 Irp->UserBuffer = NULL;
773 }
774 break;
775
776 case METHOD_IN_DIRECT:
777 case METHOD_OUT_DIRECT:
778 DPRINT("Using METHOD_IN/OUT DIRECT!\n");
779
780 /* Check if we got an input buffer */
781 if (InputBuffer)
782 {
783 /* Allocate the System Buffer */
784 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
785 InputBufferLength,
786 TAG_SYS_BUF);
787
788 /* Fail if we couldn't */
789 if (Irp->AssociatedIrp.SystemBuffer == NULL)
790 {
791 IoFreeIrp(Irp);
792 return(NULL);
793 }
794
795 /* Copy into the System Buffer */
796 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
797 InputBuffer,
798 InputBufferLength);
799
800 /* Write the flags */
801 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
802 }
803 else
804 {
805 Irp->Flags = 0;
806 }
807
808 /* Check if we got an output buffer */
809 if (OutputBuffer)
810 {
811 /* Allocate the System Buffer */
812 Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
813 OutputBufferLength,
814 FALSE,
815 FALSE,
816 Irp);
817
818 /* Fail if we couldn't */
819 if (Irp->MdlAddress == NULL)
820 {
821 IoFreeIrp(Irp);
822 return NULL;
823 }
824
825 /* Probe and Lock */
826 _SEH_TRY
827 {
828 /* Use the right Access Type */
829 if (IO_METHOD_FROM_CTL_CODE(IoControlCode) == METHOD_IN_DIRECT)
830 {
831 AccessType = IoReadAccess;
832 }
833 else
834 {
835 AccessType = IoWriteAccess;
836 }
837
838 /* Do the probe */
839 MmProbeAndLockPages(Irp->MdlAddress, KernelMode, AccessType);
840 }
841 _SEH_HANDLE
842 {
843 /* Free the MDL and IRP */
844 IoFreeMdl(Irp->MdlAddress);
845 IoFreeIrp(Irp);
846 /* FIXME - pass the exception to the caller? */
847 Irp = NULL;
848 }
849 _SEH_END;
850
851 if (!Irp)
852 return NULL;
853 }
854 break;
855
856 case METHOD_NEITHER:
857
858 /* Just save the Buffer */
859 Irp->UserBuffer = OutputBuffer;
860 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
861 break;
862 }
863
864 /* Now write the Event and IoSB */
865 if (!IoStatusBlock) KEBUGCHECK(0); /* Temporary to catch illegal ROS Drivers */
866 Irp->UserIosb = IoStatusBlock;
867 Irp->UserEvent = Event;
868
869 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
870 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
871 IoQueueThreadIrp(Irp);
872
873 /* Return the IRP */
874 return Irp;
875 }
876
877 /*
878 * @implemented
879 *
880 * FUNCTION: Allocates and builds an IRP to be sent synchronously to lower
881 * level driver(s)
882 * ARGUMENTS:
883 * MajorFunction = Major function code, one of IRP_MJ_READ,
884 * IRP_MJ_WRITE, IRP_MJ_FLUSH_BUFFERS, IRP_MJ_SHUTDOWN
885 * DeviceObject = Target device object
886 * Buffer = Buffer containing data for a read or write
887 * Length = Length in bytes of the information to be transferred
888 * StartingOffset = Offset to begin the read/write from
889 * Event (OUT) = Will be set when the operation is complete
890 * IoStatusBlock (OUT) = Set to the status of the operation
891 * RETURNS: The IRP allocated on success, or
892 * NULL on failure
893 */
894 PIRP
895 STDCALL
896 IoBuildSynchronousFsdRequest(ULONG MajorFunction,
897 PDEVICE_OBJECT DeviceObject,
898 PVOID Buffer,
899 ULONG Length,
900 PLARGE_INTEGER StartingOffset,
901 PKEVENT Event,
902 PIO_STATUS_BLOCK IoStatusBlock)
903 {
904 PIRP Irp;
905
906 DPRINT("IoBuildSynchronousFsdRequest(MajorFunction %x, DeviceObject 0x%p, "
907 "Buffer 0x%p, Length %x, StartingOffset 0x%p, Event 0x%p, "
908 "IoStatusBlock 0x%p\n",MajorFunction,DeviceObject,Buffer,Length,
909 StartingOffset,Event,IoStatusBlock);
910
911 /* Do the big work to set up the IRP */
912 Irp = IoBuildAsynchronousFsdRequest(MajorFunction,
913 DeviceObject,
914 Buffer,
915 Length,
916 StartingOffset,
917 IoStatusBlock );
918
919 /* Set the Event which makes it Syncronous */
920 Irp->UserEvent = Event;
921
922 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
923 IoQueueThreadIrp(Irp);
924 return(Irp);
925 }
926
927 /*
928 * @implemented
929 */
930 BOOLEAN
931 STDCALL
932 IoCancelIrp(PIRP Irp)
933 {
934 KIRQL oldlvl;
935 PDRIVER_CANCEL CancelRoutine;
936
937 DPRINT("IoCancelIrp(Irp 0x%p)\n",Irp);
938
939 IoAcquireCancelSpinLock(&oldlvl);
940
941 Irp->Cancel = TRUE;
942
943 CancelRoutine = IoSetCancelRoutine(Irp, NULL);
944 if (CancelRoutine == NULL)
945 {
946 IoReleaseCancelSpinLock(oldlvl);
947 return(FALSE);
948 }
949
950 Irp->CancelIrql = oldlvl;
951 CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp);
952 return(TRUE);
953 }
954
955 /**
956 * @name IoCancelThreadIo
957 *
958 * Cancel all pending I/O request associated with specified thread.
959 *
960 * @param Thread
961 * Thread to cancel requests for.
962 */
963 VOID
964 STDCALL
965 IoCancelThreadIo(PETHREAD Thread)
966 {
967 PIRP Irp;
968 KIRQL OldIrql;
969 ULONG Retries = 3000;
970 LARGE_INTEGER Interval;
971
972 /* Raise to APC to protect the IrpList */
973 OldIrql = KfRaiseIrql(APC_LEVEL);
974
975 /* Start by cancelling all the IRPs in the current thread queue. */
976 LIST_FOR_EACH(Irp, &Thread->IrpList, IRP, ThreadListEntry)
977 {
978 /* Cancel it */
979 IoCancelIrp(Irp);
980 }
981
982 /* Wait 100 milliseconds */
983 Interval.QuadPart = -1000000;
984
985 /* Wait till all the IRPs are completed or cancelled. */
986 while (!IsListEmpty(&Thread->IrpList))
987 {
988 /* Now we can lower */
989 KfLowerIrql(OldIrql);
990
991 /* Wait a short while and then look if all our IRPs were completed. */
992 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
993
994 /*
995 * Don't stay here forever if some broken driver doesn't complete
996 * the IRP.
997 */
998 if (Retries-- == 0) IopRemoveThreadIrp();
999
1000 /* Raise the IRQL Again */
1001 OldIrql = KfRaiseIrql(APC_LEVEL);
1002 }
1003
1004 /* We're done, lower the IRQL */
1005 KfLowerIrql(OldIrql);
1006 }
1007
1008 #ifdef IoCallDriver
1009 #undef IoCallDriver
1010 #endif
1011 /*
1012 * @implemented
1013 */
1014 NTSTATUS
1015 STDCALL
1016 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
1017 {
1018 /* Call fast call */
1019 return IofCallDriver(DeviceObject, Irp);
1020 }
1021
1022 /*
1023 * @implemented
1024 */
1025 #undef IoCompleteRequest
1026 VOID
1027 STDCALL
1028 IoCompleteRequest(PIRP Irp,
1029 CCHAR PriorityBoost)
1030 {
1031 /* Call the fastcall */
1032 IofCompleteRequest(Irp, PriorityBoost);
1033 }
1034
1035 /*
1036 * @implemented
1037 */
1038 VOID
1039 STDCALL
1040 IoEnqueueIrp(IN PIRP Irp)
1041 {
1042 IoQueueThreadIrp(Irp);
1043 }
1044
1045 /*
1046 * @implemented
1047 *
1048 * FUNCTION: Sends an IRP to the next lower driver
1049 */
1050 NTSTATUS
1051 FASTCALL
1052 IofCallDriver(PDEVICE_OBJECT DeviceObject,
1053 PIRP Irp)
1054
1055 {
1056 PDRIVER_OBJECT DriverObject;
1057 PIO_STACK_LOCATION Param;
1058
1059 DPRINT("IofCallDriver(DeviceObject 0x%p, Irp 0x%p)\n",DeviceObject,Irp);
1060
1061 /* Get the Driver Object */
1062 DriverObject = DeviceObject->DriverObject;
1063
1064 /* Set the Stack Location */
1065 IoSetNextIrpStackLocation(Irp);
1066
1067 /* Get the current one */
1068 Param = IoGetCurrentIrpStackLocation(Irp);
1069
1070 DPRINT("IrpSp 0x0x%p\n", Param);
1071
1072 /* Get the Device Object */
1073 Param->DeviceObject = DeviceObject;
1074
1075 /* Call it */
1076 return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject, Irp);
1077 }
1078
1079 #ifdef IoCompleteRequest
1080 #undef IoCompleteRequest
1081 #endif
1082 /*
1083 * @implemented
1084 *
1085 * FUNCTION: Indicates the caller has finished all processing for a given
1086 * I/O request and is returning the given IRP to the I/O manager
1087 * ARGUMENTS:
1088 * Irp = Irp to be cancelled
1089 * PriorityBoost = Increment by which to boost the priority of the
1090 * thread making the request
1091 */
1092 VOID
1093 FASTCALL
1094 IofCompleteRequest(PIRP Irp,
1095 CCHAR PriorityBoost)
1096 {
1097 PIO_STACK_LOCATION StackPtr;
1098 PDEVICE_OBJECT DeviceObject;
1099 PFILE_OBJECT FileObject = Irp->Tail.Overlay.OriginalFileObject;
1100 PETHREAD Thread = Irp->Tail.Overlay.Thread;
1101 NTSTATUS Status;
1102 PMDL Mdl;
1103
1104 DPRINT("IofCompleteRequest(Irp 0x%p, PriorityBoost %d) Event 0x%p THread 0x%p\n",
1105 Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
1106
1107 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
1108 ASSERT(!Irp->CancelRoutine);
1109 ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
1110
1111 /* Get the Current Stack */
1112 StackPtr = IoGetCurrentIrpStackLocation(Irp);
1113 IoSkipCurrentIrpStackLocation(Irp);
1114
1115 /* Loop the Stacks and complete the IRPs */
1116 for (;Irp->CurrentLocation <= (Irp->StackCount + 1); StackPtr++)
1117 {
1118 /* Set Pending Returned */
1119 Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED;
1120
1121 /*
1122 * Completion routines expect the current irp stack location to be the same as when
1123 * IoSetCompletionRoutine was called to set them. A side effect is that completion
1124 * routines set by highest level drivers without their own stack location will receive
1125 * an invalid current stack location (at least it should be considered as invalid).
1126 * Since the DeviceObject argument passed is taken from the current stack, this value
1127 * is also invalid (NULL).
1128 */
1129 if (Irp->CurrentLocation == (Irp->StackCount + 1))
1130 {
1131 DeviceObject = NULL;
1132 }
1133 else
1134 {
1135 DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
1136 }
1137
1138 /* Check if there is a Completion Routine to Call */
1139 if ((NT_SUCCESS(Irp->IoStatus.Status) &&
1140 (StackPtr->Control & SL_INVOKE_ON_SUCCESS)) ||
1141 (!NT_SUCCESS(Irp->IoStatus.Status) &&
1142 (StackPtr->Control & SL_INVOKE_ON_ERROR)) ||
1143 (Irp->Cancel && (StackPtr->Control & SL_INVOKE_ON_CANCEL)))
1144 {
1145 /* Call it */
1146 Status = StackPtr->CompletionRoutine(DeviceObject,
1147 Irp,
1148 StackPtr->Context);
1149
1150 /* Don't touch the Packet if this was returned. It might be gone! */
1151 if (Status == STATUS_MORE_PROCESSING_REQUIRED) return;
1152 }
1153 else
1154 {
1155 if ((Irp->CurrentLocation <= Irp->StackCount) && (Irp->PendingReturned))
1156 {
1157 IoMarkIrpPending(Irp);
1158 }
1159 }
1160
1161 /* Move to next stack */
1162 IoSkipCurrentIrpStackLocation(Irp);
1163 }
1164
1165 /* Windows NT File System Internals, page 165 */
1166 if (Irp->Flags & IRP_ASSOCIATED_IRP)
1167 {
1168 ULONG MasterIrpCount;
1169 PIRP MasterIrp = Irp->AssociatedIrp.MasterIrp;
1170
1171 DPRINT("Handling Associated IRP\n");
1172 /* This should never happen! */
1173 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1174
1175 /* Decrement and get the old count */
1176 MasterIrpCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);
1177
1178 /* Free MDLs and IRP */
1179 while ((Mdl = Irp->MdlAddress))
1180 {
1181 Irp->MdlAddress = Mdl->Next;
1182 IoFreeMdl(Mdl);
1183 }
1184 IoFreeIrp(Irp);
1185
1186 /* Complete the Master IRP */
1187 if (!MasterIrpCount) IofCompleteRequest(MasterIrp, PriorityBoost);
1188 return;
1189 }
1190
1191 /* Windows NT File System Internals, page 165 */
1192 if (Irp->Flags & (IRP_PAGING_IO|IRP_CLOSE_OPERATION))
1193 {
1194 DPRINT("Handling Paging or Close I/O\n");
1195 /* This should never happen! */
1196 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1197
1198 /* Handle a Close Operation or Sync Paging I/O (see page 165) */
1199 if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION))
1200 {
1201 /* Set the I/O Status and Signal the Event */
1202 DPRINT("Handling Sync Paging or Close I/O\n");
1203 *Irp->UserIosb = Irp->IoStatus;
1204 KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);
1205
1206 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1207 if (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO)
1208 {
1209 DPRINT("Handling Sync Paging I/O\n");
1210 IoFreeIrp(Irp);
1211 }
1212 }
1213 else
1214 {
1215 #if 0
1216 /* Page 166 */
1217 KeInitializeApc(&Irp->Tail.Apc
1218 &Irp->Tail.Overlay.Thread->Tcb,
1219 Irp->ApcEnvironment,
1220 IopCompletePageWrite,
1221 NULL,
1222 NULL,
1223 KernelMode,
1224 NULL);
1225 KeInsertQueueApc(&Irp->Tail.Apc,
1226 NULL,
1227 NULL,
1228 PriorityBoost);
1229 #else
1230 /* Not implemented yet. */
1231 ASSERT(FALSE);
1232 #endif
1233 }
1234 return;
1235 }
1236
1237 /* Unlock MDL Pages, page 167. */
1238 Mdl = Irp->MdlAddress;
1239 while (Mdl)
1240 {
1241 DPRINT("Unlocking MDL: 0x%p\n", Mdl);
1242 MmUnlockPages(Mdl);
1243 Mdl = Mdl->Next;
1244 }
1245
1246 /* Check if we should exit because of a Deferred I/O (page 168) */
1247 if (Irp->Flags & IRP_DEFER_IO_COMPLETION && !Irp->PendingReturned)
1248 {
1249 DPRINT("Quick return\n");
1250 return;
1251 }
1252
1253 /* Now queue the special APC */
1254 if (!Irp->Cancel)
1255 {
1256 DPRINT("KMODE APC QUEUE\n");
1257 KeInitializeApc(&Irp->Tail.Apc,
1258 &Thread->Tcb,
1259 Irp->ApcEnvironment,
1260 IopCompleteRequest,
1261 NULL,
1262 (PKNORMAL_ROUTINE) NULL,
1263 KernelMode,
1264 NULL);
1265 KeInsertQueueApc(&Irp->Tail.Apc,
1266 FileObject,
1267 NULL, /* This is used for REPARSE stuff */
1268 PriorityBoost);
1269 }
1270 else
1271 {
1272 /* The IRP just got cancelled... does a thread still own it? */
1273 if ((Thread = Irp->Tail.Overlay.Thread))
1274 {
1275 /* Yes! There is still hope! */
1276 DPRINT("KMODE APC QUEUE\n");
1277 KeInitializeApc(&Irp->Tail.Apc,
1278 &Thread->Tcb,
1279 Irp->ApcEnvironment,
1280 IopCompleteRequest,
1281 NULL,
1282 (PKNORMAL_ROUTINE) NULL,
1283 KernelMode,
1284 NULL);
1285 KeInsertQueueApc(&Irp->Tail.Apc,
1286 FileObject,
1287 NULL, /* This is used for REPARSE stuff */
1288 PriorityBoost);
1289 }
1290 else
1291 {
1292 /* Nothing left for us to do, kill it */
1293 IopCleanupIrp(Irp, FileObject);
1294 }
1295 }
1296 }
1297
1298 /*
1299 * @unimplemented
1300 */
1301 BOOLEAN
1302 STDCALL
1303 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject,
1304 IN PIRP Irp)
1305 {
1306 UNIMPLEMENTED;
1307 return FALSE;
1308 }
1309
1310 /*
1311 * @implemented
1312 *
1313 * FUNCTION: Releases a caller allocated irp
1314 * ARGUMENTS:
1315 * Irp = Irp to free
1316 */
1317 VOID
1318 STDCALL
1319 IoFreeIrp(PIRP Irp)
1320 {
1321 PNPAGED_LOOKASIDE_LIST List;
1322 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
1323 PKPRCB Prcb;
1324
1325 /* If this was a pool alloc, free it with the pool */
1326 if (!(Irp->AllocationFlags & IRP_ALLOCATED_FIXED_SIZE))
1327 {
1328 /* Free it */
1329 DPRINT("Freeing pool IRP\n");
1330 ExFreePool(Irp);
1331 }
1332 else
1333 {
1334 DPRINT("Freeing Lookaside IRP\n");
1335
1336 /* Check if this was a Big IRP */
1337 if (Irp->StackCount != 1)
1338 {
1339 DPRINT("Large IRP\n");
1340 ListType = LookasideLargeIrpList;
1341 }
1342
1343 /* Get the PRCB */
1344 Prcb = KeGetCurrentPrcb();
1345
1346 /* Use the P List */
1347 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
1348 List->L.TotalFrees++;
1349
1350 /* Check if the Free was within the Depth or not */
1351 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
1352 {
1353 /* Let the balancer know */
1354 List->L.FreeMisses++;
1355
1356 /* Use the L List */
1357 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
1358 List->L.TotalFrees++;
1359
1360 /* Check if the Free was within the Depth or not */
1361 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
1362 {
1363 /* All lists failed, use the pool */
1364 List->L.FreeMisses++;
1365 ExFreePool(Irp);
1366 Irp = NULL;
1367 }
1368 }
1369
1370 /* The free was within dhe Depth */
1371 if (Irp)
1372 {
1373 InterlockedPushEntrySList(&List->L.ListHead, (PSINGLE_LIST_ENTRY)Irp);
1374 }
1375 }
1376
1377 DPRINT("Free done\n");
1378 }
1379
1380 /*
1381 * @implemented
1382 */
1383 PEPROCESS STDCALL
1384 IoGetRequestorProcess(IN PIRP Irp)
1385 {
1386 return(Irp->Tail.Overlay.Thread->ThreadsProcess);
1387 }
1388
1389 /*
1390 * @implemented
1391 */
1392 ULONG
1393 STDCALL
1394 IoGetRequestorProcessId(IN PIRP Irp)
1395 {
1396 return (ULONG)(IoGetRequestorProcess(Irp)->UniqueProcessId);
1397 }
1398
1399 /*
1400 * @implemented
1401 */
1402 NTSTATUS
1403 STDCALL
1404 IoGetRequestorSessionId(IN PIRP Irp,
1405 OUT PULONG pSessionId)
1406 {
1407 *pSessionId = IoGetRequestorProcess(Irp)->Session;
1408
1409 return STATUS_SUCCESS;
1410 }
1411
1412 /*
1413 * @implemented
1414 */
1415 PIRP
1416 STDCALL
1417 IoGetTopLevelIrp(VOID)
1418 {
1419 return (PIRP)PsGetCurrentThread()->TopLevelIrp;
1420 }
1421
1422 /*
1423 * @implemented
1424 *
1425 * FUNCTION: Initalizes an irp allocated by the caller
1426 * ARGUMENTS:
1427 * Irp = IRP to initalize
1428 * PacketSize = Size in bytes of the IRP
1429 * StackSize = Number of stack locations in the IRP
1430 */
1431 VOID
1432 STDCALL
1433 IoInitializeIrp(PIRP Irp,
1434 USHORT PacketSize,
1435 CCHAR StackSize)
1436 {
1437 ASSERT(Irp != NULL);
1438
1439 DPRINT("IoInitializeIrp(StackSize %x, Irp 0x%p)\n",StackSize, Irp);
1440
1441 /* Clear it */
1442 RtlZeroMemory(Irp, PacketSize);
1443
1444 /* Set the Header and other data */
1445 Irp->Type = IO_TYPE_IRP;
1446 Irp->Size = PacketSize;
1447 Irp->StackCount = StackSize;
1448 Irp->CurrentLocation = StackSize + 1;
1449 Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex;
1450 Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
1451
1452 /* Initialize the Thread List */
1453 InitializeListHead(&Irp->ThreadListEntry);
1454
1455 DPRINT("Irp->Tail.Overlay.CurrentStackLocation 0x%p\n", Irp->Tail.Overlay.CurrentStackLocation);
1456 }
1457
1458 /*
1459 * NAME EXPORTED
1460 * IoIsOperationSynchronous@4
1461 *
1462 * DESCRIPTION
1463 * Check if the I/O operation associated with the given IRP
1464 * is synchronous.
1465 *
1466 * ARGUMENTS
1467 * Irp Packet to check.
1468 *
1469 * RETURN VALUE
1470 * TRUE if Irp's operation is synchronous; otherwise FALSE.
1471 *
1472 * @implemented
1473 */
1474 BOOLEAN
1475 STDCALL
1476 IoIsOperationSynchronous(IN PIRP Irp)
1477 {
1478 /* Check the flags */
1479 if ((Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ||
1480 (Irp->Flags & IRP_SYNCHRONOUS_API) ||
1481 (IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags &
1482 FO_SYNCHRONOUS_IO))
1483 {
1484 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1485 return TRUE;
1486 }
1487
1488 /* Otherwise, it is an asynchronous operation. */
1489 return FALSE;
1490 }
1491
1492 /*
1493 * @unimplemented
1494 */
1495 BOOLEAN
1496 STDCALL
1497 IoIsValidNameGraftingBuffer(IN PIRP Irp,
1498 IN PREPARSE_DATA_BUFFER ReparseBuffer)
1499 {
1500 UNIMPLEMENTED;
1501 return FALSE;
1502 }
1503
1504 /*
1505 * @implemented
1506 *
1507 * FUNCTION: Allocates and initializes an irp to associated with a master irp
1508 * ARGUMENTS:
1509 * Irp = Master irp
1510 * StackSize = Number of stack locations to be allocated in the irp
1511 * RETURNS: The irp allocated
1512 * NOTE: The caller is responsible for incrementing
1513 * Irp->AssociatedIrp.IrpCount.
1514 */
1515 PIRP
1516 STDCALL
1517 IoMakeAssociatedIrp(PIRP Irp,
1518 CCHAR StackSize)
1519 {
1520 PIRP AssocIrp;
1521
1522 /* Allocate the IRP */
1523 AssocIrp = IoAllocateIrp(StackSize, FALSE);
1524 if (AssocIrp == NULL) return NULL;
1525
1526 /* Set the Flags */
1527 AssocIrp->Flags |= IRP_ASSOCIATED_IRP;
1528
1529 /* Set the Thread */
1530 AssocIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
1531
1532 /* Associate them */
1533 AssocIrp->AssociatedIrp.MasterIrp = Irp;
1534
1535 return AssocIrp;
1536 }
1537
1538 /*
1539 * @implemented
1540 */
1541 NTSTATUS
1542 STDCALL
1543 IoPageRead(PFILE_OBJECT FileObject,
1544 PMDL Mdl,
1545 PLARGE_INTEGER Offset,
1546 PKEVENT Event,
1547 PIO_STATUS_BLOCK StatusBlock)
1548 {
1549 PIRP Irp;
1550 PIO_STACK_LOCATION StackPtr;
1551 PDEVICE_OBJECT DeviceObject;
1552
1553 DPRINT("IoPageRead(FileObject 0x%p, Mdl 0x%p)\n",
1554 FileObject, Mdl);
1555
1556 /* Get the Device Object */
1557 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1558
1559 /* Allocate IRP */
1560 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1561
1562 /* Get the Stack */
1563 StackPtr = IoGetNextIrpStackLocation(Irp);
1564
1565 /* Create the IRP Settings */
1566 Irp->MdlAddress = Mdl;
1567 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1568 Irp->UserIosb = StatusBlock;
1569 Irp->UserEvent = Event;
1570 Irp->RequestorMode = KernelMode;
1571 Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO | IRP_INPUT_OPERATION;
1572 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1573 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1574
1575 /* Set the Stack Settings */
1576 StackPtr->Parameters.Read.Length = MmGetMdlByteCount(Mdl);
1577 StackPtr->Parameters.Read.ByteOffset = *Offset;
1578 StackPtr->MajorFunction = IRP_MJ_READ;
1579 StackPtr->FileObject = FileObject;
1580
1581 /* Call the Driver */
1582 return IofCallDriver(DeviceObject, Irp);
1583 }
1584
1585 /*
1586 * @implemented
1587 */
1588 VOID
1589 STDCALL
1590 IoQueueThreadIrp(IN PIRP Irp)
1591 {
1592 KIRQL OldIrql;
1593
1594 /* Raise to APC */
1595 OldIrql = KfRaiseIrql(APC_LEVEL);
1596
1597 /*
1598 * Synchronous irp's are queued to requestor thread. If they are not
1599 * completed when the thread exits, they are canceled (cleaned up).
1600 * - Gunnar
1601 */
1602 InsertTailList(&Irp->Tail.Overlay.Thread->IrpList, &Irp->ThreadListEntry);
1603
1604 /* Lower back */
1605 KfLowerIrql(OldIrql);
1606 }
1607
1608 /*
1609 * @implemented
1610 * Reference: Chris Cant's "Writing WDM Device Drivers"
1611 */
1612 VOID
1613 STDCALL
1614 IoReuseIrp(IN OUT PIRP Irp,
1615 IN NTSTATUS Status)
1616 {
1617 UCHAR AllocationFlags;
1618
1619 /* Get the old flags */
1620 AllocationFlags = Irp->AllocationFlags;
1621
1622 /* Reinitialize the IRP */
1623 IoInitializeIrp(Irp, Irp->Size, Irp->StackCount);
1624
1625 /* Duplicate the data */
1626 Irp->IoStatus.Status = Status;
1627 Irp->AllocationFlags = AllocationFlags;
1628 }
1629
1630 /*
1631 * @implemented
1632 */
1633 VOID
1634 STDCALL
1635 IoSetTopLevelIrp(IN PIRP Irp)
1636 {
1637 PsGetCurrentThread()->TopLevelIrp = (ULONG)Irp;
1638 }
1639
1640 /*
1641 * @implemented
1642 */
1643 NTSTATUS
1644 STDCALL
1645 IoSynchronousPageWrite(PFILE_OBJECT FileObject,
1646 PMDL Mdl,
1647 PLARGE_INTEGER Offset,
1648 PKEVENT Event,
1649 PIO_STATUS_BLOCK StatusBlock)
1650 {
1651 PIRP Irp;
1652 PIO_STACK_LOCATION StackPtr;
1653 PDEVICE_OBJECT DeviceObject;
1654
1655 DPRINT("IoSynchronousPageWrite(FileObject 0x%p, Mdl 0x%p)\n",
1656 FileObject, Mdl);
1657
1658 /* Get the Device Object */
1659 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1660
1661 /* Allocate IRP */
1662 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1663
1664 /* Get the Stack */
1665 StackPtr = IoGetNextIrpStackLocation(Irp);
1666
1667 /* Create the IRP Settings */
1668 Irp->MdlAddress = Mdl;
1669 Irp->UserBuffer = MmGetMdlVirtualAddress(Mdl);
1670 Irp->UserIosb = StatusBlock;
1671 Irp->UserEvent = Event;
1672 Irp->RequestorMode = KernelMode;
1673 Irp->Flags = IRP_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_PAGING_IO;
1674 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1675 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1676
1677 /* Set the Stack Settings */
1678 StackPtr->Parameters.Write.Length = MmGetMdlByteCount(Mdl);
1679 StackPtr->Parameters.Write.ByteOffset = *Offset;
1680 StackPtr->MajorFunction = IRP_MJ_WRITE;
1681 StackPtr->FileObject = FileObject;
1682
1683 /* Call the Driver */
1684 return IofCallDriver(DeviceObject, Irp);
1685 }
1686
1687 /* EOF */