1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
10 * Module: UDF File System Driver (Kernel mode execution only)
13 * Contains environment-secific code to handle physical
14 * operations: read, write and device IOCTLS
16 *************************************************************************/
19 // define the file specific bug-check id
20 #define UDF_BUG_CHECK_ID UDF_FILE_ENV_SPEC
22 #define MEASURE_IO_PERFORMANCE
24 #ifdef MEASURE_IO_PERFORMANCE
25 LONGLONG IoReadTime
=0;
26 LONGLONG IoWriteTime
=0;
27 LONGLONG WrittenData
=0;
28 LONGLONG IoRelWriteTime
=0;
29 #endif //MEASURE_IO_PERFORMANCE
32 ULONG UDF_SIMULATE_WRITES
=0;
40 UDFAsyncCompletionRoutine(
41 IN PDEVICE_OBJECT DeviceObject
,
46 UDFPrint(("UDFAsyncCompletionRoutine ctx=%x\n", Contxt
));
47 PUDF_PH_CALL_CONTEXT Context
= (PUDF_PH_CALL_CONTEXT
)Contxt
;
50 Context
->IosbToUse
= Irp
->IoStatus
;
52 // Unlock pages that are described by MDL (if any)...
53 Mdl
= Irp
->MdlAddress
;
55 MmPrint((" Unlock MDL=%x\n", Mdl
));
60 Mdl
= Irp
->MdlAddress
;
62 MmPrint((" Free MDL=%x\n", Mdl
));
67 Irp
->MdlAddress
= NULL
;
70 KeSetEvent( &(Context
->event
), 0, FALSE
);
72 return STATUS_MORE_PROCESSING_REQUIRED
;
74 KeSetEvent( &(Context
->event
), 0, FALSE
);
76 return STATUS_SUCCESS
;
78 } // end UDFAsyncCompletionRoutine()
82 UDFSyncCompletionRoutine(
83 IN PDEVICE_OBJECT DeviceObject
,
88 UDFPrint(("UDFSyncCompletionRoutine ctx=%x\n", Contxt
));
89 PUDF_PH_CALL_CONTEXT Context
= (PUDF_PH_CALL_CONTEXT
)Contxt
;
91 Context
->IosbToUse
= Irp
->IoStatus
;
92 //KeSetEvent( &(Context->event), 0, FALSE );
94 return STATUS_SUCCESS
;
95 } // end UDFSyncCompletionRoutine()
99 UDFSyncCompletionRoutine2(
100 IN PDEVICE_OBJECT DeviceObject,
105 UDFPrint(("UDFSyncCompletionRoutine2\n"));
106 PKEVENT SyncEvent = (PKEVENT)Contxt;
108 KeSetEvent( SyncEvent, 0, FALSE );
110 return STATUS_SUCCESS;
111 } // end UDFSyncCompletionRoutine2()
116 Function: UDFPhReadSynchronous()
119 UDFFSD will invoke this rotine to read physical device synchronously/asynchronously
121 Expected Interrupt Level (for execution) :
123 <= IRQL_DISPATCH_LEVEL
125 Return Value: STATUS_SUCCESS/Error
130 UDFPhReadSynchronous(
131 PDEVICE_OBJECT DeviceObject
, // the physical device object
139 NTSTATUS RC
= STATUS_SUCCESS
;
140 LARGE_INTEGER ROffset
;
141 PUDF_PH_CALL_CONTEXT Context
;
143 KIRQL CurIrql
= KeGetCurrentIrql();
146 #ifdef MEASURE_IO_PERFORMANCE
147 LONGLONG IoEnterTime
;
151 #endif //MEASURE_IO_PERFORMANCE
154 if(Flags
& PH_VCB_IN_RETLEN
) {
155 Vcb
= (PVCB
)(*ReadBytes
);
157 #endif //_BROWSE_UDF_
159 #ifdef MEASURE_IO_PERFORMANCE
160 KeQuerySystemTime((PLARGE_INTEGER
)&IoEnterTime
);
161 #endif //MEASURE_IO_PERFORMANCE
163 UDFPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length
>>0xb,Offset
>>0xb));
164 // UDFPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length>>0x9,Offset>>0x9));
166 ROffset
.QuadPart
= Offset
;
170 Flags |= PH_TMP_BUFFER;
172 if(Flags
& PH_TMP_BUFFER
) {
175 IoBuf
= DbgAllocatePoolWithTag(NonPagedPool
, Length
, 'bNWD');
178 UDFPrint((" !IoBuf\n"));
179 return STATUS_INSUFFICIENT_RESOURCES
;
181 Context
= (PUDF_PH_CALL_CONTEXT
)MyAllocatePool__( NonPagedPool
, sizeof(UDF_PH_CALL_CONTEXT
) );
183 UDFPrint((" !Context\n"));
184 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
186 // Create notification event object to be used to signal the request completion.
187 KeInitializeEvent(&(Context
->event
), NotificationEvent
, FALSE
);
189 if (CurIrql
> PASSIVE_LEVEL
) {
190 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
, DeviceObject
, IoBuf
,
191 Length
, &ROffset
, &(Context
->IosbToUse
) );
193 UDFPrint((" !irp Async\n"));
194 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
196 MmPrint((" Alloc async Irp MDL=%x, ctx=%x\n", irp
->MdlAddress
, Context
));
197 IoSetCompletionRoutine( irp
, &UDFAsyncCompletionRoutine
,
198 Context
, TRUE
, TRUE
, TRUE
);
200 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
, DeviceObject
, IoBuf
,
201 Length
, &ROffset
, &(Context
->event
), &(Context
->IosbToUse
) );
203 UDFPrint((" !irp Sync\n"));
204 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
206 MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp
->MdlAddress
, Context
));
209 (IoGetNextIrpStackLocation(irp
))->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
210 RC
= IoCallDriver(DeviceObject
, irp
);
212 if (RC
== STATUS_PENDING
) {
213 DbgWaitForSingleObject(&(Context
->event
), NULL
);
214 if ((RC
= Context
->IosbToUse
.Status
) == STATUS_DATA_OVERRUN
) {
217 // *ReadBytes = Context->IosbToUse.Information;
219 // *ReadBytes = irp->IoStatus.Information;
222 (*ReadBytes
) = Context
->IosbToUse
.Information
;
224 if(!(Flags
& PH_TMP_BUFFER
)) {
225 RtlCopyMemory(Buffer
, IoBuf
, *ReadBytes
);
230 for(i=0; i<(*ReadBytes); i+=2048) {
231 UDFPrint(("IOCRC %8.8x R %x\n", crc32((PUCHAR)Buffer+i, 2048), (ULONG)((Offset+i)/2048) ));
236 RC
= UDFVRead(Vcb
, IoBuf
, Length
>> Vcb
->BlockSizeBits
, (ULONG
)(Offset
>> Vcb
->BlockSizeBits
), Flags
);
238 #endif //_BROWSE_UDF_
243 if(Context
) MyFreePool__(Context
);
244 if(IoBuf
&& !(Flags
& PH_TMP_BUFFER
)) DbgFreePool(IoBuf
);
246 #ifdef MEASURE_IO_PERFORMANCE
247 KeQuerySystemTime((PLARGE_INTEGER
)&IoExitTime
);
248 IoReadTime
+= (IoExitTime
-IoEnterTime
);
249 dt
= (ULONG
)((IoExitTime
-IoEnterTime
)/10/1000);
250 dtm
= (ULONG
)(((IoExitTime
-IoEnterTime
)/10)%1000);
251 PerfPrint(("\nUDFPhReadSynchronous() exit: %08X, after %d.%4.4d msec.\n", RC
, dt
, dtm
));
253 UDFPrint(("UDFPhReadSynchronous() exit: %08X\n", RC
));
254 #endif //MEASURE_IO_PERFORMANCE
257 } // end UDFPhReadSynchronous()
262 Function: UDFPhWriteSynchronous()
265 UDFFSD will invoke this rotine to write physical device synchronously
267 Expected Interrupt Level (for execution) :
269 <= IRQL_DISPATCH_LEVEL
271 Return Value: STATUS_SUCCESS/Error
276 UDFPhWriteSynchronous(
277 PDEVICE_OBJECT DeviceObject
, // the physical device object
285 NTSTATUS RC
= STATUS_SUCCESS
;
286 LARGE_INTEGER ROffset
;
287 PUDF_PH_CALL_CONTEXT Context
;
289 // LARGE_INTEGER timeout;
290 KIRQL CurIrql
= KeGetCurrentIrql();
293 #ifdef MEASURE_IO_PERFORMANCE
294 LONGLONG IoEnterTime
;
298 #endif //MEASURE_IO_PERFORMANCE
301 if(Flags
& PH_VCB_IN_RETLEN
) {
302 Vcb
= (PVCB
)(*WrittenBytes
);
304 #endif //_BROWSE_UDF_
306 #ifdef MEASURE_IO_PERFORMANCE
307 KeQuerySystemTime((PLARGE_INTEGER
)&IoEnterTime
);
308 #endif //MEASURE_IO_PERFORMANCE
310 #if defined UDF_DBG || defined USE_PERF_PRINT
311 ULONG Lba
= (ULONG
)(Offset
>>0xb);
312 // ASSERT(!(Lba & (32-1)));
313 PerfPrint(("UDFPhWrite: Length: %x Lba: %lx\n",Length
>>0xb,Lba
));
314 // UDFPrint(("UDFPhWrite: Length: %x Lba: %lx\n",Length>>0x9,Offset>>0x9));
318 if(UDF_SIMULATE_WRITES
) {
320 If this function is to force a read from the bufffer to simulate any segfaults, then it makes sense.
321 Else, this forloop is useless.
323 for(ULONG i=0; i<Length; i++) {
324 a = ((PUCHAR)Buffer)[i];
327 *WrittenBytes
= Length
;
328 return STATUS_SUCCESS
;
332 ROffset
.QuadPart
= Offset
;
335 /* IoBuf = ExAllocatePool(NonPagedPool, Length);
336 if (!IoBuf) return STATUS_INSUFFICIENT_RESOURCES;
337 RtlCopyMemory(IoBuf, Buffer, Length);*/
340 /* if(Flags & PH_TMP_BUFFER) {
343 IoBuf = DbgAllocatePool(NonPagedPool, Length);
344 RtlCopyMemory(IoBuf, Buffer, Length);
347 Context
= (PUDF_PH_CALL_CONTEXT
)MyAllocatePool__( NonPagedPool
, sizeof(UDF_PH_CALL_CONTEXT
) );
348 if (!Context
) try_return (RC
= STATUS_INSUFFICIENT_RESOURCES
);
349 // Create notification event object to be used to signal the request completion.
350 KeInitializeEvent(&(Context
->event
), NotificationEvent
, FALSE
);
352 if (CurIrql
> PASSIVE_LEVEL
) {
353 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
, DeviceObject
, IoBuf
,
354 Length
, &ROffset
, &(Context
->IosbToUse
) );
355 if (!irp
) try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
356 MmPrint((" Alloc async Irp MDL=%x, ctx=%x\n", irp
->MdlAddress
, Context
));
357 IoSetCompletionRoutine( irp
, &UDFAsyncCompletionRoutine
,
358 Context
, TRUE
, TRUE
, TRUE
);
360 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
, DeviceObject
, IoBuf
,
361 Length
, &ROffset
, &(Context
->event
), &(Context
->IosbToUse
) );
362 if (!irp
) try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
363 MmPrint((" Alloc Irp MDL=%x\n, ctx=%x", irp
->MdlAddress
, Context
));
366 (IoGetNextIrpStackLocation(irp
))->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
367 RC
= IoCallDriver(DeviceObject
, irp
);
369 for(i=0; i<Length; i+=2048) {
370 UDFPrint(("IOCRC %8.8x W %x\n", crc32((PUCHAR)Buffer+i, 2048), (ULONG)((Offset+i)/2048) ));
375 UDFVWrite(Vcb
, IoBuf
, Length
>> Vcb
->BlockSizeBits
, (ULONG
)(Offset
>> Vcb
->BlockSizeBits
), Flags
);
377 #endif //_BROWSE_UDF_
379 if (RC
== STATUS_PENDING
) {
380 DbgWaitForSingleObject(&(Context
->event
), NULL
);
381 if ((RC
= Context
->IosbToUse
.Status
) == STATUS_DATA_OVERRUN
) {
384 // *WrittenBytes = Context->IosbToUse.Information;
386 // *WrittenBytes = irp->IoStatus.Information;
389 (*WrittenBytes
) = Context
->IosbToUse
.Information
;
394 if(Context
) MyFreePool__(Context
);
395 // if(IoBuf) ExFreePool(IoBuf);
396 // if(IoBuf && !(Flags & PH_TMP_BUFFER)) DbgFreePool(IoBuf);
397 if(!NT_SUCCESS(RC
)) {
398 UDFPrint(("WriteError\n"));
401 #ifdef MEASURE_IO_PERFORMANCE
402 KeQuerySystemTime((PLARGE_INTEGER
)&IoExitTime
);
403 IoWriteTime
+= (IoExitTime
-IoEnterTime
);
404 if (WrittenData
> 1024*1024*8) {
405 PerfPrint(("\nUDFPhWriteSynchronous() Relative size=%I64d, time=%I64d.\n", WrittenData
, IoRelWriteTime
));
406 WrittenData
= IoRelWriteTime
= 0;
408 WrittenData
+= Length
;
409 IoRelWriteTime
+= (IoExitTime
-IoEnterTime
);
410 dt
= (ULONG
)((IoExitTime
-IoEnterTime
)/10/1000);
411 dtm
= (ULONG
)(((IoExitTime
-IoEnterTime
)/10)%1000);
412 PerfPrint(("\nUDFPhWriteSynchronous() exit: %08X, after %d.%4.4d msec.\n", RC
, dt
, dtm
));
414 UDFPrint(("nUDFPhWriteSynchronous() exit: %08X\n", RC
));
415 #endif //MEASURE_IO_PERFORMANCE
418 } // end UDFPhWriteSynchronous()
422 UDFPhWriteVerifySynchronous(
423 PDEVICE_OBJECT DeviceObject
, // the physical device object
432 //PUCHAR v_buff = NULL;
435 RC
= UDFPhWriteSynchronous(DeviceObject
, Buffer
, Length
, Offset
, WrittenBytes
, Flags
);
439 v_buff = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, Length, 'bNWD');
442 RC = UDFPhReadSynchronous(DeviceObject, v_buff, Length, Offset, &ReadBytes, Flags);
443 if(!NT_SUCCESS(RC)) {
448 if(RtlCompareMemory(v_buff, Buffer, ReadBytes) == Length) {
454 return STATUS_LOST_WRITEBEHIND_DATA;
457 } // end UDFPhWriteVerifySynchronous()
463 IN ULONG IoControlCode
,
465 IN PVOID InputBuffer
,
466 IN ULONG InputBufferLength
,
467 OUT PVOID OutputBuffer
,
468 IN ULONG OutputBufferLength
,
469 IN BOOLEAN OverrideVerify
,
470 OUT PIO_STATUS_BLOCK Iosb OPTIONAL
473 NTSTATUS RC
= STATUS_SUCCESS
;
476 Acquired
= UDFAcquireResourceExclusiveWithCheck(&(Vcb
->IoResource
));
480 RC
= UDFPhSendIOCTL(IoControlCode
,
481 Vcb
->TargetDeviceObject
,
492 UDFReleaseResource(&(Vcb
->IoResource
));
496 } // end UDFTSendIOCTL()
500 Function: UDFPhSendIOCTL()
503 UDF FSD will invoke this rotine to send IOCTL's to physical
506 Return Value: STATUS_SUCCESS/Error
512 IN ULONG IoControlCode
,
513 IN PDEVICE_OBJECT DeviceObject
,
514 IN PVOID InputBuffer
,
515 IN ULONG InputBufferLength
,
516 OUT PVOID OutputBuffer
,
517 IN ULONG OutputBufferLength
,
518 IN BOOLEAN OverrideVerify
,
519 OUT PIO_STATUS_BLOCK Iosb OPTIONAL
522 NTSTATUS RC
= STATUS_SUCCESS
;
524 PUDF_PH_CALL_CONTEXT Context
;
525 LARGE_INTEGER timeout
;
527 UDFPrint(("UDFPhDevIOCTL: Code %8x \n",IoControlCode
));
529 Context
= (PUDF_PH_CALL_CONTEXT
)MyAllocatePool__( NonPagedPool
, sizeof(UDF_PH_CALL_CONTEXT
) );
530 if (!Context
) return STATUS_INSUFFICIENT_RESOURCES
;
531 // Check if the user gave us an Iosb.
533 // Create notification event object to be used to signal the request completion.
534 KeInitializeEvent(&(Context
->event
), NotificationEvent
, FALSE
);
536 irp
= IoBuildDeviceIoControlRequest(IoControlCode
, DeviceObject
, InputBuffer
,
537 InputBufferLength
, OutputBuffer
, OutputBufferLength
,FALSE
,&(Context
->event
),&(Context
->IosbToUse
));
539 if (!irp
) try_return (RC
= STATUS_INSUFFICIENT_RESOURCES
);
540 MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp
->MdlAddress
, Context
));
542 if (KeGetCurrentIrql() > PASSIVE_LEVEL) {
543 UDFPrint(("Setting completion routine\n"));
544 IoSetCompletionRoutine( irp, &UDFSyncCompletionRoutine,
545 Context, TRUE, TRUE, TRUE );
549 (IoGetNextIrpStackLocation(irp
))->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
552 RC
= IoCallDriver(DeviceObject
, irp
);
554 if (RC
== STATUS_PENDING
) {
555 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL
);
556 UDFPrint(("Enter wait state on evt %x\n", Context
));
558 if (KeGetCurrentIrql() > PASSIVE_LEVEL
) {
559 timeout
.QuadPart
= -1000;
560 UDFPrint(("waiting, TO=%I64d\n", timeout
.QuadPart
));
561 RC
= DbgWaitForSingleObject(&(Context
->event
), &timeout
);
562 while(RC
== STATUS_TIMEOUT
) {
563 timeout
.QuadPart
*= 2;
564 UDFPrint(("waiting, TO=%I64d\n", timeout
.QuadPart
));
565 RC
= DbgWaitForSingleObject(&(Context
->event
), &timeout
);
569 DbgWaitForSingleObject(&(Context
->event
), NULL
);
571 if ((RC
= Context
->IosbToUse
.Status
) == STATUS_DATA_OVERRUN
) {
574 UDFPrint(("Exit wait state on evt %x, status %8.8x\n", Context
, RC
));
576 (*Iosb) = Context->IosbToUse;
579 UDFPrint(("No wait completion on evt %x\n", Context
));
581 (*Iosb) = irp->IoStatus;
586 (*Iosb
) = Context
->IosbToUse
;
591 if(Context
) MyFreePool__(Context
);
593 } // end UDFPhSendIOCTL()
598 UDFNotifyFullReportChange(
605 if((FI
)->ParentFile
) {
606 FsRtlNotifyFullReportChange( (V
)->NotifyIRPMutex
, &((V
)->NextNotifyIRP
),
607 (PSTRING
)&((FI
)->Fcb
->FCBName
->ObjectName
),
608 ((FI
)->ParentFile
->Fcb
->FCBName
->ObjectName
.Length
+ sizeof(WCHAR
)),
613 FsRtlNotifyFullReportChange( (V
)->NotifyIRPMutex
, &((V
)->NextNotifyIRP
),
614 (PSTRING
)&((FI
)->Fcb
->FCBName
->ObjectName
),
620 } // end UDFNotifyFullReportChange()
623 UDFNotifyVolumeEvent(
624 IN PFILE_OBJECT FileObject
,
628 /* ReactOS FIXME This is always true, and we return anyway. */
629 // if(!FsRtlNotifyVolumeEvent)
631 //FsRtlNotifyVolumeEvent(FileObject, EventCode);
632 } // end UDFNotifyVolumeEvent()