8e1d0fbe8c0c7bfe3101abb97dd0b2b08578775c
[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 NTSTATUS
60 FatLockUserBuffer (
61 IN PFAT_IRP_CONTEXT IrpContext,
62 IN LOCK_OPERATION Operation,
63 IN ULONG BufferLength)
64 /*
65 * FUNCTION:
66 *
67 *
68 * ARGUMENTS:
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.
73 * NOTES:
74 */
75 {
76 PMDL Mdl;
77 PIRP Irp;
78 NTSTATUS Status;
79
80 Mdl = NULL;
81 Irp = IrpContext->Irp;
82 Status = STATUS_SUCCESS;
83 if (Irp->MdlAddress == NULL)
84 {
85 NTSTATUS Status;
86 Mdl = IoAllocateMdl(Irp->UserBuffer,
87 BufferLength, FALSE, FALSE, Irp);
88 if (Mdl == NULL)
89 return STATUS_INSUFFICIENT_RESOURCES;
90 _SEH2_TRY
91 {
92 MmProbeAndLockPages(Mdl,
93 Irp->RequestorMode, Operation);
94 }
95 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
96 {
97 Status = _SEH2_GetExceptionCode();
98 IoFreeMdl( Mdl );
99 Irp->MdlAddress = NULL;
100 } _SEH2_END
101 }
102 return Status;
103 }
104
105 NTSTATUS
106 FatIoSyncCompletionRoutine(
107 IN PDEVICE_OBJECT DeviceObject,
108 IN PIRP Irp,
109 IN PVOID Context)
110 {
111 PFAT_IO_CONTEXT IoContext;
112
113 IoContext = (PFAT_IO_CONTEXT) Context;
114
115 /* Check if this is an associated irp. */
116 if (Irp != IoContext->Irp)
117 {
118 if (!NT_SUCCESS(Irp->IoStatus.Status))
119 IoContext->Irp->IoStatus = Irp->IoStatus;
120 IoFreeMdl(Irp->MdlAddress);
121 IoFreeIrp(Irp);
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;
127 }
128
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))
132 {
133 /* Maintain FileObject CurrentByteOffset */
134 IoContext->FileObject->CurrentByteOffset.QuadPart =
135 IoContext->Offset + IoContext->Irp->IoStatus.Information;
136 }
137
138 /* Signal about completion. */
139 KeSetEvent(&IoContext->Wait.SyncEvent, 0, FALSE);
140 return STATUS_MORE_PROCESSING_REQUIRED;
141 }
142
143 NTSTATUS
144 FatIoAsyncCompletionRoutine(
145 IN PDEVICE_OBJECT DeviceObject,
146 IN PIRP Irp,
147 IN PVOID Context)
148 {
149 PFAT_IO_CONTEXT IoContext;
150
151 IoContext = (PFAT_IO_CONTEXT) Context;
152
153 /* Check if this is an associated irp. */
154 if (Irp != IoContext->Irp)
155 {
156 if (!NT_SUCCESS(Irp->IoStatus.Status))
157 IoContext->Irp->IoStatus = Irp->IoStatus;
158 IoFreeMdl(Irp->MdlAddress);
159 IoFreeIrp(Irp);
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;
165 }
166
167
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))
171 {
172 /* Maintain FileObject Flags */
173 if (IoGetCurrentIrpStackLocation(IoContext->Irp)->MajorFunction
174 == IRP_MJ_READ)
175 {
176 SetFlag(IoContext->FileObject->Flags, FO_FILE_FAST_IO_READ);
177 }
178 else
179 {
180 SetFlag(IoContext->FileObject->Flags, FO_FILE_MODIFIED);
181 }
182 }
183 if (IoContext->Wait.Async.Resource != NULL)
184 ExReleaseResourceForThreadLite(
185 IoContext->Wait.Async.Resource,
186 IoContext->Wait.Async.ResourceThreadId);
187
188 if (IoContext->Wait.Async.PagingIoResource != NULL)
189 ExReleaseResourceForThreadLite(
190 IoContext->Wait.Async.PagingIoResource,
191 IoContext->Wait.Async.ResourceThreadId);
192
193 IoMarkIrpPending(Irp);
194 ExFreePool(Context);
195 return STATUS_SUCCESS;
196 }
197
198 NTSTATUS
199 NTAPI
200 FatPerformLboIo(
201 IN PFAT_IRP_CONTEXT IrpContext,
202 IN PLARGE_INTEGER Offset,
203 IN SIZE_T Length)
204 {
205 BOOLEAN CanWait, ReadOperation;
206 PIO_STACK_LOCATION IoStack;
207
208 CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT);
209 ReadOperation = (IrpContext->Stack->MajorFunction == IRP_MJ_READ);
210
211 /* Allocate completion context */
212 IrpContext->FatIoContext = FsRtlAllocatePoolWithTag(
213 NonPagedPool, sizeof(FAT_IO_CONTEXT), (ULONG) 'xCoI');
214
215 if (IrpContext->FatIoContext == NULL)
216 return STATUS_INSUFFICIENT_RESOURCES;
217
218 RtlZeroMemory(IrpContext->FatIoContext,
219 sizeof(FAT_IO_CONTEXT));
220
221 /* Initialize event if we are supposed to wait. */
222 if (CanWait)
223 {
224 KeInitializeEvent(
225 &IrpContext->FatIoContext->Wait.SyncEvent,
226 NotificationEvent, FALSE);
227 }
228
229 /* Set the completion routine depending on wait semantics. */
230 IoSetCompletionRoutine(IrpContext->Irp,
231 (CanWait
232 ? FatIoSyncCompletionRoutine
233 : FatIoAsyncCompletionRoutine),
234 IrpContext->FatIoContext, TRUE, TRUE, TRUE);
235
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);
243
244 IoCallDriver(
245 IrpContext->Vcb->TargetDeviceObject,
246 IrpContext->Irp);
247 if (CanWait)
248 {
249 KeWaitForSingleObject(
250 &IrpContext->FatIoContext->Wait.SyncEvent,
251 Executive, KernelMode, FALSE, NULL);
252 return IrpContext->Irp->IoStatus.Status;
253 }
254 SetFlag(IrpContext->Flags, IRPCONTEXT_STACK_IO_CONTEXT);
255 return STATUS_PENDING;
256 }
257
258
259
260 NTSTATUS
261 FatPerformVirtualNonCachedIo(
262 IN PFAT_IRP_CONTEXT IrpContext,
263 IN PFCB Fcb,
264 IN PLARGE_INTEGER Offset,
265 IN SIZE_T Length)
266 {
267 NTSTATUS Status;
268 PIO_STACK_LOCATION IoStack;
269 LONGLONG Vbo, Lbo, RunLength;
270 ULONG RunCount, CleanupIndex, FirstIndex, BeyoundLastIndex;
271 BOOLEAN CanWait, ReadOperation;
272 PIRP* RunIrp;
273 PMDL Mdl;
274
275 ASSERT(IrpContext->FatIoContext == NULL);
276
277
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),
283 Length);
284 if (!NT_SUCCESS(Status))
285 goto FatIoPerformNonCachedCleanup;
286 Vbo = Offset->QuadPart;
287 RunLength = Length;
288 _SEH2_TRY
289 {
290 BeyoundLastIndex = FatScanFat(Fcb, Vbo,
291 &Lbo, &RunLength, &FirstIndex, CanWait);
292 }
293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
294 {
295 Status = _SEH2_GetExceptionCode();
296 _SEH2_YIELD(goto FatIoPerformNonCachedCleanup;)
297 }_SEH2_END
298 RunCount = BeyoundLastIndex - FirstIndex;
299 if (RunCount == 0)
300 {
301 Status = STATUS_END_OF_FILE;
302 goto FatIoPerformNonCachedCleanup;
303 }
304 Length = sizeof(FAT_IO_CONTEXT);
305 if (RunCount > 0x1)
306 Length += RunCount * sizeof(PIRP);
307 IrpContext->FatIoContext = FsRtlAllocatePoolWithTag(
308 NonPagedPool, Length, (ULONG) 'xCoI');
309 if (IrpContext->FatIoContext == NULL)
310 {
311 Status = STATUS_INSUFFICIENT_RESOURCES;
312 goto FatIoPerformNonCachedCleanup;
313 }
314 RtlZeroMemory(IrpContext->FatIoContext, Length);
315 if (CanWait)
316 {
317 KeInitializeEvent(
318 &IrpContext->FatIoContext->Wait.SyncEvent,
319 NotificationEvent, FALSE);
320 }
321 if (RunCount == 0x1)
322 {
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,
333 SL_WRITE_THROUGH);
334 Status = IoCallDriver(
335 IrpContext->Vcb->TargetDeviceObject,
336 IrpContext->Irp);
337 goto FatIoPerformNonCachedComplete;
338 }
339 /*
340 * We already have the first run retrieved by FatiScanFat.
341 */
342 for (RunIrp = &IrpContext->FatIoContext->Irp,
343 CleanupIndex = FirstIndex;
344 CleanupIndex < BeyoundLastIndex;
345 CleanupIndex ++, RunIrp ++)
346 {
347 #if DBG
348 LONGLONG NextVbo = Vbo + RunLength;
349 BOOLEAN RunExists;
350 #endif
351 /*
352 * Allocate Irp for the run.
353 */
354 *RunIrp = IoMakeAssociatedIrp(IrpContext->Irp,
355 (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1));
356 if (*RunIrp == NULL)
357 {
358 Status = STATUS_INSUFFICIENT_RESOURCES;
359 goto FatIoPerformNonCachedCleanup;
360 }
361 CleanupIndex ++;
362 /*
363 * Build Mdl for the run range.
364 */
365 Mdl = IoAllocateMdl(
366 Add2Ptr(IrpContext->Irp->UserBuffer, Vbo, PVOID),
367 (ULONG) RunLength, FALSE, FALSE, *RunIrp);
368 if (Mdl == NULL)
369 {
370 Status = STATUS_INSUFFICIENT_RESOURCES;
371 goto FatIoPerformNonCachedCleanup;
372 }
373 IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Mdl,
374 Add2Ptr(IrpContext->Irp->UserBuffer, Vbo, PVOID),
375 (ULONG) RunLength);
376 /*
377 * Setup IRP for each run.
378 */
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;
387
388 /*
389 * Propagate write-through to the associated IRPs
390 */
391 if (FlagOn(IrpContext->Flags, IRPCONTEXT_WRITETHROUGH))
392 SetFlag(IoStack->Flags, SL_WRITE_THROUGH);
393 /*
394 * Prepare for next iteration:
395 */
396 #if DBG
397 RunExists =
398 #endif
399 FsRtlGetNextLargeMcbEntry(&Fcb->Mcb, CleanupIndex, &Vbo, &Lbo, &RunLength);
400 ASSERT(RunExists);
401 ASSERT(NextVbo == Vbo);
402 }
403 /*
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.
407 */
408 for (RunIrp = &IrpContext->FatIoContext->Irp,
409 CleanupIndex = FirstIndex;
410 CleanupIndex < BeyoundLastIndex;
411 CleanupIndex ++, RunIrp ++)
412 {
413 IoCallDriver(IrpContext->Vcb->TargetDeviceObject, *RunIrp);
414 }
415
416 FatIoPerformNonCachedComplete:
417 if (CanWait)
418 {
419 KeWaitForSingleObject(
420 &IrpContext->FatIoContext->Wait.SyncEvent,
421 Executive, KernelMode, FALSE, NULL);
422 return IrpContext->Irp->IoStatus.Status;
423 }
424 SetFlag(IrpContext->Flags, IRPCONTEXT_STACK_IO_CONTEXT);
425 return STATUS_PENDING;
426 /*
427 * The following block of code implements unwind logic
428 */
429 FatIoPerformNonCachedCleanup:
430 if (IrpContext->FatIoContext != NULL)
431 {
432 RunIrp = &IrpContext->FatIoContext->Irp;
433 while (FirstIndex < CleanupIndex)
434 {
435 if ((*RunIrp)->MdlAddress != NULL)
436 IoFreeMdl((*RunIrp)->MdlAddress);
437 IoFreeIrp(*RunIrp);
438 FirstIndex ++;
439 RunIrp ++;
440 }
441 ExFreePool(IrpContext->FatIoContext);
442 IrpContext->FatIoContext = NULL;
443 }
444 return Status;
445 }
446
447 /* EOF */