1 /*************************************************************************
5 * Module: Ext2 File System Driver (Kernel mode execution only)
8 * This file contains low level disk io routines.
10 * Author: Manoj Paul Joseph
13 *************************************************************************/
17 // define the file specific bug-check id
18 #define EXT2_BUG_CHECK_ID EXT2_FILE_IO
20 /*************************************************************************
22 * Function: Ext2PassDownMultiReadWriteIRP()
25 * pass down multiple read IRPs as Associated IRPs
27 * Expected Interrupt Level (for execution) :
31 * Return Value: STATUS_SUCCESS / STATUS_PENDING / Error
33 *************************************************************************/
34 NTSTATUS NTAPI
Ext2PassDownMultiReadWriteIRP(
35 PEXT2_IO_RUN PtrIoRuns
,
37 ULONG TotalReadWriteLength
,
38 PtrExt2IrpContext PtrIrpContext
,
40 BOOLEAN SynchronousIo
)
43 PIRP PtrAssociatedIrp
;
44 PIO_STACK_LOCATION PtrIrpSp
;
49 PEXT2_IO_CONTEXT PtrIoContext
= NULL
;
50 PKEVENT PtrSyncEvent
= NULL
;
51 ULONG LogicalBlockSize
;
52 ULONG ReadWriteLength
;
54 NTSTATUS RC
= STATUS_SUCCESS
;
56 PtrVCB
= PtrFCB
->PtrVCB
;
57 PtrMasterIrp
= PtrIrpContext
->Irp
;
58 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
64 IoMarkIrpPending( PtrIrpContext
->Irp
);
65 // We will be returning STATUS_PENDING...
68 if( !PtrMasterIrp
->MdlAddress
)
70 Ext2LockCallersBuffer( PtrMasterIrp
, TRUE
, TotalReadWriteLength
);
75 PtrSyncEvent
= Ext2AllocatePool(NonPagedPool
, Ext2QuadAlign( sizeof(KEVENT
) ) );
78 RC
= STATUS_INSUFFICIENT_RESOURCES
;
81 KeInitializeEvent( PtrSyncEvent
, SynchronizationEvent
, FALSE
);
84 // Allocate and initialize a completion context
86 PtrIoContext
= Ext2AllocatePool(NonPagedPool
, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT
) ) );
89 RC
= STATUS_INSUFFICIENT_RESOURCES
;
93 RtlZeroMemory( PtrIoContext
, sizeof(EXT2_IO_CONTEXT
) );
94 PtrIoContext
->Count
= Count
;
95 PtrIoContext
->NodeIdentifier
.NodeType
= EXT2_NODE_TYPE_IO_CONTEXT
;
96 PtrIoContext
->NodeIdentifier
.NodeSize
= sizeof( EXT2_IO_CONTEXT
);
97 PtrIoContext
->PtrMasterIrp
= PtrMasterIrp
;
98 PtrIoContext
->PtrSyncEvent
= PtrSyncEvent
;
99 PtrIoContext
->ReadWriteLength
= TotalReadWriteLength
;
103 for( ReadWriteLength
= 0, BufferOffset
= 0, i
= 0; i
< Count
; i
++, BufferOffset
+= ReadWriteLength
)
106 ReadWriteLength
= PtrIoRuns
[ i
].EndOffset
- PtrIoRuns
[ i
].StartOffset
;
109 // Allocating an Associated IRP...
111 PtrAssociatedIrp
= IoMakeAssociatedIrp( PtrMasterIrp
,
112 (CCHAR
) (PtrVCB
->TargetDeviceObject
->StackSize
+ 1 ) );
113 PtrIoRuns
[ i
].PtrAssociatedIrp
= PtrAssociatedIrp
;
114 ASSERT ( PtrAssociatedIrp
);
115 PtrMasterIrp
->AssociatedIrp
.IrpCount
++;
118 // Allocating a Memory Descriptor List...
120 PtrMdl
= IoAllocateMdl( (PCHAR
) PtrMasterIrp
->UserBuffer
+ BufferOffset
, // Virtual Address
121 ReadWriteLength
, FALSE
, FALSE
, PtrAssociatedIrp
);
124 // and building a partial MDL...
126 IoBuildPartialMdl( PtrMasterIrp
->MdlAddress
,
127 PtrMdl
, (PCHAR
)PtrMasterIrp
->UserBuffer
+ BufferOffset
, ReadWriteLength
);
130 // Create an Irp stack location for ourselves...
132 IoSetNextIrpStackLocation( PtrAssociatedIrp
);
133 PtrIrpSp
= IoGetCurrentIrpStackLocation( PtrAssociatedIrp
);
136 // Setup the Stack location to describe our read.
138 PtrIrpSp
->MajorFunction
= PtrIrpContext
->MajorFunction
;
139 if( PtrIrpContext
->MajorFunction
== IRP_MJ_READ
)
141 PtrIrpSp
->Parameters
.Read
.Length
= ReadWriteLength
;
142 PtrIrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
=
143 PtrIoRuns
[i
].LogicalBlock
* ( LogicalBlockSize
);
145 else if( PtrIrpContext
->MajorFunction
== IRP_MJ_WRITE
)
147 PtrIrpSp
->Parameters
.Write
.Length
= ReadWriteLength
;
148 PtrIrpSp
->Parameters
.Write
.ByteOffset
.QuadPart
=
149 PtrIoRuns
[i
].LogicalBlock
* ( LogicalBlockSize
);
152 // PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
153 // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock;
157 // Setup a completion routine...
159 IoSetCompletionRoutine( PtrAssociatedIrp
,
161 Ext2MultiSyncCompletionRoutine
:
162 Ext2MultiAsyncCompletionRoutine
,
163 PtrIoContext
, TRUE
, TRUE
, TRUE
);
166 // Initialise the next stack location for the driver below us to use...
168 PtrIrpSp
= IoGetNextIrpStackLocation( PtrAssociatedIrp
);
169 PtrIrpSp
->MajorFunction
= PtrIrpContext
->MajorFunction
;
170 if( PtrIrpContext
->MajorFunction
== IRP_MJ_READ
)
172 PtrIrpSp
->Parameters
.Read
.Length
= ReadWriteLength
;
173 PtrIrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= PtrIoRuns
[i
].LogicalBlock
* ( LogicalBlockSize
);
175 else if( PtrIrpContext
->MajorFunction
== IRP_MJ_WRITE
)
177 PtrIrpSp
->Parameters
.Write
.Length
= ReadWriteLength
;
178 PtrIrpSp
->Parameters
.Write
.ByteOffset
.QuadPart
= PtrIoRuns
[i
].LogicalBlock
* ( LogicalBlockSize
);
181 // PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
182 // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart =
183 // PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
186 for( i
= 0; i
< Count
; i
++ ) {
187 // DbgPrint("PASSING DOWN IRP %d TO TARGET DEVICE\n", i);
188 IoCallDriver( PtrVCB
->TargetDeviceObject
, PtrIoRuns
[ i
].PtrAssociatedIrp
);
195 // Wait for the IO to complete...
197 DbgPrint("DEADLY WAIT (%d)\n", KeGetCurrentIrql());
198 KeWaitForSingleObject( PtrSyncEvent
,
199 Executive
, KernelMode
, FALSE
, (PLARGE_INTEGER
)NULL
);
200 DbgPrint("DEADLY WAIT DONE\n");
205 // Asynchronous IO...
216 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [io]", PtrSyncEvent
);
217 ExFreePool( PtrSyncEvent
);
219 if( PtrIoContext
&& ! ( RC
== STATUS_PENDING
|| RC
== STATUS_SUCCESS
) )
222 // This means we are getting out of
223 // this function without doing a read
224 // due to an error, maybe...
226 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [io]", PtrIoContext
);
227 ExFreePool( PtrIoContext
);
233 NTSTATUS NTAPI
Ext2PassDownSingleReadWriteIRP(
234 PtrExt2IrpContext PtrIrpContext
,
237 LARGE_INTEGER ByteOffset
,
238 uint32 ReadWriteLength
,
239 BOOLEAN SynchronousIo
)
241 NTSTATUS RC
= STATUS_SUCCESS
;
243 PEXT2_IO_CONTEXT PtrIoContext
= NULL
;
244 PKEVENT PtrSyncEvent
= NULL
;
246 PIO_STACK_LOCATION PtrIrpNextSp
= NULL
;
250 if( !PtrIrp
->MdlAddress
)
252 Ext2LockCallersBuffer( PtrIrp
, TRUE
, ReadWriteLength
);
258 PtrSyncEvent
= Ext2AllocatePool( NonPagedPool
, Ext2QuadAlign( sizeof(KEVENT
) ) );
261 RC
= STATUS_INSUFFICIENT_RESOURCES
;
264 KeInitializeEvent( PtrSyncEvent
, SynchronizationEvent
, FALSE
);
268 // Allocate and initialize a completion context
270 PtrIoContext
= Ext2AllocatePool(NonPagedPool
, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT
) ) );
273 RC
= STATUS_INSUFFICIENT_RESOURCES
;
277 RtlZeroMemory( PtrIoContext
, sizeof(EXT2_IO_CONTEXT
) );
278 PtrIoContext
->Count
= 1;
279 PtrIoContext
->NodeIdentifier
.NodeType
= EXT2_NODE_TYPE_IO_CONTEXT
;
280 PtrIoContext
->NodeIdentifier
.NodeSize
= sizeof( EXT2_IO_CONTEXT
);
281 PtrIoContext
->PtrMasterIrp
= NULL
;
282 PtrIoContext
->PtrSyncEvent
= PtrSyncEvent
;
283 PtrIoContext
->ReadWriteLength
= ReadWriteLength
;
285 IoSetCompletionRoutine( PtrIrp
,
287 Ext2SingleSyncCompletionRoutine
:
288 Ext2SingleAsyncCompletionRoutine
,
289 PtrIoContext
, TRUE
, TRUE
, TRUE
);
292 // Setup the next IRP stack location in the associated Irp for the disk
293 // driver beneath us.
295 PtrIrpNextSp
= IoGetNextIrpStackLocation( PtrIrp
);
298 // Setup the Stack location to do a read from the disk driver.
300 PtrIrpNextSp
->MajorFunction
= PtrIrpContext
->MajorFunction
;
301 if( PtrIrpContext
->MajorFunction
== IRP_MJ_READ
)
303 PtrIrpNextSp
->Parameters
.Read
.Length
= ReadWriteLength
;
304 PtrIrpNextSp
->Parameters
.Read
.ByteOffset
= ByteOffset
;
306 else if( PtrIrpContext
->MajorFunction
== IRP_MJ_WRITE
)
308 PtrIrpNextSp
->Parameters
.Write
.Length
= ReadWriteLength
;
309 PtrIrpNextSp
->Parameters
.Write
.ByteOffset
= ByteOffset
;
312 // Issue the read / write request
314 RC
= IoCallDriver(PtrVCB
->TargetDeviceObject
, PtrIrp
);
319 // Wait for completion...
321 RC
= KeWaitForSingleObject( &PtrIoContext
->PtrSyncEvent
,
322 Executive
, KernelMode
, FALSE
, (PLARGE_INTEGER
)NULL
);
337 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [io]", PtrSyncEvent
);
338 ExFreePool( PtrSyncEvent
);
340 if( PtrIoContext
&& !( RC
== STATUS_PENDING
|| RC
== STATUS_SUCCESS
) )
343 // This means we are getting out of
344 // this function without doing a read / write
345 // due to an error, maybe...
347 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [io]", PtrIoContext
);
348 ExFreePool( PtrIoContext
);
355 /*************************************************************************
357 * Function: Ext2SingleSyncCompletionRoutine()
360 * Synchronous I/O Completion Routine
362 * Expected Interrupt Level (for execution) :
366 * Return Value: NTSTATUS - STATUS_SUCCESS(always)
368 *************************************************************************/
369 NTSTATUS NTAPI
Ext2SingleSyncCompletionRoutine(
370 IN PDEVICE_OBJECT DeviceObject
,
375 PEXT2_IO_CONTEXT PtrContext
= Contxt
;
377 if( Irp
->PendingReturned
)
378 IoMarkIrpPending( Irp
);
380 ASSERT( PtrContext
);
381 ASSERT( PtrContext
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_IO_CONTEXT
);
383 KeSetEvent( PtrContext
->PtrSyncEvent
, 0, FALSE
);
384 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [io]", PtrContext
);
385 ExFreePool( PtrContext
);
387 return STATUS_SUCCESS
;
390 /*************************************************************************
392 * Function: Ext2SingleAsyncCompletionRoutine()
395 * Asynchronous I/O Completion Routine
397 * Expected Interrupt Level (for execution) :
401 * Return Value: NTSTATUS - STATUS_SUCCESS(always)
403 *************************************************************************/
404 NTSTATUS NTAPI
Ext2SingleAsyncCompletionRoutine(
405 IN PDEVICE_OBJECT DeviceObject
,
410 PEXT2_IO_CONTEXT PtrContext
= Contxt
;
412 if( Irp
->PendingReturned
)
413 IoMarkIrpPending( Irp
);
415 ASSERT( PtrContext
);
416 ASSERT( PtrContext
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_IO_CONTEXT
);
418 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [io]", PtrContext
);
419 ExFreePool( PtrContext
);
421 return STATUS_SUCCESS
;
424 /*************************************************************************
426 * Function: Ext2MultiSyncCompletionRoutine()
429 * Synchronous I/O Completion Routine
431 * Expected Interrupt Level (for execution) :
435 * Return Value: NTSTATUS - STATUS_SUCCESS(always)
437 *************************************************************************/
438 NTSTATUS NTAPI
Ext2MultiSyncCompletionRoutine (
439 IN PDEVICE_OBJECT DeviceObject
,
445 PEXT2_IO_CONTEXT PtrContext
= Contxt
;
446 ASSERT( PtrContext
);
448 if( Irp
->PendingReturned
)
450 IoMarkIrpPending( Irp
);
453 if (!NT_SUCCESS( Irp
->IoStatus
.Status
))
455 PtrContext
->PtrMasterIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
458 if (InterlockedDecrement( &PtrContext
->Count
) == 0)
460 if ( NT_SUCCESS( PtrContext
->PtrMasterIrp
->IoStatus
.Status
) )
462 PtrContext
->PtrMasterIrp
->IoStatus
.Information
= PtrContext
->ReadWriteLength
;
466 PtrContext
->PtrMasterIrp
->IoStatus
.Information
= 0;
469 KeSetEvent( PtrContext
->PtrSyncEvent
, 0, FALSE
);
470 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [io]", PtrContext
);
471 ExFreePool( PtrContext
);
475 // The master Irp will be automatically completed
476 // when all the associated IRPs are completed
478 return STATUS_SUCCESS
;
481 /*************************************************************************
483 * Function: Ext2MultiAsyncCompletionRoutine()
486 * Asynchronous I/O Completion Routine
488 * Expected Interrupt Level (for execution) :
492 * Return Value: NTSTATUS - STATUS_SUCCESS(always)
494 *************************************************************************/
495 NTSTATUS NTAPI
Ext2MultiAsyncCompletionRoutine (
496 IN PDEVICE_OBJECT DeviceObject
,
502 PEXT2_IO_CONTEXT PtrContext
= Contxt
;
503 ASSERT( PtrContext
);
505 if( Irp
->PendingReturned
)
507 IoMarkIrpPending( Irp
);
510 if (!NT_SUCCESS( Irp
->IoStatus
.Status
))
512 PtrContext
->PtrMasterIrp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
515 if (InterlockedDecrement( &PtrContext
->Count
) == 0)
517 if ( NT_SUCCESS( PtrContext
->PtrMasterIrp
->IoStatus
.Status
) )
519 PtrContext
->PtrMasterIrp
->IoStatus
.Information
= PtrContext
->ReadWriteLength
;
523 PtrContext
->PtrMasterIrp
->IoStatus
.Information
= 0;
525 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [io]", PtrContext
);
526 ExFreePool( PtrContext
);
530 // The master Irp will be automatically completed
531 // when all the associated IRPs are completed
532 // Returning STATUS_SUCCESS to continue postprocessing...
534 return STATUS_SUCCESS
;