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 #pragma alloc_text(PAGE, Ext2AllocateInode)
22 #pragma alloc_text(PAGE, Ext2DestroyInode)
23 #pragma alloc_text(PAGE, Ext2CheckBitmapConsistency)
24 #pragma alloc_text(PAGE, Ext2CheckSetBlock)
25 #pragma alloc_text(PAGE, Ext2InitializeVcb)
26 #pragma alloc_text(PAGE, Ext2TearDownStream)
27 #pragma alloc_text(PAGE, Ext2DestroyVcb)
28 #pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap)
29 #pragma alloc_text(PAGE, Ext2ReaperThread)
30 #pragma alloc_text(PAGE, Ext2StartReaper)
31 #pragma alloc_text(PAGE, Ext2StopReaper)
35 Ext2AllocateIrpContext (IN PDEVICE_OBJECT DeviceObject
,
38 PIO_STACK_LOCATION irpSp
;
39 PEXT2_IRP_CONTEXT IrpContext
;
41 ASSERT(DeviceObject
!= NULL
);
44 irpSp
= IoGetCurrentIrpStackLocation(Irp
);
46 IrpContext
= (PEXT2_IRP_CONTEXT
) (
47 ExAllocateFromNPagedLookasideList(
48 &(Ext2Global
->Ext2IrpContextLookasideList
)));
50 if (IrpContext
== NULL
) {
54 RtlZeroMemory(IrpContext
, sizeof(EXT2_IRP_CONTEXT
) );
56 IrpContext
->Identifier
.Type
= EXT2ICX
;
57 IrpContext
->Identifier
.Size
= sizeof(EXT2_IRP_CONTEXT
);
59 IrpContext
->Irp
= Irp
;
60 IrpContext
->MajorFunction
= irpSp
->MajorFunction
;
61 IrpContext
->MinorFunction
= irpSp
->MinorFunction
;
62 IrpContext
->DeviceObject
= DeviceObject
;
63 IrpContext
->FileObject
= irpSp
->FileObject
;
64 if (NULL
!= IrpContext
->FileObject
) {
65 IrpContext
->Fcb
= (PEXT2_FCB
)IrpContext
->FileObject
->FsContext
;
66 IrpContext
->Ccb
= (PEXT2_CCB
)IrpContext
->FileObject
->FsContext2
;
69 if (IrpContext
->FileObject
!= NULL
) {
70 IrpContext
->RealDevice
= IrpContext
->FileObject
->DeviceObject
;
71 } else if (IrpContext
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) {
72 if (irpSp
->Parameters
.MountVolume
.Vpb
) {
73 IrpContext
->RealDevice
= irpSp
->Parameters
.MountVolume
.Vpb
->RealDevice
;
77 if (IsFlagOn(irpSp
->Flags
, SL_WRITE_THROUGH
)) {
78 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WRITE_THROUGH
);
81 if (IsFlagOn(irpSp
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
)) {
82 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_VERIFY_READ
);
85 if (IrpContext
->MajorFunction
== IRP_MJ_CLEANUP
||
86 IrpContext
->MajorFunction
== IRP_MJ_CLOSE
||
87 IrpContext
->MajorFunction
== IRP_MJ_SHUTDOWN
||
88 IrpContext
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
||
89 IrpContext
->MajorFunction
== IRP_MJ_PNP
) {
91 if (IrpContext
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
||
92 IrpContext
->MajorFunction
== IRP_MJ_PNP
) {
93 if (IoGetCurrentIrpStackLocation(Irp
)->FileObject
== NULL
||
94 IoIsOperationSynchronous(Irp
)) {
95 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
98 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
101 } else if (IoIsOperationSynchronous(Irp
)) {
103 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
106 IrpContext
->IsTopLevel
= (IoGetTopLevelIrp() == Irp
);
107 IrpContext
->ExceptionInProgress
= FALSE
;
108 INC_IRP_COUNT(IrpContext
);
114 Ext2FreeIrpContext (IN PEXT2_IRP_CONTEXT IrpContext
)
116 ASSERT(IrpContext
!= NULL
);
118 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
119 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
121 /* free the IrpContext to NonPagedList */
122 IrpContext
->Identifier
.Type
= 0;
123 IrpContext
->Identifier
.Size
= 0;
125 DEC_IRP_COUNT(IrpContext
);
126 ExFreeToNPagedLookasideList(&(Ext2Global
->Ext2IrpContextLookasideList
), IrpContext
);
138 ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb
->FcbLock
));
140 Fcb
= (PEXT2_FCB
) ExAllocateFromNPagedLookasideList(
141 &(Ext2Global
->Ext2FcbLookasideList
));
147 RtlZeroMemory(Fcb
, sizeof(EXT2_FCB
));
148 Fcb
->Identifier
.Type
= EXT2FCB
;
149 Fcb
->Identifier
.Size
= sizeof(EXT2_FCB
);
151 #ifndef _WIN2K_TARGET_
152 ExInitializeFastMutex(&Fcb
->Mutex
);
153 FsRtlSetupAdvancedHeader(&Fcb
->Header
, &Fcb
->Mutex
);
156 FsRtlInitializeOplock(&Fcb
->Oplock
);
157 FsRtlInitializeFileLock (
158 &Fcb
->FileLockAnchor
,
162 Fcb
->OpenHandleCount
= 0;
163 Fcb
->ReferenceCount
= 0;
165 Fcb
->Inode
= &Mcb
->Inode
;
167 ASSERT(Mcb
->Fcb
== NULL
);
172 DEBUG(DL_RES
, ("Ext2AllocateFcb: Fcb %p created: %wZ.\n",
173 Fcb
, &Fcb
->Mcb
->FullName
));
175 RtlZeroMemory(&Fcb
->Header
, sizeof(FSRTL_COMMON_FCB_HEADER
));
176 Fcb
->Header
.NodeTypeCode
= (USHORT
) EXT2FCB
;
177 Fcb
->Header
.NodeByteSize
= sizeof(EXT2_FCB
);
178 Fcb
->Header
.IsFastIoPossible
= FastIoIsNotPossible
;
179 Fcb
->Header
.Resource
= &(Fcb
->MainResource
);
180 Fcb
->Header
.PagingIoResource
= &(Fcb
->PagingIoResource
);
182 Fcb
->Header
.FileSize
.QuadPart
= Mcb
->Inode
.i_size
;
183 Fcb
->Header
.ValidDataLength
.QuadPart
= Mcb
->Inode
.i_size
;
184 Fcb
->Header
.AllocationSize
.QuadPart
= CEILING_ALIGNED(ULONGLONG
,
185 Fcb
->Header
.FileSize
.QuadPart
, (ULONGLONG
)Vcb
->BlockSize
);
187 Fcb
->SectionObject
.DataSectionObject
= NULL
;
188 Fcb
->SectionObject
.SharedCacheMap
= NULL
;
189 Fcb
->SectionObject
.ImageSectionObject
= NULL
;
191 ExInitializeResourceLite(&(Fcb
->MainResource
));
192 ExInitializeResourceLite(&(Fcb
->PagingIoResource
));
194 Ext2InsertFcb(Vcb
, Fcb
);
196 INC_MEM_COUNT(PS_FCB
, Fcb
, sizeof(EXT2_FCB
));
202 Ext2UnlinkFcb(IN PEXT2_FCB Fcb
)
204 PEXT2_VCB Vcb
= Fcb
->Vcb
;
207 ExAcquireResourceExclusiveLite(&Vcb
->McbLock
, TRUE
);
210 DEBUG(DL_INF
, ("Ext2FreeFcb: Fcb (%p) to be unlinked: %wZ.\n",
211 Fcb
, Mcb
? &Mcb
->FullName
: NULL
));
214 (Mcb
->Identifier
.Type
== EXT2MCB
) &&
215 (Mcb
->Identifier
.Size
== sizeof(EXT2_MCB
))) {
217 ASSERT (Mcb
->Fcb
== Fcb
);
218 if (IsMcbSpecialFile(Mcb
) ||
219 IsFileDeleted(Mcb
)) {
221 ASSERT(!IsRoot(Fcb
));
222 Ext2RemoveMcb(Vcb
, Mcb
);
225 Ext2UnlinkMcb(Vcb
, Mcb
);
227 Ext2LinkHeadMcb(Vcb
, Mcb
);
236 ExReleaseResourceLite(&Vcb
->McbLock
);
240 Ext2FreeFcb (IN PEXT2_FCB Fcb
)
242 PEXT2_VCB Vcb
= Fcb
->Vcb
;
246 ASSERT((Fcb
!= NULL
) && (Fcb
->Identifier
.Type
== EXT2FCB
) &&
247 (Fcb
->Identifier
.Size
== sizeof(EXT2_FCB
)));
248 ASSERT(0 == Fcb
->ReferenceCount
);
250 #ifndef _WIN2K_TARGET_
251 FsRtlTeardownPerStreamContexts(&Fcb
->Header
);
254 FsRtlUninitializeFileLock(&Fcb
->FileLockAnchor
);
255 FsRtlUninitializeOplock(&Fcb
->Oplock
);
256 ExDeleteResourceLite(&Fcb
->MainResource
);
257 ExDeleteResourceLite(&Fcb
->PagingIoResource
);
259 Fcb
->Identifier
.Type
= 0;
260 Fcb
->Identifier
.Size
= 0;
262 ExFreeToNPagedLookasideList(&(Ext2Global
->Ext2FcbLookasideList
), Fcb
);
263 DEC_MEM_COUNT(PS_FCB
, Fcb
, sizeof(EXT2_FCB
));
265 if (0 == Ext2DerefXcb(&Vcb
->ReferenceCount
)) {
266 if (!IsMounted(Vcb
) || IsDispending(Vcb
)) {
267 Ext2CheckDismount(NULL
, Vcb
, FALSE
);
276 Ext2ReleaseFcb (IN PEXT2_FCB Fcb
)
278 PEXT2_VCB Vcb
= Fcb
->Vcb
;
281 if (0 != Ext2DerefXcb(&Fcb
->ReferenceCount
))
284 ExAcquireResourceExclusiveLite(&Vcb
->FcbLock
, TRUE
);
285 ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, TRUE
);
288 RemoveEntryList(&Fcb
->Next
);
290 if (IsFlagOn(Fcb
->Flags
, FCB_DELETE_PENDING
) ||
291 NULL
== Mcb
|| IsFileDeleted(Mcb
)) {
292 InsertHeadList(&Vcb
->FcbList
, &Fcb
->Next
);
293 Fcb
->TsDrop
.QuadPart
= 0;
295 InsertTailList(&Vcb
->FcbList
, &Fcb
->Next
);
296 KeQuerySystemTime(&Fcb
->TsDrop
);
298 ExReleaseResourceLite(&Fcb
->MainResource
);
299 ExReleaseResourceLite(&Vcb
->FcbLock
);
301 if ((Vcb
->FcbCount
>> 6) > (ULONG
)(Ext2Global
->MaxDepth
)) {
302 KeSetEvent(&Ext2Global
->FcbReaper
.Wait
, 0, FALSE
);
306 /* Insert Fcb to Vcb->FcbList queue, with Vcb->FcbLock Acquired. */
309 Ext2InsertFcb(PEXT2_VCB Vcb
, PEXT2_FCB Fcb
)
311 ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb
->FcbLock
));
313 KeQuerySystemTime(&Fcb
->TsDrop
);
314 Ext2ReferXcb(&Vcb
->FcbCount
);
315 Ext2ReferXcb(&Vcb
->ReferenceCount
);
316 InsertTailList(&Vcb
->FcbList
, &Fcb
->Next
);
320 Ext2AllocateCcb (ULONG Flags
, PEXT2_MCB SymLink
)
324 Ccb
= (PEXT2_CCB
) (ExAllocateFromNPagedLookasideList(
325 &(Ext2Global
->Ext2CcbLookasideList
)));
330 DEBUG(DL_RES
, ( "ExtAllocateCcb: Ccb created: %ph.\n", Ccb
));
332 RtlZeroMemory(Ccb
, sizeof(EXT2_CCB
));
334 Ccb
->Identifier
.Type
= EXT2CCB
;
335 Ccb
->Identifier
.Size
= sizeof(EXT2_CCB
);
338 Ccb
->SymLink
= SymLink
;
340 ASSERT(SymLink
->Refercount
> 0);
341 Ext2ReferMcb(SymLink
);
342 DEBUG(DL_INF
, ( "ExtAllocateCcb: Ccb SymLink: %wZ.\n",
343 &Ccb
->SymLink
->FullName
));
346 Ccb
->DirectorySearchPattern
.Length
= 0;
347 Ccb
->DirectorySearchPattern
.MaximumLength
= 0;
348 Ccb
->DirectorySearchPattern
.Buffer
= 0;
350 INC_MEM_COUNT(PS_CCB
, Ccb
, sizeof(EXT2_CCB
));
356 Ext2FreeCcb (IN PEXT2_VCB Vcb
, IN PEXT2_CCB Ccb
)
359 ASSERT((Ccb
->Identifier
.Type
== EXT2CCB
) &&
360 (Ccb
->Identifier
.Size
== sizeof(EXT2_CCB
)));
362 DEBUG(DL_RES
, ( "Ext2FreeCcb: Ccb = %ph.\n", Ccb
));
365 DEBUG(DL_INF
, ( "Ext2FreeCcb: Ccb SymLink: %wZ.\n",
366 &Ccb
->SymLink
->FullName
));
367 if (IsFileDeleted(Ccb
->SymLink
->Target
)) {
368 Ext2UnlinkMcb(Vcb
, Ccb
->SymLink
);
369 Ext2DerefMcb(Ccb
->SymLink
);
370 Ext2LinkHeadMcb(Vcb
, Ccb
->SymLink
);
372 Ext2DerefMcb(Ccb
->SymLink
);
376 if (Ccb
->DirectorySearchPattern
.Buffer
!= NULL
) {
377 DEC_MEM_COUNT(PS_DIR_PATTERN
, Ccb
->DirectorySearchPattern
.Buffer
,
378 Ccb
->DirectorySearchPattern
.MaximumLength
);
379 Ext2FreePool(Ccb
->DirectorySearchPattern
.Buffer
, EXT2_DIRSP_MAGIC
);
382 ExFreeToNPagedLookasideList(&(Ext2Global
->Ext2CcbLookasideList
), Ccb
);
383 DEC_MEM_COUNT(PS_CCB
, Ccb
, sizeof(EXT2_CCB
));
387 Ext2AllocateInode (PEXT2_VCB Vcb
)
391 inode
= ExAllocateFromNPagedLookasideList(
392 &(Vcb
->InodeLookasideList
));
397 RtlZeroMemory(inode
, INODE_SIZE
);
399 DEBUG(DL_INF
, ("ExtAllocateInode: Inode created: %ph.\n", inode
));
400 INC_MEM_COUNT(PS_EXT2_INODE
, inode
, INODE_SIZE
);
406 Ext2DestroyInode (IN PEXT2_VCB Vcb
, IN PEXT2_INODE inode
)
408 ASSERT(inode
!= NULL
);
410 DEBUG(DL_INF
, ("Ext2FreeInode: Inode = %ph.\n", inode
));
412 ExFreeToNPagedLookasideList(&(Vcb
->InodeLookasideList
), inode
);
413 DEC_MEM_COUNT(PS_EXT2_INODE
, inode
, INODE_SIZE
);
416 struct dentry
* Ext2AllocateEntry()
420 de
= (struct dentry
*)ExAllocateFromNPagedLookasideList(
421 &(Ext2Global
->Ext2DentryLookasideList
));
426 RtlZeroMemory(de
, sizeof(struct dentry
));
427 INC_MEM_COUNT(PS_DENTRY
, de
, sizeof(struct dentry
));
432 VOID
Ext2FreeEntry (IN
struct dentry
*de
)
437 ExFreePool(de
->d_name
.name
);
439 ExFreeToNPagedLookasideList(&(Ext2Global
->Ext2DentryLookasideList
), de
);
440 DEC_MEM_COUNT(PS_DENTRY
, de
, sizeof(struct dentry
));
444 struct dentry
*Ext2BuildEntry(PEXT2_VCB Vcb
, PEXT2_MCB Dcb
, PUNICODE_STRING FileName
)
446 OEM_STRING Oem
= { 0 };
447 struct dentry
*de
= NULL
;
448 NTSTATUS Status
= STATUS_INSUFFICIENT_RESOURCES
;
452 de
= Ext2AllocateEntry();
454 DEBUG(DL_ERR
, ("Ext2BuildEntry: failed to allocate dentry.\n"));
459 de
->d_parent
= Dcb
->de
;
461 Oem
.MaximumLength
= (USHORT
)Ext2UnicodeToOEMSize(Vcb
, FileName
) + 1;
462 Oem
.Buffer
= ExAllocatePool(PagedPool
, Oem
.MaximumLength
);
464 DEBUG(DL_ERR
, ( "Ex2BuildEntry: failed to allocate OEM name.\n"));
467 de
->d_name
.name
= Oem
.Buffer
;
468 RtlZeroMemory(Oem
.Buffer
, Oem
.MaximumLength
);
469 Status
= Ext2UnicodeToOEM(Vcb
, &Oem
, FileName
);
470 if (!NT_SUCCESS(Status
)) {
471 DEBUG(DL_CP
, ("Ext2BuildEntry: failed to convert %S to OEM.\n", FileName
->Buffer
));
474 de
->d_name
.len
= Oem
.Length
;
478 if (!NT_SUCCESS(Status
)) {
488 Ext2AllocateExtent ()
492 Extent
= (PEXT2_EXTENT
)ExAllocateFromNPagedLookasideList(
493 &(Ext2Global
->Ext2ExtLookasideList
));
498 RtlZeroMemory(Extent
, sizeof(EXT2_EXTENT
));
499 INC_MEM_COUNT(PS_EXTENT
, Extent
, sizeof(EXT2_EXTENT
));
505 Ext2FreeExtent (IN PEXT2_EXTENT Extent
)
507 ASSERT(Extent
!= NULL
);
508 ExFreeToNPagedLookasideList(&(Ext2Global
->Ext2ExtLookasideList
), Extent
);
509 DEC_MEM_COUNT(PS_EXTENT
, Extent
, sizeof(EXT2_EXTENT
));
513 Ext2CountExtents(IN PEXT2_EXTENT Chain
)
516 PEXT2_EXTENT List
= Chain
;
528 IN PEXT2_EXTENT Chain
,
529 IN PEXT2_EXTENT Extent
535 PEXT2_EXTENT List
= Chain
;
546 Ext2DestroyExtentChain(IN PEXT2_EXTENT Chain
)
548 PEXT2_EXTENT Extent
= NULL
, List
= Chain
;
552 Ext2FreeExtent(List
);
558 Ext2ListExtents(PLARGE_MCB Extents
)
560 if (FsRtlNumberOfRunsInLargeMcb(Extents
) != 0) {
564 LONGLONG DirtyLength
;
567 for (i
= 0; FsRtlGetNextLargeMcbEntry(
568 Extents
, i
, &DirtyVba
,
569 &DirtyLba
, &DirtyLength
); i
++) {
570 if (DirtyVba
> 0 && DirtyLba
!= -1) {
571 DEBUG(DL_EXT
, ("Vba:%I64xh Lba:%I64xh Len:%I64xh.\n", DirtyVba
, DirtyLba
, DirtyLength
));
576 return n
? TRUE
: FALSE
;
597 BOOLEAN bFound
= FALSE
;
599 bFound
= FsRtlLookupLargeMcbEntry(
608 if (!bAdded
&& (!bFound
|| DirtyLbn
== -1)) {
612 if ( !bFound
|| (DirtyLbn
== -1) ||
614 (DirtyLen
< Length
)) {
618 for (Index
= 0; TRUE
; Index
++) {
620 if (!FsRtlGetNextLargeMcbEntry(
629 DEBUG(DL_EXT
, ("Index = %xh Vbn = %I64xh Lbn = %I64xh Len = %I64xh\n",
630 Index
, Vbn
, Lbn
, Length
));
637 Ext2ClearAllExtents(PLARGE_MCB Zone
)
640 FsRtlTruncateLargeMcb(Zone
, (LONGLONG
)0);
641 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
654 ULONG TriedTimes
= 0;
659 Offset
= Vbn
& (~(Vcb
->IoUnitSize
- 1));
660 Length
= (Vbn
- Offset
+ Length
+ Vcb
->IoUnitSize
- 1) &
661 ~(Vcb
->IoUnitSize
- 1);
663 ASSERT ((Offset
& (Vcb
->IoUnitSize
- 1)) == 0);
664 ASSERT ((Length
& (Vcb
->IoUnitSize
- 1)) == 0);
666 Offset
= (Offset
>> Vcb
->IoUnitBits
) + 1;
667 Length
= (Length
>> Vcb
->IoUnitBits
);
672 rc
= FsRtlAddLargeMcbEntry(
678 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
683 if (!rc
&& ++TriedTimes
< 10) {
684 Ext2Sleep(TriedTimes
* 100);
688 DEBUG(DL_EXT
, ("Ext2AddVcbExtent: Vbn=%I64xh Length=%I64xh,"
689 " rc=%d Runs=%u\n", Offset
, Length
, rc
,
690 FsRtlNumberOfRunsInLargeMcb(&Vcb
->Extents
)));
693 Ext2CheckExtent(&Vcb
->Extents
, Offset
, Offset
, Length
, TRUE
);
700 Ext2RemoveVcbExtent (
706 ULONG TriedTimes
= 0;
710 Offset
= Vbn
& (~(Vcb
->IoUnitSize
- 1));
711 Length
= (Length
+ Vbn
- Offset
+ Vcb
->IoUnitSize
- 1) & (~(Vcb
->IoUnitSize
- 1));
713 ASSERT ((Offset
& (Vcb
->IoUnitSize
- 1)) == 0);
714 ASSERT ((Length
& (Vcb
->IoUnitSize
- 1)) == 0);
716 Offset
= (Offset
>> Vcb
->IoUnitBits
) + 1;
717 Length
= (Length
>> Vcb
->IoUnitBits
);
722 FsRtlRemoveLargeMcbEntry(
727 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
732 if (!rc
&& ++TriedTimes
< 10) {
733 Ext2Sleep(TriedTimes
* 100);
737 DEBUG(DL_EXT
, ("Ext2RemoveVcbExtent: Vbn=%I64xh Length=%I64xh Runs=%u\n",
738 Offset
, Length
, FsRtlNumberOfRunsInLargeMcb(&Vcb
->Extents
)));
740 Ext2CheckExtent(&Vcb
->Extents
, Offset
, 0, Length
, FALSE
);
747 Ext2LookupVcbExtent (
757 offset
= Vbn
& (~(Vcb
->IoUnitSize
- 1));
758 ASSERT ((offset
& (Vcb
->IoUnitSize
- 1)) == 0);
759 offset
= (offset
>> Vcb
->IoUnitBits
) + 1;
761 rc
= FsRtlLookupLargeMcbEntry(
773 if (Lbn
&& ((*Lbn
) != -1)) {
775 (*Lbn
) = (((*Lbn
) - 1) << Vcb
->IoUnitBits
);
776 (*Lbn
) += ((Vbn
) & (Vcb
->IoUnitSize
- 1));
779 if (Length
&& *Length
) {
780 (*Length
) <<= Vcb
->IoUnitBits
;
781 (*Length
) -= ((Vbn
) & (Vcb
->IoUnitSize
- 1));
798 ULONG TriedTimes
= 0;
803 Base
= (LONGLONG
)BLOCK_SIZE
;
804 Bits
= (UCHAR
)BLOCK_BITS
;
806 ASSERT ((Vbn
& (Base
- 1)) == 0);
807 ASSERT ((Lbn
& (Base
- 1)) == 0);
808 ASSERT ((Length
& (Base
- 1)) == 0);
810 Vbn
= (Vbn
>> Bits
) + 1;
811 Lbn
= (Lbn
>> Bits
) + 1;
812 Length
= (Length
>> Bits
);
818 rc
= FsRtlAddLargeMcbEntry(
825 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
831 if (!rc
&& ++TriedTimes
< 10) {
832 Ext2Sleep(TriedTimes
* 100);
836 DEBUG(DL_EXT
, ("Ext2AddMcbExtent: Vbn=%I64xh Lbn=%I64xh Length=%I64xh,"
837 " rc=%d Runs=%u\n", Vbn
, Lbn
, Length
, rc
,
838 FsRtlNumberOfRunsInLargeMcb(&Mcb
->Extents
)));
841 Ext2CheckExtent(&Mcb
->Extents
, Vbn
, Lbn
, Length
, TRUE
);
848 Ext2RemoveMcbExtent (
855 ULONG TriedTimes
= 0;
860 Base
= (LONGLONG
)BLOCK_SIZE
;
861 Bits
= (UCHAR
)BLOCK_BITS
;
863 ASSERT ((Vbn
& (Base
- 1)) == 0);
864 ASSERT ((Length
& (Base
- 1)) == 0);
866 Vbn
= (Vbn
>> Bits
) + 1;
867 Length
= (Length
>> Bits
);
872 FsRtlRemoveLargeMcbEntry(
877 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
882 if (!rc
&& ++TriedTimes
< 10) {
883 Ext2Sleep(TriedTimes
* 100);
887 DEBUG(DL_EXT
, ("Ext2RemoveMcbExtent: Vbn=%I64xh Length=%I64xh Runs=%u\n",
888 Vbn
, Length
, FsRtlNumberOfRunsInLargeMcb(&Mcb
->Extents
)));
890 Ext2CheckExtent(&Mcb
->Extents
, Vbn
, 0, Length
, FALSE
);
897 Ext2LookupMcbExtent (
908 offset
= Vbn
& (~((LONGLONG
)BLOCK_SIZE
- 1));
909 ASSERT ((offset
& (BLOCK_SIZE
- 1)) == 0);
910 offset
= (offset
>> BLOCK_BITS
) + 1;
912 rc
= FsRtlLookupLargeMcbEntry(
924 if (Lbn
&& ((*Lbn
) != -1)) {
926 (*Lbn
) = (((*Lbn
) - 1) << BLOCK_BITS
);
927 (*Lbn
) += ((Vbn
) & ((LONGLONG
)BLOCK_SIZE
- 1));
930 if (Length
&& *Length
) {
931 (*Length
) <<= BLOCK_BITS
;
932 (*Length
) -= ((Vbn
) & ((LONGLONG
)BLOCK_SIZE
- 1));
948 ULONG TriedTimes
= 0;
949 LONGLONG Lbn
= Block
+ 1;
956 rc
= FsRtlAddLargeMcbEntry(
963 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
969 if (!rc
&& ++TriedTimes
< 10) {
970 Ext2Sleep(TriedTimes
* 100);
974 DEBUG(DL_EXT
, ("Ext2AddMcbMetaExts: Block: %xh-%xh rc=%d Runs=%u\n", Block
,
975 Length
, rc
, FsRtlNumberOfRunsInLargeMcb(&Mcb
->MetaExts
)));
978 Ext2CheckExtent(&Mcb
->MetaExts
, Lbn
, Lbn
, Length
, TRUE
);
985 Ext2RemoveMcbMetaExts (
992 ULONG TriedTimes
= 0;
993 LONGLONG Lbn
= Block
+ 1;
1000 FsRtlRemoveLargeMcbEntry(
1006 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
1011 if (!rc
&& ++TriedTimes
< 10) {
1012 Ext2Sleep(TriedTimes
* 100);
1016 DEBUG(DL_EXT
, ("Ext2RemoveMcbMetaExts: Block: %xh-%xhh Runs=%u\n", Block
,
1017 Length
, FsRtlNumberOfRunsInLargeMcb(&Mcb
->MetaExts
)));
1019 Ext2CheckExtent(&Mcb
->MetaExts
, Lbn
, 0, Length
, FALSE
);
1037 LONGLONG Length
= 0;
1039 Vbn
= ((LONGLONG
) Start
) << BLOCK_BITS
;
1040 Lbn
= ((LONGLONG
) Block
) << BLOCK_BITS
;
1041 Length
= ((LONGLONG
)Number
<< BLOCK_BITS
);
1045 ULONG _block
= 0, _mapped
= 0;
1046 BOOLEAN _rc
= Ext2LookupBlockExtent(Vcb
, Mcb
, Start
, &_block
, &_mapped
);
1047 if (_rc
&& _block
!= 0 && (_block
!= Block
)) {
1051 return Ext2AddMcbExtent(Vcb
, Mcb
, Vbn
, Lbn
, Length
);
1055 ASSERT(Start
== Block
);
1056 return Ext2AddVcbExtent(Vcb
, Vbn
, Length
);
1061 Ext2LookupBlockExtent(
1071 LONGLONG Length
= 0;
1075 Vbn
= ((LONGLONG
) Start
) << BLOCK_BITS
;
1078 rc
= Ext2LookupMcbExtent(Vcb
, Mcb
, Vbn
, &Lbn
, &Length
);
1080 rc
= Ext2LookupVcbExtent(Vcb
, Vbn
, &Lbn
, &Length
);
1084 *Mapped
= (ULONG
)(Length
>> BLOCK_BITS
);
1085 if (Lbn
!= -1 && Length
> 0) {
1086 *Block
= (ULONG
)(Lbn
>> BLOCK_BITS
);
1097 Ext2RemoveBlockExtent(
1105 LONGLONG Length
= 0;
1108 Vbn
= ((LONGLONG
) Start
) << BLOCK_BITS
;
1109 Length
= ((LONGLONG
)Number
<< BLOCK_BITS
);
1112 rc
= Ext2RemoveMcbExtent(Vcb
, Mcb
, Vbn
, Length
);
1114 rc
= Ext2RemoveVcbExtent(Vcb
, Vbn
, Length
);
1122 IN PEXT2_IRP_CONTEXT IrpContext
,
1127 NTSTATUS Status
= STATUS_SUCCESS
;
1134 Ext2ClearAllExtents(&Mcb
->Extents
);
1135 Ext2ClearAllExtents(&Mcb
->MetaExts
);
1137 ASSERT(Mcb
!= NULL
);
1138 End
= (ULONG
)((Mcb
->Inode
.i_size
+ BLOCK_SIZE
- 1) >> BLOCK_BITS
);
1140 while (Start
< End
) {
1144 /* mapping file offset to ext2 block */
1145 if (INODE_HAS_EXTENT(&Mcb
->Inode
)) {
1146 Status
= Ext2MapExtent(
1156 Status
= Ext2MapIndirect(
1167 if (!NT_SUCCESS(Status
)) {
1171 /* skip wrong blocks, in case wrongly treating symlink
1172 target names as blocks, silly */
1173 if (Block
>= TOTAL_BLOCKS
) {
1178 if (!Ext2AddBlockExtent(Vcb
, Mcb
, Start
, Block
, Mapped
)) {
1180 ClearFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
1181 Ext2ClearAllExtents(&Mcb
->Extents
);
1182 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1185 DEBUG(DL_MAP
, ("Ext2InitializeZone %wZ: Block = %xh Mapped = %xh\n",
1186 &Mcb
->FullName
, Block
, Mapped
));
1189 /* Mapped is total number of continous blocks or NULL blocks */
1193 /* set mcb zone as initialized */
1194 SetLongFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
1198 if (!IsZoneInited(Mcb
)) {
1199 Ext2ClearAllExtents(&Mcb
->Extents
);
1200 Ext2ClearAllExtents(&Mcb
->MetaExts
);
1208 IN PEXT2_IRP_CONTEXT IrpContext
,
1211 IN ULONGLONG Offset
,
1214 OUT PEXT2_EXTENT
* Chain
1221 NTSTATUS Status
= STATUS_SUCCESS
;
1223 PEXT2_EXTENT Extent
= NULL
;
1224 PEXT2_EXTENT List
= *Chain
= NULL
;
1226 if (!IsZoneInited(Mcb
)) {
1227 Status
= Ext2InitializeZone(IrpContext
, Vcb
, Mcb
);
1228 if (!NT_SUCCESS(Status
)) {
1233 if ((IrpContext
&& IrpContext
->Irp
) &&
1234 ((IrpContext
->Irp
->Flags
& IRP_NOCACHE
) ||
1235 (IrpContext
->Irp
->Flags
& IRP_PAGING_IO
))) {
1236 Size
= (Size
+ SECTOR_SIZE
- 1) & (~(SECTOR_SIZE
- 1));
1239 Start
= (ULONG
)(Offset
>> BLOCK_BITS
);
1240 End
= (ULONG
)((Size
+ Offset
+ BLOCK_SIZE
- 1) >> BLOCK_BITS
);
1242 if (End
> (ULONG
)((Mcb
->Inode
.i_size
+ BLOCK_SIZE
- 1) >> BLOCK_BITS
) ) {
1243 End
= (ULONG
)((Mcb
->Inode
.i_size
+ BLOCK_SIZE
- 1) >> BLOCK_BITS
);
1246 while (Size
> 0 && Start
< End
) {
1254 /* try to map file offset to ext2 block upon Extents cache */
1255 if (IsZoneInited(Mcb
)) {
1256 rc
= Ext2LookupBlockExtent(
1264 /* we likely get a sparse file here */
1270 /* try to BlockMap in case failed to access Extents cache */
1271 if (!IsZoneInited(Mcb
) || (bAlloc
&& Block
== 0)) {
1273 Status
= Ext2BlockMap(
1282 if (!NT_SUCCESS(Status
)) {
1286 /* skip wrong blocks, in case wrongly treating symlink
1287 target names as blocks, silly */
1288 if (Block
>= TOTAL_BLOCKS
) {
1292 /* add new allocated blocks to Mcb zone */
1293 if (IsZoneInited(Mcb
) && Block
) {
1294 if (!Ext2AddBlockExtent(Vcb
, Mcb
, Start
, Block
, Mapped
)) {
1296 ClearFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
1297 Ext2ClearAllExtents(&Mcb
->Extents
);
1302 /* calculate i/o extent */
1303 Lba
= ((LONGLONG
)Block
<< BLOCK_BITS
) + Offset
- ((LONGLONG
)Start
<< BLOCK_BITS
);
1304 Length
= (ULONG
)(((LONGLONG
)(Start
+ Mapped
) << BLOCK_BITS
) - Offset
);
1305 if (Length
> Size
) {
1315 Offset
= (ULONGLONG
)Start
<< BLOCK_BITS
;
1319 if (List
&& List
->Lba
+ List
->Length
== Lba
) {
1321 /* it's continuous upon previous Extent */
1322 List
->Length
+= Length
;
1326 /* have to allocate a new Extent */
1327 Extent
= Ext2AllocateExtent();
1329 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1335 Extent
->Length
= Length
;
1336 Extent
->Offset
= Total
;
1338 /* insert new Extent to chain */
1340 List
->Next
= Extent
;
1343 *Chain
= List
= Extent
;
1362 IN OUT PUNICODE_STRING Target
,
1363 IN PUNICODE_STRING File
,
1364 IN PUNICODE_STRING Parent
1368 USHORT ParentLen
= 0;
1369 BOOLEAN bBackslash
= TRUE
;
1371 /* free the original buffer */
1372 if (Target
->Buffer
) {
1373 DEC_MEM_COUNT(PS_MCB_NAME
, Target
->Buffer
, Target
->MaximumLength
);
1374 Ext2FreePool(Target
->Buffer
, EXT2_FNAME_MAGIC
);
1375 Target
->Length
= Target
->MaximumLength
= 0;
1378 /* check the parent directory's name and backslash */
1379 if (Parent
&& Parent
->Buffer
&& Parent
->Length
> 0) {
1380 ParentLen
= Parent
->Length
/ sizeof(WCHAR
);
1381 if (Parent
->Buffer
[ParentLen
- 1] == L
'\\') {
1386 if (Parent
== NULL
|| File
->Buffer
[0] == L
'\\') {
1387 /* must be root inode */
1388 ASSERT(ParentLen
== 0);
1392 /* allocate and initialize new name buffer */
1393 Length
= File
->Length
;
1394 Length
+= (ParentLen
+ (bBackslash
? 1 : 0)) * sizeof(WCHAR
);
1396 Target
->Buffer
= Ext2AllocatePool(
1402 if (!Target
->Buffer
) {
1403 DEBUG(DL_ERR
, ( "Ex2BuildName: failed to allocate name bufer.\n"));
1406 RtlZeroMemory(Target
->Buffer
, Length
+ 2);
1409 RtlCopyMemory(&Target
->Buffer
[0],
1411 ParentLen
* sizeof(WCHAR
));
1415 Target
->Buffer
[ParentLen
++] = L
'\\';
1418 RtlCopyMemory( &Target
->Buffer
[ParentLen
],
1422 INC_MEM_COUNT(PS_MCB_NAME
, Target
->Buffer
, Length
+ 2);
1423 Target
->Length
= Length
;
1424 Target
->MaximumLength
= Length
+ 2;
1432 IN PUNICODE_STRING FileName
,
1433 IN PUNICODE_STRING Parent
,
1437 PEXT2_MCB Mcb
= NULL
;
1438 NTSTATUS Status
= STATUS_SUCCESS
;
1440 /* need wake the reaper thread if there are many Mcb allocated */
1441 if (Ext2Global
->PerfStat
.Current
.Mcb
> (((ULONG
)Ext2Global
->MaxDepth
) * 4)) {
1442 KeSetEvent(&Ext2Global
->McbReaper
.Wait
, 0, FALSE
);
1445 /* allocate Mcb from LookasideList */
1446 Mcb
= (PEXT2_MCB
) (ExAllocateFromNPagedLookasideList(
1447 &(Ext2Global
->Ext2McbLookasideList
)));
1453 /* initialize Mcb header */
1454 RtlZeroMemory(Mcb
, sizeof(EXT2_MCB
));
1455 Mcb
->Identifier
.Type
= EXT2MCB
;
1456 Mcb
->Identifier
.Size
= sizeof(EXT2_MCB
);
1457 Mcb
->FileAttr
= FileAttr
;
1459 Mcb
->Inode
.i_priv
= (PVOID
)Mcb
;
1460 Mcb
->Inode
.i_sb
= &Vcb
->sb
;
1462 /* initialize Mcb names */
1466 if ( FileName
->Length
== 2 &&
1467 FileName
->Buffer
[0] == L
'\\') {
1468 DEBUG(DL_RES
, ( "Ext2AllocateMcb: Root Mcb is to be created !\n"));
1471 if ( FileName
->Length
== 2 &&
1472 FileName
->Buffer
[0] == L
'.') {
1476 if ( FileName
->Length
== 4 &&
1477 FileName
->Buffer
[0] == L
'.' &&
1478 FileName
->Buffer
[1] == L
'.' ) {
1483 if (( FileName
->Length
>= 4 && FileName
->Buffer
[0] == L
'.') &&
1484 ((FileName
->Length
== 4 && FileName
->Buffer
[1] != L
'.') ||
1485 FileName
->Length
>= 6 )) {
1486 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_HIDDEN
);
1489 if (!Ext2BuildName(&Mcb
->ShortName
, FileName
, NULL
)) {
1492 if (!Ext2BuildName(&Mcb
->FullName
, FileName
, Parent
)) {
1497 /* initialize Mcb Extents, it will raise an expcetion if failed */
1499 FsRtlInitializeLargeMcb(&(Mcb
->Extents
), NonPagedPool
);
1500 FsRtlInitializeLargeMcb(&(Mcb
->MetaExts
), NonPagedPool
);
1501 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
1502 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1506 if (!NT_SUCCESS(Status
)) {
1510 INC_MEM_COUNT(PS_MCB
, Mcb
, sizeof(EXT2_MCB
));
1511 DEBUG(DL_INF
, ( "Ext2AllocateMcb: Mcb %wZ created.\n", &Mcb
->FullName
));
1519 if (Mcb
->ShortName
.Buffer
) {
1520 DEC_MEM_COUNT(PS_MCB_NAME
, Mcb
->ShortName
.Buffer
,
1521 Mcb
->ShortName
.MaximumLength
);
1522 Ext2FreePool(Mcb
->ShortName
.Buffer
, EXT2_FNAME_MAGIC
);
1525 if (Mcb
->FullName
.Buffer
) {
1526 DEC_MEM_COUNT(PS_MCB_NAME
, Mcb
->FullName
.Buffer
,
1527 Mcb
->FullName
.MaximumLength
);
1528 Ext2FreePool(Mcb
->FullName
.Buffer
, EXT2_FNAME_MAGIC
);
1531 ExFreeToNPagedLookasideList(&(Ext2Global
->Ext2McbLookasideList
), Mcb
);
1538 Ext2FreeMcb (IN PEXT2_VCB Vcb
, IN PEXT2_MCB Mcb
)
1541 PEXT2_MCB Parent
= Mcb
->Parent
;
1544 ASSERT(Mcb
!= NULL
);
1546 ASSERT((Mcb
->Identifier
.Type
== EXT2MCB
) &&
1547 (Mcb
->Identifier
.Size
== sizeof(EXT2_MCB
)));
1549 if ((Mcb
->Identifier
.Type
!= EXT2MCB
) ||
1550 (Mcb
->Identifier
.Size
!= sizeof(EXT2_MCB
))) {
1554 DEBUG(DL_INF
, ( "Ext2FreeMcb: Mcb %wZ will be freed.\n", &Mcb
->FullName
));
1556 if (IsMcbSymLink(Mcb
) && Mcb
->Target
) {
1557 Ext2DerefMcb(Mcb
->Target
);
1560 if (FsRtlNumberOfRunsInLargeMcb(&Mcb
->Extents
)) {
1561 DEBUG(DL_EXT
, ("List data extents for: %wZ\n", &Mcb
->FullName
));
1562 Ext2ListExtents(&Mcb
->Extents
);
1564 FsRtlUninitializeLargeMcb(&(Mcb
->Extents
));
1565 if (FsRtlNumberOfRunsInLargeMcb(&Mcb
->MetaExts
)) {
1566 DEBUG(DL_EXT
, ("List meta extents for: %wZ\n", &Mcb
->FullName
));
1567 Ext2ListExtents(&Mcb
->MetaExts
);
1569 FsRtlUninitializeLargeMcb(&(Mcb
->MetaExts
));
1570 ClearLongFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
1572 if (Mcb
->ShortName
.Buffer
) {
1573 DEC_MEM_COUNT(PS_MCB_NAME
, Mcb
->ShortName
.Buffer
,
1574 Mcb
->ShortName
.MaximumLength
);
1575 Ext2FreePool(Mcb
->ShortName
.Buffer
, EXT2_FNAME_MAGIC
);
1578 if (Mcb
->FullName
.Buffer
) {
1579 DEC_MEM_COUNT(PS_MCB_NAME
, Mcb
->FullName
.Buffer
,
1580 Mcb
->FullName
.MaximumLength
);
1581 Ext2FreePool(Mcb
->FullName
.Buffer
, EXT2_FNAME_MAGIC
);
1586 Ext2FreeEntry(Mcb
->de
);
1589 Mcb
->Identifier
.Type
= 0;
1590 Mcb
->Identifier
.Size
= 0;
1592 ExFreeToNPagedLookasideList(&(Ext2Global
->Ext2McbLookasideList
), Mcb
);
1593 DEC_MEM_COUNT(PS_MCB
, Mcb
, sizeof(EXT2_MCB
));
1601 PUNICODE_STRING FileName
1604 BOOLEAN LockAcquired
= FALSE
;
1605 PEXT2_MCB Mcb
= NULL
;
1608 ExAcquireResourceSharedLite(&Vcb
->McbLock
, TRUE
);
1609 LockAcquired
= TRUE
;
1610 Mcb
= Ext2SearchMcbWithoutLock(Parent
, FileName
);
1613 ExReleaseResourceLite(&Vcb
->McbLock
);
1622 Ext2SearchMcbWithoutLock(
1624 PUNICODE_STRING FileName
1627 PEXT2_MCB TmpMcb
= NULL
;
1629 DEBUG(DL_RES
, ("Ext2SearchMcb: %wZ\n", FileName
));
1633 Ext2ReferMcb(Parent
);
1635 if (Ext2IsDot(FileName
)) {
1637 Ext2ReferMcb(Parent
);
1641 if (Ext2IsDotDot(FileName
)) {
1642 if (IsMcbRoot(Parent
)) {
1645 TmpMcb
= Parent
->Parent
;
1648 Ext2ReferMcb(TmpMcb
);
1653 if (IsMcbSymLink(Parent
)) {
1654 if (Parent
->Target
) {
1655 TmpMcb
= Parent
->Target
->Child
;
1656 ASSERT(!IsMcbSymLink(Parent
->Target
));
1662 TmpMcb
= Parent
->Child
;
1667 if (!RtlCompareUnicodeString(
1668 &(TmpMcb
->ShortName
),
1670 Ext2ReferMcb(TmpMcb
);
1674 TmpMcb
= TmpMcb
->Next
;
1679 Ext2DerefMcb(Parent
);
1692 BOOLEAN LockAcquired
= FALSE
;
1693 PEXT2_MCB Mcb
= NULL
;
1697 ExAcquireResourceExclusiveLite(
1700 LockAcquired
= TRUE
;
1702 /* use it's target if it's a symlink */
1703 if (IsMcbSymLink(Parent
)) {
1704 Parent
= Parent
->Target
;
1705 ASSERT(!IsMcbSymLink(Parent
));
1708 Mcb
= Parent
->Child
;
1717 /* already attached in the list */
1718 DEBUG(DL_ERR
, ( "Ext2InsertMcb: Child Mcb is alreay attached.\n"));
1719 if (!IsFlagOn(Mcb
->Flags
, MCB_ENTRY_TREE
)) {
1720 SetLongFlag(Child
->Flags
, MCB_ENTRY_TREE
);
1721 DEBUG(DL_ERR
, ( "Ext2InsertMcb: Child Mcb's flag isn't set.\n"));
1728 /* insert this Mcb into the head */
1729 Child
->Next
= Parent
->Child
;
1730 Parent
->Child
= Child
;
1731 Child
->Parent
= Parent
;
1732 Child
->de
->d_parent
= Parent
->de
;
1733 Ext2ReferMcb(Parent
);
1734 SetLongFlag(Child
->Flags
, MCB_ENTRY_TREE
);
1740 ExReleaseResourceLite(&Vcb
->McbLock
);
1751 PEXT2_MCB TmpMcb
= NULL
;
1752 BOOLEAN LockAcquired
= FALSE
;
1753 BOOLEAN bLinked
= FALSE
;
1757 ExAcquireResourceExclusiveLite(&Vcb
->McbLock
, TRUE
);
1758 LockAcquired
= TRUE
;
1762 if (Mcb
->Parent
->Child
== Mcb
) {
1763 Mcb
->Parent
->Child
= Mcb
->Next
;
1766 TmpMcb
= Mcb
->Parent
->Child
;
1768 while (TmpMcb
&& TmpMcb
->Next
!= Mcb
) {
1769 TmpMcb
= TmpMcb
->Next
;
1773 TmpMcb
->Next
= Mcb
->Next
;
1776 /* we got errors: link broken */
1781 if (IsFlagOn(Mcb
->Flags
, MCB_ENTRY_TREE
)) {
1782 DEBUG(DL_RES
, ("Mcb %p %wZ removed from Mcb %p %wZ\n", Mcb
,
1783 &Mcb
->FullName
, Mcb
->Parent
, &Mcb
->Parent
->FullName
));
1784 Ext2DerefMcb(Mcb
->Parent
);
1785 ClearLongFlag(Mcb
->Flags
, MCB_ENTRY_TREE
);
1790 if (IsFlagOn(Mcb
->Flags
, MCB_ENTRY_TREE
)) {
1791 ClearLongFlag(Mcb
->Flags
, MCB_ENTRY_TREE
);
1796 Mcb
->de
->d_parent
= NULL
;
1802 ExReleaseResourceLite(&Vcb
->McbLock
);
1810 Ext2CleanupAllMcbs(PEXT2_VCB Vcb
)
1812 BOOLEAN LockAcquired
= FALSE
;
1813 PEXT2_MCB Mcb
= NULL
;
1817 ExAcquireResourceExclusiveLite(
1820 LockAcquired
= TRUE
;
1822 while ((Mcb
= Ext2FirstUnusedMcb(Vcb
, TRUE
, Vcb
->NumOfMcb
)) != 0) {
1824 PEXT2_MCB Next
= Mcb
->Next
;
1825 if (IsMcbSymLink(Mcb
)) {
1828 Ext2FreeMcb(Vcb
, Mcb
);
1832 Ext2FreeMcb(Vcb
, Vcb
->McbTree
);
1833 Vcb
->McbTree
= NULL
;
1838 ExReleaseResourceLite(&Vcb
->McbLock
);
1844 Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext
, PEXT2_VCB Vcb
, LONGLONG Block
)
1846 PEXT2_GROUP_DESC gd
;
1847 struct buffer_head
*gb
= NULL
;
1848 struct buffer_head
*bh
= NULL
;
1849 ULONG group
, dwBlk
, Length
;
1851 BOOLEAN bModified
= FALSE
;
1853 group
= (ULONG
)(Block
- EXT2_FIRST_DATA_BLOCK
) / BLOCKS_PER_GROUP
;
1854 dwBlk
= (ULONG
)(Block
- EXT2_FIRST_DATA_BLOCK
) % BLOCKS_PER_GROUP
;
1856 gd
= ext4_get_group_desc(&Vcb
->sb
, group
, &gb
);
1860 bh
= sb_getblk(&Vcb
->sb
, ext4_block_bitmap(&Vcb
->sb
, gd
));
1862 if (group
== Vcb
->sbi
.s_groups_count
- 1) {
1863 Length
= (ULONG
)(TOTAL_BLOCKS
% BLOCKS_PER_GROUP
);
1865 /* s_blocks_count is integer multiple of s_blocks_per_group */
1867 Length
= BLOCKS_PER_GROUP
;
1869 Length
= BLOCKS_PER_GROUP
;
1872 if (dwBlk
>= Length
) {
1879 RtlInitializeBitMap(&bitmap
, (PULONG
)bh
->b_data
, Length
);
1881 if (RtlCheckBit(&bitmap
, dwBlk
) == 0) {
1883 RtlSetBits(&bitmap
, dwBlk
, 1);
1885 mark_buffer_dirty(bh
);
1891 return (!bModified
);
1895 Ext2CheckBitmapConsistency(PEXT2_IRP_CONTEXT IrpContext
, PEXT2_VCB Vcb
)
1897 ULONG i
, j
, InodeBlocks
;
1899 for (i
= 0; i
< Vcb
->sbi
.s_groups_count
; i
++) {
1901 PEXT2_GROUP_DESC gd
;
1902 struct buffer_head
*bh
= NULL
;
1904 gd
= ext4_get_group_desc(&Vcb
->sb
, i
, &bh
);
1907 Ext2CheckSetBlock(IrpContext
, Vcb
, ext4_block_bitmap(&Vcb
->sb
, gd
));
1908 Ext2CheckSetBlock(IrpContext
, Vcb
, ext4_inode_bitmap(&Vcb
->sb
, gd
));
1911 if (i
== Vcb
->sbi
.s_groups_count
- 1) {
1912 InodeBlocks
= ((INODES_COUNT
% INODES_PER_GROUP
) *
1913 Vcb
->InodeSize
+ Vcb
->BlockSize
- 1) /
1916 InodeBlocks
= (INODES_PER_GROUP
* Vcb
->InodeSize
+
1917 Vcb
->BlockSize
- 1) / (Vcb
->BlockSize
);
1920 for (j
= 0; j
< InodeBlocks
; j
++ )
1921 Ext2CheckSetBlock(IrpContext
, Vcb
, ext4_inode_table(&Vcb
->sb
, gd
) + j
);
1929 /* Ext2Global->Resource should be already acquired */
1931 Ext2InsertVcb(PEXT2_VCB Vcb
)
1933 InsertTailList(&(Ext2Global
->VcbList
), &Vcb
->Next
);
1937 /* Ext2Global->Resource should be already acquired */
1939 Ext2RemoveVcb(PEXT2_VCB Vcb
)
1941 RemoveEntryList(&Vcb
->Next
);
1942 InitializeListHead(&Vcb
->Next
);
1946 Ext2QueryVolumeParams(IN PEXT2_VCB Vcb
, IN PUNICODE_STRING Params
)
1949 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1951 UNICODE_STRING UniName
;
1952 PUSHORT UniBuffer
= NULL
;
1960 RtlZeroMemory(Params
, sizeof(UNICODE_STRING
));
1962 /* constructing volume UUID name */
1963 memset(UUID
, 0, sizeof(USHORT
) * 50);
1964 for (i
=0; i
< 16; i
++) {
1966 swprintf((wchar_t *)&UUID
[len
], L
"{%2.2X",Vcb
->SuperBlock
->s_uuid
[i
]);
1968 } else if (i
== 15) {
1969 swprintf((wchar_t *)&UUID
[len
], L
"-%2.2X}", Vcb
->SuperBlock
->s_uuid
[i
]);
1972 swprintf((wchar_t *)&UUID
[len
], L
"-%2.2X", Vcb
->SuperBlock
->s_uuid
[i
]);
1977 /* allocating memory for UniBuffer */
1978 UniBuffer
= Ext2AllocatePool(PagedPool
, 1024, EXT2_PARAM_MAGIC
);
1979 if (NULL
== UniBuffer
) {
1980 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1983 RtlZeroMemory(UniBuffer
, 1024);
1985 /* querying volume parameter string */
1986 RtlZeroMemory(&QueryTable
[0], sizeof(RTL_QUERY_REGISTRY_TABLE
) * 2);
1987 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1988 QueryTable
[0].Name
= UUID
;
1989 QueryTable
[0].EntryContext
= &(UniName
);
1990 UniName
.MaximumLength
= 1024;
1992 UniName
.Buffer
= UniBuffer
;
1994 Status
= RtlQueryRegistryValues(
1995 RTL_REGISTRY_ABSOLUTE
,
1996 Ext2Global
->RegistryPath
.Buffer
,
2002 if (!NT_SUCCESS(Status
)) {
2008 if (NT_SUCCESS(Status
)) {
2012 Ext2FreePool(UniBuffer
, EXT2_PARAM_MAGIC
);
2020 Ext2ParseRegistryVolumeParams(
2021 IN PUNICODE_STRING Params
,
2022 OUT PEXT2_VOLUME_PROPERTY3 Property
2025 WCHAR Codepage
[CODEPAGE_MAXLEN
];
2026 WCHAR Prefix
[HIDINGPAT_LEN
];
2027 WCHAR Suffix
[HIDINGPAT_LEN
];
2028 USHORT MountPoint
[4];
2030 WCHAR wUID
[8], wGID
[8], wEUID
[8], wEGID
[8];
2031 CHAR sUID
[8], sGID
[8], sEUID
[8], sEGID
[8];
2033 BOOLEAN bWriteSupport
= FALSE
,
2034 bCheckBitmap
= FALSE
,
2036 bMountPoint
= FALSE
;
2037 BOOLEAN bUID
= 0, bGID
= 0, bEUID
= 0, bEGID
= 0;
2040 PWCHAR Name
; /* parameters name */
2041 PBOOLEAN bExist
; /* is it contained in params */
2042 USHORT Length
; /* parameter value length */
2043 PWCHAR uValue
; /* value buffer in unicode */
2044 PCHAR aValue
; /* value buffer in ansi */
2045 } ParamPattern
[] = {
2046 /* writing support */
2047 {READING_ONLY
, &Property
->bReadonly
, 0, NULL
, NULL
},
2048 {WRITING_SUPPORT
, &bWriteSupport
, 0, NULL
, NULL
},
2049 {EXT3_FORCEWRITING
, &Property
->bExt3Writable
, 0, NULL
, NULL
},
2051 /* need check bitmap */
2052 {CHECKING_BITMAP
, &bCheckBitmap
, 0, NULL
, NULL
},
2054 {CODEPAGE_NAME
, &bCodeName
, CODEPAGE_MAXLEN
,
2055 &Codepage
[0], Property
->Codepage
},
2056 /* filter prefix and suffix */
2057 {HIDING_PREFIX
, &Property
->bHidingPrefix
, HIDINGPAT_LEN
,
2058 &Prefix
[0], Property
->sHidingPrefix
},
2059 {HIDING_SUFFIX
, &Property
->bHidingSuffix
, HIDINGPAT_LEN
,
2060 &Suffix
[0], Property
->sHidingSuffix
},
2061 {MOUNT_POINT
, &bMountPoint
, 4,
2062 &MountPoint
[0], &DrvLetter
[0]},
2064 {UID
, &bUID
, 8, &wUID
[0], &sUID
[0],},
2065 {GID
, &bGID
, 8, &wGID
[0], &sGID
[0]},
2066 {EUID
, &bEUID
, 8, &wEUID
[0], &sEUID
[0]},
2067 {EGID
, &bEGID
, 8, &wEGID
[0], &sEGID
[0]},
2070 {NULL
, NULL
, 0, NULL
}
2075 RtlZeroMemory(Codepage
, sizeof(WCHAR
) * CODEPAGE_MAXLEN
);
2076 RtlZeroMemory(Prefix
, sizeof(WCHAR
) * HIDINGPAT_LEN
);
2077 RtlZeroMemory(Suffix
, sizeof(WCHAR
) * HIDINGPAT_LEN
);
2078 RtlZeroMemory(MountPoint
, sizeof(USHORT
) * 4);
2079 RtlZeroMemory(DrvLetter
, sizeof(CHAR
) * 4);
2081 RtlZeroMemory(Property
, sizeof(EXT2_VOLUME_PROPERTY3
));
2082 Property
->Magic
= EXT2_VOLUME_PROPERTY_MAGIC
;
2083 Property
->Command
= APP_CMD_SET_PROPERTY3
;
2085 for (i
=0; ParamPattern
[i
].Name
!= NULL
; i
++) {
2087 UNICODE_STRING Name1
=*Params
, Name2
;
2088 RtlInitUnicodeString(&Name2
, ParamPattern
[i
].Name
);
2089 *ParamPattern
[i
].bExist
= FALSE
;
2091 for (j
=0; j
* sizeof(WCHAR
) + Name2
.Length
<= Params
->Length
; j
++) {
2093 Name1
.MaximumLength
= Params
->Length
- j
* sizeof(WCHAR
);
2094 Name1
.Length
= Name2
.Length
;
2095 Name1
.Buffer
= &Params
->Buffer
[j
];
2097 if (!RtlCompareUnicodeString(&Name1
, &Name2
, TRUE
)) {
2098 if (j
* sizeof(WCHAR
) + Name2
.Length
== Params
->Length
||
2099 Name1
.Buffer
[Name2
.Length
/sizeof(WCHAR
)] == L
';' ||
2100 Name1
.Buffer
[Name2
.Length
/sizeof(WCHAR
)] == L
',' ) {
2101 *(ParamPattern
[i
].bExist
) = TRUE
;
2102 } else if ((j
* 2 + Name2
.Length
< Params
->Length
+ 2) ||
2103 (Name1
.Buffer
[Name2
.Length
/sizeof(WCHAR
)] == L
'=' )) {
2104 j
+= Name2
.Length
/sizeof(WCHAR
) + 1;
2106 while ( j
+ k
< Params
->Length
/2 &&
2107 k
< ParamPattern
[i
].Length
&&
2108 Params
->Buffer
[j
+k
] != L
';' &&
2109 Params
->Buffer
[j
+k
] != L
',' ) {
2111 ParamPattern
[i
].uValue
[k
] = Params
->Buffer
[j
+ k
];
2114 ParamPattern
[i
].uValue
[k
] = Params
->Buffer
[j
+ k
++];
2119 ANSI_STRING AnsiName
;
2120 AnsiName
.Length
= 0;
2121 AnsiName
.MaximumLength
=ParamPattern
[i
].Length
;
2122 AnsiName
.Buffer
= ParamPattern
[i
].aValue
;
2124 Name2
.Buffer
= ParamPattern
[i
].uValue
;
2125 Name2
.MaximumLength
= Name2
.Length
= k
* sizeof(WCHAR
);
2126 status
= RtlUnicodeStringToAnsiString(
2127 &AnsiName
, &Name2
, FALSE
);
2128 if (NT_SUCCESS(status
)) {
2129 *(ParamPattern
[i
].bExist
) = TRUE
;
2131 *ParamPattern
[i
].bExist
= FALSE
;
2141 Property
->DrvLetter
= DrvLetter
[0];
2142 Property
->DrvLetter
|= 0x80;
2146 SetFlag(Property
->Flags2
, EXT2_VPROP3_USERIDS
);
2147 sUID
[7] = sGID
[7] = sEUID
[7] = sEGID
[7] = 0;
2148 Property
->uid
= (USHORT
)atoi(sUID
);
2149 Property
->gid
= (USHORT
)atoi(sGID
);
2151 Property
->euid
= (USHORT
)atoi(sEUID
);
2152 Property
->egid
= (USHORT
)atoi(sEGID
);
2153 Property
->EIDS
= TRUE
;
2155 Property
->EIDS
= FALSE
;
2158 ClearFlag(Property
->Flags2
, EXT2_VPROP3_USERIDS
);
2163 Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb
)
2166 UNICODE_STRING VolumeParams
;
2168 Status
= Ext2QueryVolumeParams(Vcb
, &VolumeParams
);
2169 if (NT_SUCCESS(Status
)) {
2171 /* set Vcb settings from registery */
2172 EXT2_VOLUME_PROPERTY3 Property
;
2173 Ext2ParseRegistryVolumeParams(&VolumeParams
, &Property
);
2174 Ext2ProcessVolumeProperty(Vcb
, &Property
, sizeof(Property
));
2178 /* don't support auto mount */
2179 if (IsFlagOn(Ext2Global
->Flags
, EXT2_AUTO_MOUNT
)) {
2180 Status
= STATUS_SUCCESS
;
2182 Status
= STATUS_UNSUCCESSFUL
;
2186 /* set Vcb settings from Ext2Global */
2187 if (IsFlagOn(Ext2Global
->Flags
, EXT2_SUPPORT_WRITING
)) {
2188 if (Vcb
->IsExt3fs
) {
2189 if (IsFlagOn(Ext2Global
->Flags
, EXT3_FORCE_WRITING
)) {
2190 ClearLongFlag(Vcb
->Flags
, VCB_READ_ONLY
);
2192 SetLongFlag(Vcb
->Flags
, VCB_READ_ONLY
);
2195 ClearLongFlag(Vcb
->Flags
, VCB_READ_ONLY
);
2198 SetLongFlag(Vcb
->Flags
, VCB_READ_ONLY
);
2201 /* set the default codepage */
2202 Vcb
->Codepage
.PageTable
= Ext2Global
->Codepage
.PageTable
;
2203 memcpy(Vcb
->Codepage
.AnsiName
, Ext2Global
->Codepage
.AnsiName
, CODEPAGE_MAXLEN
);
2204 Vcb
->Codepage
.PageTable
= Ext2Global
->Codepage
.PageTable
;
2206 if (Vcb
->bHidingPrefix
== Ext2Global
->bHidingPrefix
) {
2207 RtlCopyMemory( Vcb
->sHidingPrefix
,
2208 Ext2Global
->sHidingPrefix
,
2211 RtlZeroMemory( Vcb
->sHidingPrefix
,
2215 if (Vcb
->bHidingSuffix
== Ext2Global
->bHidingSuffix
) {
2216 RtlCopyMemory( Vcb
->sHidingSuffix
,
2217 Ext2Global
->sHidingSuffix
,
2220 RtlZeroMemory( Vcb
->sHidingSuffix
,
2227 if (VolumeParams
.Buffer
) {
2228 Ext2FreePool(VolumeParams
.Buffer
, EXT2_PARAM_MAGIC
);
2235 Ext2InitializeLabel(
2237 IN PEXT2_SUPER_BLOCK Sb
2243 UNICODE_STRING Label
;
2246 Label
.MaximumLength
= 16 * sizeof(WCHAR
);
2248 Label
.Buffer
= Vcb
->Vpb
->VolumeLabel
;
2249 Vcb
->Vpb
->VolumeLabelLength
= 0;
2250 RtlZeroMemory(Label
.Buffer
, Label
.MaximumLength
);
2253 while ( (Length
> 0) &&
2254 ((Sb
->s_volume_name
[Length
-1] == 0x00) ||
2255 (Sb
->s_volume_name
[Length
- 1] == 0x20) )
2261 return STATUS_SUCCESS
;
2264 OemName
.Buffer
= Sb
->s_volume_name
;
2265 OemName
.MaximumLength
= 16;
2266 OemName
.Length
= Length
;
2268 status
= Ext2OEMToUnicode(Vcb
, &Label
, &OemName
);
2269 if (NT_SUCCESS(status
)) {
2270 Vcb
->Vpb
->VolumeLabelLength
= Label
.Length
;
2276 static __inline BOOLEAN
Ext2IsNullUuid (__u8
* uuid
)
2279 for (i
= 0; i
< 16; i
++) {
2288 #define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
2291 Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext
,
2293 IN PEXT2_SUPER_BLOCK sb
,
2294 IN PDEVICE_OBJECT TargetDevice
,
2295 IN PDEVICE_OBJECT VolumeDevice
,
2298 NTSTATUS Status
= STATUS_UNRECOGNIZED_VOLUME
;
2302 UNICODE_STRING RootNode
;
2304 ULONG ChangeCount
= 0, features
;
2305 CC_FILE_SIZES FileSizes
;
2306 int i
, has_huge_files
;
2308 BOOLEAN VcbResourceInitialized
= FALSE
;
2309 BOOLEAN NotifySyncInitialized
= FALSE
;
2310 BOOLEAN ExtentsInitialized
= FALSE
;
2311 BOOLEAN InodeLookasideInitialized
= FALSE
;
2312 BOOLEAN GroupLoaded
= FALSE
;
2317 Status
= STATUS_DEVICE_NOT_READY
;
2321 /* Reject mounting volume if we encounter unsupported incompat features */
2322 if (FlagOn(sb
->s_feature_incompat
, ~EXT4_FEATURE_INCOMPAT_SUPP
)) {
2323 Status
= STATUS_UNRECOGNIZED_VOLUME
;
2327 /* Mount the volume RO if we encounter unsupported ro_compat features */
2328 if (FlagOn(sb
->s_feature_ro_compat
, ~EXT4_FEATURE_RO_COMPAT_SUPP
)) {
2329 SetLongFlag(Vcb
->Flags
, VCB_RO_COMPAT_READ_ONLY
);
2332 /* Recognize the filesystem as Ext3fs if it supports journalling */
2333 if (IsFlagOn(sb
->s_feature_compat
, EXT4_FEATURE_COMPAT_HAS_JOURNAL
)) {
2334 Vcb
->IsExt3fs
= TRUE
;
2337 /* check block size */
2338 Vcb
->BlockSize
= (EXT2_MIN_BLOCK_SIZE
<< sb
->s_log_block_size
);
2339 /* we cannot handle volume with block size bigger than 64k */
2340 if (Vcb
->BlockSize
> EXT2_MAX_USER_BLKSIZE
) {
2341 Status
= STATUS_UNRECOGNIZED_VOLUME
;
2345 if (Vcb
->BlockSize
>= PAGE_SIZE
) {
2346 Vcb
->IoUnitBits
= PAGE_SHIFT
;
2347 Vcb
->IoUnitSize
= PAGE_SIZE
;
2349 Vcb
->IoUnitSize
= Vcb
->BlockSize
;
2350 Vcb
->IoUnitBits
= Ext2Log2(Vcb
->BlockSize
);
2353 /* initialize vcb header members ... */
2354 Vcb
->Header
.IsFastIoPossible
= FastIoIsNotPossible
;
2355 Vcb
->Header
.Resource
= &(Vcb
->MainResource
);
2356 Vcb
->Header
.PagingIoResource
= &(Vcb
->PagingIoResource
);
2357 Vcb
->OpenVolumeCount
= 0;
2358 Vcb
->OpenHandleCount
= 0;
2359 Vcb
->ReferenceCount
= 0;
2361 /* initialize eresources */
2362 ExInitializeResourceLite(&Vcb
->MainResource
);
2363 ExInitializeResourceLite(&Vcb
->PagingIoResource
);
2364 ExInitializeResourceLite(&Vcb
->MetaInode
);
2365 ExInitializeResourceLite(&Vcb
->MetaBlock
);
2366 ExInitializeResourceLite(&Vcb
->McbLock
);
2367 ExInitializeResourceLite(&Vcb
->FcbLock
);
2368 ExInitializeResourceLite(&Vcb
->sbi
.s_gd_lock
);
2369 #ifndef _WIN2K_TARGET_
2370 ExInitializeFastMutex(&Vcb
->Mutex
);
2371 FsRtlSetupAdvancedHeader(&Vcb
->Header
, &Vcb
->Mutex
);
2373 VcbResourceInitialized
= TRUE
;
2375 /* initialize Fcb list head */
2376 InitializeListHead(&Vcb
->FcbList
);
2378 /* initialize Mcb list head */
2379 InitializeListHead(&(Vcb
->McbList
));
2381 /* initialize directory notify list */
2382 InitializeListHead(&Vcb
->NotifyList
);
2383 FsRtlNotifyInitializeSync(&Vcb
->NotifySync
);
2384 NotifySyncInitialized
= TRUE
;
2386 /* superblock checking */
2387 Vcb
->SuperBlock
= sb
;
2389 /* initialize Vpb and Label */
2390 Vcb
->DeviceObject
= VolumeDevice
;
2391 Vcb
->TargetDeviceObject
= TargetDevice
;
2393 Vcb
->RealDevice
= Vpb
->RealDevice
;
2394 Vpb
->DeviceObject
= VolumeDevice
;
2396 /* set inode size */
2397 Vcb
->InodeSize
= (ULONG
)sb
->s_inode_size
;
2398 if (Vcb
->InodeSize
== 0) {
2399 Vcb
->InodeSize
= EXT2_GOOD_OLD_INODE_SIZE
;
2402 /* initialize inode lookaside list */
2403 ExInitializeNPagedLookasideList(&(Vcb
->InodeLookasideList
),
2404 NULL
, NULL
, 0, Vcb
->InodeSize
,
2407 InodeLookasideInitialized
= TRUE
;
2409 /* initialize label in Vpb */
2410 Status
= Ext2InitializeLabel(Vcb
, sb
);
2411 if (!NT_SUCCESS(Status
)) {
2415 /* check device characteristics flags */
2416 if (IsFlagOn(Vpb
->RealDevice
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
2417 SetLongFlag(Vcb
->Flags
, VCB_REMOVABLE_MEDIA
);
2420 if (IsFlagOn(Vpb
->RealDevice
->Characteristics
, FILE_FLOPPY_DISKETTE
)) {
2421 SetLongFlag(Vcb
->Flags
, VCB_FLOPPY_DISK
);
2424 if (IsFlagOn(Vpb
->RealDevice
->Characteristics
, FILE_READ_ONLY_DEVICE
)) {
2425 SetLongFlag(Vcb
->Flags
, VCB_WRITE_PROTECTED
);
2428 if (IsFlagOn(TargetDevice
->Characteristics
, FILE_READ_ONLY_DEVICE
)) {
2429 SetLongFlag(Vcb
->Flags
, VCB_WRITE_PROTECTED
);
2432 /* verify device is writable ? */
2433 if (Ext2IsMediaWriteProtected(IrpContext
, TargetDevice
)) {
2434 SetFlag(Vcb
->Flags
, VCB_WRITE_PROTECTED
);
2437 /* initialize UUID and serial number */
2438 if (Ext2IsNullUuid(sb
->s_uuid
)) {
2439 ExUuidCreate((UUID
*)sb
->s_uuid
);
2441 Vpb
->SerialNumber
= ((ULONG
*)sb
->s_uuid
)[0] +
2442 ((ULONG
*)sb
->s_uuid
)[1] +
2443 ((ULONG
*)sb
->s_uuid
)[2] +
2444 ((ULONG
*)sb
->s_uuid
)[3];
2446 /* query partition size and disk geometry parameters */
2447 DiskSize
= Vcb
->DiskGeometry
.Cylinders
.QuadPart
*
2448 Vcb
->DiskGeometry
.TracksPerCylinder
*
2449 Vcb
->DiskGeometry
.SectorsPerTrack
*
2450 Vcb
->DiskGeometry
.BytesPerSector
;
2452 IoctlSize
= sizeof(PARTITION_INFORMATION
);
2453 Status
= Ext2DiskIoControl(
2455 IOCTL_DISK_GET_PARTITION_INFO
,
2458 &Vcb
->PartitionInformation
,
2460 if (NT_SUCCESS(Status
)) {
2461 PartSize
= Vcb
->PartitionInformation
.PartitionLength
.QuadPart
;
2463 Vcb
->PartitionInformation
.StartingOffset
.QuadPart
= 0;
2464 Vcb
->PartitionInformation
.PartitionLength
.QuadPart
= DiskSize
;
2465 PartSize
= DiskSize
;
2466 Status
= STATUS_SUCCESS
;
2468 Vcb
->Header
.AllocationSize
.QuadPart
=
2469 Vcb
->Header
.FileSize
.QuadPart
= PartSize
;
2471 Vcb
->Header
.ValidDataLength
.QuadPart
=
2472 Vcb
->Header
.FileSize
.QuadPart
;
2475 IoctlSize
= sizeof(ULONG
);
2476 Status
= Ext2DiskIoControl(
2478 IOCTL_DISK_CHECK_VERIFY
,
2484 if (!NT_SUCCESS(Status
)) {
2487 Vcb
->ChangeCount
= ChangeCount
;
2489 /* create the stream object for ext2 volume */
2490 Vcb
->Volume
= IoCreateStreamFileObject(NULL
, Vcb
->Vpb
->RealDevice
);
2492 Status
= STATUS_UNRECOGNIZED_VOLUME
;
2496 /* initialize streaming object file */
2497 Vcb
->Volume
->SectionObjectPointer
= &(Vcb
->SectionObject
);
2498 Vcb
->Volume
->ReadAccess
= TRUE
;
2499 Vcb
->Volume
->WriteAccess
= TRUE
;
2500 Vcb
->Volume
->DeleteAccess
= TRUE
;
2501 Vcb
->Volume
->FsContext
= (PVOID
) Vcb
;
2502 Vcb
->Volume
->FsContext2
= NULL
;
2503 Vcb
->Volume
->Vpb
= Vcb
->Vpb
;
2505 FileSizes
.AllocationSize
.QuadPart
=
2506 FileSizes
.FileSize
.QuadPart
=
2507 FileSizes
.ValidDataLength
.QuadPart
=
2508 Vcb
->Header
.AllocationSize
.QuadPart
;
2510 CcInitializeCacheMap( Vcb
->Volume
,
2513 &(Ext2Global
->CacheManagerNoOpCallbacks
),
2516 /* initialize disk block LargetMcb and entry Mcb,
2517 it will raise an expcetion if failed */
2519 FsRtlInitializeLargeMcb(&(Vcb
->Extents
), PagedPool
);
2520 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
2521 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2524 if (!NT_SUCCESS(Status
)) {
2527 ExtentsInitialized
= TRUE
;
2529 /* set block device */
2530 Vcb
->bd
.bd_dev
= Vcb
->RealDevice
;
2531 Vcb
->bd
.bd_geo
= Vcb
->DiskGeometry
;
2532 Vcb
->bd
.bd_part
= Vcb
->PartitionInformation
;
2533 Vcb
->bd
.bd_volume
= Vcb
->Volume
;
2534 Vcb
->bd
.bd_priv
= (void *) Vcb
;
2535 memset(&Vcb
->bd
.bd_bh_root
, 0, sizeof(struct rb_root
));
2536 InitializeListHead(&Vcb
->bd
.bd_bh_free
);
2537 ExInitializeResourceLite(&Vcb
->bd
.bd_bh_lock
);
2538 KeInitializeEvent(&Vcb
->bd
.bd_bh_notify
,
2539 NotificationEvent
, TRUE
);
2540 Vcb
->bd
.bd_bh_cache
= kmem_cache_create("bd_bh_buffer",
2541 Vcb
->BlockSize
, 0, 0, NULL
);
2542 if (!Vcb
->bd
.bd_bh_cache
) {
2543 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2547 Vcb
->SectorBits
= Ext2Log2(SECTOR_SIZE
);
2548 Vcb
->sb
.s_magic
= sb
->s_magic
;
2549 Vcb
->sb
.s_bdev
= &Vcb
->bd
;
2550 Vcb
->sb
.s_blocksize
= BLOCK_SIZE
;
2551 Vcb
->sb
.s_blocksize_bits
= BLOCK_BITS
;
2552 Vcb
->sb
.s_priv
= (void *) Vcb
;
2553 Vcb
->sb
.s_fs_info
= &Vcb
->sbi
;
2556 Vcb
->sbi
.s_blocks_per_group
= sb
->s_blocks_per_group
;
2557 Vcb
->sbi
.s_first_ino
= sb
->s_first_ino
;
2558 Vcb
->sbi
.s_desc_size
= sb
->s_desc_size
;
2560 if (EXT3_HAS_INCOMPAT_FEATURE(&Vcb
->sb
, EXT4_FEATURE_INCOMPAT_64BIT
)) {
2561 if (Vcb
->sbi
.s_desc_size
< EXT4_MIN_DESC_SIZE_64BIT
||
2562 Vcb
->sbi
.s_desc_size
> EXT4_MAX_DESC_SIZE
||
2563 !is_power_of_2(Vcb
->sbi
.s_desc_size
)) {
2564 DEBUG(DL_ERR
, ("EXT4-fs: unsupported descriptor size %lu\n", Vcb
->sbi
.s_desc_size
));
2565 Status
= STATUS_DISK_CORRUPT_ERROR
;
2569 Vcb
->sbi
.s_desc_size
= EXT4_MIN_DESC_SIZE
;
2572 Vcb
->sbi
.s_blocks_per_group
= sb
->s_blocks_per_group
;
2573 Vcb
->sbi
.s_inodes_per_group
= sb
->s_inodes_per_group
;
2574 if (EXT3_INODES_PER_GROUP(&Vcb
->sb
) == 0) {
2575 Status
= STATUS_DISK_CORRUPT_ERROR
;
2578 Vcb
->sbi
.s_inodes_per_block
= BLOCK_SIZE
/ Vcb
->InodeSize
;
2579 if (Vcb
->sbi
.s_inodes_per_block
== 0) {
2580 Status
= STATUS_DISK_CORRUPT_ERROR
;
2583 Vcb
->sbi
.s_itb_per_group
= Vcb
->sbi
.s_inodes_per_group
/
2584 Vcb
->sbi
.s_inodes_per_block
;
2587 Vcb
->sbi
.s_desc_per_block
= BLOCK_SIZE
/ GROUP_DESC_SIZE
;
2588 Vcb
->sbi
.s_desc_per_block_bits
= ilog2(Vcb
->sbi
.s_desc_per_block
);
2590 for (i
=0; i
< 4; i
++) {
2591 Vcb
->sbi
.s_hash_seed
[i
] = sb
->s_hash_seed
[i
];
2593 Vcb
->sbi
.s_def_hash_version
= sb
->s_def_hash_version
;
2595 if (le32_to_cpu(sb
->s_rev_level
) == EXT3_GOOD_OLD_REV
&&
2596 (EXT3_HAS_COMPAT_FEATURE(&Vcb
->sb
, ~0U) ||
2597 EXT3_HAS_RO_COMPAT_FEATURE(&Vcb
->sb
, ~0U) ||
2598 EXT3_HAS_INCOMPAT_FEATURE(&Vcb
->sb
, ~0U))) {
2600 "EXT3-fs warning: feature flags set on rev 0 fs, "
2601 "running e2fsck is recommended\n");
2605 * Check feature flags regardless of the revision level, since we
2606 * previously didn't change the revision level when setting the flags,
2607 * so there is a chance incompat flags are set on a rev 0 filesystem.
2609 features
= EXT3_HAS_INCOMPAT_FEATURE(&Vcb
->sb
, ~EXT4_FEATURE_INCOMPAT_SUPP
);
2610 if (features
& EXT4_FEATURE_INCOMPAT_DIRDATA
) {
2611 SetLongFlag(Vcb
->Flags
, VCB_READ_ONLY
);
2612 ClearFlag(features
, EXT4_FEATURE_INCOMPAT_DIRDATA
);
2615 printk(KERN_ERR
"EXT3-fs: %s: couldn't mount because of "
2616 "unsupported optional features (%x).\n",
2617 Vcb
->sb
.s_id
, le32_to_cpu(features
));
2618 Status
= STATUS_UNRECOGNIZED_VOLUME
;
2622 features
= EXT3_HAS_RO_COMPAT_FEATURE(&Vcb
->sb
, ~EXT4_FEATURE_RO_COMPAT_SUPP
);
2624 printk(KERN_ERR
"EXT3-fs: %s: unsupported optional features in this volume: (%x).\n",
2625 Vcb
->sb
.s_id
, le32_to_cpu(features
));
2626 if (CanIWrite(Vcb
)) {
2628 SetLongFlag(Vcb
->Flags
, VCB_READ_ONLY
);
2632 has_huge_files
= EXT3_HAS_RO_COMPAT_FEATURE(&Vcb
->sb
, EXT4_FEATURE_RO_COMPAT_HUGE_FILE
);
2634 Vcb
->sb
.s_maxbytes
= ext3_max_size(BLOCK_BITS
, has_huge_files
);
2635 Vcb
->max_bitmap_bytes
= ext3_max_bitmap_size(BLOCK_BITS
,
2637 Vcb
->max_bytes
= ext3_max_size(BLOCK_BITS
, has_huge_files
);
2639 /* calculate maximum file bocks ... */
2641 ULONG dwData
[EXT2_BLOCK_TYPES
] = {EXT2_NDIR_BLOCKS
, 1, 1, 1};
2644 ASSERT(BLOCK_BITS
== Ext2Log2(BLOCK_SIZE
));
2646 Vcb
->sbi
.s_groups_count
= (ULONG
)(ext3_blocks_count(sb
) - sb
->s_first_data_block
+
2647 sb
->s_blocks_per_group
- 1) / sb
->s_blocks_per_group
;
2649 Vcb
->max_data_blocks
= 0;
2650 for (i
= 0; i
< EXT2_BLOCK_TYPES
; i
++) {
2651 if (BLOCK_BITS
>= 12 && i
== (EXT2_BLOCK_TYPES
- 1)) {
2652 dwData
[i
] = 0x40000000;
2654 dwData
[i
] = dwData
[i
] << ((BLOCK_BITS
- 2) * i
);
2656 Vcb
->max_blocks_per_layer
[i
] = dwData
[i
];
2657 Vcb
->max_data_blocks
+= Vcb
->max_blocks_per_layer
[i
];
2661 Vcb
->sbi
.s_gdb_count
= (Vcb
->sbi
.s_groups_count
+ Vcb
->sbi
.s_desc_per_block
- 1) /
2662 Vcb
->sbi
.s_desc_per_block
;
2663 /* load all gorup desc */
2664 if (!Ext2LoadGroup(Vcb
)) {
2665 Status
= STATUS_UNSUCCESSFUL
;
2670 /* recovery journal since it's ext3 */
2671 if (Vcb
->IsExt3fs
) {
2672 Ext2RecoverJournal(IrpContext
, Vcb
);
2673 if (IsFlagOn(Vcb
->Flags
, VCB_JOURNAL_RECOVER
)) {
2674 SetLongFlag(Vcb
->Flags
, VCB_READ_ONLY
);
2678 /* Now allocating the mcb for root ... */
2681 RootNode
.Buffer
= Buffer
;
2682 RootNode
.MaximumLength
= RootNode
.Length
= 2;
2683 Vcb
->McbTree
= Ext2AllocateMcb(
2684 Vcb
, &RootNode
, NULL
,
2685 FILE_ATTRIBUTE_DIRECTORY
2687 if (!Vcb
->McbTree
) {
2689 Status
= STATUS_UNSUCCESSFUL
;
2693 Vcb
->sb
.s_root
= Ext2BuildEntry(Vcb
, NULL
, &RootNode
);
2694 if (!Vcb
->sb
.s_root
) {
2696 Status
= STATUS_UNSUCCESSFUL
;
2699 Vcb
->sb
.s_root
->d_sb
= &Vcb
->sb
;
2700 Vcb
->sb
.s_root
->d_inode
= &Vcb
->McbTree
->Inode
;
2701 Vcb
->McbTree
->de
= Vcb
->sb
.s_root
;
2703 /* load root inode */
2704 Vcb
->McbTree
->Inode
.i_ino
= EXT2_ROOT_INO
;
2705 Vcb
->McbTree
->Inode
.i_sb
= &Vcb
->sb
;
2706 if (!Ext2LoadInode(Vcb
, &Vcb
->McbTree
->Inode
)) {
2708 Status
= STATUS_CANT_WAIT
;
2712 /* initializeroot node */
2713 Vcb
->McbTree
->CreationTime
= Ext2NtTime(Vcb
->McbTree
->Inode
.i_ctime
);
2714 Vcb
->McbTree
->LastAccessTime
= Ext2NtTime(Vcb
->McbTree
->Inode
.i_atime
);
2715 Vcb
->McbTree
->LastWriteTime
= Ext2NtTime(Vcb
->McbTree
->Inode
.i_mtime
);
2716 Vcb
->McbTree
->ChangeTime
= Ext2NtTime(Vcb
->McbTree
->Inode
.i_mtime
);
2718 /* check bitmap if user specifies it */
2719 if (IsFlagOn(Ext2Global
->Flags
, EXT2_CHECKING_BITMAP
)) {
2720 Ext2CheckBitmapConsistency(IrpContext
, Vcb
);
2723 /* get anything doen, then refer target device */
2724 ObReferenceObject(Vcb
->TargetDeviceObject
);
2726 /* query parameters from registry */
2727 Ext2PerformRegistryVolumeParams(Vcb
);
2729 SetLongFlag(Vcb
->Flags
, VCB_INITIALIZED
);
2733 if (!NT_SUCCESS(Status
)) {
2736 Ext2FreeMcb(Vcb
, Vcb
->McbTree
);
2739 if (InodeLookasideInitialized
) {
2740 ExDeleteNPagedLookasideList(&(Vcb
->InodeLookasideList
));
2743 if (ExtentsInitialized
) {
2744 if (Vcb
->bd
.bd_bh_cache
) {
2747 kmem_cache_destroy(Vcb
->bd
.bd_bh_cache
);
2749 FsRtlUninitializeLargeMcb(&(Vcb
->Extents
));
2753 if (Vcb
->Volume
->PrivateCacheMap
) {
2754 Ext2SyncUninitializeCacheMap(Vcb
->Volume
);
2756 ObDereferenceObject(Vcb
->Volume
);
2759 if (NotifySyncInitialized
) {
2760 FsRtlNotifyUninitializeSync(&Vcb
->NotifySync
);
2763 if (VcbResourceInitialized
) {
2764 ExDeleteResourceLite(&Vcb
->FcbLock
);
2765 ExDeleteResourceLite(&Vcb
->McbLock
);
2766 ExDeleteResourceLite(&Vcb
->MetaInode
);
2767 ExDeleteResourceLite(&Vcb
->MetaBlock
);
2768 ExDeleteResourceLite(&Vcb
->sbi
.s_gd_lock
);
2769 ExDeleteResourceLite(&Vcb
->MainResource
);
2770 ExDeleteResourceLite(&Vcb
->PagingIoResource
);
2780 Ext2TearDownStream(IN PEXT2_VCB Vcb
)
2782 PFILE_OBJECT Stream
= Vcb
->Volume
;
2783 IO_STATUS_BLOCK IoStatus
;
2785 ASSERT(Vcb
!= NULL
);
2786 ASSERT((Vcb
->Identifier
.Type
== EXT2VCB
) &&
2787 (Vcb
->Identifier
.Size
== sizeof(EXT2_VCB
)));
2793 if (IsFlagOn(Stream
->Flags
, FO_FILE_MODIFIED
)) {
2794 CcFlushCache(&(Vcb
->SectionObject
), NULL
, 0, &IoStatus
);
2795 ClearFlag(Stream
->Flags
, FO_FILE_MODIFIED
);
2798 if (Stream
->PrivateCacheMap
) {
2799 Ext2SyncUninitializeCacheMap(Stream
);
2802 ObDereferenceObject(Stream
);
2807 Ext2DestroyVcb (IN PEXT2_VCB Vcb
)
2809 ASSERT(Vcb
!= NULL
);
2810 ASSERT((Vcb
->Identifier
.Type
== EXT2VCB
) &&
2811 (Vcb
->Identifier
.Size
== sizeof(EXT2_VCB
)));
2813 DEBUG(DL_FUN
, ("Ext2DestroyVcb ...\n"));
2816 Ext2TearDownStream(Vcb
);
2818 ASSERT(NULL
== Vcb
->Volume
);
2820 FsRtlNotifyUninitializeSync(&Vcb
->NotifySync
);
2821 Ext2ListExtents(&Vcb
->Extents
);
2822 FsRtlUninitializeLargeMcb(&(Vcb
->Extents
));
2824 Ext2CleanupAllMcbs(Vcb
);
2828 if (Vcb
->bd
.bd_bh_cache
)
2829 kmem_cache_destroy(Vcb
->bd
.bd_bh_cache
);
2830 ExDeleteResourceLite(&Vcb
->bd
.bd_bh_lock
);
2832 if (Vcb
->SuperBlock
) {
2833 Ext2FreePool(Vcb
->SuperBlock
, EXT2_SB_MAGIC
);
2834 Vcb
->SuperBlock
= NULL
;
2837 if (IsFlagOn(Vcb
->Flags
, VCB_NEW_VPB
)) {
2838 ASSERT(Vcb
->Vpb2
!= NULL
);
2839 DEBUG(DL_DBG
, ("Ext2DestroyVcb: Vpb2 to be freed: %p\n", Vcb
->Vpb2
));
2840 ExFreePoolWithTag(Vcb
->Vpb2
, TAG_VPB
);
2841 DEC_MEM_COUNT(PS_VPB
, Vcb
->Vpb2
, sizeof(VPB
));
2845 ObDereferenceObject(Vcb
->TargetDeviceObject
);
2847 ExDeleteNPagedLookasideList(&(Vcb
->InodeLookasideList
));
2848 ExDeleteResourceLite(&Vcb
->FcbLock
);
2849 ExDeleteResourceLite(&Vcb
->McbLock
);
2850 ExDeleteResourceLite(&Vcb
->MetaInode
);
2851 ExDeleteResourceLite(&Vcb
->MetaBlock
);
2852 ExDeleteResourceLite(&Vcb
->sbi
.s_gd_lock
);
2853 ExDeleteResourceLite(&Vcb
->PagingIoResource
);
2854 ExDeleteResourceLite(&Vcb
->MainResource
);
2856 DEBUG(DL_DBG
, ("Ext2DestroyVcb: DevObject=%p Vcb=%p\n", Vcb
->DeviceObject
, Vcb
));
2857 IoDeleteDevice(Vcb
->DeviceObject
);
2858 DEC_MEM_COUNT(PS_VCB
, Vcb
->DeviceObject
, sizeof(EXT2_VCB
));
2862 /* uninitialize cache map */
2865 Ext2SyncUninitializeCacheMap (
2866 IN PFILE_OBJECT FileObject
2869 CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent
;
2870 NTSTATUS WaitStatus
;
2871 LARGE_INTEGER Ext2LargeZero
= {0,0};
2874 KeInitializeEvent( &UninitializeCompleteEvent
.Event
,
2875 SynchronizationEvent
,
2878 CcUninitializeCacheMap( FileObject
,
2880 &UninitializeCompleteEvent
);
2882 WaitStatus
= KeWaitForSingleObject( &UninitializeCompleteEvent
.Event
,
2888 ASSERT (NT_SUCCESS(WaitStatus
));
2891 /* Link Mcb to tail of Vcb->McbList queue */
2894 Ext2LinkTailMcb(PEXT2_VCB Vcb
, PEXT2_MCB Mcb
)
2896 if (Mcb
->Inode
.i_ino
== EXT2_ROOT_INO
) {
2900 ExAcquireResourceExclusiveLite(&Vcb
->McbLock
, TRUE
);
2902 if (IsFlagOn(Mcb
->Flags
, MCB_VCB_LINK
)) {
2903 DEBUG(DL_RES
, ( "Ext2LinkTailMcb: %wZ already linked.\n",
2906 InsertTailList(&Vcb
->McbList
, &Mcb
->Link
);
2907 SetLongFlag(Mcb
->Flags
, MCB_VCB_LINK
);
2908 Ext2ReferXcb(&Vcb
->NumOfMcb
);
2911 ExReleaseResourceLite(&Vcb
->McbLock
);
2914 /* Link Mcb to head of Vcb->McbList queue */
2917 Ext2LinkHeadMcb(PEXT2_VCB Vcb
, PEXT2_MCB Mcb
)
2919 if (Mcb
->Inode
.i_ino
== EXT2_ROOT_INO
) {
2923 ExAcquireResourceExclusiveLite(&Vcb
->McbLock
, TRUE
);
2925 if (!IsFlagOn(Mcb
->Flags
, MCB_VCB_LINK
)) {
2926 InsertHeadList(&Vcb
->McbList
, &Mcb
->Link
);
2927 SetLongFlag(Mcb
->Flags
, MCB_VCB_LINK
);
2928 Ext2ReferXcb(&Vcb
->NumOfMcb
);
2930 DEBUG(DL_RES
, ( "Ext2LinkHeadMcb: %wZ already linked.\n",
2933 ExReleaseResourceLite(&Vcb
->McbLock
);
2936 /* Unlink Mcb from Vcb->McbList queue */
2939 Ext2UnlinkMcb(PEXT2_VCB Vcb
, PEXT2_MCB Mcb
)
2941 if (Mcb
->Inode
.i_ino
== EXT2_ROOT_INO
) {
2945 ExAcquireResourceExclusiveLite(&Vcb
->McbLock
, TRUE
);
2947 if (IsFlagOn(Mcb
->Flags
, MCB_VCB_LINK
)) {
2948 RemoveEntryList(&(Mcb
->Link
));
2949 ClearLongFlag(Mcb
->Flags
, MCB_VCB_LINK
);
2950 Ext2DerefXcb(&Vcb
->NumOfMcb
);
2952 DEBUG(DL_RES
, ( "Ext2UnlinkMcb: %wZ already unlinked.\n",
2955 ExReleaseResourceLite(&Vcb
->McbLock
);
2958 /* get the first Mcb record in Vcb->McbList */
2961 Ext2FirstUnusedMcb(PEXT2_VCB Vcb
, BOOLEAN Wait
, ULONG Number
)
2963 PEXT2_MCB Head
= NULL
;
2964 PEXT2_MCB Tail
= NULL
;
2965 PEXT2_MCB Mcb
= NULL
;
2966 PLIST_ENTRY List
= NULL
;
2968 LARGE_INTEGER start
, now
;
2970 if (!ExAcquireResourceExclusiveLite(&Vcb
->McbLock
, Wait
)) {
2974 KeQuerySystemTime(&start
);
2978 BOOLEAN Skip
= TRUE
;
2980 if (IsListEmpty(&Vcb
->McbList
)) {
2984 while (i
++ < Vcb
->NumOfMcb
) {
2986 KeQuerySystemTime(&now
);
2987 if (now
.QuadPart
> start
.QuadPart
+ (LONGLONG
)10*1000*1000) {
2991 List
= RemoveHeadList(&Vcb
->McbList
);
2992 Mcb
= CONTAINING_RECORD(List
, EXT2_MCB
, Link
);
2993 ASSERT(IsFlagOn(Mcb
->Flags
, MCB_VCB_LINK
));
2995 if (Mcb
->Fcb
== NULL
&& !IsMcbRoot(Mcb
) &&
2996 Mcb
->Refercount
== 0 &&
2997 (Mcb
->Child
== NULL
|| IsMcbSymLink(Mcb
))) {
2999 Ext2RemoveMcb(Vcb
, Mcb
);
3000 ClearLongFlag(Mcb
->Flags
, MCB_VCB_LINK
);
3001 Ext2DerefXcb(&Vcb
->NumOfMcb
);
3003 /* attach all Mcb into a chain*/
3005 ASSERT(Tail
!= NULL
);
3016 InsertTailList(&Vcb
->McbList
, &Mcb
->Link
);
3025 ExReleaseResourceLite(&Vcb
->McbLock
);
3031 /* Reaper thread to release unused Mcb blocks */
3033 Ext2McbReaperThread(
3037 PEXT2_REAPER Reaper
= Context
;
3038 PLIST_ENTRY List
= NULL
;
3039 LARGE_INTEGER Timeout
;
3041 PEXT2_VCB Vcb
= NULL
;
3042 PEXT2_MCB Mcb
= NULL
;
3046 BOOLEAN GlobalAcquired
= FALSE
;
3048 BOOLEAN DidNothing
= TRUE
;
3049 BOOLEAN LastState
= TRUE
;
3054 Reaper
->Thread
= PsGetCurrentThread();
3056 /* wake up DirverEntry */
3057 KeSetEvent(&Reaper
->Engine
, 0, FALSE
);
3059 /* now process looping */
3060 while (!IsFlagOn(Reaper
->Flags
, EXT2_REAPER_FLAG_STOP
)) {
3064 /* calculate how long we need wait */
3065 if (Ext2Global
->PerfStat
.Current
.Mcb
> (((ULONG
)Ext2Global
->MaxDepth
) * 128)) {
3066 Timeout
.QuadPart
= (LONGLONG
)-1000*1000; /* 0.1 second */
3067 NumOfMcbs
= Ext2Global
->MaxDepth
* 4;
3069 } else if (Ext2Global
->PerfStat
.Current
.Mcb
> (((ULONG
)Ext2Global
->MaxDepth
) * 32)) {
3070 Timeout
.QuadPart
= (LONGLONG
)-1000*1000*5; /* 0.5 second */
3071 NumOfMcbs
= Ext2Global
->MaxDepth
* 2;
3073 } else if (Ext2Global
->PerfStat
.Current
.Mcb
> (((ULONG
)Ext2Global
->MaxDepth
) * 8)) {
3074 Timeout
.QuadPart
= (LONGLONG
)-1000*1000*10; /* 1 second */
3075 NumOfMcbs
= Ext2Global
->MaxDepth
;
3076 } else if (Ext2Global
->PerfStat
.Current
.Mcb
> (((ULONG
)Ext2Global
->MaxDepth
) * 2)) {
3077 Timeout
.QuadPart
= (LONGLONG
)-2*1000*1000*10; /* 2 second */
3078 NumOfMcbs
= Ext2Global
->MaxDepth
/ 4;
3079 } else if (Ext2Global
->PerfStat
.Current
.Mcb
> (ULONG
)Ext2Global
->MaxDepth
) {
3080 Timeout
.QuadPart
= (LONGLONG
)-4*1000*1000*10; /* 4 seconds */
3081 NumOfMcbs
= Ext2Global
->MaxDepth
/ 8;
3082 } else if (DidNothing
) {
3083 Timeout
.QuadPart
= (LONGLONG
)-8*1000*1000*10; /* 8 seconds */
3085 Timeout
.QuadPart
*= 2;
3087 NumOfMcbs
= Ext2Global
->MaxDepth
/ 16;
3089 Timeout
.QuadPart
= (LONGLONG
)-5*1000*1000*10; /* 5 seconds */
3091 Timeout
.QuadPart
*= 2;
3093 NumOfMcbs
= Ext2Global
->MaxDepth
/ 32;
3099 LastState
= DidNothing
;
3101 /* wait until it is waken or it times out */
3102 KeWaitForSingleObject(
3110 if (IsFlagOn(Reaper
->Flags
, EXT2_REAPER_FLAG_STOP
))
3115 /* acquire global exclusive lock */
3116 if (!ExAcquireResourceSharedLite(&Ext2Global
->Resource
, WaitLock
)) {
3119 GlobalAcquired
= TRUE
;
3121 /* search all Vcb to get unused resources freed to system */
3122 for (List
= Ext2Global
->VcbList
.Flink
;
3123 List
!= &(Ext2Global
->VcbList
);
3124 List
= List
->Flink
) {
3126 Vcb
= CONTAINING_RECORD(List
, EXT2_VCB
, Next
);
3128 Mcb
= Ext2FirstUnusedMcb(Vcb
, WaitLock
, NumOfMcbs
);
3130 PEXT2_MCB Next
= Mcb
->Next
;
3131 DEBUG(DL_RES
, ( "Ext2ReaperThread: releasing Mcb (%p): %wZ"
3132 " Total: %xh\n", Mcb
, &Mcb
->FullName
,
3133 Ext2Global
->PerfStat
.Current
.Mcb
));
3134 Ext2FreeMcb(Vcb
, Mcb
);
3136 LastState
= DidNothing
= FALSE
;
3140 KeClearEvent(&Reaper
->Wait
);
3142 if (GlobalAcquired
) {
3143 ExReleaseResourceLite(&Ext2Global
->Resource
);
3144 GlobalAcquired
= FALSE
;
3150 if (GlobalAcquired
) {
3151 ExReleaseResourceLite(&Ext2Global
->Resource
);
3154 KeSetEvent(&Reaper
->Engine
, 0, FALSE
);
3157 PsTerminateSystemThread(STATUS_SUCCESS
);
3161 /* get buffer heads from global Vcb BH list */
3164 Ext2QueryUnusedBH(PEXT2_VCB Vcb
, PLIST_ENTRY head
)
3166 struct buffer_head
*bh
= NULL
;
3167 PLIST_ENTRY next
= NULL
;
3168 LARGE_INTEGER start
, now
;
3169 BOOLEAN wake
= FALSE
;
3171 KeQuerySystemTime(&start
);
3173 ExAcquireResourceExclusiveLite(&Vcb
->bd
.bd_bh_lock
, TRUE
);
3175 while (!IsListEmpty(&Vcb
->bd
.bd_bh_free
)) {
3177 KeQuerySystemTime(&now
);
3178 if (now
.QuadPart
> start
.QuadPart
+ (LONGLONG
)10*1000*1000) {
3182 next
= RemoveHeadList(&Vcb
->bd
.bd_bh_free
);
3183 bh
= CONTAINING_RECORD(next
, struct buffer_head
, b_link
);
3184 if (atomic_read(&bh
->b_count
)) {
3185 InitializeListHead(&bh
->b_link
);
3186 /* to be inserted by brelse */
3190 if ( IsFlagOn(Vcb
->Flags
, VCB_BEING_DROPPED
) ||
3191 (bh
->b_ts_drop
.QuadPart
+ (LONGLONG
)10*1000*1000*15) > now
.QuadPart
||
3192 (bh
->b_ts_creat
.QuadPart
+ (LONGLONG
)10*1000*1000*180) > now
.QuadPart
) {
3193 InsertTailList(head
, &bh
->b_link
);
3194 buffer_head_remove(&Vcb
->bd
, bh
);
3196 InsertHeadList(&Vcb
->bd
.bd_bh_free
, &bh
->b_link
);
3201 wake
= IsListEmpty(&Vcb
->bd
.bd_bh_free
);
3202 ExReleaseResourceLite(&Vcb
->bd
.bd_bh_lock
);
3205 KeSetEvent(&Vcb
->bd
.bd_bh_notify
, 0, FALSE
);
3207 return IsFlagOn(Vcb
->Flags
, VCB_BEING_DROPPED
);
3211 /* Reaper thread to release unused buffer heads */
3217 PEXT2_REAPER Reaper
= Context
;
3218 PEXT2_VCB Vcb
= NULL
;
3219 LIST_ENTRY List
, *Link
;
3220 LARGE_INTEGER Timeout
;
3222 BOOLEAN GlobalAcquired
= FALSE
;
3223 BOOLEAN DidNothing
= FALSE
;
3224 BOOLEAN NonWait
= FALSE
;
3228 Reaper
->Thread
= PsGetCurrentThread();
3230 /* wake up DirverEntry */
3231 KeSetEvent(&Reaper
->Engine
, 0, FALSE
);
3233 /* now process looping */
3234 while (!IsFlagOn(Reaper
->Flags
, EXT2_REAPER_FLAG_STOP
)) {
3236 /* wait until it is waken or it times out */
3238 Timeout
.QuadPart
= (LONGLONG
)-10*1000*10;
3240 } else if (DidNothing
) {
3241 Timeout
.QuadPart
= Timeout
.QuadPart
* 2;
3243 Timeout
.QuadPart
= (LONGLONG
)-10*1000*1000*10; /* 10 seconds */
3245 KeWaitForSingleObject(
3253 if (IsFlagOn(Reaper
->Flags
, EXT2_REAPER_FLAG_STOP
))
3256 InitializeListHead(&List
);
3258 /* acquire global exclusive lock */
3259 ExAcquireResourceSharedLite(&Ext2Global
->Resource
, TRUE
);
3260 GlobalAcquired
= TRUE
;
3261 /* search all Vcb to get unused resources freed to system */
3262 for (Link
= Ext2Global
->VcbList
.Flink
;
3263 Link
!= &(Ext2Global
->VcbList
);
3264 Link
= Link
->Flink
) {
3266 Vcb
= CONTAINING_RECORD(Link
, EXT2_VCB
, Next
);
3267 NonWait
= Ext2QueryUnusedBH(Vcb
, &List
);
3269 DidNothing
= IsListEmpty(&List
);
3271 KeClearEvent(&Reaper
->Wait
);
3273 if (GlobalAcquired
) {
3274 ExReleaseResourceLite(&Ext2Global
->Resource
);
3275 GlobalAcquired
= FALSE
;
3278 while (!IsListEmpty(&List
)) {
3279 struct buffer_head
*bh
;
3280 Link
= RemoveHeadList(&List
);
3281 bh
= CONTAINING_RECORD(Link
, struct buffer_head
, b_link
);
3282 ASSERT(0 == atomic_read(&bh
->b_count
));
3283 free_buffer_head(bh
);
3289 if (GlobalAcquired
) {
3290 ExReleaseResourceLite(&Ext2Global
->Resource
);
3293 KeSetEvent(&Reaper
->Engine
, 0, FALSE
);
3296 PsTerminateSystemThread(STATUS_SUCCESS
);
3299 /* get unused Fcbs to free */
3302 Ext2QueryUnusedFcb(PEXT2_VCB Vcb
, PLIST_ENTRY list
)
3305 PLIST_ENTRY next
= NULL
;
3306 LARGE_INTEGER start
, now
;
3310 BOOLEAN wake
= FALSE
;
3311 BOOLEAN retry
= TRUE
;
3313 KeQuerySystemTime(&start
);
3315 ExAcquireResourceExclusiveLite(&Vcb
->FcbLock
, TRUE
);
3319 KeQuerySystemTime(&now
);
3320 while (!IsListEmpty(&Vcb
->FcbList
)) {
3322 next
= RemoveHeadList(&Vcb
->FcbList
);
3323 Fcb
= CONTAINING_RECORD(next
, EXT2_FCB
, Next
);
3325 if (Fcb
->ReferenceCount
> 0) {
3326 InsertTailList(&Vcb
->FcbList
, &Fcb
->Next
);
3332 if (now
.QuadPart
< Fcb
->TsDrop
.QuadPart
+ 10*1000*1000*120) {
3333 InsertHeadList(&Vcb
->FcbList
, &Fcb
->Next
);
3338 Ext2DerefXcb(&Vcb
->FcbCount
);
3339 InsertTailList(list
, &Fcb
->Next
);
3340 if (++count
>= Ext2Global
->MaxDepth
) {
3345 if (start
.QuadPart
+ 10*1000*1000 > now
.QuadPart
) {
3350 if (++tries
< (Vcb
->FcbCount
>> 4) )
3354 ExReleaseResourceLite(&Vcb
->FcbLock
);
3359 /* Reaper thread to release Fcb */
3361 Ext2FcbReaperThread(
3365 PEXT2_REAPER Reaper
= Context
;
3366 PEXT2_VCB Vcb
= NULL
;
3367 LIST_ENTRY List
, *Link
;
3368 LARGE_INTEGER Timeout
;
3370 BOOLEAN GlobalAcquired
= FALSE
;
3371 BOOLEAN DidNothing
= FALSE
;
3372 BOOLEAN NonWait
= FALSE
;
3376 Reaper
->Thread
= PsGetCurrentThread();
3378 /* wake up DirverEntry */
3379 KeSetEvent(&Reaper
->Engine
, 0, FALSE
);
3381 /* now process looping */
3382 while (!IsFlagOn(Reaper
->Flags
, EXT2_REAPER_FLAG_STOP
)) {
3384 /* wait until it is waken or it times out */
3386 Timeout
.QuadPart
= (LONGLONG
)-10*1000*100;
3388 } else if (DidNothing
) {
3389 Timeout
.QuadPart
= Timeout
.QuadPart
* 2;
3391 Timeout
.QuadPart
= (LONGLONG
)-10*1000*1000*20; /* 20 seconds */
3393 KeWaitForSingleObject(
3401 if (IsFlagOn(Reaper
->Flags
, EXT2_REAPER_FLAG_STOP
))
3404 InitializeListHead(&List
);
3406 /* acquire global exclusive lock */
3407 ExAcquireResourceSharedLite(&Ext2Global
->Resource
, TRUE
);
3408 GlobalAcquired
= TRUE
;
3409 /* search all Vcb to get unused resources freed to system */
3410 for (Link
= Ext2Global
->VcbList
.Flink
;
3411 Link
!= &(Ext2Global
->VcbList
);
3412 Link
= Link
->Flink
) {
3414 Vcb
= CONTAINING_RECORD(Link
, EXT2_VCB
, Next
);
3415 NonWait
= Ext2QueryUnusedFcb(Vcb
, &List
);
3417 DidNothing
= IsListEmpty(&List
);
3419 KeClearEvent(&Reaper
->Wait
);
3421 if (GlobalAcquired
) {
3422 ExReleaseResourceLite(&Ext2Global
->Resource
);
3423 GlobalAcquired
= FALSE
;
3426 while (!IsListEmpty(&List
)) {
3428 Link
= RemoveHeadList(&List
);
3429 Fcb
= CONTAINING_RECORD(Link
, EXT2_FCB
, Next
);
3430 ASSERT(0 == Fcb
->ReferenceCount
);
3437 if (GlobalAcquired
) {
3438 ExReleaseResourceLite(&Ext2Global
->Resource
);
3441 KeSetEvent(&Reaper
->Engine
, 0, FALSE
);
3444 PsTerminateSystemThread(STATUS_SUCCESS
);
3448 Ext2StartReaper(PEXT2_REAPER Reaper
, EXT2_REAPER_RELEASE Free
)
3450 NTSTATUS status
= STATUS_SUCCESS
;
3451 OBJECT_ATTRIBUTES oa
;
3453 LARGE_INTEGER timeout
;
3455 Reaper
->Free
= Free
;
3457 /* initialize wait event */
3460 SynchronizationEvent
, FALSE
3463 /* Reaper thread engine event */
3466 SynchronizationEvent
, FALSE
3470 InitializeObjectAttributes(
3473 OBJ_CASE_INSENSITIVE
|
3479 /* start a new system thread */
3480 status
= PsCreateSystemThread(
3490 if (NT_SUCCESS(status
)) {
3493 /* make sure Reaperthread is started */
3494 timeout
.QuadPart
= (LONGLONG
)-10*1000*1000*2; /* 2 seconds */
3495 status
= KeWaitForSingleObject(
3502 if (status
!= STATUS_SUCCESS
) {
3503 status
= STATUS_INSUFFICIENT_RESOURCES
;
3512 Ext2StopReaper(PEXT2_REAPER Reaper
)
3514 LARGE_INTEGER timeout
;
3516 Reaper
->Flags
|= EXT2_REAPER_FLAG_STOP
;
3517 KeSetEvent(&Reaper
->Wait
, 0, FALSE
);
3519 /* make sure Reaperthread is started */
3520 timeout
.QuadPart
= (LONGLONG
)-10*1000*1000*2; /* 2 seconds */
3521 KeWaitForSingleObject(