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