2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/filesystems/fastfat/blockdev.c
5 * PURPOSE: Temporary sector reading support
6 * PROGRAMMERS: Alexey Vlasov
9 /* INCLUDES *****************************************************************/
14 /* FUNCTIONS ***************************************************************/
15 //FIXME: There is a conflicting function FatPerformDevIoCtrl doing same thing!
18 IN PDEVICE_OBJECT DeviceObject
,
21 IN ULONG InputBufferSize
,
22 IN OUT PVOID OutputBuffer
,
23 IN OUT PULONG OutputBufferSize OPTIONAL
)
29 IO_STATUS_BLOCK IoStatus
;
31 /* Set out buffer size if it was supplied. */
32 OutBufferSize
= (ARGUMENT_PRESENT(OutputBufferSize
)
33 ? 0 : *OutputBufferSize
);
35 /* Initialize event if the operation will be pended. */
36 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
39 Irp
= IoBuildDeviceIoControlRequest(IoCtlCode
, DeviceObject
,
40 InputBuffer
, InputBufferSize
, OutputBuffer
, OutBufferSize
,
41 FALSE
, &Event
, &IoStatus
);
43 return STATUS_INSUFFICIENT_RESOURCES
;
45 /* Send IRP to Disk Device */
46 Status
= IoCallDriver(DeviceObject
, Irp
);
47 if (Status
== STATUS_PENDING
)
49 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
50 Status
= IoStatus
.Status
;
53 /* Return output buffer length if required. */
54 if (ARGUMENT_PRESENT(OutputBufferSize
))
55 *OutputBufferSize
= IoStatus
.Information
;
61 IN PFAT_IRP_CONTEXT IrpContext
,
62 IN LOCK_OPERATION Operation
,
63 IN ULONG BufferLength
)
69 * IrpContext = Pointer to FCB structure for the file.
70 * Operation = Type of lock operation.
71 * BufferLength = Buffer length to be locked.
72 * RETURNS: Status Value.
81 Irp
= IrpContext
->Irp
;
82 Status
= STATUS_SUCCESS
;
83 if (Irp
->MdlAddress
== NULL
)
86 Mdl
= IoAllocateMdl(Irp
->UserBuffer
,
87 BufferLength
, FALSE
, FALSE
, Irp
);
89 return STATUS_INSUFFICIENT_RESOURCES
;
92 MmProbeAndLockPages(Mdl
,
93 Irp
->RequestorMode
, Operation
);
95 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
97 Status
= _SEH2_GetExceptionCode();
99 Irp
->MdlAddress
= NULL
;
106 FatIoSyncCompletionRoutine(
107 IN PDEVICE_OBJECT DeviceObject
,
111 PFAT_IO_CONTEXT IoContext
;
113 IoContext
= (PFAT_IO_CONTEXT
) Context
;
115 /* Check if this is an associated irp. */
116 if (Irp
!= IoContext
->Irp
)
118 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
119 IoContext
->Irp
->IoStatus
= Irp
->IoStatus
;
120 IoFreeMdl(Irp
->MdlAddress
);
122 if (InterlockedDecrement(&IoContext
->RunCount
) != 0)
123 return STATUS_MORE_PROCESSING_REQUIRED
;
124 /* This was the last run, update master irp. */
125 if (NT_SUCCESS(IoContext
->Irp
->IoStatus
.Status
))
126 IoContext
->Irp
->IoStatus
.Information
= IoContext
->Length
;
129 /* This is the last associated irp or a single irp IO. */
130 if (NT_SUCCESS(IoContext
->Irp
->IoStatus
.Status
) &&
131 !FlagOn(IoContext
->Irp
->Flags
, IRP_PAGING_IO
))
133 /* Maintain FileObject CurrentByteOffset */
134 IoContext
->FileObject
->CurrentByteOffset
.QuadPart
=
135 IoContext
->Offset
+ IoContext
->Irp
->IoStatus
.Information
;
138 /* Signal about completion. */
139 KeSetEvent(&IoContext
->Wait
.SyncEvent
, 0, FALSE
);
140 return STATUS_MORE_PROCESSING_REQUIRED
;
144 FatIoAsyncCompletionRoutine(
145 IN PDEVICE_OBJECT DeviceObject
,
149 PFAT_IO_CONTEXT IoContext
;
151 IoContext
= (PFAT_IO_CONTEXT
) Context
;
153 /* Check if this is an associated irp. */
154 if (Irp
!= IoContext
->Irp
)
156 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
157 IoContext
->Irp
->IoStatus
= Irp
->IoStatus
;
158 IoFreeMdl(Irp
->MdlAddress
);
160 if (InterlockedDecrement(&IoContext
->RunCount
) != 0)
161 return STATUS_MORE_PROCESSING_REQUIRED
;
162 /* This was the last run, update master irp. */
163 if (NT_SUCCESS(IoContext
->Irp
->IoStatus
.Status
))
164 IoContext
->Irp
->IoStatus
.Information
= IoContext
->Length
;
168 /* This is the last associated irp or a single irp IO. */
169 if (NT_SUCCESS(IoContext
->Irp
->IoStatus
.Status
) &&
170 !FlagOn(IoContext
->Irp
->Flags
, IRP_PAGING_IO
))
172 /* Maintain FileObject Flags */
173 if (IoGetCurrentIrpStackLocation(IoContext
->Irp
)->MajorFunction
176 SetFlag(IoContext
->FileObject
->Flags
, FO_FILE_FAST_IO_READ
);
180 SetFlag(IoContext
->FileObject
->Flags
, FO_FILE_MODIFIED
);
183 if (IoContext
->Wait
.Async
.Resource
!= NULL
)
184 ExReleaseResourceForThreadLite(
185 IoContext
->Wait
.Async
.Resource
,
186 IoContext
->Wait
.Async
.ResourceThreadId
);
188 if (IoContext
->Wait
.Async
.PagingIoResource
!= NULL
)
189 ExReleaseResourceForThreadLite(
190 IoContext
->Wait
.Async
.PagingIoResource
,
191 IoContext
->Wait
.Async
.ResourceThreadId
);
193 IoMarkIrpPending(Irp
);
195 return STATUS_SUCCESS
;
201 IN PFAT_IRP_CONTEXT IrpContext
,
202 IN PLARGE_INTEGER Offset
,
205 BOOLEAN CanWait
, ReadOperation
;
206 PIO_STACK_LOCATION IoStack
;
208 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
209 ReadOperation
= (IrpContext
->Stack
->MajorFunction
== IRP_MJ_READ
);
211 /* Allocate completion context */
212 IrpContext
->FatIoContext
= FsRtlAllocatePoolWithTag(
213 NonPagedPool
, sizeof(FAT_IO_CONTEXT
), (ULONG
) 'xCoI');
215 if (IrpContext
->FatIoContext
== NULL
)
216 return STATUS_INSUFFICIENT_RESOURCES
;
218 RtlZeroMemory(IrpContext
->FatIoContext
,
219 sizeof(FAT_IO_CONTEXT
));
221 /* Initialize event if we are supposed to wait. */
225 &IrpContext
->FatIoContext
->Wait
.SyncEvent
,
226 NotificationEvent
, FALSE
);
229 /* Set the completion routine depending on wait semantics. */
230 IoSetCompletionRoutine(IrpContext
->Irp
,
232 ? FatIoSyncCompletionRoutine
233 : FatIoAsyncCompletionRoutine
),
234 IrpContext
->FatIoContext
, TRUE
, TRUE
, TRUE
);
236 /* Setup stack location. */
237 IoStack
= IoGetNextIrpStackLocation(IrpContext
->Irp
);
238 IoStack
->MajorFunction
= IrpContext
->MajorFunction
;
239 IoStack
->Parameters
.Read
.Length
= (ULONG
) Length
;
240 IoStack
->Parameters
.Read
.ByteOffset
= *Offset
;
241 if (FlagOn(IrpContext
->Flags
, IRPCONTEXT_WRITETHROUGH
))
242 SetFlag(IoStack
->Flags
, SL_WRITE_THROUGH
);
245 IrpContext
->Vcb
->TargetDeviceObject
,
249 KeWaitForSingleObject(
250 &IrpContext
->FatIoContext
->Wait
.SyncEvent
,
251 Executive
, KernelMode
, FALSE
, NULL
);
252 return IrpContext
->Irp
->IoStatus
.Status
;
254 SetFlag(IrpContext
->Flags
, IRPCONTEXT_STACK_IO_CONTEXT
);
255 return STATUS_PENDING
;
261 FatPerformVirtualNonCachedIo(
262 IN PFAT_IRP_CONTEXT IrpContext
,
264 IN PLARGE_INTEGER Offset
,
268 PIO_STACK_LOCATION IoStack
;
269 LONGLONG Vbo
, Lbo
, RunLength
;
270 ULONG RunCount
, CleanupIndex
, FirstIndex
, BeyoundLastIndex
;
271 BOOLEAN CanWait
, ReadOperation
;
275 ASSERT(IrpContext
->FatIoContext
== NULL
);
278 FirstIndex
= CleanupIndex
= 0;
279 CanWait
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
280 ReadOperation
= (IrpContext
->Stack
->MajorFunction
== IRP_MJ_READ
);
281 Status
= FatLockUserBuffer(IrpContext
,
282 (ReadOperation
? IoWriteAccess
: IoReadAccess
),
284 if (!NT_SUCCESS(Status
))
285 goto FatIoPerformNonCachedCleanup
;
286 Vbo
= Offset
->QuadPart
;
290 BeyoundLastIndex
= FatScanFat(Fcb
, Vbo
,
291 &Lbo
, &RunLength
, &FirstIndex
, CanWait
);
293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
295 Status
= _SEH2_GetExceptionCode();
296 _SEH2_YIELD(goto FatIoPerformNonCachedCleanup
;)
298 RunCount
= BeyoundLastIndex
- FirstIndex
;
301 Status
= STATUS_END_OF_FILE
;
302 goto FatIoPerformNonCachedCleanup
;
304 Length
= sizeof(FAT_IO_CONTEXT
);
306 Length
+= RunCount
* sizeof(PIRP
);
307 IrpContext
->FatIoContext
= FsRtlAllocatePoolWithTag(
308 NonPagedPool
, Length
, (ULONG
) 'xCoI');
309 if (IrpContext
->FatIoContext
== NULL
)
311 Status
= STATUS_INSUFFICIENT_RESOURCES
;
312 goto FatIoPerformNonCachedCleanup
;
314 RtlZeroMemory(IrpContext
->FatIoContext
, Length
);
318 &IrpContext
->FatIoContext
->Wait
.SyncEvent
,
319 NotificationEvent
, FALSE
);
323 IoSetCompletionRoutine(IrpContext
->Irp
,
324 (CanWait
? FatIoSyncCompletionRoutine
325 : FatIoAsyncCompletionRoutine
),
326 IrpContext
->FatIoContext
, TRUE
, TRUE
, TRUE
);
327 IoStack
= IoGetNextIrpStackLocation(IrpContext
->Irp
);
328 IoStack
->MajorFunction
= IrpContext
->Stack
->MajorFunction
;
329 IoStack
->Parameters
.Read
.Length
= (ULONG
) RunLength
;
330 IoStack
->Parameters
.Read
.ByteOffset
.QuadPart
= Lbo
;
331 IoStack
->Flags
= FlagOn(
332 IrpContext
->Stack
->Flags
,
334 Status
= IoCallDriver(
335 IrpContext
->Vcb
->TargetDeviceObject
,
337 goto FatIoPerformNonCachedComplete
;
340 * We already have the first run retrieved by FatiScanFat.
342 for (RunIrp
= &IrpContext
->FatIoContext
->Irp
,
343 CleanupIndex
= FirstIndex
;
344 CleanupIndex
< BeyoundLastIndex
;
345 CleanupIndex
++, RunIrp
++)
348 LONGLONG NextVbo
= Vbo
+ RunLength
;
352 * Allocate Irp for the run.
354 *RunIrp
= IoMakeAssociatedIrp(IrpContext
->Irp
,
355 (CCHAR
)(IrpContext
->Vcb
->TargetDeviceObject
->StackSize
+ 1));
358 Status
= STATUS_INSUFFICIENT_RESOURCES
;
359 goto FatIoPerformNonCachedCleanup
;
363 * Build Mdl for the run range.
366 Add2Ptr(IrpContext
->Irp
->UserBuffer
, Vbo
, PVOID
),
367 (ULONG
) RunLength
, FALSE
, FALSE
, *RunIrp
);
370 Status
= STATUS_INSUFFICIENT_RESOURCES
;
371 goto FatIoPerformNonCachedCleanup
;
373 IoBuildPartialMdl(IrpContext
->Irp
->MdlAddress
, Mdl
,
374 Add2Ptr(IrpContext
->Irp
->UserBuffer
, Vbo
, PVOID
),
377 * Setup IRP for each run.
379 IoSetCompletionRoutine(IrpContext
->Irp
,
380 (CanWait
? FatIoSyncCompletionRoutine
381 : FatIoAsyncCompletionRoutine
),
382 IrpContext
->FatIoContext
, TRUE
, TRUE
, TRUE
);
383 IoStack
= IoGetNextIrpStackLocation(*RunIrp
);
384 IoStack
->MajorFunction
= IrpContext
->Stack
->MajorFunction
;
385 IoStack
->Parameters
.Read
.Length
= (ULONG
) RunLength
;
386 IoStack
->Parameters
.Read
.ByteOffset
.QuadPart
= Lbo
;
389 * Propagate write-through to the associated IRPs
391 if (FlagOn(IrpContext
->Flags
, IRPCONTEXT_WRITETHROUGH
))
392 SetFlag(IoStack
->Flags
, SL_WRITE_THROUGH
);
394 * Prepare for next iteration:
399 FsRtlGetNextLargeMcbEntry(&Fcb
->Mcb
, CleanupIndex
, &Vbo
, &Lbo
, &RunLength
);
401 ASSERT(NextVbo
== Vbo
);
404 * Send all IRPs to the volume device, we don't need to check
405 * status code because cleanup will be done
406 * by the completion routine in any case.
408 for (RunIrp
= &IrpContext
->FatIoContext
->Irp
,
409 CleanupIndex
= FirstIndex
;
410 CleanupIndex
< BeyoundLastIndex
;
411 CleanupIndex
++, RunIrp
++)
413 IoCallDriver(IrpContext
->Vcb
->TargetDeviceObject
, *RunIrp
);
416 FatIoPerformNonCachedComplete
:
419 KeWaitForSingleObject(
420 &IrpContext
->FatIoContext
->Wait
.SyncEvent
,
421 Executive
, KernelMode
, FALSE
, NULL
);
422 return IrpContext
->Irp
->IoStatus
.Status
;
424 SetFlag(IrpContext
->Flags
, IRPCONTEXT_STACK_IO_CONTEXT
);
425 return STATUS_PENDING
;
427 * The following block of code implements unwind logic
429 FatIoPerformNonCachedCleanup
:
430 if (IrpContext
->FatIoContext
!= NULL
)
432 RunIrp
= &IrpContext
->FatIoContext
->Irp
;
433 while (FirstIndex
< CleanupIndex
)
435 if ((*RunIrp
)->MdlAddress
!= NULL
)
436 IoFreeMdl((*RunIrp
)->MdlAddress
);
441 ExFreePool(IrpContext
->FatIoContext
);
442 IrpContext
->FatIoContext
= NULL
;