c91ae3a670148d3e4cb66cc96a38575d60a01b63
[reactos.git] / reactos / drivers / filesystems / fastfat_new / blockdev.c
1 /*
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
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "fastfat.h"
13
14 /* FUNCTIONS ***************************************************************/
15 //FIXME: There is a conflicting function FatPerformDevIoCtrl doing same thing!
16 NTSTATUS
17 FatDiskIoControl_(
18 IN PDEVICE_OBJECT DeviceObject,
19 IN ULONG IoCtlCode,
20 IN PVOID InputBuffer,
21 IN ULONG InputBufferSize,
22 IN OUT PVOID OutputBuffer,
23 IN OUT PULONG OutputBufferSize OPTIONAL)
24 {
25 PIRP Irp;
26 KEVENT Event;
27 NTSTATUS Status;
28 ULONG OutBufferSize;
29 IO_STATUS_BLOCK IoStatus;
30
31 /* Set out buffer size if it was supplied. */
32 OutBufferSize = (ARGUMENT_PRESENT(OutputBufferSize)
33 ? 0 : *OutputBufferSize);
34
35 /* Initialize event if the operation will be pended. */
36 KeInitializeEvent(&Event, NotificationEvent, FALSE);
37
38 /* Build the Irp. */
39 Irp = IoBuildDeviceIoControlRequest(IoCtlCode, DeviceObject,
40 InputBuffer, InputBufferSize, OutputBuffer, OutBufferSize,
41 FALSE, &Event, &IoStatus);
42 if (Irp == NULL)
43 return STATUS_INSUFFICIENT_RESOURCES;
44
45 /* Send IRP to Disk Device */
46 Status = IoCallDriver(DeviceObject, Irp);
47 if (Status == STATUS_PENDING)
48 {
49 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
50 Status = IoStatus.Status;
51 }
52
53 /* Return output buffer length if required. */
54 if (ARGUMENT_PRESENT(OutputBufferSize))
55 *OutputBufferSize = IoStatus.Information;
56 return Status;
57 }
58
59 PVOID
60 FatMapUserBuffer(
61 IN OUT PIRP Irp)
62 /*
63 * FUNCTION:
64 *
65 *
66 * ARGUMENTS:
67 * IrpContext = Pointer to FCB structure for the file.
68 * Irp = Pointer to the IRP structure
69 * RETURNS: Status Value.
70 * NOTES:
71 */
72 {
73 PVOID Address;
74
75 if (Irp->MdlAddress == NULL)
76 return Irp->UserBuffer;
77 Address = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
78 if (Address == NULL)
79 ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
80 return Address;
81 }
82
83 NTSTATUS
84 FatLockUserBuffer (
85 IN PFAT_IRP_CONTEXT IrpContext,
86 IN LOCK_OPERATION Operation,
87 IN ULONG BufferLength)
88 /*
89 * FUNCTION:
90 *
91 *
92 * ARGUMENTS:
93 * IrpContext = Pointer to FCB structure for the file.
94 * Operation = Type of lock operation.
95 * BufferLength = Buffer length to be locked.
96 * RETURNS: Status Value.
97 * NOTES:
98 */
99 {
100 PMDL Mdl;
101 PIRP Irp;
102 NTSTATUS Status;
103
104 Mdl = NULL;
105 Irp = IrpContext->Irp;
106 Status = STATUS_SUCCESS;
107 if (Irp->MdlAddress == NULL)
108 {
109 NTSTATUS Status;
110 Mdl = IoAllocateMdl(Irp->UserBuffer,
111 BufferLength, FALSE, FALSE, Irp);
112 if (Mdl == NULL)
113 return STATUS_INSUFFICIENT_RESOURCES;
114 _SEH2_TRY
115 {
116 MmProbeAndLockPages(Mdl,
117 Irp->RequestorMode, Operation);
118 }
119 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
120 {
121 Status = _SEH2_GetExceptionCode();
122 IoFreeMdl( Mdl );
123 Irp->MdlAddress = NULL;
124 } _SEH2_END
125 }
126 return Status;
127 }
128
129 NTSTATUS
130 FatIoSyncCompletionRoutine(
131 IN PDEVICE_OBJECT DeviceObject,
132 IN PIRP Irp,
133 IN PVOID Context)
134 {
135 PFAT_IO_CONTEXT IoContext;
136
137 IoContext = (PFAT_IO_CONTEXT) Context;
138
139 /* Check if this is an associated irp. */
140 if (Irp != IoContext->Irp)
141 {
142 if (!NT_SUCCESS(Irp->IoStatus.Status))
143 IoContext->Irp->IoStatus = Irp->IoStatus;
144 IoFreeMdl(Irp->MdlAddress);
145 IoFreeIrp(Irp);
146 if (InterlockedDecrement(&IoContext->RunCount) != 0)
147 return STATUS_MORE_PROCESSING_REQUIRED;
148 /* This was the last run, update master irp. */
149 if (NT_SUCCESS(IoContext->Irp->IoStatus.Status))
150 IoContext->Irp->IoStatus.Information = IoContext->Length;
151 }
152
153 /* This is the last associated irp or a single irp IO. */
154 if (NT_SUCCESS(IoContext->Irp->IoStatus.Status) &&
155 !FlagOn(IoContext->Irp->Flags, IRP_PAGING_IO))
156 {
157 /* Maintain FileObject CurrentByteOffset */
158 IoContext->FileObject->CurrentByteOffset.QuadPart =
159 IoContext->Offset + IoContext->Irp->IoStatus.Information;
160 }
161
162 /* Signal about completion. */
163 KeSetEvent(&IoContext->Wait.SyncEvent, 0, FALSE);
164 return STATUS_MORE_PROCESSING_REQUIRED;
165 }
166
167 NTSTATUS
168 FatIoAsyncCompletionRoutine(
169 IN PDEVICE_OBJECT DeviceObject,
170 IN PIRP Irp,
171 IN PVOID Context)
172 {
173 PFAT_IO_CONTEXT IoContext;
174
175 IoContext = (PFAT_IO_CONTEXT) Context;
176
177 /* Check if this is an associated irp. */
178 if (Irp != IoContext->Irp)
179 {
180 if (!NT_SUCCESS(Irp->IoStatus.Status))
181 IoContext->Irp->IoStatus = Irp->IoStatus;
182 IoFreeMdl(Irp->MdlAddress);
183 IoFreeIrp(Irp);
184 if (InterlockedDecrement(&IoContext->RunCount) != 0)
185 return STATUS_MORE_PROCESSING_REQUIRED;
186 /* This was the last run, update master irp. */
187 if (NT_SUCCESS(IoContext->Irp->IoStatus.Status))
188 IoContext->Irp->IoStatus.Information = IoContext->Length;
189 }
190
191
192 /* This is the last associated irp or a single irp IO. */
193 if (NT_SUCCESS(IoContext->Irp->IoStatus.Status) &&
194 !FlagOn(IoContext->Irp->Flags, IRP_PAGING_IO))
195 {
196 /* Maintain FileObject Flags */
197 if (IoGetCurrentIrpStackLocation(IoContext->Irp)->MajorFunction
198 == IRP_MJ_READ)
199 {
200 SetFlag(IoContext->FileObject->Flags, FO_FILE_FAST_IO_READ);
201 }
202 else
203 {
204 SetFlag(IoContext->FileObject->Flags, FO_FILE_MODIFIED);
205 }
206 }
207 if (IoContext->Wait.Async.Resource != NULL)
208 ExReleaseResourceForThreadLite(
209 IoContext->Wait.Async.Resource,
210 IoContext->Wait.Async.ResourceThreadId);
211
212 if (IoContext->Wait.Async.PagingIoResource != NULL)
213 ExReleaseResourceForThreadLite(
214 IoContext->Wait.Async.PagingIoResource,
215 IoContext->Wait.Async.ResourceThreadId);
216
217 IoMarkIrpPending(Irp);
218 ExFreePool(Context);
219 return STATUS_SUCCESS;
220 }
221
222 NTSTATUS
223 NTAPI
224 FatPerformLboIo(
225 IN PFAT_IRP_CONTEXT IrpContext,
226 IN PLARGE_INTEGER Offset,
227 IN SIZE_T Length)
228 {
229 BOOLEAN CanWait, ReadOperation;
230 PIO_STACK_LOCATION IoStack;
231
232 CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT);
233 ReadOperation = (IrpContext->Stack->MajorFunction == IRP_MJ_READ);
234
235 /* Allocate completion context */
236 IrpContext->FatIoContext = FsRtlAllocatePoolWithTag(
237 NonPagedPool, sizeof(FAT_IO_CONTEXT), (ULONG) 'xCoI');
238
239 if (IrpContext->FatIoContext == NULL)
240 return STATUS_INSUFFICIENT_RESOURCES;
241
242 RtlZeroMemory(IrpContext->FatIoContext,
243 sizeof(FAT_IO_CONTEXT));
244
245 /* Initialize event if we are supposed to wait. */
246 if (CanWait)
247 {
248 KeInitializeEvent(
249 &IrpContext->FatIoContext->Wait.SyncEvent,
250 NotificationEvent, FALSE);
251 }
252
253 /* Set the completion routine depending on wait semantics. */
254 IoSetCompletionRoutine(IrpContext->Irp,
255 (CanWait
256 ? FatIoSyncCompletionRoutine
257 : FatIoAsyncCompletionRoutine),
258 IrpContext->FatIoContext, TRUE, TRUE, TRUE);
259
260 /* Setup stack location. */
261 IoStack = IoGetNextIrpStackLocation(IrpContext->Irp);
262 IoStack->MajorFunction = IrpContext->MajorFunction;
263 IoStack->Parameters.Read.Length = (ULONG) Length;
264 IoStack->Parameters.Read.ByteOffset = *Offset;
265 if (FlagOn(IrpContext->Flags, IRPCONTEXT_WRITETHROUGH))
266 SetFlag(IoStack->Flags, SL_WRITE_THROUGH);
267
268 IoCallDriver(
269 IrpContext->Vcb->TargetDeviceObject,
270 IrpContext->Irp);
271 if (CanWait)
272 {
273 KeWaitForSingleObject(
274 &IrpContext->FatIoContext->Wait.SyncEvent,
275 Executive, KernelMode, FALSE, NULL);
276 return IrpContext->Irp->IoStatus.Status;
277 }
278 SetFlag(IrpContext->Flags, IRPCONTEXT_STACK_IO_CONTEXT);
279 return STATUS_PENDING;
280 }
281
282
283
284 NTSTATUS
285 FatPerformVirtualNonCachedIo(
286 IN PFAT_IRP_CONTEXT IrpContext,
287 IN PFCB Fcb,
288 IN PLARGE_INTEGER Offset,
289 IN SIZE_T Length)
290 {
291 NTSTATUS Status;
292 PIO_STACK_LOCATION IoStack;
293 LONGLONG Vbo, Lbo, RunLength;
294 ULONG RunCount, CleanupIndex, FirstIndex, BeyoundLastIndex;
295 BOOLEAN CanWait, ReadOperation;
296 PIRP* RunIrp;
297 PMDL Mdl;
298
299 ASSERT(IrpContext->FatIoContext == NULL);
300
301
302 FirstIndex = CleanupIndex = 0;
303 CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT);
304 ReadOperation = (IrpContext->Stack->MajorFunction == IRP_MJ_READ);
305 Status = FatLockUserBuffer(IrpContext,
306 (ReadOperation ? IoWriteAccess : IoReadAccess),
307 Length);
308 if (!NT_SUCCESS(Status))
309 goto FatIoPerformNonCachedCleanup;
310 Vbo = Offset->QuadPart;
311 RunLength = Length;
312 _SEH2_TRY
313 {
314 BeyoundLastIndex = FatScanFat(Fcb, Vbo,
315 &Lbo, &RunLength, &FirstIndex, CanWait);
316 }
317 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
318 {
319 Status = _SEH2_GetExceptionCode();
320 _SEH2_YIELD(goto FatIoPerformNonCachedCleanup;)
321 }_SEH2_END
322 RunCount = BeyoundLastIndex - FirstIndex;
323 if (RunCount == 0)
324 {
325 Status = STATUS_END_OF_FILE;
326 goto FatIoPerformNonCachedCleanup;
327 }
328 Length = sizeof(FAT_IO_CONTEXT);
329 if (RunCount > 0x1)
330 Length += RunCount * sizeof(PIRP);
331 IrpContext->FatIoContext = FsRtlAllocatePoolWithTag(
332 NonPagedPool, Length, (ULONG) 'xCoI');
333 if (IrpContext->FatIoContext == NULL)
334 {
335 Status = STATUS_INSUFFICIENT_RESOURCES;
336 goto FatIoPerformNonCachedCleanup;
337 }
338 RtlZeroMemory(IrpContext->FatIoContext, Length);
339 if (CanWait)
340 {
341 KeInitializeEvent(
342 &IrpContext->FatIoContext->Wait.SyncEvent,
343 NotificationEvent, FALSE);
344 }
345 if (RunCount == 0x1)
346 {
347 IoSetCompletionRoutine(IrpContext->Irp,
348 (CanWait ? FatIoSyncCompletionRoutine
349 : FatIoAsyncCompletionRoutine),
350 IrpContext->FatIoContext, TRUE, TRUE, TRUE);
351 IoStack = IoGetNextIrpStackLocation(IrpContext->Irp);
352 IoStack->MajorFunction = IrpContext->Stack->MajorFunction;
353 IoStack->Parameters.Read.Length = (ULONG) RunLength;
354 IoStack->Parameters.Read.ByteOffset.QuadPart = Lbo;
355 IoStack->Flags = FlagOn(
356 IrpContext->Stack->Flags,
357 SL_WRITE_THROUGH);
358 Status = IoCallDriver(
359 IrpContext->Vcb->TargetDeviceObject,
360 IrpContext->Irp);
361 goto FatIoPerformNonCachedComplete;
362 }
363 /*
364 * We already have the first run retrieved by FatiScanFat.
365 */
366 for (RunIrp = &IrpContext->FatIoContext->Irp,
367 CleanupIndex = FirstIndex;
368 CleanupIndex < BeyoundLastIndex;
369 CleanupIndex ++, RunIrp ++)
370 {
371 #if DBG
372 LONGLONG NextVbo = Vbo + RunLength;
373 BOOLEAN RunExists;
374 #endif
375 /*
376 * Allocate Irp for the run.
377 */
378 *RunIrp = IoMakeAssociatedIrp(IrpContext->Irp,
379 (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1));
380 if (*RunIrp == NULL)
381 {
382 Status = STATUS_INSUFFICIENT_RESOURCES;
383 goto FatIoPerformNonCachedCleanup;
384 }
385 CleanupIndex ++;
386 /*
387 * Build Mdl for the run range.
388 */
389 Mdl = IoAllocateMdl(
390 Add2Ptr(IrpContext->Irp->UserBuffer, Vbo, PVOID),
391 (ULONG) RunLength, FALSE, FALSE, *RunIrp);
392 if (Mdl == NULL)
393 {
394 Status = STATUS_INSUFFICIENT_RESOURCES;
395 goto FatIoPerformNonCachedCleanup;
396 }
397 IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Mdl,
398 Add2Ptr(IrpContext->Irp->UserBuffer, Vbo, PVOID),
399 (ULONG) RunLength);
400 /*
401 * Setup IRP for each run.
402 */
403 IoSetCompletionRoutine(IrpContext->Irp,
404 (CanWait ? FatIoSyncCompletionRoutine
405 : FatIoAsyncCompletionRoutine),
406 IrpContext->FatIoContext, TRUE, TRUE, TRUE);
407 IoStack = IoGetNextIrpStackLocation(*RunIrp);
408 IoStack->MajorFunction = IrpContext->Stack->MajorFunction;
409 IoStack->Parameters.Read.Length = (ULONG) RunLength;
410 IoStack->Parameters.Read.ByteOffset.QuadPart = Lbo;
411
412 /*
413 * Propagate write-through to the associated IRPs
414 */
415 if (FlagOn(IrpContext->Flags, IRPCONTEXT_WRITETHROUGH))
416 SetFlag(IoStack->Flags, SL_WRITE_THROUGH);
417 /*
418 * Prepare for next iteration:
419 */
420 #if DBG
421 RunExists =
422 #endif
423 FsRtlGetNextLargeMcbEntry(&Fcb->Mcb, CleanupIndex, &Vbo, &Lbo, &RunLength);
424 ASSERT(RunExists);
425 ASSERT(NextVbo == Vbo);
426 }
427 /*
428 * Send all IRPs to the volume device, we don't need to check
429 * status code because cleanup will be done
430 * by the completion routine in any case.
431 */
432 for (RunIrp = &IrpContext->FatIoContext->Irp,
433 CleanupIndex = FirstIndex;
434 CleanupIndex < BeyoundLastIndex;
435 CleanupIndex ++, RunIrp ++)
436 {
437 IoCallDriver(IrpContext->Vcb->TargetDeviceObject, *RunIrp);
438 }
439
440 FatIoPerformNonCachedComplete:
441 if (CanWait)
442 {
443 KeWaitForSingleObject(
444 &IrpContext->FatIoContext->Wait.SyncEvent,
445 Executive, KernelMode, FALSE, NULL);
446 return IrpContext->Irp->IoStatus.Status;
447 }
448 SetFlag(IrpContext->Flags, IRPCONTEXT_STACK_IO_CONTEXT);
449 return STATUS_PENDING;
450 /*
451 * The following block of code implements unwind logic
452 */
453 FatIoPerformNonCachedCleanup:
454 if (IrpContext->FatIoContext != NULL)
455 {
456 RunIrp = &IrpContext->FatIoContext->Irp;
457 while (FirstIndex < CleanupIndex)
458 {
459 if ((*RunIrp)->MdlAddress != NULL)
460 IoFreeMdl((*RunIrp)->MdlAddress);
461 IoFreeIrp(*RunIrp);
462 FirstIndex ++;
463 RunIrp ++;
464 }
465 ExFreePool(IrpContext->FatIoContext);
466 IrpContext->FatIoContext = NULL;
467 }
468 return Status;
469 }
470
471 /* EOF */