1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 ////////////////////////////////////////////////////////////////////
5 /*************************************************************************
9 * Module: UDF File System Driver (Kernel mode execution only)
12 * Contains environment-secific code to handle physical
13 * operations: read, write and device IOCTLS
15 *************************************************************************/
18 // define the file specific bug-check id
19 #define UDF_BUG_CHECK_ID UDF_FILE_ENV_SPEC
21 #define MEASURE_IO_PERFORMANCE
23 #ifdef MEASURE_IO_PERFORMANCE
24 LONGLONG IoReadTime
=0;
25 LONGLONG IoWriteTime
=0;
26 LONGLONG WrittenData
=0;
27 LONGLONG IoRelWriteTime
=0;
28 #endif //MEASURE_IO_PERFORMANCE
31 ULONG UDF_SIMULATE_WRITES
=0;
39 UDFAsyncCompletionRoutine(
40 IN PDEVICE_OBJECT DeviceObject
,
45 KdPrint(("UDFAsyncCompletionRoutine ctx=%x\n", Contxt
));
46 PUDF_PH_CALL_CONTEXT Context
= (PUDF_PH_CALL_CONTEXT
)Contxt
;
49 Context
->IosbToUse
= Irp
->IoStatus
;
51 // Unlock pages that are described by MDL (if any)...
52 Mdl
= Irp
->MdlAddress
;
54 MmPrint((" Unlock MDL=%x\n", Mdl
));
59 Mdl
= Irp
->MdlAddress
;
61 MmPrint((" Free MDL=%x\n", Mdl
));
66 Irp
->MdlAddress
= NULL
;
69 KeSetEvent( &(Context
->event
), 0, FALSE
);
71 return STATUS_MORE_PROCESSING_REQUIRED
;
73 KeSetEvent( &(Context
->event
), 0, FALSE
);
75 return STATUS_SUCCESS
;
77 } // end UDFAsyncCompletionRoutine()
81 UDFSyncCompletionRoutine(
82 IN PDEVICE_OBJECT DeviceObject
,
87 KdPrint(("UDFSyncCompletionRoutine ctx=%x\n", Contxt
));
88 PUDF_PH_CALL_CONTEXT Context
= (PUDF_PH_CALL_CONTEXT
)Contxt
;
90 Context
->IosbToUse
= Irp
->IoStatus
;
91 //KeSetEvent( &(Context->event), 0, FALSE );
93 return STATUS_SUCCESS
;
94 } // end UDFSyncCompletionRoutine()
98 UDFSyncCompletionRoutine2(
99 IN PDEVICE_OBJECT DeviceObject,
104 KdPrint(("UDFSyncCompletionRoutine2\n"));
105 PKEVENT SyncEvent = (PKEVENT)Contxt;
107 KeSetEvent( SyncEvent, 0, FALSE );
109 return STATUS_SUCCESS;
110 } // end UDFSyncCompletionRoutine2()
115 Function: UDFPhReadSynchronous()
118 UDFFSD will invoke this rotine to read physical device synchronously/asynchronously
120 Expected Interrupt Level (for execution) :
122 <= IRQL_DISPATCH_LEVEL
124 Return Value: STATUS_SUCCESS/Error
129 UDFPhReadSynchronous(
130 PDEVICE_OBJECT DeviceObject
, // the physical device object
138 NTSTATUS RC
= STATUS_SUCCESS
;
139 LARGE_INTEGER ROffset
;
140 PUDF_PH_CALL_CONTEXT Context
;
142 KIRQL CurIrql
= KeGetCurrentIrql();
145 #ifdef MEASURE_IO_PERFORMANCE
146 LONGLONG IoEnterTime
;
150 #endif //MEASURE_IO_PERFORMANCE
153 if(Flags
& PH_VCB_IN_RETLEN
) {
154 Vcb
= (PVCB
)(*ReadBytes
);
156 #endif //_BROWSE_UDF_
158 #ifdef MEASURE_IO_PERFORMANCE
159 KeQuerySystemTime((PLARGE_INTEGER
)&IoEnterTime
);
160 #endif //MEASURE_IO_PERFORMANCE
162 KdPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length
>>0xb,Offset
>>0xb));
163 // KdPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length>>0x9,Offset>>0x9));
165 ROffset
.QuadPart
= Offset
;
169 Flags |= PH_TMP_BUFFER;
171 if(Flags
& PH_TMP_BUFFER
) {
174 IoBuf
= DbgAllocatePoolWithTag(NonPagedPool
, Length
, 'bNWD');
177 KdPrint((" !IoBuf\n"));
178 return STATUS_INSUFFICIENT_RESOURCES
;
180 Context
= (PUDF_PH_CALL_CONTEXT
)MyAllocatePool__( NonPagedPool
, sizeof(UDF_PH_CALL_CONTEXT
) );
182 KdPrint((" !Context\n"));
183 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
185 // Create notification event object to be used to signal the request completion.
186 KeInitializeEvent(&(Context
->event
), NotificationEvent
, FALSE
);
188 if (CurIrql
> PASSIVE_LEVEL
) {
189 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_READ
, DeviceObject
, IoBuf
,
190 Length
, &ROffset
, &(Context
->IosbToUse
) );
192 KdPrint((" !irp Async\n"));
193 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
195 MmPrint((" Alloc async Irp MDL=%x, ctx=%x\n", irp
->MdlAddress
, Context
));
196 IoSetCompletionRoutine( irp
, &UDFAsyncCompletionRoutine
,
197 Context
, TRUE
, TRUE
, TRUE
);
199 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
, DeviceObject
, IoBuf
,
200 Length
, &ROffset
, &(Context
->event
), &(Context
->IosbToUse
) );
202 KdPrint((" !irp Sync\n"));
203 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
205 MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp
->MdlAddress
, Context
));
208 (IoGetNextIrpStackLocation(irp
))->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
209 RC
= IoCallDriver(DeviceObject
, irp
);
211 if (RC
== STATUS_PENDING
) {
212 DbgWaitForSingleObject(&(Context
->event
), NULL
);
213 if ((RC
= Context
->IosbToUse
.Status
) == STATUS_DATA_OVERRUN
) {
216 // *ReadBytes = Context->IosbToUse.Information;
218 // *ReadBytes = irp->IoStatus.Information;
221 (*ReadBytes
) = Context
->IosbToUse
.Information
;
223 if(!(Flags
& PH_TMP_BUFFER
)) {
224 RtlCopyMemory(Buffer
, IoBuf
, *ReadBytes
);
229 for(i=0; i<(*ReadBytes); i+=2048) {
230 KdPrint(("IOCRC %8.8x R %x\n", crc32((PUCHAR)Buffer+i, 2048), (ULONG)((Offset+i)/2048) ));
235 RC
= UDFVRead(Vcb
, IoBuf
, Length
>> Vcb
->BlockSizeBits
, (ULONG
)(Offset
>> Vcb
->BlockSizeBits
), Flags
);
237 #endif //_BROWSE_UDF_
242 if(Context
) MyFreePool__(Context
);
243 if(IoBuf
&& !(Flags
& PH_TMP_BUFFER
)) DbgFreePool(IoBuf
);
245 #ifdef MEASURE_IO_PERFORMANCE
246 KeQuerySystemTime((PLARGE_INTEGER
)&IoExitTime
);
247 IoReadTime
+= (IoExitTime
-IoEnterTime
);
248 dt
= (ULONG
)((IoExitTime
-IoEnterTime
)/10/1000);
249 dtm
= (ULONG
)(((IoExitTime
-IoEnterTime
)/10)%1000);
250 PerfPrint(("\nUDFPhReadSynchronous() exit: %08X, after %d.%4.4d msec.\n", RC
, dt
, dtm
));
252 KdPrint(("UDFPhReadSynchronous() exit: %08X\n", RC
));
253 #endif //MEASURE_IO_PERFORMANCE
256 } // end UDFPhReadSynchronous()
261 Function: UDFPhWriteSynchronous()
264 UDFFSD will invoke this rotine to write physical device synchronously
266 Expected Interrupt Level (for execution) :
268 <= IRQL_DISPATCH_LEVEL
270 Return Value: STATUS_SUCCESS/Error
275 UDFPhWriteSynchronous(
276 PDEVICE_OBJECT DeviceObject
, // the physical device object
284 NTSTATUS RC
= STATUS_SUCCESS
;
285 LARGE_INTEGER ROffset
;
286 PUDF_PH_CALL_CONTEXT Context
;
288 // LARGE_INTEGER timeout;
289 KIRQL CurIrql
= KeGetCurrentIrql();
292 #ifdef MEASURE_IO_PERFORMANCE
293 LONGLONG IoEnterTime
;
297 #endif //MEASURE_IO_PERFORMANCE
300 if(Flags
& PH_VCB_IN_RETLEN
) {
301 Vcb
= (PVCB
)(*WrittenBytes
);
303 #endif //_BROWSE_UDF_
305 #ifdef MEASURE_IO_PERFORMANCE
306 KeQuerySystemTime((PLARGE_INTEGER
)&IoEnterTime
);
307 #endif //MEASURE_IO_PERFORMANCE
309 #if defined DBG || defined USE_PERF_PRINT
310 ULONG Lba
= (ULONG
)(Offset
>>0xb);
311 // ASSERT(!(Lba & (32-1)));
312 PerfPrint(("UDFPhWrite: Length: %x Lba: %lx\n",Length
>>0xb,Lba
));
313 // KdPrint(("UDFPhWrite: Length: %x Lba: %lx\n",Length>>0x9,Offset>>0x9));
317 if(UDF_SIMULATE_WRITES
) {
319 for(ULONG i
=0; i
<Length
; i
++) {
320 a
= ((PUCHAR
)Buffer
)[i
];
322 *WrittenBytes
= Length
;
323 return STATUS_SUCCESS
;
327 ROffset
.QuadPart
= Offset
;
330 /* IoBuf = ExAllocatePool(NonPagedPool, Length);
331 if (!IoBuf) return STATUS_INSUFFICIENT_RESOURCES;
332 RtlCopyMemory(IoBuf, Buffer, Length);*/
335 /* if(Flags & PH_TMP_BUFFER) {
338 IoBuf = DbgAllocatePool(NonPagedPool, Length);
339 RtlCopyMemory(IoBuf, Buffer, Length);
342 Context
= (PUDF_PH_CALL_CONTEXT
)MyAllocatePool__( NonPagedPool
, sizeof(UDF_PH_CALL_CONTEXT
) );
343 if (!Context
) try_return (RC
= STATUS_INSUFFICIENT_RESOURCES
);
344 // Create notification event object to be used to signal the request completion.
345 KeInitializeEvent(&(Context
->event
), NotificationEvent
, FALSE
);
347 if (CurIrql
> PASSIVE_LEVEL
) {
348 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
, DeviceObject
, IoBuf
,
349 Length
, &ROffset
, &(Context
->IosbToUse
) );
350 if (!irp
) try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
351 MmPrint((" Alloc async Irp MDL=%x, ctx=%x\n", irp
->MdlAddress
, Context
));
352 IoSetCompletionRoutine( irp
, &UDFAsyncCompletionRoutine
,
353 Context
, TRUE
, TRUE
, TRUE
);
355 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
, DeviceObject
, IoBuf
,
356 Length
, &ROffset
, &(Context
->event
), &(Context
->IosbToUse
) );
357 if (!irp
) try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
358 MmPrint((" Alloc Irp MDL=%x\n, ctx=%x", irp
->MdlAddress
, Context
));
361 (IoGetNextIrpStackLocation(irp
))->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
362 RC
= IoCallDriver(DeviceObject
, irp
);
364 for(i=0; i<Length; i+=2048) {
365 KdPrint(("IOCRC %8.8x W %x\n", crc32((PUCHAR)Buffer+i, 2048), (ULONG)((Offset+i)/2048) ));
370 UDFVWrite(Vcb
, IoBuf
, Length
>> Vcb
->BlockSizeBits
, (ULONG
)(Offset
>> Vcb
->BlockSizeBits
), Flags
);
372 #endif //_BROWSE_UDF_
374 if (RC
== STATUS_PENDING
) {
375 DbgWaitForSingleObject(&(Context
->event
), NULL
);
376 if ((RC
= Context
->IosbToUse
.Status
) == STATUS_DATA_OVERRUN
) {
379 // *WrittenBytes = Context->IosbToUse.Information;
381 // *WrittenBytes = irp->IoStatus.Information;
384 (*WrittenBytes
) = Context
->IosbToUse
.Information
;
389 if(Context
) MyFreePool__(Context
);
390 // if(IoBuf) ExFreePool(IoBuf);
391 // if(IoBuf && !(Flags & PH_TMP_BUFFER)) DbgFreePool(IoBuf);
392 if(!NT_SUCCESS(RC
)) {
393 KdPrint(("WriteError\n"));
396 #ifdef MEASURE_IO_PERFORMANCE
397 KeQuerySystemTime((PLARGE_INTEGER
)&IoExitTime
);
398 IoWriteTime
+= (IoExitTime
-IoEnterTime
);
399 if (WrittenData
> 1024*1024*8) {
400 PerfPrint(("\nUDFPhWriteSynchronous() Relative size=%I64d, time=%I64d.\n", WrittenData
, IoRelWriteTime
));
401 WrittenData
= IoRelWriteTime
= 0;
403 WrittenData
+= Length
;
404 IoRelWriteTime
+= (IoExitTime
-IoEnterTime
);
405 dt
= (ULONG
)((IoExitTime
-IoEnterTime
)/10/1000);
406 dtm
= (ULONG
)(((IoExitTime
-IoEnterTime
)/10)%1000);
407 PerfPrint(("\nUDFPhWriteSynchronous() exit: %08X, after %d.%4.4d msec.\n", RC
, dt
, dtm
));
409 KdPrint(("nUDFPhWriteSynchronous() exit: %08X\n", RC
));
410 #endif //MEASURE_IO_PERFORMANCE
413 } // end UDFPhWriteSynchronous()
417 UDFPhWriteVerifySynchronous(
418 PDEVICE_OBJECT DeviceObject
, // the physical device object
427 //PUCHAR v_buff = NULL;
430 RC
= UDFPhWriteSynchronous(DeviceObject
, Buffer
, Length
, Offset
, WrittenBytes
, Flags
);
434 v_buff = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, Length, 'bNWD');
437 RC = UDFPhReadSynchronous(DeviceObject, v_buff, Length, Offset, &ReadBytes, Flags);
438 if(!NT_SUCCESS(RC)) {
443 if(RtlCompareMemory(v_buff, Buffer, ReadBytes) == Length) {
449 return STATUS_LOST_WRITEBEHIND_DATA;
452 } // end UDFPhWriteVerifySynchronous()
458 IN ULONG IoControlCode
,
460 IN PVOID InputBuffer
,
461 IN ULONG InputBufferLength
,
462 OUT PVOID OutputBuffer
,
463 IN ULONG OutputBufferLength
,
464 IN BOOLEAN OverrideVerify
,
465 OUT PIO_STATUS_BLOCK Iosb OPTIONAL
468 NTSTATUS RC
= STATUS_SUCCESS
;
471 Acquired
= UDFAcquireResourceExclusiveWithCheck(&(Vcb
->IoResource
));
475 RC
= UDFPhSendIOCTL(IoControlCode
,
476 Vcb
->TargetDeviceObject
,
487 UDFReleaseResource(&(Vcb
->IoResource
));
491 } // end UDFTSendIOCTL()
495 Function: UDFPhSendIOCTL()
498 UDF FSD will invoke this rotine to send IOCTL's to physical
501 Return Value: STATUS_SUCCESS/Error
507 IN ULONG IoControlCode
,
508 IN PDEVICE_OBJECT DeviceObject
,
509 IN PVOID InputBuffer
,
510 IN ULONG InputBufferLength
,
511 OUT PVOID OutputBuffer
,
512 IN ULONG OutputBufferLength
,
513 IN BOOLEAN OverrideVerify
,
514 OUT PIO_STATUS_BLOCK Iosb OPTIONAL
517 NTSTATUS RC
= STATUS_SUCCESS
;
519 PUDF_PH_CALL_CONTEXT Context
;
520 LARGE_INTEGER timeout
;
522 KdPrint(("UDFPhDevIOCTL: Code %8x \n",IoControlCode
));
524 Context
= (PUDF_PH_CALL_CONTEXT
)MyAllocatePool__( NonPagedPool
, sizeof(UDF_PH_CALL_CONTEXT
) );
525 if (!Context
) return STATUS_INSUFFICIENT_RESOURCES
;
526 // Check if the user gave us an Iosb.
528 // Create notification event object to be used to signal the request completion.
529 KeInitializeEvent(&(Context
->event
), NotificationEvent
, FALSE
);
531 irp
= IoBuildDeviceIoControlRequest(IoControlCode
, DeviceObject
, InputBuffer
,
532 InputBufferLength
, OutputBuffer
, OutputBufferLength
,FALSE
,&(Context
->event
),&(Context
->IosbToUse
));
534 if (!irp
) try_return (RC
= STATUS_INSUFFICIENT_RESOURCES
);
535 MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp
->MdlAddress
, Context
));
537 if (KeGetCurrentIrql() > PASSIVE_LEVEL) {
538 KdPrint(("Setting completion routine\n"));
539 IoSetCompletionRoutine( irp, &UDFSyncCompletionRoutine,
540 Context, TRUE, TRUE, TRUE );
544 (IoGetNextIrpStackLocation(irp
))->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
547 RC
= IoCallDriver(DeviceObject
, irp
);
549 if (RC
== STATUS_PENDING
) {
550 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL
);
551 KdPrint(("Enter wait state on evt %x\n", Context
));
553 if (KeGetCurrentIrql() > PASSIVE_LEVEL
) {
554 timeout
.QuadPart
= -1000;
555 KdPrint(("waiting, TO=%I64d\n", timeout
.QuadPart
));
556 RC
= DbgWaitForSingleObject(&(Context
->event
), &timeout
);
557 while(RC
== STATUS_TIMEOUT
) {
558 timeout
.QuadPart
*= 2;
559 KdPrint(("waiting, TO=%I64d\n", timeout
.QuadPart
));
560 RC
= DbgWaitForSingleObject(&(Context
->event
), &timeout
);
564 DbgWaitForSingleObject(&(Context
->event
), NULL
);
566 if ((RC
= Context
->IosbToUse
.Status
) == STATUS_DATA_OVERRUN
) {
569 KdPrint(("Exit wait state on evt %x, status %8.8x\n", Context
, RC
));
571 (*Iosb) = Context->IosbToUse;
574 KdPrint(("No wait completion on evt %x\n", Context
));
576 (*Iosb) = irp->IoStatus;
581 (*Iosb
) = Context
->IosbToUse
;
586 if(Context
) MyFreePool__(Context
);
588 } // end UDFPhSendIOCTL()
593 UDFNotifyFullReportChange(
600 if((FI
)->ParentFile
) {
601 FsRtlNotifyFullReportChange( (V
)->NotifyIRPMutex
, &((V
)->NextNotifyIRP
),
602 (PSTRING
)&((FI
)->Fcb
->FCBName
->ObjectName
),
603 ((FI
)->ParentFile
->Fcb
->FCBName
->ObjectName
.Length
+ sizeof(WCHAR
)),
608 FsRtlNotifyFullReportChange( (V
)->NotifyIRPMutex
, &((V
)->NextNotifyIRP
),
609 (PSTRING
)&((FI
)->Fcb
->FCBName
->ObjectName
),
615 } // end UDFNotifyFullReportChange()
618 UDFNotifyVolumeEvent(
619 IN PFILE_OBJECT FileObject
,
623 if(!FsRtlNotifyVolumeEvent
)
625 //FsRtlNotifyVolumeEvent(FileObject, EventCode);
626 } // end UDFNotifyVolumeEvent()