2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
10 /* INCLUDES *****************************************************************/
14 /* GLOBALS ***************************************************************/
16 extern PEXT2_GLOBAL Ext2Global
;
18 /* DEFINITIONS *************************************************************/
21 Ext2ReadWriteBlockSyncCompletionRoutine (
22 IN PDEVICE_OBJECT DeviceObject
,
27 Ext2ReadWriteBlockAsyncCompletionRoutine (
28 IN PDEVICE_OBJECT DeviceObject
,
34 Ext2MediaEjectControlCompletion (
35 IN PDEVICE_OBJECT DeviceObject
,
40 #pragma alloc_text(PAGE, Ext2LockUserBuffer)
41 #pragma alloc_text(PAGE, Ext2ReadSync)
42 #pragma alloc_text(PAGE, Ext2ReadDisk)
43 #pragma alloc_text(PAGE, Ext2DiskIoControl)
44 #pragma alloc_text(PAGE, Ext2MediaEjectControl)
45 #pragma alloc_text(PAGE, Ext2DiskShutDown)
49 /* FUNCTIONS ***************************************************************/
61 ASSERT (Buffer
!= NULL
);
62 Mdl
= IoAllocateMdl (Buffer
, Length
, FALSE
, FALSE
, NULL
);
64 Status
= STATUS_INSUFFICIENT_RESOURCES
;
67 if (MmIsNonPagedSystemAddressValid(Buffer
)) {
68 MmBuildMdlForNonPagedPool(Mdl
);
70 MmProbeAndLockPages(Mdl
, KernelMode
, op
);
72 Status
= STATUS_SUCCESS
;
73 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
77 Status
= STATUS_INVALID_USER_BUFFER
;
85 Ext2DestroyMdl (IN PMDL Mdl
)
92 if (IsFlagOn(Mdl
->MdlFlags
, MDL_PAGES_LOCKED
)) {
101 Ext2LockUserBuffer (IN PIRP Irp
,
103 IN LOCK_OPERATION Operation
)
108 if (Irp
->MdlAddress
!= NULL
) {
109 return STATUS_SUCCESS
;
112 IoAllocateMdl(Irp
->UserBuffer
, Length
, FALSE
, FALSE
, Irp
);
113 if (Irp
->MdlAddress
== NULL
) {
114 return STATUS_INSUFFICIENT_RESOURCES
;
119 MmProbeAndLockPages(Irp
->MdlAddress
, Irp
->RequestorMode
, Operation
);
120 Status
= STATUS_SUCCESS
;
122 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
125 IoFreeMdl(Irp
->MdlAddress
);
126 Irp
->MdlAddress
= NULL
;
127 Status
= STATUS_INVALID_USER_BUFFER
;
134 Ext2GetUserBuffer (IN PIRP Irp
)
138 if (Irp
->MdlAddress
) {
140 #if (_WIN32_WINNT >= 0x0500)
141 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
143 return MmGetSystemAddressForMdl(Irp
->MdlAddress
);
147 return Irp
->UserBuffer
;
152 Ext2ReadWriteBlockSyncCompletionRoutine (
153 IN PDEVICE_OBJECT DeviceObject
,
157 PEXT2_RW_CONTEXT pContext
= (PEXT2_RW_CONTEXT
)Context
;
159 if (Irp
!= pContext
->MasterIrp
) {
161 if (!NT_SUCCESS(Irp
->IoStatus
.Status
)) {
162 pContext
->MasterIrp
->IoStatus
= Irp
->IoStatus
;
165 IoFreeMdl(Irp
->MdlAddress
);
169 if (InterlockedDecrement(&pContext
->Blocks
) == 0) {
171 pContext
->MasterIrp
->IoStatus
.Information
= 0;
172 if (NT_SUCCESS(pContext
->MasterIrp
->IoStatus
.Status
)) {
174 pContext
->MasterIrp
->IoStatus
.Information
=
178 KeSetEvent(&pContext
->Event
, 0, FALSE
);
181 return STATUS_MORE_PROCESSING_REQUIRED
;
185 Ext2ReadWriteBlockAsyncCompletionRoutine (
186 IN PDEVICE_OBJECT DeviceObject
,
191 PEXT2_RW_CONTEXT pContext
= (PEXT2_RW_CONTEXT
)Context
;
192 PIO_STACK_LOCATION iosp
;
194 ASSERT(FALSE
== pContext
->Wait
);
196 if (Irp
!= pContext
->MasterIrp
&& !NT_SUCCESS(Irp
->IoStatus
.Status
)) {
197 pContext
->MasterIrp
->IoStatus
= Irp
->IoStatus
;
200 if (InterlockedDecrement(&pContext
->Blocks
) == 0) {
202 if (NT_SUCCESS(pContext
->MasterIrp
->IoStatus
.Status
)) {
204 /* set written bytes to status information */
205 pContext
->MasterIrp
->IoStatus
.Information
= pContext
->Length
;
207 if (pContext
->FileObject
!= NULL
&& !IsFlagOn(pContext
->MasterIrp
->Flags
, IRP_PAGING_IO
)) {
209 /* modify FileObject flags, skip this for volume direct access */
210 SetFlag( pContext
->FileObject
->Flags
,
211 IsFlagOn(pContext
->Flags
, EXT2_RW_CONTEXT_WRITE
) ?
212 FO_FILE_MODIFIED
: FO_FILE_FAST_IO_READ
);
214 /* update Current Byteoffset */
215 if (IsFlagOn(pContext
->FileObject
->Flags
, FO_SYNCHRONOUS_IO
)) {
216 iosp
= IoGetCurrentIrpStackLocation(pContext
->MasterIrp
);
217 pContext
->FileObject
->CurrentByteOffset
.QuadPart
=
218 iosp
->Parameters
.Read
.ByteOffset
.QuadPart
+ pContext
->Length
;
224 pContext
->MasterIrp
->IoStatus
.Information
= 0;
227 /* release the locked resource acquired by the caller */
228 if (pContext
->Resource
) {
229 ExReleaseResourceForThread(pContext
->Resource
, pContext
->ThreadId
);
232 Ext2FreePool(pContext
, EXT2_RWC_MAGIC
);
233 DEC_MEM_COUNT(PS_RW_CONTEXT
, pContext
, sizeof(EXT2_RW_CONTEXT
));
236 return STATUS_SUCCESS
;
241 IN PEXT2_IRP_CONTEXT IrpContext
,
243 IN PEXT2_EXTENT Chain
,
248 PIRP MasterIrp
= IrpContext
->Irp
;
249 PIO_STACK_LOCATION IrpSp
;
251 PEXT2_RW_CONTEXT pContext
= NULL
;
254 NTSTATUS Status
= STATUS_SUCCESS
;
255 BOOLEAN bMasterCompleted
= FALSE
;
256 BOOLEAN bBugCheck
= FALSE
;
262 pContext
= Ext2AllocatePool(NonPagedPool
, sizeof(EXT2_RW_CONTEXT
), EXT2_RWC_MAGIC
);
265 DEBUG(DL_ERR
, ( "Ex2ReadWriteBlocks: failed to allocate pContext.\n"));
266 Status
= STATUS_INSUFFICIENT_RESOURCES
;
270 INC_MEM_COUNT(PS_RW_CONTEXT
, pContext
, sizeof(EXT2_RW_CONTEXT
));
271 RtlZeroMemory(pContext
, sizeof(EXT2_RW_CONTEXT
));
272 pContext
->Wait
= Ext2CanIWait();
273 pContext
->MasterIrp
= MasterIrp
;
274 pContext
->Length
= Length
;
276 if (IrpContext
->MajorFunction
== IRP_MJ_WRITE
) {
277 SetFlag(pContext
->Flags
, EXT2_RW_CONTEXT_WRITE
);
280 if (pContext
->Wait
) {
282 KeInitializeEvent(&(pContext
->Event
), NotificationEvent
, FALSE
);
284 } else if (IrpContext
->Fcb
->Identifier
.Type
== EXT2FCB
) {
286 if (IsFlagOn(MasterIrp
->Flags
, IRP_PAGING_IO
)) {
287 pContext
->Resource
= &IrpContext
->Fcb
->PagingIoResource
;
289 pContext
->Resource
= &IrpContext
->Fcb
->MainResource
;
292 pContext
->FileObject
= IrpContext
->FileObject
;
293 pContext
->ThreadId
= ExGetCurrentResourceThread();
297 if (NULL
== Chain
->Next
&& 0 == Chain
->Offset
) {
299 /* we get only 1 extent to dispatch, then don't bother allocating new irps */
301 /* setup the Stack location to do a read from the disk driver. */
302 IrpSp
= IoGetNextIrpStackLocation(MasterIrp
);
303 IrpSp
->MajorFunction
= IrpContext
->MajorFunction
;
304 IrpSp
->Parameters
.Read
.Length
= Chain
->Length
;
305 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= Chain
->Lba
;
306 if (IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
)) {
307 SetFlag(IrpSp
->Flags
, SL_WRITE_THROUGH
);
309 if (IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_VERIFY_READ
)) {
310 SetFlag(IrpSp
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
313 IoSetCompletionRoutine(
316 Ext2ReadWriteBlockSyncCompletionRoutine
:
317 Ext2ReadWriteBlockAsyncCompletionRoutine
,
323 /* intialize context block */
324 Chain
->Irp
= MasterIrp
;
325 pContext
->Blocks
= 1;
329 for (Extent
= Chain
; Extent
!= NULL
; Extent
= Extent
->Next
) {
331 Irp
= IoMakeAssociatedIrp(
333 (CCHAR
)(Vcb
->TargetDeviceObject
->StackSize
+ 1) );
336 Status
= STATUS_INSUFFICIENT_RESOURCES
;
340 Mdl
= IoAllocateMdl( (PCHAR
)MasterIrp
->UserBuffer
+
348 Status
= STATUS_INSUFFICIENT_RESOURCES
;
352 IoBuildPartialMdl( MasterIrp
->MdlAddress
,
354 (PCHAR
)MasterIrp
->UserBuffer
+Extent
->Offset
,
357 IoSetNextIrpStackLocation(Irp
);
358 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
360 IrpSp
->MajorFunction
= IrpContext
->MajorFunction
;
361 IrpSp
->Parameters
.Read
.Length
= Extent
->Length
;
362 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= Extent
->Lba
;
364 IoSetCompletionRoutine(
367 Ext2ReadWriteBlockSyncCompletionRoutine
:
368 Ext2ReadWriteBlockAsyncCompletionRoutine
,
374 IrpSp
= IoGetNextIrpStackLocation(Irp
);
376 IrpSp
->MajorFunction
= IrpContext
->MajorFunction
;
377 IrpSp
->Parameters
.Read
.Length
=Extent
->Length
;
378 IrpSp
->Parameters
.Read
.ByteOffset
.QuadPart
= Extent
->Lba
;
380 /* set write through flag */
381 if (IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
)) {
382 SetFlag( IrpSp
->Flags
, SL_WRITE_THROUGH
);
385 /* set verify flag */
386 if (IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_VERIFY_READ
)) {
387 SetFlag(IrpSp
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
391 pContext
->Blocks
+= 1;
394 MasterIrp
->AssociatedIrp
.IrpCount
= pContext
->Blocks
;
395 if (Ext2CanIWait()) {
396 MasterIrp
->AssociatedIrp
.IrpCount
+= 1;
399 if (!Ext2CanIWait()) {
400 /* mark MasterIrp pending */
401 IoMarkIrpPending(pContext
->MasterIrp
);
406 for (Extent
= Chain
; Extent
!= NULL
; Extent
= Extent
->Next
) {
407 Status
= IoCallDriver ( Vcb
->TargetDeviceObject
,
412 if (Ext2CanIWait()) {
413 KeWaitForSingleObject( &(pContext
->Event
),
414 Executive
, KernelMode
, FALSE
, NULL
);
415 KeClearEvent( &(pContext
->Event
) );
417 bMasterCompleted
= TRUE
;
422 for (Extent
= Chain
; Extent
!= NULL
; Extent
= Extent
->Next
) {
423 if (Extent
->Irp
!= NULL
) {
424 if (Extent
->Irp
->MdlAddress
!= NULL
) {
425 IoFreeMdl(Extent
->Irp
->MdlAddress
);
427 IoFreeIrp(Extent
->Irp
);
431 if (IrpContext
->ExceptionInProgress
) {
434 Ext2BugCheck(EXT2_BUGCHK_BLOCK
, 0, 0, 0);
439 if (Ext2CanIWait()) {
441 Status
= MasterIrp
->IoStatus
.Status
;
444 Ext2FreePool(pContext
, EXT2_RWC_MAGIC
);
445 DEC_MEM_COUNT(PS_RW_CONTEXT
, pContext
, sizeof(EXT2_RW_CONTEXT
));
448 if (bMasterCompleted
) {
449 IrpContext
->Irp
= NULL
;
450 Status
= STATUS_PENDING
;
468 PKEVENT Event
= NULL
;
471 IO_STATUS_BLOCK IoStatus
;
472 NTSTATUS Status
= STATUS_INSUFFICIENT_RESOURCES
;
476 ASSERT(Vcb
->TargetDeviceObject
!= NULL
);
477 ASSERT(Buffer
!= NULL
);
481 Event
= Ext2AllocatePool(NonPagedPool
, sizeof(KEVENT
), 'EK2E');
484 DEBUG(DL_ERR
, ( "Ex2ReadSync: failed to allocate Event.\n"));
488 INC_MEM_COUNT(PS_DISK_EVENT
, Event
, sizeof(KEVENT
));
490 KeInitializeEvent(Event
, NotificationEvent
, FALSE
);
492 Irp
= IoBuildSynchronousFsdRequest(
494 Vcb
->TargetDeviceObject
,
497 (PLARGE_INTEGER
)(&Offset
),
503 Status
= STATUS_INSUFFICIENT_RESOURCES
;
508 SetFlag( IoGetNextIrpStackLocation(Irp
)->Flags
,
509 SL_OVERRIDE_VERIFY_VOLUME
);
512 Status
= IoCallDriver(Vcb
->TargetDeviceObject
, Irp
);
514 if (Status
== STATUS_PENDING
) {
515 KeWaitForSingleObject(
523 Status
= IoStatus
.Status
;
529 Ext2FreePool(Event
, 'EK2E');
530 DEC_MEM_COUNT(PS_DISK_EVENT
, Event
, sizeof(KEVENT
));
551 Lba
= Offset
& (~((ULONGLONG
)SECTOR_SIZE
- 1));
552 Length
= (ULONG
)(Size
+ Offset
+ SECTOR_SIZE
- 1 - Lba
) &
553 (~((ULONG
)SECTOR_SIZE
- 1));
555 Buf
= Ext2AllocatePool(PagedPool
, Length
, EXT2_DATA_MAGIC
);
557 DEBUG(DL_ERR
, ( "Ext2ReadDisk: failed to allocate Buffer.\n"));
558 Status
= STATUS_INSUFFICIENT_RESOURCES
;
562 INC_MEM_COUNT(PS_DISK_BUFFER
, Buf
, Length
);
564 Status
= Ext2ReadSync( Vcb
,
570 if (!NT_SUCCESS(Status
)) {
571 DEBUG(DL_ERR
, ( "Ext2ReadDisk: disk device error.\n"));
576 RtlCopyMemory(Buffer
, &Buf
[Offset
- Lba
], Size
);
581 Ext2FreePool(Buf
, EXT2_DATA_MAGIC
);
582 DEC_MEM_COUNT(PS_DISK_BUFFER
, Buf
, Length
);
591 IN PDEVICE_OBJECT DeviceObject
,
593 IN PVOID InputBuffer
,
594 IN ULONG InputBufferSize
,
595 IN OUT PVOID OutputBuffer
,
596 IN OUT PULONG OutputBufferSize
)
598 ULONG OutBufferSize
= 0;
601 IO_STATUS_BLOCK IoStatus
;
604 ASSERT(DeviceObject
!= NULL
);
606 if (OutputBufferSize
)
608 OutBufferSize
= *OutputBufferSize
;
611 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
613 Irp
= IoBuildDeviceIoControlRequest(
626 DEBUG(DL_ERR
, ( "Ext2DiskIoControl: failed to build Irp!\n"));
627 return STATUS_INSUFFICIENT_RESOURCES
;
630 Status
= IoCallDriver(DeviceObject
, Irp
);
632 if (Status
== STATUS_PENDING
) {
633 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
634 Status
= IoStatus
.Status
;
637 if (OutputBufferSize
) {
638 *OutputBufferSize
= (ULONG
)(IoStatus
.Information
);
646 Ext2MediaEjectControlCompletion (
647 IN PDEVICE_OBJECT DeviceObject
,
652 PKEVENT Event
= (PKEVENT
)Contxt
;
654 KeSetEvent( Event
, 0, FALSE
);
656 UNREFERENCED_PARAMETER( DeviceObject
);
658 return STATUS_SUCCESS
;
662 Ext2MediaEjectControl (
663 IN PEXT2_IRP_CONTEXT IrpContext
,
671 PREVENT_MEDIA_REMOVAL Prevent
;
672 IO_STATUS_BLOCK IoStatus
;
675 ExAcquireResourceExclusiveLite(
679 if (bPrevent
!= IsFlagOn(Vcb
->Flags
, VCB_REMOVAL_PREVENTED
)) {
681 SetFlag(Vcb
->Flags
, VCB_REMOVAL_PREVENTED
);
683 ClearFlag(Vcb
->Flags
, VCB_REMOVAL_PREVENTED
);
687 ExReleaseResourceLite(&Vcb
->MainResource
);
689 Prevent
.PreventMediaRemoval
= bPrevent
;
691 KeInitializeEvent( &Event
, NotificationEvent
, FALSE
);
693 Irp
= IoBuildDeviceIoControlRequest( IOCTL_DISK_MEDIA_REMOVAL
,
694 Vcb
->TargetDeviceObject
,
696 sizeof(PREVENT_MEDIA_REMOVAL
),
704 IoSetCompletionRoutine( Irp
,
705 Ext2MediaEjectControlCompletion
,
711 Status
= IoCallDriver(Vcb
->TargetDeviceObject
, Irp
);
713 if (Status
== STATUS_PENDING
) {
714 Status
= KeWaitForSingleObject( &Event
,
725 Ext2DiskShutDown(PEXT2_VCB Vcb
)
731 IO_STATUS_BLOCK IoStatus
;
733 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
735 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
736 Vcb
->TargetDeviceObject
,
744 Status
= IoCallDriver(Vcb
->TargetDeviceObject
, Irp
);
746 if (Status
== STATUS_PENDING
) {
747 KeWaitForSingleObject(&Event
,
753 Status
= IoStatus
.Status
;
756 Status
= IoStatus
.Status
;