/* $Id$ * reactos Cache Manager (Cc*) SharedCacheMap structure of libcaptive * Copyright (C) 2003 Jan Kratochvil * * 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; exactly version 2 of June 1991 is required * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "sharedcachemap.h" /* self */ #include "sharedcachemap-priv.h" /* self */ #include "io.h" #include "marshallers.h" #include #include "privatebcbpin.h" #include "captive/macros.h" #include #include "reactos/ddk/obfuncs.h" #include static GHashTable *CaptiveSharedCacheMapObject_hash; static void CaptiveSharedCacheMapObject_hash_init(void) { if (CaptiveSharedCacheMapObject_hash) return; CaptiveSharedCacheMapObject_hash=g_hash_table_new( g_direct_hash, /* hash_func */ g_direct_equal); /* key_equal_func */ } static gpointer captive_shared_cache_map_object_parent_class=NULL; static void captive_shared_cache_map_object_finalize(CaptiveSharedCacheMapObject *captive_shared_cache_map_object) { static const CC_FILE_SIZES FileSizes_zero; gboolean errbool; guint64 offset; CaptiveSharedCacheMapObject_page *page; g_return_if_fail(captive_shared_cache_map_object!=NULL); for (offset=0;offsetAllocationSize,PAGE_SIZE);offset+=PAGE_SIZE) { page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE; if (!page->data_valid) continue; g_assert(!page->dirty); /* FIXME: Is it allowed by W32? */ } CaptiveSharedCacheMapObject_hash_init(); errbool=g_hash_table_remove(CaptiveSharedCacheMapObject_hash,captive_shared_cache_map_object); g_assert(errbool==TRUE); captive_shared_cache_map_FileSizes_set(captive_shared_cache_map_object,&FileSizes_zero); g_assert(captive_shared_cache_map_object->buffer==NULL); g_assert(captive_shared_cache_map_object->pages==NULL); if (captive_shared_cache_map_object->pin_hash) { captive_private_bcb_pin_object_hash_destroy(captive_shared_cache_map_object->pin_hash); captive_shared_cache_map_object->pin_hash=NULL; } g_assert(captive_shared_cache_map_object->map==NULL); if (captive_shared_cache_map_object->SectionObjectPointer) { g_assert(captive_shared_cache_map_object==captive_shared_cache_map_object->SectionObjectPointer->SharedCacheMap); captive_shared_cache_map_object->SectionObjectPointer->SharedCacheMap=NULL; } if (captive_shared_cache_map_object->FileObject) { /* W32 dereferences twice. */ ObDereferenceObject(captive_shared_cache_map_object->FileObject); captive_shared_cache_map_object->FileObject=NULL; } G_OBJECT_CLASS(captive_shared_cache_map_object_parent_class)->finalize((GObject *)captive_shared_cache_map_object); } static guint FileSizes_changed_signal; static guint purge_signal; static void captive_shared_cache_map_object_FileSizes_changed(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, guint64 AllocationSize,guint64 FileSize,guint64 ValidDataLength); static void captive_shared_cache_map_object_purge(CaptiveSharedCacheMapObject *captive_shared_cache_map_object); static void captive_shared_cache_map_object_class_init(CaptiveSharedCacheMapObjectClass *class) { GObjectClass *gobject_class=G_OBJECT_CLASS(class); captive_shared_cache_map_object_parent_class=g_type_class_ref(g_type_parent(G_TYPE_FROM_CLASS(class))); gobject_class->finalize=(void (*)(GObject *object))captive_shared_cache_map_object_finalize; class->FileSizes_changed=captive_shared_cache_map_object_FileSizes_changed; class->purge=captive_shared_cache_map_object_purge; FileSizes_changed_signal=g_signal_new("FileSizes_changed", G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(CaptiveSharedCacheMapObjectClass,FileSizes_changed), NULL,NULL, captive_cc_VOID__UINT64_UINT64_UINT64, G_TYPE_NONE,3,G_TYPE_UINT64,G_TYPE_UINT64,G_TYPE_UINT64); purge_signal=g_signal_new("purge", G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(CaptiveSharedCacheMapObjectClass,purge), NULL,NULL, captive_cc_VOID__VOID, G_TYPE_NONE,0); } static void captive_shared_cache_map_object_init(CaptiveSharedCacheMapObject *captive_shared_cache_map_object) { captive_shared_cache_map_object->pin_hash=captive_private_bcb_pin_object_hash_new(); captive_shared_cache_map_w32_ref(captive_shared_cache_map_object); g_object_unref(captive_shared_cache_map_object); /* ==sink */ CaptiveSharedCacheMapObject_hash_init(); g_hash_table_insert(CaptiveSharedCacheMapObject_hash, captive_shared_cache_map_object,captive_shared_cache_map_object); } GType captive_shared_cache_map_object_get_type(void) { static GType captive_shared_cache_map_object_type=0; if (!captive_shared_cache_map_object_type) { static const GTypeInfo captive_shared_cache_map_object_info={ sizeof(CaptiveSharedCacheMapObjectClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc)captive_shared_cache_map_object_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof(CaptiveSharedCacheMapObject), 5, /* n_preallocs */ (GInstanceInitFunc)captive_shared_cache_map_object_init, }; captive_shared_cache_map_object_type=g_type_register_static(G_TYPE_OBJECT, "CaptiveSharedCacheMapObject",&captive_shared_cache_map_object_info,0); } return captive_shared_cache_map_object_type; } static void captive_shared_cache_map_object_FileSizes_changed(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, guint64 AllocationSize,guint64 FileSize,guint64 ValidDataLength) { size_t size_old,size_new; guint64 size64_old,size64_new; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_assert((!captive_shared_cache_map_object->buffer)==(!captive_shared_cache_map_object->AllocationSize)); g_assert((!captive_shared_cache_map_object->pages)==(!captive_shared_cache_map_object->AllocationSize)); size64_old=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE); size_old=size64_old; g_assert(size_old==size64_old); size64_new=CAPTIVE_ROUND_UP64(AllocationSize,PAGE_SIZE); size_new=size64_new; if (size_new!=size64_new) { size_new_big: g_error("Mapped size %" G_GUINT64_FORMAT " is too big; FIXME: non-mmap(2)-able areas not yet supported",size64_new); g_assert_not_reached(); } if (size_old!=size_new) { gpointer buffer_new; /* ntfs.sys of NT-5.1sp1 may extend StreamFileObject while dirty pins exist. * How to extend SharedCacheMap size without changing the memory location? * I hope ntfs.sys does not expect long-term absolute position of its * StreamFileObject: */ if (!(captive_shared_cache_map_object->FileObject->Flags&FO_STREAM_FILE)) { /* These two assertions should be already catched by pin/map signal handlers. */ g_assert(!captive_shared_cache_map_object->map); g_assert(!g_hash_table_size(captive_shared_cache_map_object->pin_hash)); } if (AllocationSize) { gpointer base; int errint; base=mmap( NULL, /* start */ PAGE_SIZE+size_new+PAGE_SIZE, /* length; leading and trailing boundary check pages */ PROT_READ|PROT_WRITE, /* prot; read/write must be possible although write is not guaranteed to be flushed yet */ MAP_PRIVATE|MAP_ANONYMOUS /* flags */ |MAP_NORESERVE, /* At least ext2fsd maps the whole disk. */ -1, /* fd; ignored due to MAP_ANONYMOUS */ 0); /* offset; ignored due to MAP_ANONYMOUS */ if (base==MAP_FAILED) goto size_new_big; g_assert(base!=NULL); base+=PAGE_SIZE; errint=munmap(base-PAGE_SIZE,PAGE_SIZE); /* unmap leading boundary check page */ g_assert(errint==0); errint=munmap(base+size_new,PAGE_SIZE); /* unmap trailing boundary check page */ g_assert(errint==0); buffer_new=base; } else buffer_new=NULL; memcpy(buffer_new,captive_shared_cache_map_object->buffer, MIN(AllocationSize,captive_shared_cache_map_object->AllocationSize)); if (captive_shared_cache_map_object->AllocationSize) { int errint; errint=munmap(captive_shared_cache_map_object->buffer,size_old); g_assert(errint==0); } captive_shared_cache_map_object->buffer=buffer_new; #if 0 /* It appears it is valid to squeeze out 'dirty' blocks. FIXME: Flush them? */ if (size_old>size_new) { guint64 now; for (now=size_new;nowpages[now/PAGE_SIZE].data_valid) continue; g_assert(!captive_shared_cache_map_object->pages[now/PAGE_SIZE].dirty); } } #endif captive_shared_cache_map_object->pages=g_realloc(captive_shared_cache_map_object->pages, size_new/PAGE_SIZE*sizeof(*captive_shared_cache_map_object->pages)); if (size_new>size_old) /* prevent 'size_new-size_old' as it is unsigned! */ memset(captive_shared_cache_map_object->pages+(size_old/PAGE_SIZE),0, (size_new-size_old)/PAGE_SIZE*sizeof(*captive_shared_cache_map_object->pages)); } captive_shared_cache_map_object->AllocationSize=AllocationSize; captive_shared_cache_map_object->FileSize=FileSize; captive_shared_cache_map_object->ValidDataLength=ValidDataLength; g_assert((!captive_shared_cache_map_object->buffer)==(!captive_shared_cache_map_object->AllocationSize)); g_assert((!captive_shared_cache_map_object->pages)==(!captive_shared_cache_map_object->AllocationSize)); } static void captive_shared_cache_map_object_purge(CaptiveSharedCacheMapObject *captive_shared_cache_map_object) { g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); /* NOP; just to provide slot for checking by Bcbs */ } CaptiveSharedCacheMapObject *captive_shared_cache_map_get_ref(FILE_OBJECT *FileObject, const CC_FILE_SIZES *FileSizes,BOOLEAN PinAccess,const CACHE_MANAGER_CALLBACKS *CallBacks,VOID *LazyWriterContext) { CaptiveSharedCacheMapObject *captive_shared_cache_map_object; g_return_val_if_fail(FileObject!=NULL,NULL); g_return_val_if_fail(FileObject->SectionObjectPointer!=NULL,NULL); g_return_val_if_fail(FileSizes!=NULL,NULL); g_return_val_if_fail(CallBacks!=NULL,NULL); if ((captive_shared_cache_map_object=FileObject->SectionObjectPointer->SharedCacheMap)) { captive_shared_cache_map_w32_ref(captive_shared_cache_map_object); } else { captive_shared_cache_map_object=g_object_new( CAPTIVE_SHARED_CACHE_MAP_TYPE_OBJECT, /* object_type */ NULL); /* first_property_name; FIXME: support properties */ /* FIXME: When to drop SharedCacheMap? * Currently we never close it. * Fix also CcZeroData() workaround. */ g_object_ref(captive_shared_cache_map_object); /* W32 references twice. */ ObReferenceObject(FileObject); captive_shared_cache_map_object->FileObject=FileObject; captive_shared_cache_map_object->SectionObjectPointer=FileObject->SectionObjectPointer; captive_shared_cache_map_object->AllocationSize=0; captive_shared_cache_map_object->FileSize=0; captive_shared_cache_map_object->ValidDataLength=0; captive_shared_cache_map_object->PinAccess=PinAccess; captive_shared_cache_map_object->CallBacks=*CallBacks; captive_shared_cache_map_object->LazyWriterContext=LazyWriterContext; FileObject->SectionObjectPointer->SharedCacheMap=captive_shared_cache_map_object; } g_assert(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); /* FileObject may differ - we can have a different reference to the same FCB. */ g_assert(FileObject->SectionObjectPointer==captive_shared_cache_map_object->SectionObjectPointer); g_assert(PinAccess==captive_shared_cache_map_object->PinAccess); g_assert(CallBacks->AcquireForLazyWrite==captive_shared_cache_map_object->CallBacks.AcquireForLazyWrite); g_assert(CallBacks->ReleaseFromLazyWrite==captive_shared_cache_map_object->CallBacks.ReleaseFromLazyWrite); g_assert(CallBacks->AcquireForReadAhead==captive_shared_cache_map_object->CallBacks.AcquireForReadAhead); g_assert(CallBacks->ReleaseFromReadAhead==captive_shared_cache_map_object->CallBacks.ReleaseFromReadAhead); g_assert(LazyWriterContext==captive_shared_cache_map_object->LazyWriterContext); captive_shared_cache_map_FileSizes_set(captive_shared_cache_map_object,FileSizes); return captive_shared_cache_map_object; } void captive_shared_cache_map_FileSizes_set(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, const CC_FILE_SIZES *FileSizes) { guint64 AllocationSize,FileSize,ValidDataLength; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(FileSizes!=NULL); AllocationSize=FileSizes->AllocationSize.QuadPart; FileSize=FileSizes->FileSize.QuadPart; ValidDataLength=FileSizes->ValidDataLength.QuadPart; if (ValidDataLength==G_MAXINT64) ValidDataLength=FileSize; g_assert(AllocationSize>=0); g_assert(FileSize>=0); g_assert(ValidDataLength>=0); g_assert(ValidDataLength<=FileSize); /* Do not: g_assert(0==(AllocationSize%0x200)); * as it is true for ntfs.sys of NT-5.1sp1 but it fails for fastfat.sys of NT-5.1sp1. */ /* AllocationSize can be much higher: */ g_assert(FileSize<=AllocationSize); /* Prevent signalling if not needed. */ if (0 || captive_shared_cache_map_object->AllocationSize!=AllocationSize || captive_shared_cache_map_object->FileSize!=FileSize || captive_shared_cache_map_object->ValidDataLength!=ValidDataLength) { /* Signalling is forbidden in captive_shared_cache_map_object_finalize(). */ if (G_OBJECT(captive_shared_cache_map_object)->ref_count==0) { (*CAPTIVE_SHARED_CACHE_MAP_OBJECT_GET_CLASS(captive_shared_cache_map_object)->FileSizes_changed) (captive_shared_cache_map_object,AllocationSize,FileSize,ValidDataLength); } else { g_signal_emit(captive_shared_cache_map_object,FileSizes_changed_signal,0, AllocationSize,FileSize,ValidDataLength); } } g_assert(captive_shared_cache_map_object->AllocationSize==AllocationSize); g_assert(captive_shared_cache_map_object->FileSize==FileSize); g_assert(captive_shared_cache_map_object->ValidDataLength==ValidDataLength); } CaptiveSharedCacheMapObject *captive_SectionObjectPointers_to_SharedCacheMap(SECTION_OBJECT_POINTERS *SectionObjectPointers) { g_return_val_if_fail(SectionObjectPointers!=NULL,NULL); g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(SectionObjectPointers->SharedCacheMap),NULL); return SectionObjectPointers->SharedCacheMap; } CaptiveSharedCacheMapObject *captive_FileObject_to_SharedCacheMap(FILE_OBJECT *FileObject) { g_return_val_if_fail(FileObject!=NULL,NULL); return captive_SectionObjectPointers_to_SharedCacheMap(FileObject->SectionObjectPointer); } void captive_shared_cache_map_w32_ref(CaptiveSharedCacheMapObject *captive_shared_cache_map_object) { g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_object_ref(captive_shared_cache_map_object); captive_shared_cache_map_object->w32_ref_count++; } void captive_shared_cache_map_w32_unref(CaptiveSharedCacheMapObject *captive_shared_cache_map_object) { g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(G_OBJECT(captive_shared_cache_map_object)->ref_count>0); captive_shared_cache_map_object->w32_ref_count--; g_object_unref(captive_shared_cache_map_object); } gint captive_shared_cache_map_query_w32_ref(CaptiveSharedCacheMapObject *captive_shared_cache_map_object) { g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),0); return captive_shared_cache_map_object->w32_ref_count; } void captive_shared_cache_map_data_validate_read(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, FILE_OBJECT *FileObject,guint64 start,guint64 end) { guint64 now; gboolean after_eof=FALSE; /* Did we reached the end of file already? */ g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(captive_shared_cache_map_object==captive_FileObject_to_SharedCacheMap(FileObject)); g_return_if_fail(start<=end); g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE)); start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE); end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE); for (now=start;nowpages[now/PAGE_SIZE].data_valid) continue; now_LargeInteger.QuadPart=now; got=captive_Cc_IoPageRead(FileObject,captive_shared_cache_map_object->buffer+now,PAGE_SIZE,&now_LargeInteger); if (after_eof) g_assert(got==0); else g_assert(got<=PAGE_SIZE); after_eof=(gotpages[now/PAGE_SIZE].data_valid=TRUE; captive_shared_cache_map_object->pages[now/PAGE_SIZE].dirty=FALSE; } } void captive_shared_cache_map_data_validate_noread(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, guint64 start,guint64 end) { guint64 now; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(start<=end); g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE)); start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE); end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE); for (now=start;nowpages[now/PAGE_SIZE].data_valid); } } void captive_shared_cache_map_set_data_valid(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, guint64 start,guint64 end) { guint64 now; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(start<=end); g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE)); start=CAPTIVE_ROUND_UP64(start,PAGE_SIZE); if (endFileSize) end=CAPTIVE_ROUND_DOWN64(end,PAGE_SIZE); else { /* We can validate the last page of the file * even if it does not end on PAGE_SIZE boundary. */ end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE); } /* We may get endpages[now/PAGE_SIZE].data_valid=TRUE; /* .dirty is undefined */ } } void captive_shared_cache_map_set_data_invalid(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, guint64 start,guint64 end) { guint64 now; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(start<=end); g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE)); start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE); end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE); for (now=start;nowpages[now/PAGE_SIZE].data_valid=FALSE; } } void captive_shared_cache_map_set_dirty(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, guint64 start,guint64 end) { guint64 now; CaptiveSharedCacheMapObject_page *page; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE)); start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE); end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE); for (now=start;nowpages+now/PAGE_SIZE; g_assert(page->data_valid); if (!page->dirty) { page->dirty=TRUE; page->lsn_oldest=0; page->lsn_newest=0; } } } gboolean captive_shared_cache_map_is_page_dirty(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, guint64 offset) { CaptiveSharedCacheMapObject_page *page; g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),FALSE); g_return_val_if_fail(offsetAllocationSize,PAGE_SIZE),FALSE); g_return_val_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(offset,PAGE_SIZE),FALSE); page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE; g_return_val_if_fail(page->data_valid,FALSE); return page->dirty; } void captive_shared_cache_map_page_set_lsn(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, guint64 offset,gint64 lsn) { CaptiveSharedCacheMapObject_page *page; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(offset<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE)); g_return_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(offset,PAGE_SIZE)); page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE; g_return_if_fail(page->data_valid); g_return_if_fail(page->dirty); g_return_if_fail(page->lsn_oldest<=page->lsn_newest); g_return_if_fail(!page->lsn_newest || lsn>=page->lsn_newest); g_return_if_fail(captive_shared_cache_map_object->LogHandle_set); g_return_if_fail(captive_shared_cache_map_object->FlushToLsnRoutine_set); if (!page->lsn_oldest) page->lsn_oldest=lsn; page->lsn_newest=lsn; } void captive_shared_cache_map_purge(CaptiveSharedCacheMapObject *captive_shared_cache_map_object) { guint64 offset; CaptiveSharedCacheMapObject_page *page; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_signal_emit(captive_shared_cache_map_object,purge_signal,0); /* Needed by fastfat.sys of NT-5.1sp1 during FAT32 unmount * otherwise it fails on: g_assert(!page->dirty); * It corrupts the disk if the buffer is dropped instead. */ captive_shared_cache_map_flush(captive_shared_cache_map_object, 0,CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE)); for (offset=0;offsetAllocationSize,PAGE_SIZE);offset+=PAGE_SIZE) { page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE; if (!page->data_valid) continue; g_assert(!page->dirty); page->data_valid=FALSE; } } static VOID *captive_LogHandle; static PFLUSH_TO_LSN captive_FlushToLsnRoutine; void captive_shared_cache_map_set_LogHandle(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,VOID *LogHandle) { g_return_if_fail(!captive_shared_cache_map_object || CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); /* FIXME: 'captive_shared_cache_map_object->LogHandle_set' may be set. * Does it mean 'LogHandle_set' is 'FileObject'-based instead of 'SharedCacheMap'-based? */ if (!LogHandle) return; g_assert(!captive_LogHandle || captive_LogHandle==LogHandle); captive_LogHandle=LogHandle; if (LogHandle && captive_shared_cache_map_object) captive_shared_cache_map_object->LogHandle_set=TRUE; } void captive_shared_cache_map_set_FlushToLsnRoutine (CaptiveSharedCacheMapObject *captive_shared_cache_map_object,PFLUSH_TO_LSN FlushToLsnRoutine) { g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); /* FIXME: 'captive_shared_cache_map_object->FlushToLsnRoutine_set' may be set. * Does it mean 'FlushToLsnRoutine_set' is 'FileObject'-based instead of 'SharedCacheMap'-based? */ if (!FlushToLsnRoutine) return; g_assert(!captive_FlushToLsnRoutine || captive_FlushToLsnRoutine==FlushToLsnRoutine); captive_FlushToLsnRoutine=FlushToLsnRoutine; if (FlushToLsnRoutine) captive_shared_cache_map_object->FlushToLsnRoutine_set=TRUE; } static void captive_shared_cache_map_page_write(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, guint64 offset) { LARGE_INTEGER offset_LargeInteger; static gint64 lsn_last; CaptiveSharedCacheMapObject_page *page; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(captive_shared_cache_map_object->FileObject!=NULL); g_return_if_fail(offset<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE)); g_return_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(offset,PAGE_SIZE)); page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE; g_return_if_fail(page->data_valid); g_return_if_fail(page->dirty); if (page->lsn_newest) { /* sanity check */ g_assert(!lsn_last || lsn_last<=page->lsn_newest); lsn_last=page->lsn_newest; captive_stdcall_call_12((CaptiveStdCallFunc12)captive_FlushToLsnRoutine, captive_LogHandle, (gpointer)(guint32)(page->lsn_newest>> 0U), /* 'LARGE_INTEGER' argument */ (gpointer)(guint32)(page->lsn_newest>>32U)); } offset_LargeInteger.QuadPart=offset; captive_Cc_IoPageWrite(captive_shared_cache_map_object->FileObject, captive_shared_cache_map_object->buffer+offset,PAGE_SIZE,&offset_LargeInteger); page->dirty=FALSE; page->lsn_oldest=0; page->lsn_newest=0; } typedef struct _captive_shared_cache_map_flush_lsn_sort captive_shared_cache_map_flush_lsn_sort; struct _captive_shared_cache_map_flush_lsn_sort { gint64 lsn; CaptiveSharedCacheMapObject *captive_shared_cache_map_object; guint64 offset; }; typedef struct _captive_shared_cache_map_flush_lsn_pages_foreach_param captive_shared_cache_map_flush_lsn_pages_foreach_param; struct _captive_shared_cache_map_flush_lsn_pages_foreach_param { gint64 lsn_target; guint lsn_pages_count; captive_shared_cache_map_flush_lsn_sort *lsn_pages_pointer; /* Not filled in if NULL */ }; static void captive_shared_cache_map_flush_lsn_pages_foreach( CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */ CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */ captive_shared_cache_map_flush_lsn_pages_foreach_param *param) /* user_data */ { guint64 now; CaptiveSharedCacheMapObject_page *page; #if 0 /* acceleration */ g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value); g_return_if_fail(param!=NULL); #endif for (now=0;nowAllocationSize;now+=PAGE_SIZE) { page=captive_shared_cache_map_object->pages+now/PAGE_SIZE; if (!page->data_valid) continue; if (!page->dirty) continue; if (!page->lsn_newest) continue; if (page->lsn_newest>param->lsn_target) continue; param->lsn_pages_count++; if (!param->lsn_pages_pointer) continue; param->lsn_pages_pointer->lsn=page->lsn_newest; param->lsn_pages_pointer->captive_shared_cache_map_object=captive_shared_cache_map_object; param->lsn_pages_pointer->offset=now; param->lsn_pages_pointer++; } } static int captive_shared_cache_map_flush_lsn_pages_compar (const captive_shared_cache_map_flush_lsn_sort *a,const captive_shared_cache_map_flush_lsn_sort *b) { #if 0 /* acceleration */ g_return_val_if_fail(a!=NULL,0); g_return_val_if_fail(b!=NULL,0); #endif return (a->lsn>b->lsn)-(b->lsn>a->lsn); } guint64 captive_shared_cache_map_flush(CaptiveSharedCacheMapObject *captive_shared_cache_map_object, guint64 start,guint64 end) { guint64 flushed; guint64 now; gint lsn_target; captive_shared_cache_map_flush_lsn_pages_foreach_param lsn_pages_foreach_param; captive_shared_cache_map_flush_lsn_sort *lsn_pages_pointer; const captive_shared_cache_map_flush_lsn_sort *lsn_page; guint lsn_pages_count; g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),0); g_return_val_if_fail(start<=end,0); end=MIN(end,CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE)); start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE); end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE); lsn_target=0; for (now=start;nowpages+now/PAGE_SIZE; if (!page->data_valid) continue; if (!page->dirty) continue; if (!page->lsn_newest) continue; if (!lsn_target || lsn_targetlsn_newest) lsn_target=page->lsn_newest; } lsn_pages_foreach_param.lsn_target=lsn_target; lsn_pages_foreach_param.lsn_pages_count=0; lsn_pages_foreach_param.lsn_pages_pointer=NULL; /* Not yet filling */ g_hash_table_foreach( CaptiveSharedCacheMapObject_hash, /* hash_table */ (GHFunc)captive_shared_cache_map_flush_lsn_pages_foreach, /* func */ &lsn_pages_foreach_param); /* user_data */ lsn_pages_count=lsn_pages_foreach_param.lsn_pages_count; captive_newn(lsn_pages_pointer,lsn_pages_count); g_assert(lsn_pages_foreach_param.lsn_target==lsn_target); lsn_pages_foreach_param.lsn_pages_count=0; lsn_pages_foreach_param.lsn_pages_pointer=lsn_pages_pointer; g_hash_table_foreach( CaptiveSharedCacheMapObject_hash, /* hash_table */ (GHFunc)captive_shared_cache_map_flush_lsn_pages_foreach, /* func */ &lsn_pages_foreach_param); /* user_data */ g_assert(lsn_pages_foreach_param.lsn_target==lsn_target); g_assert(lsn_pages_foreach_param.lsn_pages_count==lsn_pages_count); g_assert(lsn_pages_foreach_param.lsn_pages_pointer==lsn_pages_pointer+lsn_pages_count); qsort(lsn_pages_pointer,lsn_pages_count,sizeof(*lsn_pages_pointer), (int (*)(const void *,const void *))captive_shared_cache_map_flush_lsn_pages_compar); flushed=0; for (lsn_page=lsn_pages_pointer;lsn_pagecaptive_shared_cache_map_object,lsn_page->offset); flushed+=PAGE_SIZE; } g_free(lsn_pages_pointer); for (now=start;nowpages+now/PAGE_SIZE; if (!page->data_valid) continue; if (!page->dirty) continue; captive_shared_cache_map_page_write(captive_shared_cache_map_object,now); flushed+=PAGE_SIZE; } /* We were calling W32 code - recheck our task completion. */ for (now=start;nowpages+now/PAGE_SIZE; if (!page->data_valid) continue; g_assert(!page->dirty); } return flushed; } static void captive_shared_cache_map_is_any_dirty_foreach( CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */ CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */ gboolean *dirty_foundp) /* user_data */ { guint64 now; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value); g_return_if_fail(dirty_foundp!=NULL); for (now=0;nowAllocationSize;now+=PAGE_SIZE) { CaptiveSharedCacheMapObject_page *page; page=captive_shared_cache_map_object->pages+now/PAGE_SIZE; if (!page->data_valid) continue; if (!page->dirty) continue; *dirty_foundp=TRUE; /* FIXME: stop the traversal. */ break; } } gboolean captive_shared_cache_map_is_any_dirty(void) { gboolean dirty_found; CaptiveSharedCacheMapObject_hash_init(); dirty_found=FALSE; g_hash_table_foreach( CaptiveSharedCacheMapObject_hash, /* hash_table */ (GHFunc)captive_shared_cache_map_is_any_dirty_foreach, /* func */ &dirty_found); /* user_data */ return dirty_found; } typedef struct _captive_shared_cache_map_CcGetDirtyPages_foreach_param captive_shared_cache_map_CcGetDirtyPages_foreach_param; struct _captive_shared_cache_map_CcGetDirtyPages_foreach_param { PDIRTY_PAGE_ROUTINE DirtyPageRoutine; VOID *Context1; VOID *Context2; gint64 result; }; static void captive_shared_cache_map_CcGetDirtyPages_foreach( CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */ CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */ captive_shared_cache_map_CcGetDirtyPages_foreach_param *param) /* user_data */ { gint64 now; CaptiveSharedCacheMapObject_page *page; g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(captive_shared_cache_map_object->FileObject!=NULL); g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value); g_return_if_fail(param!=NULL); for (now=CAPTIVE_ROUND_DOWN64(captive_shared_cache_map_object->AllocationSize-1,PAGE_SIZE);now>=0;now-=PAGE_SIZE) { LARGE_INTEGER now_LargeInteger,lsn_oldest_LargeInteger,lsn_newest_LargeInteger; page=captive_shared_cache_map_object->pages+now/PAGE_SIZE; if (!page->data_valid) continue; if (!page->dirty) continue; if (page->lsn_oldest && (!param->result || param->result>page->lsn_oldest)) param->result=page->lsn_oldest; now_LargeInteger.QuadPart=now; lsn_oldest_LargeInteger.QuadPart=page->lsn_oldest; lsn_newest_LargeInteger.QuadPart=page->lsn_newest; (*param->DirtyPageRoutine)( captive_shared_cache_map_object->FileObject, /* FileObject */ &now_LargeInteger, /* FileOffset */ PAGE_SIZE, /* Length */ &lsn_oldest_LargeInteger, /* OldestLsn */ &lsn_newest_LargeInteger, /* NewestLsn */ param->Context1, /* Context1 */ param->Context2); /* Context2 */ } } gint64 captive_shared_cache_map_CcGetDirtyPages(PDIRTY_PAGE_ROUTINE DirtyPageRoutine,VOID *Context1,VOID *Context2) { captive_shared_cache_map_CcGetDirtyPages_foreach_param param; g_return_val_if_fail(DirtyPageRoutine!=NULL,0); param.DirtyPageRoutine=DirtyPageRoutine; param.Context1=Context1; param.Context2=Context2; param.result=0; CaptiveSharedCacheMapObject_hash_init(); g_hash_table_foreach( CaptiveSharedCacheMapObject_hash, /* hash_table */ (GHFunc)captive_shared_cache_map_CcGetDirtyPages_foreach, /* func */ ¶m); /* user_data */ return param.result; } gpointer captive_shared_cache_map_get_buffer(CaptiveSharedCacheMapObject *captive_shared_cache_map_object) { g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),NULL); g_return_val_if_fail(captive_shared_cache_map_object->buffer!=NULL,NULL); return captive_shared_cache_map_object->buffer; } static void captive_cc_FileObject_delete_foreach( CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */ CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */ FILE_OBJECT *FileObject) /* user_data */ { g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object)); g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value); g_return_if_fail(FileObject!=NULL); g_assert(FileObject!=captive_shared_cache_map_object->FileObject); } BOOLEAN captive_cc_FileObject_delete(FILE_OBJECT *FileObject) { g_return_val_if_fail(FileObject!=NULL,FALSE); CaptiveSharedCacheMapObject_hash_init(); g_hash_table_foreach( CaptiveSharedCacheMapObject_hash, /* hash_table */ (GHFunc)captive_cc_FileObject_delete_foreach, /* func */ FileObject); /* user_data */ return FALSE; /* FIXME: remove useless return code. */ }