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