2000-12-10 23:42:01 +00:00
|
|
|
/*
|
|
|
|
* ReactOS kernel
|
2001-03-06 14:41:18 +00:00
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001 David Welch <welch@cwcom.net>
|
2000-12-10 23:42:01 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
2001-03-08 22:06:02 +00:00
|
|
|
/* $Id: view.c,v 1.17 2001/03/08 22:06:01 dwelch Exp $
|
2000-02-26 22:41:35 +00:00
|
|
|
*
|
1998-12-21 15:48:21 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/cc/view.c
|
|
|
|
* PURPOSE: Cache manager
|
|
|
|
* PROGRAMMER: David Welch (welch@mcmail.com)
|
|
|
|
* UPDATE HISTORY:
|
|
|
|
* Created 22/05/98
|
|
|
|
*/
|
|
|
|
|
2000-12-10 23:42:01 +00:00
|
|
|
/* NOTES **********************************************************************
|
|
|
|
*
|
|
|
|
* This is not the NT implementation of a file cache nor anything much like
|
|
|
|
* it.
|
|
|
|
*
|
|
|
|
* The general procedure for a filesystem to implement a read or write
|
|
|
|
* dispatch routine is as follows
|
|
|
|
*
|
|
|
|
* (1) If caching for the FCB hasn't been initiated then so do by calling
|
|
|
|
* CcInitializeFileCache.
|
|
|
|
*
|
|
|
|
* (2) For each 4k region which is being read or written obtain a cache page
|
|
|
|
* by calling CcRequestCachePage.
|
|
|
|
*
|
|
|
|
* (3) If either the page is being read or not completely written, and it is
|
|
|
|
* not up to date then read its data from the underlying medium. If the read
|
|
|
|
* fails then call CcReleaseCachePage with VALID as FALSE and return a error.
|
|
|
|
*
|
|
|
|
* (4) Copy the data into or out of the page as necessary.
|
|
|
|
*
|
|
|
|
* (5) Release the cache page
|
|
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
1998-12-21 15:48:21 +00:00
|
|
|
|
|
|
|
#include <ddk/ntddk.h>
|
|
|
|
#include <ddk/ntifs.h>
|
1999-04-05 15:04:46 +00:00
|
|
|
#include <internal/mm.h>
|
2000-03-05 19:17:43 +00:00
|
|
|
#include <internal/cc.h>
|
2001-03-07 16:48:45 +00:00
|
|
|
#include <internal/pool.h>
|
1998-12-21 15:48:21 +00:00
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
#define NDEBUG
|
1998-12-21 15:48:21 +00:00
|
|
|
#include <internal/debug.h>
|
|
|
|
|
2001-01-01 04:42:12 +00:00
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
|
|
|
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
|
|
|
|
#define ROUND_DOWN(N, S) (ROUND_UP(N, S) - S)
|
|
|
|
|
2001-03-07 16:48:45 +00:00
|
|
|
#define TAG_CSEG TAG('C', 'S', 'E', 'G')
|
|
|
|
#define TAG_BCB TAG('B', 'C', 'B', ' ')
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
1999-01-16 21:03:00 +00:00
|
|
|
|
2000-12-10 23:42:01 +00:00
|
|
|
NTSTATUS STDCALL
|
2001-01-01 04:42:12 +00:00
|
|
|
CcFlushCacheSegment(PCACHE_SEGMENT CacheSeg)
|
1999-05-29 00:15:17 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Asks the FSD to flush the contents of the page back to disk
|
|
|
|
*/
|
1998-12-21 15:48:21 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
KeWaitForSingleObject(&CacheSeg->Lock,
|
|
|
|
Executive,
|
|
|
|
KernelMode,
|
|
|
|
FALSE,
|
|
|
|
NULL);
|
2000-12-23 02:37:41 +00:00
|
|
|
/* FIXME: Build an IRP_MJ_WRITE and send it to the filesystem */
|
1999-05-29 00:15:17 +00:00
|
|
|
KeSetEvent(&CacheSeg->Lock, IO_NO_INCREMENT, 0);
|
|
|
|
return(STATUS_NOT_IMPLEMENTED);
|
|
|
|
}
|
1998-12-21 15:48:21 +00:00
|
|
|
|
2000-12-10 23:42:01 +00:00
|
|
|
NTSTATUS STDCALL
|
2001-01-01 04:42:12 +00:00
|
|
|
CcReleaseCacheSegment(PBCB Bcb,
|
|
|
|
PCACHE_SEGMENT CacheSeg,
|
|
|
|
BOOLEAN Valid)
|
1999-05-29 00:15:17 +00:00
|
|
|
{
|
|
|
|
DPRINT("CcReleaseCachePage(Bcb %x, CacheSeg %x, Valid %d)\n",
|
|
|
|
Bcb, CacheSeg, Valid);
|
|
|
|
|
|
|
|
CacheSeg->ReferenceCount--;
|
|
|
|
CacheSeg->Valid = Valid;
|
|
|
|
KeSetEvent(&CacheSeg->Lock, IO_NO_INCREMENT, FALSE);
|
|
|
|
|
|
|
|
DPRINT("CcReleaseCachePage() finished\n");
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
1998-12-21 15:48:21 +00:00
|
|
|
|
2000-12-10 23:42:01 +00:00
|
|
|
NTSTATUS STDCALL
|
2001-01-01 04:42:12 +00:00
|
|
|
CcRequestCacheSegment(PBCB Bcb,
|
|
|
|
ULONG FileOffset,
|
|
|
|
PVOID* BaseAddress,
|
|
|
|
PBOOLEAN UptoDate,
|
|
|
|
PCACHE_SEGMENT* CacheSeg)
|
2000-12-10 23:42:01 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Request a page mapping for a BCB
|
|
|
|
*/
|
1998-12-21 15:48:21 +00:00
|
|
|
{
|
1999-02-01 20:58:37 +00:00
|
|
|
KIRQL oldirql;
|
1999-01-16 21:03:00 +00:00
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PCACHE_SEGMENT current;
|
2001-01-01 04:42:12 +00:00
|
|
|
ULONG i;
|
1999-04-05 15:04:46 +00:00
|
|
|
|
2001-01-01 04:42:12 +00:00
|
|
|
if ((FileOffset % Bcb->CacheSegmentSize) != 0)
|
|
|
|
{
|
|
|
|
KeBugCheck(0);
|
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
DPRINT("CcRequestCachePage(Bcb %x, FileOffset %x, BaseAddress %x, "
|
|
|
|
"UptoDate %x, CacheSeg %x)\n", Bcb, FileOffset, BaseAddress,
|
|
|
|
UptoDate, CacheSeg);
|
1999-01-16 21:03:00 +00:00
|
|
|
|
1999-02-01 20:58:37 +00:00
|
|
|
KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
|
1999-01-16 21:03:00 +00:00
|
|
|
|
1999-02-01 20:58:37 +00:00
|
|
|
current_entry = Bcb->CacheSegmentListHead.Flink;
|
|
|
|
while (current_entry != &Bcb->CacheSegmentListHead)
|
1999-01-16 21:03:00 +00:00
|
|
|
{
|
1999-04-05 15:04:46 +00:00
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, ListEntry);
|
2001-01-01 04:42:12 +00:00
|
|
|
if (current->FileOffset == FileOffset)
|
1999-01-16 21:03:00 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
DPRINT("Found existing segment at %x\n", current);
|
1999-04-05 15:04:46 +00:00
|
|
|
current->ReferenceCount++;
|
1999-02-01 20:58:37 +00:00
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
|
1999-05-29 00:15:17 +00:00
|
|
|
DPRINT("Waiting for segment\n");
|
1999-04-05 15:04:46 +00:00
|
|
|
KeWaitForSingleObject(¤t->Lock,
|
|
|
|
Executive,
|
|
|
|
KernelMode,
|
|
|
|
FALSE,
|
|
|
|
NULL);
|
|
|
|
*UptoDate = current->Valid;
|
1999-05-29 00:15:17 +00:00
|
|
|
*BaseAddress = current->BaseAddress;
|
|
|
|
*CacheSeg = current;
|
|
|
|
DPRINT("Returning %x (UptoDate %d)\n", current, current->Valid);
|
1999-02-01 20:58:37 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1999-01-28 15:54:26 +00:00
|
|
|
}
|
1999-01-16 21:03:00 +00:00
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
}
|
1999-04-05 15:04:46 +00:00
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
DPRINT("Creating new segment\n");
|
|
|
|
|
|
|
|
KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
|
|
|
|
|
2001-03-07 16:48:45 +00:00
|
|
|
current = ExAllocatePoolWithTag(NonPagedPool, sizeof(CACHE_SEGMENT),
|
|
|
|
TAG_CSEG);
|
1999-04-05 15:04:46 +00:00
|
|
|
current->BaseAddress = NULL;
|
|
|
|
MmCreateMemoryArea(KernelMode,
|
2001-01-01 04:42:12 +00:00
|
|
|
MmGetKernelAddressSpace(),
|
1999-04-05 15:04:46 +00:00
|
|
|
MEMORY_AREA_CACHE_SEGMENT,
|
|
|
|
¤t->BaseAddress,
|
2001-01-01 04:42:12 +00:00
|
|
|
Bcb->CacheSegmentSize,
|
1999-04-05 15:04:46 +00:00
|
|
|
PAGE_READWRITE,
|
1999-05-29 00:15:17 +00:00
|
|
|
(PMEMORY_AREA*)¤t->MemoryArea);
|
1999-04-05 15:04:46 +00:00
|
|
|
current->Valid = FALSE;
|
2001-01-01 04:42:12 +00:00
|
|
|
current->FileOffset = FileOffset;
|
1999-05-29 00:15:17 +00:00
|
|
|
current->Bcb = Bcb;
|
|
|
|
KeInitializeEvent(¤t->Lock, SynchronizationEvent, FALSE);
|
1999-04-05 15:04:46 +00:00
|
|
|
current->ReferenceCount = 1;
|
|
|
|
InsertTailList(&Bcb->CacheSegmentListHead, ¤t->ListEntry);
|
|
|
|
*UptoDate = current->Valid;
|
|
|
|
*BaseAddress = current->BaseAddress;
|
1999-05-29 00:15:17 +00:00
|
|
|
*CacheSeg = current;
|
2001-01-01 04:42:12 +00:00
|
|
|
for (i = 0; i < (Bcb->CacheSegmentSize / PAGESIZE); i++)
|
|
|
|
{
|
|
|
|
MmCreateVirtualMapping(NULL,
|
|
|
|
current->BaseAddress + (i * PAGESIZE),
|
|
|
|
PAGE_READWRITE,
|
|
|
|
(ULONG)MmAllocPage(0));
|
|
|
|
}
|
1999-01-16 21:03:00 +00:00
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
|
|
|
|
DPRINT("Returning %x (BaseAddress %x)\n", current, *BaseAddress);
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2001-02-10 22:51:11 +00:00
|
|
|
static
|
2001-03-08 22:06:02 +00:00
|
|
|
VOID CcFreeCachePage(PVOID Context, PVOID Address, ULONG PhysAddr)
|
2001-02-10 22:51:11 +00:00
|
|
|
{
|
|
|
|
if (PhysAddr != 0)
|
|
|
|
{
|
|
|
|
MmDereferencePage((PVOID)PhysAddr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-12-10 23:42:01 +00:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
CcFreeCacheSegment(PBCB Bcb,
|
|
|
|
PCACHE_SEGMENT CacheSeg)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Releases a cache segment associated with a BCB
|
|
|
|
*/
|
1999-05-29 00:15:17 +00:00
|
|
|
{
|
|
|
|
MmFreeMemoryArea(NULL,
|
|
|
|
CacheSeg->BaseAddress,
|
2001-01-01 04:42:12 +00:00
|
|
|
Bcb->CacheSegmentSize,
|
2001-02-10 22:51:11 +00:00
|
|
|
CcFreeCachePage,
|
|
|
|
NULL);
|
1999-05-29 00:15:17 +00:00
|
|
|
ExFreePool(CacheSeg);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2000-12-10 23:42:01 +00:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
CcReleaseFileCache(PFILE_OBJECT FileObject,
|
|
|
|
PBCB Bcb)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Releases the BCB associated with a file object
|
|
|
|
*/
|
1999-05-29 00:15:17 +00:00
|
|
|
{
|
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PCACHE_SEGMENT current;
|
|
|
|
|
|
|
|
DPRINT("CcReleaseFileCache(FileObject %x, Bcb %x)\n",
|
|
|
|
FileObject, Bcb);
|
|
|
|
|
|
|
|
current_entry = Bcb->CacheSegmentListHead.Flink;
|
|
|
|
while (current_entry != (&Bcb->CacheSegmentListHead))
|
|
|
|
{
|
|
|
|
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, ListEntry);
|
|
|
|
current_entry = current_entry->Flink;
|
2000-12-10 23:42:01 +00:00
|
|
|
CcFreeCacheSegment(Bcb,
|
1999-05-29 00:15:17 +00:00
|
|
|
current);
|
|
|
|
}
|
|
|
|
|
|
|
|
ExFreePool(Bcb);
|
|
|
|
|
|
|
|
DPRINT("CcReleaseFileCache() finished\n");
|
1999-04-05 15:04:46 +00:00
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
1998-12-21 15:48:21 +00:00
|
|
|
}
|
|
|
|
|
2000-12-10 23:42:01 +00:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
CcInitializeFileCache(PFILE_OBJECT FileObject,
|
2001-01-01 04:42:12 +00:00
|
|
|
PBCB* Bcb,
|
|
|
|
ULONG CacheSegmentSize)
|
2000-12-10 23:42:01 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Initializes a BCB for a file object
|
|
|
|
*/
|
1998-12-21 15:48:21 +00:00
|
|
|
{
|
1999-04-05 15:04:46 +00:00
|
|
|
DPRINT("CcInitializeFileCache(FileObject %x)\n",FileObject);
|
|
|
|
|
2001-03-07 16:48:45 +00:00
|
|
|
(*Bcb) = ExAllocatePoolWithTag(NonPagedPool, sizeof(BCB), TAG_BCB);
|
1999-02-01 20:58:37 +00:00
|
|
|
if ((*Bcb) == NULL)
|
1999-01-28 15:54:26 +00:00
|
|
|
{
|
1999-04-05 15:04:46 +00:00
|
|
|
return(STATUS_UNSUCCESSFUL);
|
1999-01-28 15:54:26 +00:00
|
|
|
}
|
|
|
|
|
1999-02-01 20:58:37 +00:00
|
|
|
(*Bcb)->FileObject = FileObject;
|
|
|
|
InitializeListHead(&(*Bcb)->CacheSegmentListHead);
|
|
|
|
KeInitializeSpinLock(&(*Bcb)->BcbLock);
|
2001-01-01 04:42:12 +00:00
|
|
|
(*Bcb)->CacheSegmentSize = CacheSegmentSize;
|
|
|
|
|
1999-04-05 15:04:46 +00:00
|
|
|
DPRINT("Finished CcInitializeFileCache() = %x\n", *Bcb);
|
|
|
|
|
1999-02-01 20:58:37 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1998-12-21 15:48:21 +00:00
|
|
|
}
|
1999-02-01 20:58:37 +00:00
|
|
|
|
|
|
|
|
2000-03-05 19:17:43 +00:00
|
|
|
/**********************************************************************
|
|
|
|
* NAME INTERNAL
|
|
|
|
* CcMdlReadCompleteDev@8
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
|
|
|
* MdlChain
|
|
|
|
* DeviceObject
|
|
|
|
*
|
|
|
|
* RETURN VALUE
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
* NOTE
|
|
|
|
* Used by CcMdlReadComplete@8 and FsRtl
|
|
|
|
*/
|
2000-12-23 02:37:41 +00:00
|
|
|
VOID STDCALL
|
|
|
|
CcMdlReadCompleteDev (IN PMDL MdlChain,
|
|
|
|
IN PDEVICE_OBJECT DeviceObject)
|
2000-03-05 19:17:43 +00:00
|
|
|
{
|
2001-01-01 04:42:12 +00:00
|
|
|
UNIMPLEMENTED;
|
2000-03-05 19:17:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* NAME EXPORTED
|
|
|
|
* CcMdlReadComplete@8
|
|
|
|
*
|
|
|
|
* DESCRIPTION
|
|
|
|
*
|
|
|
|
* ARGUMENTS
|
|
|
|
*
|
|
|
|
* RETURN VALUE
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
* NOTE
|
|
|
|
* From Bo Branten's ntifs.h v13.
|
|
|
|
*/
|
2000-12-23 02:37:41 +00:00
|
|
|
VOID STDCALL
|
|
|
|
CcMdlReadComplete (IN PFILE_OBJECT FileObject,
|
|
|
|
IN PMDL MdlChain)
|
2000-03-05 19:17:43 +00:00
|
|
|
{
|
2000-12-23 02:37:41 +00:00
|
|
|
PDEVICE_OBJECT DeviceObject = NULL;
|
|
|
|
|
|
|
|
DeviceObject = IoGetRelatedDeviceObject (FileObject);
|
|
|
|
/* FIXME: try fast I/O first */
|
|
|
|
CcMdlReadCompleteDev (MdlChain,
|
|
|
|
DeviceObject);
|
2000-03-05 19:17:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-02-26 22:41:35 +00:00
|
|
|
/* EOF */
|