- Update to r53061
[reactos.git] / drivers / filesystems / ext2 / src / io.c
1 /*************************************************************************
2 *
3 * File: io.c
4 *
5 * Module: Ext2 File System Driver (Kernel mode execution only)
6 *
7 * Description:
8 * This file contains low level disk io routines.
9 *
10 * Author: Manoj Paul Joseph
11 *
12 *
13 *************************************************************************/
14
15 #include "ext2fsd.h"
16
17 // define the file specific bug-check id
18 #define EXT2_BUG_CHECK_ID EXT2_FILE_IO
19
20 /*************************************************************************
21 *
22 * Function: Ext2PassDownMultiReadWriteIRP()
23 *
24 * Description:
25 * pass down multiple read IRPs as Associated IRPs
26 *
27 * Expected Interrupt Level (for execution) :
28 *
29 * ?
30 *
31 * Return Value: STATUS_SUCCESS / STATUS_PENDING / Error
32 *
33 *************************************************************************/
34 NTSTATUS NTAPI Ext2PassDownMultiReadWriteIRP(
35 PEXT2_IO_RUN PtrIoRuns,
36 UINT Count,
37 ULONG TotalReadWriteLength,
38 PtrExt2IrpContext PtrIrpContext,
39 PtrExt2FCB PtrFCB,
40 BOOLEAN SynchronousIo)
41 {
42 PIRP PtrMasterIrp;
43 PIRP PtrAssociatedIrp;
44 PIO_STACK_LOCATION PtrIrpSp;
45 PMDL PtrMdl;
46 PtrExt2VCB PtrVCB;
47 UINT i;
48 ULONG BufferOffset;
49 PEXT2_IO_CONTEXT PtrIoContext = NULL;
50 PKEVENT PtrSyncEvent = NULL;
51 ULONG LogicalBlockSize;
52 ULONG ReadWriteLength;
53
54 NTSTATUS RC = STATUS_SUCCESS;
55
56 PtrVCB = PtrFCB->PtrVCB;
57 PtrMasterIrp = PtrIrpContext->Irp;
58 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
59
60 try
61 {
62 if( !SynchronousIo )
63 {
64 IoMarkIrpPending( PtrIrpContext->Irp );
65 // We will be returning STATUS_PENDING...
66 }
67
68 if( !PtrMasterIrp->MdlAddress )
69 {
70 Ext2LockCallersBuffer( PtrMasterIrp, TRUE, TotalReadWriteLength );
71 }
72
73 if( SynchronousIo )
74 {
75 PtrSyncEvent = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) );
76 if ( !PtrSyncEvent )
77 {
78 RC = STATUS_INSUFFICIENT_RESOURCES;
79 try_return();
80 }
81 KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE );
82 }
83 //
84 // Allocate and initialize a completion context
85 //
86 PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) );
87 if ( !PtrIoContext )
88 {
89 RC = STATUS_INSUFFICIENT_RESOURCES;
90 try_return();
91 }
92
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;
100
101
102
103 for( ReadWriteLength = 0, BufferOffset = 0, i = 0; i < Count; i++, BufferOffset += ReadWriteLength )
104 {
105
106 ReadWriteLength = PtrIoRuns[ i].EndOffset - PtrIoRuns[ i].StartOffset;
107
108 //
109 // Allocating an Associated IRP...
110 //
111 PtrAssociatedIrp = IoMakeAssociatedIrp( PtrMasterIrp,
112 (CCHAR) (PtrVCB->TargetDeviceObject->StackSize + 1 ) );
113 PtrIoRuns[ i].PtrAssociatedIrp = PtrAssociatedIrp;
114 ASSERT ( PtrAssociatedIrp );
115 PtrMasterIrp->AssociatedIrp.IrpCount ++;
116
117 //
118 // Allocating a Memory Descriptor List...
119 //
120 PtrMdl = IoAllocateMdl( (PCHAR) PtrMasterIrp->UserBuffer + BufferOffset, // Virtual Address
121 ReadWriteLength, FALSE, FALSE, PtrAssociatedIrp );
122
123 //
124 // and building a partial MDL...
125 //
126 IoBuildPartialMdl( PtrMasterIrp->MdlAddress,
127 PtrMdl, (PCHAR)PtrMasterIrp->UserBuffer + BufferOffset, ReadWriteLength );
128
129 //
130 // Create an Irp stack location for ourselves...
131 //
132 IoSetNextIrpStackLocation( PtrAssociatedIrp );
133 PtrIrpSp = IoGetCurrentIrpStackLocation( PtrAssociatedIrp );
134
135 //
136 // Setup the Stack location to describe our read.
137 //
138 PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction;
139 if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
140 {
141 PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
142 PtrIrpSp->Parameters.Read.ByteOffset.QuadPart =
143 PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
144 }
145 else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
146 {
147 PtrIrpSp->Parameters.Write.Length = ReadWriteLength;
148 PtrIrpSp->Parameters.Write.ByteOffset.QuadPart =
149 PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
150 }
151
152 // PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
153 // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock;
154
155
156 //
157 // Setup a completion routine...
158 //
159 IoSetCompletionRoutine( PtrAssociatedIrp,
160 SynchronousIo ?
161 Ext2MultiSyncCompletionRoutine :
162 Ext2MultiAsyncCompletionRoutine,
163 PtrIoContext, TRUE, TRUE, TRUE );
164
165 //
166 // Initialise the next stack location for the driver below us to use...
167 //
168 PtrIrpSp = IoGetNextIrpStackLocation( PtrAssociatedIrp );
169 PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction;
170 if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
171 {
172 PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
173 PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
174 }
175 else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
176 {
177 PtrIrpSp->Parameters.Write.Length = ReadWriteLength;
178 PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
179 }
180
181 // PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
182 // PtrIrpSp->Parameters.Read.ByteOffset.QuadPart =
183 // PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
184 }
185
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 );
189 }
190
191 if( SynchronousIo )
192 {
193 //
194 // Synchronous IO
195 // Wait for the IO to complete...
196 //
197 DbgPrint("DEADLY WAIT (%d)\n", KeGetCurrentIrql());
198 KeWaitForSingleObject( PtrSyncEvent,
199 Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
200 DbgPrint("DEADLY WAIT DONE\n");
201 try_return();
202 }
203 else
204 {
205 // Asynchronous IO...
206 RC = STATUS_PENDING;
207 try_return();
208 }
209
210 try_exit: NOTHING;
211 }
212 finally
213 {
214 if( PtrSyncEvent )
215 {
216 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent );
217 ExFreePool( PtrSyncEvent );
218 }
219 if( PtrIoContext && ! ( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) )
220 {
221 //
222 // This means we are getting out of
223 // this function without doing a read
224 // due to an error, maybe...
225 //
226 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext);
227 ExFreePool( PtrIoContext );
228 }
229 }
230 return(RC);
231 }
232
233 NTSTATUS NTAPI Ext2PassDownSingleReadWriteIRP(
234 PtrExt2IrpContext PtrIrpContext,
235 PIRP PtrIrp,
236 PtrExt2VCB PtrVCB,
237 LARGE_INTEGER ByteOffset,
238 uint32 ReadWriteLength,
239 BOOLEAN SynchronousIo)
240 {
241 NTSTATUS RC = STATUS_SUCCESS;
242
243 PEXT2_IO_CONTEXT PtrIoContext = NULL;
244 PKEVENT PtrSyncEvent = NULL;
245
246 PIO_STACK_LOCATION PtrIrpNextSp = NULL;
247
248 try
249 {
250 if( !PtrIrp->MdlAddress )
251 {
252 Ext2LockCallersBuffer( PtrIrp, TRUE, ReadWriteLength );
253 }
254
255
256 if( SynchronousIo )
257 {
258 PtrSyncEvent = Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) ) );
259 if ( !PtrSyncEvent )
260 {
261 RC = STATUS_INSUFFICIENT_RESOURCES;
262 try_return();
263 }
264 KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE );
265 }
266
267 //
268 // Allocate and initialize a completion context
269 //
270 PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) ) );
271 if ( !PtrIoContext )
272 {
273 RC = STATUS_INSUFFICIENT_RESOURCES;
274 try_return();
275 }
276
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;
284
285 IoSetCompletionRoutine( PtrIrp,
286 SynchronousIo ?
287 Ext2SingleSyncCompletionRoutine:
288 Ext2SingleAsyncCompletionRoutine,
289 PtrIoContext, TRUE, TRUE, TRUE );
290
291 //
292 // Setup the next IRP stack location in the associated Irp for the disk
293 // driver beneath us.
294 //
295 PtrIrpNextSp = IoGetNextIrpStackLocation( PtrIrp );
296
297 //
298 // Setup the Stack location to do a read from the disk driver.
299 //
300 PtrIrpNextSp->MajorFunction = PtrIrpContext->MajorFunction;
301 if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
302 {
303 PtrIrpNextSp->Parameters.Read.Length = ReadWriteLength;
304 PtrIrpNextSp->Parameters.Read.ByteOffset = ByteOffset;
305 }
306 else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
307 {
308 PtrIrpNextSp->Parameters.Write.Length = ReadWriteLength;
309 PtrIrpNextSp->Parameters.Write.ByteOffset = ByteOffset;
310 }
311 //
312 // Issue the read / write request
313 //
314 RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp);
315
316 if( SynchronousIo )
317 {
318 //
319 // Wait for completion...
320 //
321 RC = KeWaitForSingleObject( &PtrIoContext->PtrSyncEvent,
322 Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
323
324 RC = STATUS_SUCCESS;
325 }
326 else
327 {
328 RC = STATUS_PENDING;
329 }
330
331 try_exit: NOTHING;
332 }
333 finally
334 {
335 if( PtrSyncEvent )
336 {
337 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrSyncEvent );
338 ExFreePool( PtrSyncEvent );
339 }
340 if( PtrIoContext && !( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) )
341 {
342 //
343 // This means we are getting out of
344 // this function without doing a read / write
345 // due to an error, maybe...
346 //
347 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrIoContext );
348 ExFreePool( PtrIoContext );
349 }
350 }
351 return RC;
352 }
353
354
355 /*************************************************************************
356 *
357 * Function: Ext2SingleSyncCompletionRoutine()
358 *
359 * Description:
360 * Synchronous I/O Completion Routine
361 *
362 * Expected Interrupt Level (for execution) :
363 *
364 * ?
365 *
366 * Return Value: NTSTATUS - STATUS_SUCCESS(always)
367 *
368 *************************************************************************/
369 NTSTATUS NTAPI Ext2SingleSyncCompletionRoutine(
370 IN PDEVICE_OBJECT DeviceObject,
371 IN PIRP Irp,
372 IN PVOID Contxt
373 )
374 {
375 PEXT2_IO_CONTEXT PtrContext = Contxt;
376
377 if( Irp->PendingReturned )
378 IoMarkIrpPending( Irp );
379
380 ASSERT( PtrContext );
381 ASSERT( PtrContext->NodeIdentifier.NodeType == EXT2_NODE_TYPE_IO_CONTEXT );
382
383 KeSetEvent( PtrContext->PtrSyncEvent, 0, FALSE );
384 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext );
385 ExFreePool( PtrContext );
386
387 return STATUS_SUCCESS;
388 }
389
390 /*************************************************************************
391 *
392 * Function: Ext2SingleAsyncCompletionRoutine()
393 *
394 * Description:
395 * Asynchronous I/O Completion Routine
396 *
397 * Expected Interrupt Level (for execution) :
398 *
399 * ?
400 *
401 * Return Value: NTSTATUS - STATUS_SUCCESS(always)
402 *
403 *************************************************************************/
404 NTSTATUS NTAPI Ext2SingleAsyncCompletionRoutine(
405 IN PDEVICE_OBJECT DeviceObject,
406 IN PIRP Irp,
407 IN PVOID Contxt
408 )
409 {
410 PEXT2_IO_CONTEXT PtrContext = Contxt;
411
412 if( Irp->PendingReturned )
413 IoMarkIrpPending( Irp );
414
415 ASSERT( PtrContext );
416 ASSERT( PtrContext->NodeIdentifier.NodeType == EXT2_NODE_TYPE_IO_CONTEXT );
417
418 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext );
419 ExFreePool( PtrContext );
420
421 return STATUS_SUCCESS;
422 }
423
424 /*************************************************************************
425 *
426 * Function: Ext2MultiSyncCompletionRoutine()
427 *
428 * Description:
429 * Synchronous I/O Completion Routine
430 *
431 * Expected Interrupt Level (for execution) :
432 *
433 * ?
434 *
435 * Return Value: NTSTATUS - STATUS_SUCCESS(always)
436 *
437 *************************************************************************/
438 NTSTATUS NTAPI Ext2MultiSyncCompletionRoutine (
439 IN PDEVICE_OBJECT DeviceObject,
440 IN PIRP Irp,
441 IN PVOID Contxt
442 )
443 {
444
445 PEXT2_IO_CONTEXT PtrContext = Contxt;
446 ASSERT( PtrContext );
447
448 if( Irp->PendingReturned )
449 {
450 IoMarkIrpPending( Irp );
451 }
452
453 if (!NT_SUCCESS( Irp->IoStatus.Status ))
454 {
455 PtrContext->PtrMasterIrp->IoStatus.Status = Irp->IoStatus.Status;
456 }
457
458 if (InterlockedDecrement( &PtrContext->Count ) == 0)
459 {
460 if ( NT_SUCCESS( PtrContext->PtrMasterIrp->IoStatus.Status ) )
461 {
462 PtrContext->PtrMasterIrp->IoStatus.Information = PtrContext->ReadWriteLength;
463 }
464 else
465 {
466 PtrContext->PtrMasterIrp->IoStatus.Information = 0;
467 }
468
469 KeSetEvent( PtrContext->PtrSyncEvent, 0, FALSE );
470 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext );
471 ExFreePool( PtrContext );
472 }
473
474 //
475 // The master Irp will be automatically completed
476 // when all the associated IRPs are completed
477 //
478 return STATUS_SUCCESS;
479 }
480
481 /*************************************************************************
482 *
483 * Function: Ext2MultiAsyncCompletionRoutine()
484 *
485 * Description:
486 * Asynchronous I/O Completion Routine
487 *
488 * Expected Interrupt Level (for execution) :
489 *
490 * ?
491 *
492 * Return Value: NTSTATUS - STATUS_SUCCESS(always)
493 *
494 *************************************************************************/
495 NTSTATUS NTAPI Ext2MultiAsyncCompletionRoutine (
496 IN PDEVICE_OBJECT DeviceObject,
497 IN PIRP Irp,
498 IN PVOID Contxt
499 )
500 {
501
502 PEXT2_IO_CONTEXT PtrContext = Contxt;
503 ASSERT( PtrContext );
504
505 if( Irp->PendingReturned )
506 {
507 IoMarkIrpPending( Irp );
508 }
509
510 if (!NT_SUCCESS( Irp->IoStatus.Status ))
511 {
512 PtrContext->PtrMasterIrp->IoStatus.Status = Irp->IoStatus.Status;
513 }
514
515 if (InterlockedDecrement( &PtrContext->Count ) == 0)
516 {
517 if ( NT_SUCCESS( PtrContext->PtrMasterIrp->IoStatus.Status ) )
518 {
519 PtrContext->PtrMasterIrp->IoStatus.Information = PtrContext->ReadWriteLength;
520 }
521 else
522 {
523 PtrContext->PtrMasterIrp->IoStatus.Information = 0;
524 }
525 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [io]", PtrContext );
526 ExFreePool( PtrContext );
527 }
528
529 //
530 // The master Irp will be automatically completed
531 // when all the associated IRPs are completed
532 // Returning STATUS_SUCCESS to continue postprocessing...
533 //
534 return STATUS_SUCCESS;
535 }