#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
/* 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) &&
return FALSE;
}
+
RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
if (RtlCheckBit(&bitmap, dwBlk) == 0) {
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++) {
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 {
/* 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 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) {
- Ext2DropGroup(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);
}
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);
ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
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 {
/* 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 the first Mcb record in Vcb->McbList */
+
+BOOLEAN
+Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
+{
+ struct buffer_head *bh = NULL;
+ PLIST_ENTRY list = NULL;
+ LARGE_INTEGER now;
+ BOOLEAN wake = FALSE;
+
+ KeQuerySystemTime(&now);
+
+ ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
+ while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
+ list = RemoveHeadList(&Vcb->bd.bd_bh_free);
+ bh = CONTAINING_RECORD(list, struct buffer_head, b_link);
+ if (atomic_read(&bh->b_count)) {
+ InitializeListHead(&bh->b_link);
+ 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 {
+
+ /* 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);
+ if (Ext2QueryUnusedBH(Vcb, &List))
+ NonWait = TRUE;
+ }
+ 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);
+}
+
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);
+}