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