Io_stack_location and IRP are two very basic things in the drive, in order to understand these two things, find a little information.
1. The IRP can be seen as a message in the Win32 window program, Device_object can be seen as a window in a WIN32 window program (Windows)
2. When creating an IRP, any kernel-mode program also creates an array of io_stack_location structures associated with it: each stack cell in the array corresponds to a driver that will process the IRP.
The head of the IRP has an array index of the current io_stack_location, as well as a pointer to the io_stack_location. The index is starting from 1, with no 0. The IoCallDriver routine can be called when the driver prepares to pass an IRP to the secondary low-level driver, one of which is to decrement the index of the current io_stack_location to match the driver on the next layer. However, the index will not be set to 0, and if set to 0, the system will crash. That is, the bottom-most driver does not call the IoCallDriver routine.
3. Io_stack_location has a member of the Pio_completion_routine type Completionroutine, which is the address of an I/O completion routine, The address is set by a more up-level driver for the driver that corresponds to this stack unit . You should never set this field directly, you should call the Iosetcompletionroutine function, which knows how to refer to the stack unit of the next layer of the driver. The lowest-level drivers for the device stack do not need to complete the routines, because they must complete the request directly. However, the initiator of the request does sometimes need a completion routine, but usually does not have its own stack unit. This is why each level of the driver uses the next-level driver's stack unit to save its own completion routine pointer.
voidiosetcompletionroutine (__in pirp Irp, __in_opt pio_completion_routine Completi Onroutine, __in_opt __drv_aliasesmem PVOID Context, __in boolean invokeonsuccess, __in boolean invokeonerror, __in BOOLEAN invokeoncancel) {pio_stack_location irpsp; ASSERT ((invokeonsuccess | | Invokeonerror | | Invokeoncancel)? (Completionroutine! = NULL): TRUE); IRPSP = Iogetnextirpstacklocation (IRP); Irpsp->completionroutine = Completionroutine; Irpsp->context = Context; Irpsp->control = 0; if (invokeonsuccess) {Irpsp->control = sl_invoke_on_success; } if (invokeonerror) {Irpsp->control |= sl_invoke_on_error; } if (invokeoncancel) {Irpsp->control |= sl_invoke_on_cancel; }}
1234567891011121314151617181920212223242526272829 | TD class= "Code" >
Finally explains why the completion routine is set in the next IO stack in the iosetcompletionroutine. The lowest-level driver should not install a completion routine.
4. Framework for completing routines
12345678910 |
NTSTATUS completionroutine (pdevice_object device, pirp IRP, PVOID context) { if (irp->pendingreturned) { iomarkirppending (IRP); } // ... Return status_success/* or some other STATUS code */;} |
If irp->pendingreturned is true, then any completion routine that does not return status_more_processing_required should call iomarkirppending, which is almost entirely true, but there are still exceptions. If the driver assigns an IRP, installs the completion routine, and then calls IoCallDriver without changing the stack pointer, the completion routine should not contain these two lines of code, because there is no stack unit associated with your driver. (The underlined part of the understanding is not very clear, you can first do not understand, the actual situation to pay attention to it.) Some books don't even mention it.)
5. If your driver does not care what happens after the IRP is passed to the downlevel driver, there is no need to spend processor time (call Iocopycurrentirpstacklocationtonext) to copy your stack unit contents to the next stack cell. Because that stack cell already contains the parameters that the next layer of drivers will get, and any completion routine pointers that the driver on the previous layer might give. So you can use the following code:
123456 |
NTSTATUS Forwardandforget (pdevice_object fdo, pirp Irp) { pdevice_extension PDX = (pdevice_extension) fdo-> deviceextension; Ioskipcurrentirpstacklocation (IRP); Return IoCallDriver (Pdx->lowerdeviceobject, IRP);} |
Is this code often seen in filter drivers?
6. Iocopycurrentirpstacklocationtonext and Ioskipcurrentirpstacklocation
Iocopycurrentirpstacklocationtonext copies the IO stack in addition to the completion routines and the contents of the completion routine parameters.
123456789101112 |
Voidiocopycurrentirpstacklocationtonext ( __inout pirp Irp) { pio_stack_location irpsp; Pio_stack_location NEXTIRPSP; IRPSP = Iogetcurrentirpstacklocation (IRP); NEXTIRPSP = Iogetnextirpstacklocation (IRP); Rtlcopymemory (NEXTIRPSP, IRPSP, Field_offset (Io_stack_location, Completionroutine)); Nextirpsp->control = 0;} |
Ioskipcurrentirpstacklocation makes the stack pointer less forward, while the IoCallDriver function causes the stack pointer to move forward, and the result is that the stack pointer does not change. When the dispatch routine of the next driver calls Iogetcurrentirpstacklocation, it will receive the exact same io_stack_location pointer that we are using.
123456789 |
Voidioskipcurrentirpstacklocation ( __inout pirp Irp) { ASSERT (irp->currentlocation <= irp-> Stackcount); irp->currentlocation++; irp->tail.overlay.currentstacklocation++;} |
Originally I was Here in doubt: an IRP corresponds to a io_stack_location, if you use ioskipcurrentirpstacklocation that is not a io_stack_location? Yes, that is true, the book is not clear ~ ~ Look at the following chart:
The diagram shows a scenario where a device stack has three drivers, your driver (functional device object [FDO]), and two other drivers (an upper filter device object [FiDO], a PDO). In figure (a), you will see the relationship between the Iocopycurrentirpstacklocationtonext function that executes the copy stack unit, the stack cell, each parameter, and the completion routine. In figure (b), you will see this relationship, but using the Ioskipcurrentirpstacklocation function, the third and last stack units are skipped.
7. IRP completion routines and status_more_processing_required
If the driver of a layer wants the issued IRP to be able to gain control of the IRP again at the time of completion, then the status_more_processing_required can be returned in the completed routine. The code looks like this:
12345678910111213141516171819202122 |
ntstatus forwardandwait (pdevice_object fdo, pirp Irp) {KEVENT event; Keinitializeevent (&event, notificationevent, FALSE); Iocopycurrentirpstacklocationtonext (IRP); I Osetcompletionroutine (IRP, (Pio_completion_routine) Onrequestcomplete, (PVOID) &event,true,true,true); Pdevice_extension PDX = (pdevice_extension) fdo->deviceextension;iocalldriver (Pdx->lowerdeviceobject, IRP); KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL); return irp->iostatus.status;} ntstatus Onrequestcomplete (pdevice_object fdo, pirp Irp, Pkevent pev) {kesetevent (PEV, 0, FALSE); return Status_
more_processing_required;} |
Once we call IoCallDriver, we give up control of the IRP until some code that runs in the context of any thread calls IoCompleteRequest to notify the IRP to complete, and IoCompleteRequest calls our completion routines. By returning status_more_processing_required in the completion routine, we stopped the back-volume processing of the I/O stack. At this point, any completion routines installed by the upper filter driver are not called, and the I/O Manager stops working on the IRP. This situation is like not having called iocompleterequest at all, except, of course, some of the low-level completion routines that have been called. At this point, the IRP will be in an intermediate state, but our forwardandwait routine will get ownership of the IRP again.
Why do you want to re-control the IRP? One situation is: This IRP is the current dynamic allocation of the drive, after forwarding to the lower driver, the IRP always after the following driver processing, the IRP allocated space to reclaim it?
Reference: Programming the Microsoft Window
A little note on the io_stack_location and the IRP