/* DEFINITIONS *************************************************************/
#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, Ext2AllocateFcb)
-#pragma alloc_text(PAGE, Ext2FreeFcb)
#pragma alloc_text(PAGE, Ext2AllocateInode)
#pragma alloc_text(PAGE, Ext2DestroyInode)
#pragma alloc_text(PAGE, Ext2CheckBitmapConsistency)
#pragma alloc_text(PAGE, Ext2CheckSetBlock)
#pragma alloc_text(PAGE, Ext2InitializeVcb)
-#pragma alloc_text(PAGE, Ext2FreeCcb)
-#pragma alloc_text(PAGE, Ext2AllocateCcb)
#pragma alloc_text(PAGE, Ext2TearDownStream)
#pragma alloc_text(PAGE, Ext2DestroyVcb)
#pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap)
#pragma alloc_text(PAGE, Ext2ReaperThread)
-#pragma alloc_text(PAGE, Ext2StartReaperThread)
+#pragma alloc_text(PAGE, Ext2StartReaper)
+#pragma alloc_text(PAGE, Ext2StopReaper)
#endif
PEXT2_IRP_CONTEXT
{
PEXT2_FCB Fcb;
- ASSERT(!IsMcbSymLink(Mcb));
+ ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->FcbLock));
Fcb = (PEXT2_FCB) ExAllocateFromNPagedLookasideList(
&(Ext2Global->Ext2FcbLookasideList));
}
VOID
-Ext2FreeFcb (IN PEXT2_FCB Fcb)
+Ext2UnlinkFcb(IN PEXT2_FCB Fcb)
{
- PEXT2_VCB Vcb = Fcb->Vcb;
+ PEXT2_VCB Vcb = Fcb->Vcb;
+ PEXT2_MCB Mcb;
- ASSERT((Fcb != NULL) && (Fcb->Identifier.Type == EXT2FCB) &&
- (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
- ASSERT((Fcb->Mcb->Identifier.Type == EXT2MCB) &&
- (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB)));
+ ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
+ Mcb = Fcb->Mcb;
-#ifndef _WIN2K_TARGET_
- FsRtlTeardownPerStreamContexts(&Fcb->Header);
-#endif
+ DEBUG(DL_ERR, ("Ext2FreeFcb: Fcb (%p) to be unlinked: %wZ.\n",
+ Fcb, Mcb ? &Mcb->FullName : NULL));
- if ((Fcb->Mcb->Identifier.Type == EXT2MCB) &&
- (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
+ if ((Mcb != NULL) &&
+ (Mcb->Identifier.Type == EXT2MCB) &&
+ (Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
- ASSERT (Fcb->Mcb->Fcb == Fcb);
- if (IsMcbSpecialFile(Fcb->Mcb) || IsFileDeleted(Fcb->Mcb)) {
+ ASSERT (Mcb->Fcb == Fcb);
+ if (IsMcbSpecialFile(Mcb) ||
+ IsFileDeleted(Mcb)) {
ASSERT(!IsRoot(Fcb));
- Ext2RemoveMcb(Fcb->Vcb, Fcb->Mcb);
- Fcb->Mcb->Fcb = NULL;
+ Ext2RemoveMcb(Vcb, Mcb);
+ Mcb->Fcb = NULL;
- Ext2UnlinkMcb(Vcb, Fcb->Mcb);
- Ext2DerefMcb(Fcb->Mcb);
- Ext2LinkHeadMcb(Vcb, Fcb->Mcb);
+ Ext2UnlinkMcb(Vcb, Mcb);
+ Ext2DerefMcb(Mcb);
+ Ext2LinkHeadMcb(Vcb, Mcb);
} else {
-
- Fcb->Mcb->Fcb = NULL;
- Ext2DerefMcb(Fcb->Mcb);
+ Mcb->Fcb = NULL;
+ Ext2DerefMcb(Mcb);
}
-
- } else {
- DbgBreak();
+ Fcb->Mcb = NULL;
}
- Ext2RemoveFcb(Fcb->Vcb, Fcb);
+ ExReleaseResourceLite(&Vcb->McbLock);
+}
- FsRtlUninitializeFileLock(&Fcb->FileLockAnchor);
- FsRtlUninitializeOplock(&Fcb->Oplock);
- ExDeleteResourceLite(&Fcb->MainResource);
- ExDeleteResourceLite(&Fcb->PagingIoResource);
+VOID
+Ext2FreeFcb (IN PEXT2_FCB Fcb)
+{
+ PEXT2_VCB Vcb = Fcb->Vcb;
- DEBUG(DL_RES, ( "Ext2FreeFcb: Fcb (%p) is being released: %wZ.\n",
- Fcb, &Fcb->Mcb->FullName));
+ _SEH2_TRY {
- Fcb->Identifier.Type = 0;
- Fcb->Identifier.Size = 0;
+ ASSERT((Fcb != NULL) && (Fcb->Identifier.Type == EXT2FCB) &&
+ (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+ ASSERT(0 == Fcb->ReferenceCount);
- ExFreeToNPagedLookasideList(&(Ext2Global->Ext2FcbLookasideList), Fcb);
- DEC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
-}
+#ifndef _WIN2K_TARGET_
+ FsRtlTeardownPerStreamContexts(&Fcb->Header);
+#endif
+
+ FsRtlUninitializeFileLock(&Fcb->FileLockAnchor);
+ FsRtlUninitializeOplock(&Fcb->Oplock);
+ ExDeleteResourceLite(&Fcb->MainResource);
+ ExDeleteResourceLite(&Fcb->PagingIoResource);
+
+ Fcb->Identifier.Type = 0;
+ Fcb->Identifier.Size = 0;
-/* Insert Fcb to Vcb->FcbList queue */
+ ExFreeToNPagedLookasideList(&(Ext2Global->Ext2FcbLookasideList), Fcb);
+ DEC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
+
+ if (0 == Ext2DerefXcb(&Vcb->ReferenceCount)) {
+ if (!IsMounted(Vcb) || IsDispending(Vcb)) {
+ Ext2CheckDismount(NULL, Vcb, FALSE);
+ }
+ }
+
+ } _SEH2_FINALLY {
+ } _SEH2_END;
+}
VOID
-Ext2InsertFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
+Ext2ReleaseFcb (IN PEXT2_FCB Fcb)
{
- ExInterlockedInsertTailList(&Vcb->FcbList, &Fcb->Next, &Vcb->FcbLock);
- Ext2ReferXcb(&Vcb->FcbCount);
+ PEXT2_VCB Vcb = Fcb->Vcb;
+ PEXT2_MCB Mcb;
+
+ if (0 != Ext2DerefXcb(&Fcb->ReferenceCount))
+ return;
+
+ ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+ ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
+
+ Mcb = Fcb->Mcb;
+ RemoveEntryList(&Fcb->Next);
+
+ if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) ||
+ NULL == Mcb || IsFileDeleted(Mcb)) {
+ InsertHeadList(&Vcb->FcbList, &Fcb->Next);
+ Fcb->TsDrop.QuadPart = 0;
+ } else {
+ InsertTailList(&Vcb->FcbList, &Fcb->Next);
+ KeQuerySystemTime(&Fcb->TsDrop);
+ }
+ ExReleaseResourceLite(&Fcb->MainResource);
+ ExReleaseResourceLite(&Vcb->FcbLock);
+
+ if ((Vcb->FcbCount >> 6) > (ULONG)(Ext2Global->MaxDepth)) {
+ KeSetEvent(&Ext2Global->FcbReaper.Wait, 0, FALSE);
+ }
}
-/* Remove Fcb from Vcb->FcbList queue */
+/* Insert Fcb to Vcb->FcbList queue, with Vcb->FcbLock Acquired. */
VOID
-Ext2RemoveFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
+Ext2InsertFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
{
- KIRQL irql;
+ ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->FcbLock));
- KeAcquireSpinLock(&Vcb->FcbLock, &irql);
- RemoveEntryList(&(Fcb->Next));
- if (Vcb->FcbCount > 0) {
- Ext2DerefXcb(&Vcb->FcbCount);
- } else {
- DbgBreak();
- }
- KeReleaseSpinLock(&Vcb->FcbLock, irql);
+ KeQuerySystemTime(&Fcb->TsDrop);
+ Ext2ReferXcb(&Vcb->FcbCount);
+ Ext2ReferXcb(&Vcb->ReferenceCount);
+ InsertTailList(&Vcb->FcbList, &Fcb->Next);
}
PEXT2_CCB
-Ext2AllocateCcb (PEXT2_MCB SymLink)
+Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink)
{
PEXT2_CCB Ccb;
Ccb->Identifier.Type = EXT2CCB;
Ccb->Identifier.Size = sizeof(EXT2_CCB);
+ Ccb->Flags = Flags;
Ccb->SymLink = SymLink;
if (SymLink) {
Ext2FreeCcb (IN PEXT2_VCB Vcb, IN PEXT2_CCB Ccb)
{
ASSERT(Ccb != NULL);
-
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
NTSTATUS Status = STATUS_SUCCESS;
PEXT2_EXTENT Extent = NULL;
- PEXT2_EXTENT List = *Chain;
+ PEXT2_EXTENT List = *Chain = NULL;
if (!IsZoneInited(Mcb)) {
Status = Ext2InitializeZone(IrpContext, Vcb, Mcb);
&Mapped
);
if (!NT_SUCCESS(Status)) {
- goto errorout;
+ break;
}
/* skip wrong blocks, in case wrongly treating symlink
Length = Size;
}
+ if (0 == Length) {
+ DbgBreak();
+ break;
+ }
+
Start += Mapped;
Offset = (ULONGLONG)Start << BLOCK_BITS;
Extent = Ext2AllocateExtent();
if (!Extent) {
Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
+ DbgBreak();
+ break;
}
Extent->Lba = Lba;
*Chain = List = Extent;
}
}
+ } else {
+ if (bAlloc) {
+ DbgBreak();
+ }
}
Total += Length;
Size -= Length;
}
-errorout:
-
return Status;
}
/* need wake the reaper thread if there are many Mcb allocated */
if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 4)) {
- KeSetEvent(&Ext2Global->Reaper.Wait, 0, FALSE);
+ KeSetEvent(&Ext2Global->McbReaper.Wait, 0, FALSE);
}
/* allocate Mcb from LookasideList */
#ifndef __REACTOS__
PEXT2_MCB Parent = Mcb->Parent;
#endif
+
ASSERT(Mcb != NULL);
ASSERT((Mcb->Identifier.Type == EXT2MCB) &&
BOOLEAN
Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
{
- PEXT2_GROUP_DESC gd;
- ULONG Group, dwBlk, Length;
-
- RTL_BITMAP BlockBitmap;
- PVOID BitmapCache;
- PBCB BitmapBcb;
-
- LARGE_INTEGER Offset;
-
- BOOLEAN bModified = FALSE;
-
-
- Group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
+ struct buffer_head *bh = NULL;
+ ULONG group, dwBlk, Length;
+ RTL_BITMAP bitmap;
+ BOOLEAN bModified = FALSE;
+
+ group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
dwBlk = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
- gd = ext4_get_group_desc(&Vcb->sb, Group, NULL);
+ gd = ext4_get_group_desc(&Vcb->sb, group, &gb);
if (!gd) {
return FALSE;
}
- Offset.QuadPart = ext4_block_bitmap(&Vcb->sb, gd);
- Offset.QuadPart <<= BLOCK_BITS;
+ bh = sb_getblk(&Vcb->sb, ext4_block_bitmap(&Vcb->sb, gd));
- if (Group == Vcb->sbi.s_groups_count - 1) {
+ if (group == Vcb->sbi.s_groups_count - 1) {
Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
/* s_blocks_count is integer multiple of s_blocks_per_group */
Length = BLOCKS_PER_GROUP;
}
- if (dwBlk >= Length)
- return FALSE;
-
- if (!CcPinRead( Vcb->Volume,
- &Offset,
- Vcb->BlockSize,
- PIN_WAIT,
- &BitmapBcb,
- &BitmapCache ) ) {
-
- DEBUG(DL_ERR, ( "Ext2CheckSetBlock: Failed to PinLock block %xh ...\n",
- ext4_block_bitmap(&Vcb->sb, gd)));
+ if (dwBlk >= Length) {
+ fini_bh(&gb);
+ fini_bh(&bh);
return FALSE;
}
- RtlInitializeBitMap( &BlockBitmap,
- BitmapCache,
- Length );
- if (RtlCheckBit(&BlockBitmap, dwBlk) == 0) {
+ RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
+
+ if (RtlCheckBit(&bitmap, dwBlk) == 0) {
DbgBreak();
- RtlSetBits(&BlockBitmap, dwBlk, 1);
+ RtlSetBits(&bitmap, dwBlk, 1);
bModified = TRUE;
+ mark_buffer_dirty(bh);
}
- if (bModified) {
- CcSetDirtyPinnedData(BitmapBcb, NULL );
- Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)BLOCK_SIZE);
- }
-
- {
- CcUnpinData(BitmapBcb);
- BitmapBcb = NULL;
- BitmapCache = NULL;
-
- RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
- }
+ fini_bh(&gb);
+ fini_bh(&bh);
return (!bModified);
}
for (i = 0; i < Vcb->sbi.s_groups_count; i++) {
PEXT2_GROUP_DESC gd;
+ struct buffer_head *bh = NULL;
- gd = ext4_get_group_desc(&Vcb->sb, i, NULL);
+ gd = ext4_get_group_desc(&Vcb->sb, i, &bh);
if (!gd)
continue;
Ext2CheckSetBlock(IrpContext, Vcb, ext4_block_bitmap(&Vcb->sb, gd));
for (j = 0; j < InodeBlocks; j++ )
Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_table(&Vcb->sb, gd) + j);
+
+ fini_bh(&bh);
}
return TRUE;
VOID
Ext2ParseRegistryVolumeParams(
IN PUNICODE_STRING Params,
- OUT PEXT2_VOLUME_PROPERTY2 Property
+ OUT PEXT2_VOLUME_PROPERTY3 Property
)
{
WCHAR Codepage[CODEPAGE_MAXLEN];
WCHAR Suffix[HIDINGPAT_LEN];
USHORT MountPoint[4];
UCHAR DrvLetter[4];
+ WCHAR wUID[8], wGID[8], wEUID[8], wEGID[8];
+ CHAR sUID[8], sGID[8], sEUID[8], sEGID[8];
BOOLEAN bWriteSupport = FALSE,
bCheckBitmap = FALSE,
bCodeName = FALSE,
bMountPoint = FALSE;
+ BOOLEAN bUID = 0, bGID = 0, bEUID = 0, bEGID = 0;
+
struct {
PWCHAR Name; /* parameters name */
PBOOLEAN bExist; /* is it contained in params */
{MOUNT_POINT, &bMountPoint, 4,
&MountPoint[0], &DrvLetter[0]},
+ {UID, &bUID, 8, &wUID[0], &sUID[0],},
+ {GID, &bGID, 8, &wGID[0], &sGID[0]},
+ {EUID, &bEUID, 8, &wEUID[0], &sEUID[0]},
+ {EGID, &bEGID, 8, &wEGID[0], &sEGID[0]},
+
/* end */
{NULL, NULL, 0, NULL}
};
RtlZeroMemory(MountPoint, sizeof(USHORT) * 4);
RtlZeroMemory(DrvLetter, sizeof(CHAR) * 4);
- RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY2));
+ RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY3));
Property->Magic = EXT2_VOLUME_PROPERTY_MAGIC;
- Property->Command = APP_CMD_SET_PROPERTY2;
+ Property->Command = APP_CMD_SET_PROPERTY3;
for (i=0; ParamPattern[i].Name != NULL; i++) {
k < ParamPattern[i].Length &&
Params->Buffer[j+k] != L';' &&
Params->Buffer[j+k] != L',' ) {
+#ifdef __REACTOS__
+ ParamPattern[i].uValue[k] = Params->Buffer[j + k];
+ k++;
+#else
ParamPattern[i].uValue[k] = Params->Buffer[j + k++];
+#endif
}
if (k) {
NTSTATUS status;
Property->DrvLetter = DrvLetter[0];
Property->DrvLetter |= 0x80;
}
+
+ if (bUID && bGID) {
+ SetFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
+ sUID[7] = sGID[7] = sEUID[7] = sEGID[7] = 0;
+ Property->uid = (USHORT)atoi(sUID);
+ Property->gid = (USHORT)atoi(sGID);
+ if (bEUID) {
+ Property->euid = (USHORT)atoi(sEUID);
+ Property->egid = (USHORT)atoi(sEGID);
+ Property->EIDS = TRUE;
+ } else {
+ Property->EIDS = FALSE;
+ }
+ } else {
+ ClearFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
+ }
}
NTSTATUS
if (NT_SUCCESS(Status)) {
/* set Vcb settings from registery */
- EXT2_VOLUME_PROPERTY2 Property;
+ EXT2_VOLUME_PROPERTY3 Property;
Ext2ParseRegistryVolumeParams(&VolumeParams, &Property);
Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property));
memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN);
Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
- if ((Vcb->bHidingPrefix = Ext2Global->bHidingPrefix) != 0) {
+ if (Vcb->bHidingPrefix == Ext2Global->bHidingPrefix) {
RtlCopyMemory( Vcb->sHidingPrefix,
Ext2Global->sHidingPrefix,
HIDINGPAT_LEN);
HIDINGPAT_LEN);
}
- if ((Vcb->bHidingSuffix = Ext2Global->bHidingSuffix) != 0) {
+ if (Vcb->bHidingSuffix == Ext2Global->bHidingSuffix) {
RtlCopyMemory( Vcb->sHidingSuffix,
Ext2Global->sHidingSuffix,
HIDINGPAT_LEN);
BOOLEAN NotifySyncInitialized = FALSE;
BOOLEAN ExtentsInitialized = FALSE;
BOOLEAN InodeLookasideInitialized = FALSE;
+ BOOLEAN GroupLoaded = FALSE;
_SEH2_TRY {
_SEH2_LEAVE;
}
- /* checking in/compat features */
- if (IsFlagOn(sb->s_feature_compat, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
- Vcb->IsExt3fs = TRUE;
- }
-
- /* don't mount any volumes with external journal devices */
- if (IsFlagOn(sb->s_feature_incompat, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
+ /* Reject mounting volume if we encounter unsupported incompat features */
+ if (FlagOn(sb->s_feature_incompat, ~EXT4_FEATURE_INCOMPAT_SUPP)) {
Status = STATUS_UNRECOGNIZED_VOLUME;
_SEH2_LEAVE;
}
+ /* Mount the volume RO if we encounter unsupported ro_compat features */
+ if (FlagOn(sb->s_feature_ro_compat, ~EXT4_FEATURE_RO_COMPAT_SUPP)) {
+ SetLongFlag(Vcb->Flags, VCB_RO_COMPAT_READ_ONLY);
+ }
+
+ /* Recognize the filesystem as Ext3fs if it supports journalling */
+ if (IsFlagOn(sb->s_feature_compat, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
+ Vcb->IsExt3fs = TRUE;
+ }
+
/* check block size */
Vcb->BlockSize = (EXT2_MIN_BLOCK_SIZE << sb->s_log_block_size);
/* we cannot handle volume with block size bigger than 64k */
/* initialize eresources */
ExInitializeResourceLite(&Vcb->MainResource);
ExInitializeResourceLite(&Vcb->PagingIoResource);
- ExInitializeResourceLite(&Vcb->MetaLock);
+ ExInitializeResourceLite(&Vcb->MetaInode);
+ ExInitializeResourceLite(&Vcb->MetaBlock);
ExInitializeResourceLite(&Vcb->McbLock);
+ ExInitializeResourceLite(&Vcb->sbi.s_gd_lock);
#ifndef _WIN2K_TARGET_
ExInitializeFastMutex(&Vcb->Mutex);
FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->Mutex);
/* initialize Fcb list head */
InitializeListHead(&Vcb->FcbList);
- KeInitializeSpinLock(&Vcb->FcbLock);
+ ExInitializeResourceLite(&Vcb->FcbLock);
/* initialize Mcb list head */
InitializeListHead(&(Vcb->McbList));
/* initialize UUID and serial number */
if (Ext2IsNullUuid(sb->s_uuid)) {
ExUuidCreate((UUID *)sb->s_uuid);
- } else {
- /* query parameters from registry */
- if (!NT_SUCCESS(Ext2PerformRegistryVolumeParams(Vcb))) {
- /* don't mount this volume */
- Status = STATUS_UNRECOGNIZED_VOLUME;
- _SEH2_LEAVE;
- }
}
-
Vpb->SerialNumber = ((ULONG*)sb->s_uuid)[0] +
((ULONG*)sb->s_uuid)[1] +
((ULONG*)sb->s_uuid)[2] +
Vcb->bd.bd_volume = Vcb->Volume;
Vcb->bd.bd_priv = (void *) Vcb;
memset(&Vcb->bd.bd_bh_root, 0, sizeof(struct rb_root));
- spin_lock_init(&Vcb->bd.bd_bh_lock);
+ InitializeListHead(&Vcb->bd.bd_bh_free);
+ ExInitializeResourceLite(&Vcb->bd.bd_bh_lock);
+ KeInitializeEvent(&Vcb->bd.bd_bh_notify,
+ NotificationEvent, TRUE);
Vcb->bd.bd_bh_cache = kmem_cache_create("bd_bh_buffer",
Vcb->BlockSize, 0, 0, NULL);
if (!Vcb->bd.bd_bh_cache) {
Status = STATUS_UNSUCCESSFUL;
_SEH2_LEAVE;
}
+ GroupLoaded = TRUE;
/* recovery journal since it's ext3 */
if (Vcb->IsExt3fs) {
/* get anything doen, then refer target device */
ObReferenceObject(Vcb->TargetDeviceObject);
+
+ /* query parameters from registry */
+ Ext2PerformRegistryVolumeParams(Vcb);
+
SetLongFlag(Vcb->Flags, VCB_INITIALIZED);
} _SEH2_FINALLY {
}
if (ExtentsInitialized) {
- Ext2PutGroup(Vcb);
- if (Vcb->bd.bd_bh_cache)
+ if (Vcb->bd.bd_bh_cache) {
+ if (GroupLoaded)
+ Ext2PutGroup(Vcb);
kmem_cache_destroy(Vcb->bd.bd_bh_cache);
+ }
FsRtlUninitializeLargeMcb(&(Vcb->Extents));
}
if (VcbResourceInitialized) {
ExDeleteResourceLite(&Vcb->McbLock);
- ExDeleteResourceLite(&Vcb->MetaLock);
+ ExDeleteResourceLite(&Vcb->MetaInode);
+ ExDeleteResourceLite(&Vcb->MetaBlock);
+ ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
ExDeleteResourceLite(&Vcb->MainResource);
ExDeleteResourceLite(&Vcb->PagingIoResource);
}
Ext2CleanupAllMcbs(Vcb);
- Ext2PutGroup(Vcb);
+ Ext2DropBH(Vcb);
if (Vcb->bd.bd_bh_cache)
kmem_cache_destroy(Vcb->bd.bd_bh_cache);
+ ExDeleteResourceLite(&Vcb->bd.bd_bh_lock);
if (Vcb->SuperBlock) {
Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC);
if (IsFlagOn(Vcb->Flags, VCB_NEW_VPB)) {
ASSERT(Vcb->Vpb2 != NULL);
- Ext2FreePool(Vcb->Vpb2, TAG_VPB);
+ DEBUG(DL_DBG, ("Ext2DestroyVcb: Vpb2 to be freed: %p\n", Vcb->Vpb2));
+ ExFreePoolWithTag(Vcb->Vpb2, TAG_VPB);
DEC_MEM_COUNT(PS_VPB, Vcb->Vpb2, sizeof(VPB));
Vcb->Vpb2 = NULL;
}
ObDereferenceObject(Vcb->TargetDeviceObject);
ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
+ ExDeleteResourceLite(&Vcb->FcbLock);
ExDeleteResourceLite(&Vcb->McbLock);
- ExDeleteResourceLite(&Vcb->MetaLock);
+ ExDeleteResourceLite(&Vcb->MetaInode);
+ ExDeleteResourceLite(&Vcb->MetaBlock);
+ ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
ExDeleteResourceLite(&Vcb->PagingIoResource);
ExDeleteResourceLite(&Vcb->MainResource);
/* Reaper thread to release unused Mcb blocks */
VOID NTAPI
-Ext2ReaperThread(
+Ext2McbReaperThread(
PVOID Context
)
{
- BOOLEAN GlobalAcquired = FALSE;
-
- BOOLEAN DidNothing = TRUE;
- BOOLEAN LastState = TRUE;
- BOOLEAN WaitLock;
-
+ PEXT2_REAPER Reaper = Context;
PLIST_ENTRY List = NULL;
LARGE_INTEGER Timeout;
ULONG i, NumOfMcbs;
+ BOOLEAN GlobalAcquired = FALSE;
+
+ BOOLEAN DidNothing = TRUE;
+ BOOLEAN LastState = TRUE;
+ BOOLEAN WaitLock;
+
_SEH2_TRY {
+ Reaper->Thread = PsGetCurrentThread();
+
/* wake up DirverEntry */
- KeSetEvent(&Ext2Global->Reaper.Engine, 0, FALSE);
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
/* now process looping */
- while (TRUE) {
+ while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
WaitLock = FALSE;
/* wait until it is waken or it times out */
KeWaitForSingleObject(
- &(Ext2Global->Reaper.Wait),
+ &Reaper->Wait,
Executive,
KernelMode,
FALSE,
&Timeout
);
+ if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
+ break;
+
DidNothing = TRUE;
/* acquire global exclusive lock */
if (GlobalAcquired) {
ExReleaseResourceLite(&Ext2Global->Resource);
}
+
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+ } _SEH2_END;
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+
+/* get buffer heads from global Vcb BH list */
+
+BOOLEAN
+Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
+{
+ struct buffer_head *bh = NULL;
+ PLIST_ENTRY next = NULL;
+ LARGE_INTEGER now;
+ BOOLEAN wake = FALSE;
+
+ KeQuerySystemTime(&now);
+
+ ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
+
+ while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
+ next = RemoveHeadList(&Vcb->bd.bd_bh_free);
+ bh = CONTAINING_RECORD(next, struct buffer_head, b_link);
+ if (atomic_read(&bh->b_count)) {
+ InitializeListHead(&bh->b_link);
+ /* to be inserted by brelse */
+ continue;
+ }
+
+ if ( IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED) ||
+ (bh->b_ts_drop.QuadPart + (LONGLONG)10*1000*1000*15) > now.QuadPart ||
+ (bh->b_ts_creat.QuadPart + (LONGLONG)10*1000*1000*180) > now.QuadPart) {
+ InsertTailList(head, &bh->b_link);
+ } else {
+ InsertHeadList(&Vcb->bd.bd_bh_free, &bh->b_link);
+ break;
+ }
+ }
+
+ wake = IsListEmpty(&Vcb->bd.bd_bh_free);
+ ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
+
+ if (wake)
+ KeSetEvent(&Vcb->bd.bd_bh_notify, 0, FALSE);
+
+ return IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED);
+}
+
+
+/* Reaper thread to release unused buffer heads */
+VOID NTAPI
+Ext2bhReaperThread(
+ PVOID Context
+)
+{
+ PEXT2_REAPER Reaper = Context;
+ PEXT2_VCB Vcb = NULL;
+ LIST_ENTRY List, *Link;
+ LARGE_INTEGER Timeout;
+
+ BOOLEAN GlobalAcquired = FALSE;
+ BOOLEAN DidNothing = FALSE;
+ BOOLEAN NonWait = FALSE;
+
+ _SEH2_TRY {
+
+ Reaper->Thread = PsGetCurrentThread();
+
+ /* wake up DirverEntry */
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+
+ /* now process looping */
+ while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
+
+ /* wait until it is waken or it times out */
+ if (NonWait) {
+ Timeout.QuadPart = (LONGLONG)-10*1000*10;
+ NonWait = FALSE;
+ } else if (DidNothing) {
+ Timeout.QuadPart = Timeout.QuadPart * 2;
+ } else {
+ Timeout.QuadPart = (LONGLONG)-10*1000*1000*10; /* 10 seconds */
+ }
+ KeWaitForSingleObject(
+ &Reaper->Wait,
+ Executive,
+ KernelMode,
+ FALSE,
+ &Timeout
+ );
+
+ if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
+ break;
+
+ InitializeListHead(&List);
+
+ /* acquire global exclusive lock */
+ ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
+ GlobalAcquired = TRUE;
+ /* search all Vcb to get unused resources freed to system */
+ for (Link = Ext2Global->VcbList.Flink;
+ Link != &(Ext2Global->VcbList);
+ Link = Link->Flink ) {
+
+ Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
+ NonWait = Ext2QueryUnusedBH(Vcb, &List);
+ }
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ GlobalAcquired = FALSE;
+ }
+
+ DidNothing = IsListEmpty(&List);
+ while (!IsListEmpty(&List)) {
+ struct buffer_head *bh;
+ Link = RemoveHeadList(&List);
+ bh = CONTAINING_RECORD(Link, struct buffer_head, b_link);
+ ASSERT(0 == atomic_read(&bh->b_count));
+ free_buffer_head(bh);
+ }
+ }
+
+ } _SEH2_FINALLY {
+
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ }
+
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
} _SEH2_END;
PsTerminateSystemThread(STATUS_SUCCESS);
}
+/* get unused Fcbs to free */
+
+BOOLEAN
+Ext2QueryUnusedFcb(PEXT2_VCB Vcb, PLIST_ENTRY list)
+{
+ PEXT2_FCB Fcb;
+ PLIST_ENTRY next = NULL;
+ LARGE_INTEGER now;
+
+ ULONG count = 0;
+ ULONG tries = 0;
+ BOOLEAN wake = FALSE;
+ BOOLEAN retry = TRUE;
+
+ KeQuerySystemTime(&now);
+
+ ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+
+again:
+
+ while (!IsListEmpty(&Vcb->FcbList)) {
+
+ next = RemoveHeadList(&Vcb->FcbList);
+ Fcb = CONTAINING_RECORD(next, EXT2_FCB, Next);
+
+ if (Fcb->ReferenceCount > 0) {
+ InsertTailList(&Vcb->FcbList, &Fcb->Next);
+ break;
+ }
+
+ retry = FALSE;
+
+ if (now.QuadPart < Fcb->TsDrop.QuadPart + 10*1000*1000*120) {
+ InsertHeadList(&Vcb->FcbList, &Fcb->Next);
+ break;
+ }
+
+ Ext2UnlinkFcb(Fcb);
+ Ext2DerefXcb(&Vcb->FcbCount);
+ InsertTailList(list, &Fcb->Next);
+ if (++count >= Ext2Global->MaxDepth) {
+ break;
+ }
+ }
+
+ if (retry) {
+ if (++tries < (Vcb->FcbCount >> 4) )
+ goto again;
+ }
+
+ ExReleaseResourceLite(&Vcb->FcbLock);
+
+ return 0;
+}
+
+/* Reaper thread to release Fcb */
+VOID NTAPI
+Ext2FcbReaperThread(
+ PVOID Context
+)
+{
+ PEXT2_REAPER Reaper = Context;
+ PEXT2_VCB Vcb = NULL;
+ LIST_ENTRY List, *Link;
+ LARGE_INTEGER Timeout;
+
+ BOOLEAN GlobalAcquired = FALSE;
+ BOOLEAN DidNothing = FALSE;
+ BOOLEAN NonWait = FALSE;
+
+ _SEH2_TRY {
+
+ Reaper->Thread = PsGetCurrentThread();
+
+ /* wake up DirverEntry */
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+
+ /* now process looping */
+ while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
+
+ /* wait until it is waken or it times out */
+ if (NonWait) {
+ Timeout.QuadPart = (LONGLONG)-10*1000*100;
+ NonWait = FALSE;
+ } else if (DidNothing) {
+ Timeout.QuadPart = Timeout.QuadPart * 2;
+ } else {
+ Timeout.QuadPart = (LONGLONG)-10*1000*1000*20; /* 20 seconds */
+ }
+ KeWaitForSingleObject(
+ &Reaper->Wait,
+ Executive,
+ KernelMode,
+ FALSE,
+ &Timeout
+ );
+
+ if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
+ break;
+
+ InitializeListHead(&List);
+
+ /* acquire global exclusive lock */
+ ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
+ GlobalAcquired = TRUE;
+ /* search all Vcb to get unused resources freed to system */
+ for (Link = Ext2Global->VcbList.Flink;
+ Link != &(Ext2Global->VcbList);
+ Link = Link->Flink ) {
+
+ Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
+ NonWait = Ext2QueryUnusedFcb(Vcb, &List);
+ }
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ GlobalAcquired = FALSE;
+ }
+
+ DidNothing = IsListEmpty(&List);
+ while (!IsListEmpty(&List)) {
+ PEXT2_FCB Fcb;
+ Link = RemoveHeadList(&List);
+ Fcb = CONTAINING_RECORD(Link, EXT2_FCB, Next);
+ ASSERT(0 == Fcb->ReferenceCount);
+ Ext2FreeFcb(Fcb);
+ }
+ }
+
+ } _SEH2_FINALLY {
+
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ }
+
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+ } _SEH2_END;
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
NTSTATUS
-Ext2StartReaperThread()
+Ext2StartReaper(PEXT2_REAPER Reaper, EXT2_REAPER_RELEASE Free)
{
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES oa;
HANDLE handle = 0;
+ LARGE_INTEGER timeout;
+
+ Reaper->Free = Free;
/* initialize wait event */
KeInitializeEvent(
- &Ext2Global->Reaper.Wait,
+ &Reaper->Wait,
+ SynchronizationEvent, FALSE
+ );
+
+ /* Reaper thread engine event */
+ KeInitializeEvent(
+ &Reaper->Engine,
SynchronizationEvent, FALSE
);
&oa,
NULL,
NULL,
- Ext2ReaperThread,
- NULL
+ Free,
+ (PVOID)Reaper
);
if (NT_SUCCESS(status)) {
ZwClose(handle);
+
+ /* make sure Reaperthread is started */
+ timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
+ status = KeWaitForSingleObject(
+ &Reaper->Engine,
+ Executive,
+ KernelMode,
+ FALSE,
+ &timeout
+ );
+ if (status != STATUS_SUCCESS) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
}
return status;
}
+
+
+VOID NTAPI
+Ext2StopReaper(PEXT2_REAPER Reaper)
+{
+ LARGE_INTEGER timeout;
+
+ Reaper->Flags |= EXT2_REAPER_FLAG_STOP;
+ KeSetEvent(&Reaper->Wait, 0, FALSE);
+
+ /* make sure Reaperthread is started */
+ timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
+ KeWaitForSingleObject(
+ &Reaper->Engine,
+ Executive,
+ KernelMode,
+ FALSE,
+ &timeout);
+}