2 * reactos Cache Manager (Cc*) SharedCacheMap structure of libcaptive
3 * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "sharedcachemap.h" /* self */
23 #include "sharedcachemap-priv.h" /* self */
25 #include "marshallers.h"
26 #include <glib-object.h>
27 #include "privatebcbpin.h"
28 #include "captive/macros.h"
30 #include "reactos/ddk/obfuncs.h"
33 static GHashTable *CaptiveSharedCacheMapObject_hash;
35 static void CaptiveSharedCacheMapObject_hash_init(void)
37 if (CaptiveSharedCacheMapObject_hash)
39 CaptiveSharedCacheMapObject_hash=g_hash_table_new(
40 g_direct_hash, /* hash_func */
41 g_direct_equal); /* key_equal_func */
45 static gpointer captive_shared_cache_map_object_parent_class=NULL;
48 static void captive_shared_cache_map_object_finalize(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
50 static const CC_FILE_SIZES FileSizes_zero;
53 CaptiveSharedCacheMapObject_page *page;
55 g_return_if_fail(captive_shared_cache_map_object!=NULL);
57 for (offset=0;offset<CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE);offset+=PAGE_SIZE) {
58 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
59 if (!page->data_valid)
61 g_assert(!page->dirty); /* FIXME: Is it allowed by W32? */
64 CaptiveSharedCacheMapObject_hash_init();
65 errbool=g_hash_table_remove(CaptiveSharedCacheMapObject_hash,captive_shared_cache_map_object);
66 g_assert(errbool==TRUE);
68 captive_shared_cache_map_FileSizes_set(captive_shared_cache_map_object,&FileSizes_zero);
69 g_assert(captive_shared_cache_map_object->buffer==NULL);
70 g_assert(captive_shared_cache_map_object->pages==NULL);
72 if (captive_shared_cache_map_object->pin_hash) {
73 captive_private_bcb_pin_object_hash_destroy(captive_shared_cache_map_object->pin_hash);
74 captive_shared_cache_map_object->pin_hash=NULL;
76 g_assert(captive_shared_cache_map_object->map==NULL);
77 if (captive_shared_cache_map_object->SectionObjectPointer) {
78 g_assert(captive_shared_cache_map_object==captive_shared_cache_map_object->SectionObjectPointer->SharedCacheMap);
79 captive_shared_cache_map_object->SectionObjectPointer->SharedCacheMap=NULL;
82 if (captive_shared_cache_map_object->FileObject) {
83 /* W32 dereferences twice. */
84 ObDereferenceObject(captive_shared_cache_map_object->FileObject);
85 captive_shared_cache_map_object->FileObject=NULL;
88 G_OBJECT_CLASS(captive_shared_cache_map_object_parent_class)->finalize((GObject *)captive_shared_cache_map_object);
91 static guint FileSizes_changed_signal;
92 static guint purge_signal;
94 static void captive_shared_cache_map_object_FileSizes_changed(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
95 guint64 AllocationSize,guint64 FileSize,guint64 ValidDataLength);
96 static void captive_shared_cache_map_object_purge(CaptiveSharedCacheMapObject *captive_shared_cache_map_object);
98 static void captive_shared_cache_map_object_class_init(CaptiveSharedCacheMapObjectClass *class)
100 GObjectClass *gobject_class=G_OBJECT_CLASS(class);
102 captive_shared_cache_map_object_parent_class=g_type_class_ref(g_type_parent(G_TYPE_FROM_CLASS(class)));
103 gobject_class->finalize=(void (*)(GObject *object))captive_shared_cache_map_object_finalize;
105 class->FileSizes_changed=captive_shared_cache_map_object_FileSizes_changed;
106 class->purge=captive_shared_cache_map_object_purge;
108 FileSizes_changed_signal=g_signal_new("FileSizes_changed",
109 G_TYPE_FROM_CLASS(gobject_class),
111 G_STRUCT_OFFSET(CaptiveSharedCacheMapObjectClass,FileSizes_changed),
113 captive_cc_VOID__UINT64_UINT64_UINT64,
114 G_TYPE_NONE,3,G_TYPE_UINT64,G_TYPE_UINT64,G_TYPE_UINT64);
115 purge_signal=g_signal_new("purge",
116 G_TYPE_FROM_CLASS(gobject_class),
118 G_STRUCT_OFFSET(CaptiveSharedCacheMapObjectClass,purge),
120 captive_cc_VOID__VOID,
125 static void captive_shared_cache_map_object_init(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
127 captive_shared_cache_map_object->pin_hash=captive_private_bcb_pin_object_hash_new();
129 captive_shared_cache_map_w32_ref(captive_shared_cache_map_object);
130 g_object_unref(captive_shared_cache_map_object); /* ==sink */
132 CaptiveSharedCacheMapObject_hash_init();
133 g_hash_table_insert(CaptiveSharedCacheMapObject_hash,
134 captive_shared_cache_map_object,captive_shared_cache_map_object);
138 GType captive_shared_cache_map_object_get_type(void)
140 static GType captive_shared_cache_map_object_type=0;
142 if (!captive_shared_cache_map_object_type) {
143 static const GTypeInfo captive_shared_cache_map_object_info={
144 sizeof(CaptiveSharedCacheMapObjectClass),
145 NULL, /* base_init */
146 NULL, /* base_finalize */
147 (GClassInitFunc)captive_shared_cache_map_object_class_init,
148 NULL, /* class_finalize */
149 NULL, /* class_data */
150 sizeof(CaptiveSharedCacheMapObject),
152 (GInstanceInitFunc)captive_shared_cache_map_object_init,
155 captive_shared_cache_map_object_type=g_type_register_static(G_TYPE_OBJECT,
156 "CaptiveSharedCacheMapObject",&captive_shared_cache_map_object_info,0);
159 return captive_shared_cache_map_object_type;
162 static void captive_shared_cache_map_object_FileSizes_changed(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
163 guint64 AllocationSize,guint64 FileSize,guint64 ValidDataLength)
165 size_t size_old,size_new;
166 guint64 size64_old,size64_new;
168 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
170 g_assert((!captive_shared_cache_map_object->buffer)==(!captive_shared_cache_map_object->AllocationSize));
171 g_assert((!captive_shared_cache_map_object->pages)==(!captive_shared_cache_map_object->AllocationSize));
173 size64_old=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE);
175 g_assert(size_old==size64_old);
176 size64_new=CAPTIVE_ROUND_UP64(AllocationSize,PAGE_SIZE);
178 if (size_new!=size64_new) {
180 g_error("Mapped size %" G_GUINT64_FORMAT " is too big; FIXME: non-mmap(2)-able areas not yet supported",size64_new);
181 g_assert_not_reached();
184 if (size_old!=size_new) {
187 /* ntfs.sys of NT-5.1sp1 may extend StreamFileObject while dirty pins exist.
188 * How to extend SharedCacheMap size without changing the memory location?
189 * I hope ntfs.sys does not expect long-term absolute position of its
192 if (!(captive_shared_cache_map_object->FileObject->Flags&FO_STREAM_FILE)) {
193 /* These two assertions should be already catched by pin/map signal handlers. */
194 g_assert(!captive_shared_cache_map_object->map);
195 g_assert(!g_hash_table_size(captive_shared_cache_map_object->pin_hash));
198 if (AllocationSize) {
204 PAGE_SIZE+size_new+PAGE_SIZE, /* length; leading and trailing boundary check pages */
205 PROT_READ|PROT_WRITE, /* prot; read/write must be possible although write is not guaranteed to be flushed yet */
206 MAP_PRIVATE|MAP_ANONYMOUS /* flags */
207 |MAP_NORESERVE, /* At least ext2fsd maps the whole disk. */
208 -1, /* fd; ignored due to MAP_ANONYMOUS */
209 0); /* offset; ignored due to MAP_ANONYMOUS */
210 if (base==MAP_FAILED)
212 g_assert(base!=NULL);
215 errint=munmap(base-PAGE_SIZE,PAGE_SIZE); /* unmap leading boundary check page */
217 errint=munmap(base+size_new,PAGE_SIZE); /* unmap trailing boundary check page */
225 memcpy(buffer_new,captive_shared_cache_map_object->buffer,
226 MIN(AllocationSize,captive_shared_cache_map_object->AllocationSize));
228 if (captive_shared_cache_map_object->AllocationSize) {
231 errint=munmap(captive_shared_cache_map_object->buffer,size_old);
235 captive_shared_cache_map_object->buffer=buffer_new;
237 #if 0 /* It appears it is valid to squeeze out 'dirty' blocks. FIXME: Flush them? */
238 if (size_old>size_new) {
241 for (now=size_new;now<size_old;now+=PAGE_SIZE) {
242 if (!captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid)
244 g_assert(!captive_shared_cache_map_object->pages[now/PAGE_SIZE].dirty);
248 captive_shared_cache_map_object->pages=g_realloc(captive_shared_cache_map_object->pages,
249 size_new/PAGE_SIZE*sizeof(*captive_shared_cache_map_object->pages));
250 if (size_new>size_old) /* prevent 'size_new-size_old' as it is unsigned! */
251 memset(captive_shared_cache_map_object->pages+(size_old/PAGE_SIZE),0,
252 (size_new-size_old)/PAGE_SIZE*sizeof(*captive_shared_cache_map_object->pages));
255 captive_shared_cache_map_object->AllocationSize=AllocationSize;
256 captive_shared_cache_map_object->FileSize=FileSize;
257 captive_shared_cache_map_object->ValidDataLength=ValidDataLength;
259 g_assert((!captive_shared_cache_map_object->buffer)==(!captive_shared_cache_map_object->AllocationSize));
260 g_assert((!captive_shared_cache_map_object->pages)==(!captive_shared_cache_map_object->AllocationSize));
263 static void captive_shared_cache_map_object_purge(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
265 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
267 /* NOP; just to provide slot for checking by Bcbs */
270 CaptiveSharedCacheMapObject *captive_shared_cache_map_get_ref(FILE_OBJECT *FileObject,
271 const CC_FILE_SIZES *FileSizes,BOOLEAN PinAccess,const CACHE_MANAGER_CALLBACKS *CallBacks,VOID *LazyWriterContext)
273 CaptiveSharedCacheMapObject *captive_shared_cache_map_object;
275 g_return_val_if_fail(FileObject!=NULL,NULL);
276 g_return_val_if_fail(FileObject->SectionObjectPointer!=NULL,NULL);
277 g_return_val_if_fail(FileSizes!=NULL,NULL);
278 g_return_val_if_fail(CallBacks!=NULL,NULL);
280 if ((captive_shared_cache_map_object=FileObject->SectionObjectPointer->SharedCacheMap)) {
281 captive_shared_cache_map_w32_ref(captive_shared_cache_map_object);
284 captive_shared_cache_map_object=g_object_new(
285 CAPTIVE_SHARED_CACHE_MAP_TYPE_OBJECT, /* object_type */
286 NULL); /* first_property_name; FIXME: support properties */
288 /* FIXME: When to drop SharedCacheMap?
289 * Currently we never close it.
290 * Fix also CcZeroData() workaround.
292 g_object_ref(captive_shared_cache_map_object);
294 /* W32 references twice. */
295 ObReferenceObject(FileObject);
296 captive_shared_cache_map_object->FileObject=FileObject;
297 captive_shared_cache_map_object->SectionObjectPointer=FileObject->SectionObjectPointer;
298 captive_shared_cache_map_object->AllocationSize=0;
299 captive_shared_cache_map_object->FileSize=0;
300 captive_shared_cache_map_object->ValidDataLength=0;
301 captive_shared_cache_map_object->PinAccess=PinAccess;
302 captive_shared_cache_map_object->CallBacks=*CallBacks;
303 captive_shared_cache_map_object->LazyWriterContext=LazyWriterContext;
305 FileObject->SectionObjectPointer->SharedCacheMap=captive_shared_cache_map_object;
308 g_assert(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
309 /* FileObject may differ - we can have a different reference to the same FCB. */
310 g_assert(FileObject->SectionObjectPointer==captive_shared_cache_map_object->SectionObjectPointer);
311 g_assert(PinAccess==captive_shared_cache_map_object->PinAccess);
312 g_assert(CallBacks->AcquireForLazyWrite==captive_shared_cache_map_object->CallBacks.AcquireForLazyWrite);
313 g_assert(CallBacks->ReleaseFromLazyWrite==captive_shared_cache_map_object->CallBacks.ReleaseFromLazyWrite);
314 g_assert(CallBacks->AcquireForReadAhead==captive_shared_cache_map_object->CallBacks.AcquireForReadAhead);
315 g_assert(CallBacks->ReleaseFromReadAhead==captive_shared_cache_map_object->CallBacks.ReleaseFromReadAhead);
316 g_assert(LazyWriterContext==captive_shared_cache_map_object->LazyWriterContext);
318 captive_shared_cache_map_FileSizes_set(captive_shared_cache_map_object,FileSizes);
320 return captive_shared_cache_map_object;
323 void captive_shared_cache_map_FileSizes_set(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
324 const CC_FILE_SIZES *FileSizes)
326 guint64 AllocationSize,FileSize,ValidDataLength;
328 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
329 g_return_if_fail(FileSizes!=NULL);
331 AllocationSize=FileSizes->AllocationSize.QuadPart;
332 FileSize=FileSizes->FileSize.QuadPart;
333 ValidDataLength=FileSizes->ValidDataLength.QuadPart;
335 if (ValidDataLength==G_MAXINT64)
336 ValidDataLength=FileSize;
338 g_assert(AllocationSize>=0);
339 g_assert(FileSize>=0);
340 g_assert(ValidDataLength>=0);
342 g_assert(ValidDataLength<=FileSize);
343 /* Do not: g_assert(0==(AllocationSize%0x200));
344 * as it is true for ntfs.sys of NT-5.1sp1 but it fails for fastfat.sys of NT-5.1sp1.
346 /* AllocationSize can be much higher: */
347 g_assert(FileSize<=AllocationSize);
349 /* Prevent signalling if not needed. */
351 || captive_shared_cache_map_object->AllocationSize!=AllocationSize
352 || captive_shared_cache_map_object->FileSize!=FileSize
353 || captive_shared_cache_map_object->ValidDataLength!=ValidDataLength) {
354 /* Signalling is forbidden in captive_shared_cache_map_object_finalize(). */
355 if (G_OBJECT(captive_shared_cache_map_object)->ref_count==0) {
356 (*CAPTIVE_SHARED_CACHE_MAP_OBJECT_GET_CLASS(captive_shared_cache_map_object)->FileSizes_changed)
357 (captive_shared_cache_map_object,AllocationSize,FileSize,ValidDataLength);
360 g_signal_emit(captive_shared_cache_map_object,FileSizes_changed_signal,0,
361 AllocationSize,FileSize,ValidDataLength);
365 g_assert(captive_shared_cache_map_object->AllocationSize==AllocationSize);
366 g_assert(captive_shared_cache_map_object->FileSize==FileSize);
367 g_assert(captive_shared_cache_map_object->ValidDataLength==ValidDataLength);
370 CaptiveSharedCacheMapObject *captive_SectionObjectPointers_to_SharedCacheMap(SECTION_OBJECT_POINTERS *SectionObjectPointers)
372 g_return_val_if_fail(SectionObjectPointers!=NULL,NULL);
373 g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(SectionObjectPointers->SharedCacheMap),NULL);
375 return SectionObjectPointers->SharedCacheMap;
378 CaptiveSharedCacheMapObject *captive_FileObject_to_SharedCacheMap(FILE_OBJECT *FileObject)
380 g_return_val_if_fail(FileObject!=NULL,NULL);
382 return captive_SectionObjectPointers_to_SharedCacheMap(FileObject->SectionObjectPointer);
385 void captive_shared_cache_map_w32_ref(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
387 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
389 g_object_ref(captive_shared_cache_map_object);
390 captive_shared_cache_map_object->w32_ref_count++;
393 void captive_shared_cache_map_w32_unref(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
395 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
396 g_return_if_fail(G_OBJECT(captive_shared_cache_map_object)->ref_count>0);
398 captive_shared_cache_map_object->w32_ref_count--;
399 g_object_unref(captive_shared_cache_map_object);
402 gint captive_shared_cache_map_query_w32_ref(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
404 g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),0);
406 return captive_shared_cache_map_object->w32_ref_count;
409 void captive_shared_cache_map_data_validate_read(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
410 FILE_OBJECT *FileObject,guint64 start,guint64 end)
413 gboolean after_eof=FALSE; /* Did we reached the end of file already? */
415 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
416 g_return_if_fail(captive_shared_cache_map_object==captive_FileObject_to_SharedCacheMap(FileObject));
417 g_return_if_fail(start<=end);
418 g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
420 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
421 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
423 for (now=start;now<end;now+=PAGE_SIZE) {
424 LARGE_INTEGER now_LargeInteger;
427 if (captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid)
429 now_LargeInteger.QuadPart=now;
430 got=captive_Cc_IoPageRead(FileObject,captive_shared_cache_map_object->buffer+now,PAGE_SIZE,&now_LargeInteger);
434 g_assert(got<=PAGE_SIZE);
435 after_eof=(got<PAGE_SIZE);
436 captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid=TRUE;
437 captive_shared_cache_map_object->pages[now/PAGE_SIZE].dirty=FALSE;
441 void captive_shared_cache_map_data_validate_noread(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
442 guint64 start,guint64 end)
446 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
447 g_return_if_fail(start<=end);
448 g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
450 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
451 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
453 for (now=start;now<end;now+=PAGE_SIZE) {
454 g_assert(captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid);
458 void captive_shared_cache_map_set_data_valid(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
459 guint64 start,guint64 end)
463 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
464 g_return_if_fail(start<=end);
465 g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
467 start=CAPTIVE_ROUND_UP64(start,PAGE_SIZE);
468 if (end<captive_shared_cache_map_object->FileSize)
469 end=CAPTIVE_ROUND_DOWN64(end,PAGE_SIZE);
471 /* We can validate the last page of the file
472 * even if it does not end on PAGE_SIZE boundary.
474 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
476 /* We may get end<start here - it is valid to not to validate anything. */
478 for (now=start;now<end;now+=PAGE_SIZE) {
479 captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid=TRUE;
480 /* .dirty is undefined */
484 void captive_shared_cache_map_set_data_invalid(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
485 guint64 start,guint64 end)
489 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
490 g_return_if_fail(start<=end);
491 g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
493 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
494 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
496 for (now=start;now<end;now+=PAGE_SIZE) {
497 captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid=FALSE;
501 void captive_shared_cache_map_set_dirty(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
502 guint64 start,guint64 end)
505 CaptiveSharedCacheMapObject_page *page;
507 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
508 g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
510 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
511 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
513 for (now=start;now<end;now+=PAGE_SIZE) {
514 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
515 g_assert(page->data_valid);
524 gboolean captive_shared_cache_map_is_page_dirty(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
527 CaptiveSharedCacheMapObject_page *page;
529 g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),FALSE);
530 g_return_val_if_fail(offset<CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE),FALSE);
531 g_return_val_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(offset,PAGE_SIZE),FALSE);
532 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
533 g_return_val_if_fail(page->data_valid,FALSE);
538 void captive_shared_cache_map_page_set_lsn(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
539 guint64 offset,gint64 lsn)
541 CaptiveSharedCacheMapObject_page *page;
543 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
544 g_return_if_fail(offset<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
545 g_return_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(offset,PAGE_SIZE));
546 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
547 g_return_if_fail(page->data_valid);
548 g_return_if_fail(page->dirty);
549 g_return_if_fail(page->lsn_oldest<=page->lsn_newest);
550 g_return_if_fail(!page->lsn_newest || lsn>=page->lsn_newest);
551 g_return_if_fail(captive_shared_cache_map_object->LogHandle_set);
552 g_return_if_fail(captive_shared_cache_map_object->FlushToLsnRoutine_set);
554 if (!page->lsn_oldest)
555 page->lsn_oldest=lsn;
556 page->lsn_newest=lsn;
559 void captive_shared_cache_map_purge(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
562 CaptiveSharedCacheMapObject_page *page;
564 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
566 g_signal_emit(captive_shared_cache_map_object,purge_signal,0);
568 /* Needed by fastfat.sys of NT-5.1sp1 during FAT32 unmount
569 * otherwise it fails on: g_assert(!page->dirty);
570 * It corrupts the disk if the buffer is dropped instead.
572 captive_shared_cache_map_flush(captive_shared_cache_map_object,
573 0,CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
575 for (offset=0;offset<CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE);offset+=PAGE_SIZE) {
576 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
577 if (!page->data_valid)
579 g_assert(!page->dirty);
580 page->data_valid=FALSE;
584 static VOID *captive_LogHandle;
585 static PFLUSH_TO_LSN captive_FlushToLsnRoutine;
587 void captive_shared_cache_map_set_LogHandle(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,VOID *LogHandle)
589 g_return_if_fail(!captive_shared_cache_map_object || CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
590 /* FIXME: 'captive_shared_cache_map_object->LogHandle_set' may be set.
591 * Does it mean 'LogHandle_set' is 'FileObject'-based instead of 'SharedCacheMap'-based?
596 g_assert(!captive_LogHandle || captive_LogHandle==LogHandle);
597 captive_LogHandle=LogHandle;
598 if (LogHandle && captive_shared_cache_map_object)
599 captive_shared_cache_map_object->LogHandle_set=TRUE;
602 void captive_shared_cache_map_set_FlushToLsnRoutine
603 (CaptiveSharedCacheMapObject *captive_shared_cache_map_object,PFLUSH_TO_LSN FlushToLsnRoutine)
605 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
606 /* FIXME: 'captive_shared_cache_map_object->FlushToLsnRoutine_set' may be set.
607 * Does it mean 'FlushToLsnRoutine_set' is 'FileObject'-based instead of 'SharedCacheMap'-based?
610 if (!FlushToLsnRoutine)
612 g_assert(!captive_FlushToLsnRoutine || captive_FlushToLsnRoutine==FlushToLsnRoutine);
613 captive_FlushToLsnRoutine=FlushToLsnRoutine;
614 if (FlushToLsnRoutine)
615 captive_shared_cache_map_object->FlushToLsnRoutine_set=TRUE;
618 static void captive_shared_cache_map_page_write(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
621 LARGE_INTEGER offset_LargeInteger;
622 static gint64 lsn_last;
623 CaptiveSharedCacheMapObject_page *page;
625 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
626 g_return_if_fail(captive_shared_cache_map_object->FileObject!=NULL);
627 g_return_if_fail(offset<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
628 g_return_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(offset,PAGE_SIZE));
629 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
630 g_return_if_fail(page->data_valid);
631 g_return_if_fail(page->dirty);
633 if (page->lsn_newest) {
635 g_assert(!lsn_last || lsn_last<=page->lsn_newest);
636 lsn_last=page->lsn_newest;
638 captive_stdcall_call_12((CaptiveStdCallFunc12)captive_FlushToLsnRoutine,
640 (gpointer)(guint32)(page->lsn_newest>> 0U), /* 'LARGE_INTEGER' argument */
641 (gpointer)(guint32)(page->lsn_newest>>32U));
644 offset_LargeInteger.QuadPart=offset;
645 captive_Cc_IoPageWrite(captive_shared_cache_map_object->FileObject,
646 captive_shared_cache_map_object->buffer+offset,PAGE_SIZE,&offset_LargeInteger);
653 typedef struct _captive_shared_cache_map_page_write_lsn_foreach_param captive_shared_cache_map_page_write_lsn_foreach_param;
654 struct _captive_shared_cache_map_page_write_lsn_foreach_param {
657 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_best;
661 static void captive_shared_cache_map_page_write_lsn_foreach(
662 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
663 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
664 captive_shared_cache_map_page_write_lsn_foreach_param *param) /* user_data */
667 CaptiveSharedCacheMapObject_page *page;
669 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
670 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
671 g_return_if_fail(param!=NULL);
673 for (now=0;now<captive_shared_cache_map_object->AllocationSize;now+=PAGE_SIZE) {
674 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
675 if (!page->data_valid)
679 if (!page->lsn_newest)
681 if (page->lsn_newest>=param->lsn_target)
683 if (param->lsn_best && page->lsn_newest>param->lsn_best)
685 param->lsn_best=page->lsn_newest;
686 param->captive_shared_cache_map_object_best=captive_shared_cache_map_object;
687 param->offset_best=now;
691 static void captive_shared_cache_map_page_write_lsn(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
694 CaptiveSharedCacheMapObject_page *page;
696 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
697 g_return_if_fail(captive_shared_cache_map_object->FileObject!=NULL);
698 g_return_if_fail(offset<CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
699 g_return_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(offset,PAGE_SIZE));
700 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
701 g_return_if_fail(page->data_valid);
702 g_return_if_fail(page->dirty);
704 if (page->lsn_newest) {
705 CaptiveSharedCacheMapObject_hash_init();
707 captive_shared_cache_map_page_write_lsn_foreach_param param;
709 param.lsn_target=page->lsn_newest;
711 g_hash_table_foreach(
712 CaptiveSharedCacheMapObject_hash, /* hash_table */
713 (GHFunc)captive_shared_cache_map_page_write_lsn_foreach, /* func */
714 ¶m); /* user_data */
717 captive_shared_cache_map_page_write(param.captive_shared_cache_map_object_best,param.offset_best);
721 captive_shared_cache_map_page_write(captive_shared_cache_map_object,offset);
724 guint64 captive_shared_cache_map_flush(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
725 guint64 start,guint64 end)
730 g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),0);
731 g_return_val_if_fail(start<=end,0);
733 end=MIN(end,CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
735 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
736 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
739 for (now=start;now<end;now+=PAGE_SIZE) {
740 if (!captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid)
742 if (!captive_shared_cache_map_object->pages[now/PAGE_SIZE].dirty)
744 captive_shared_cache_map_page_write_lsn(captive_shared_cache_map_object,now);
748 /* We were calling W32 code - recheck our task completion. */
749 for (now=start;now<end;now+=PAGE_SIZE) {
750 if (!captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid)
752 g_assert(!captive_shared_cache_map_object->pages[now/PAGE_SIZE].dirty);
758 static void captive_shared_cache_map_is_any_dirty_foreach(
759 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
760 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
761 gboolean *dirty_foundp) /* user_data */
765 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
766 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
767 g_return_if_fail(dirty_foundp!=NULL);
769 for (now=0;now<captive_shared_cache_map_object->AllocationSize;now+=PAGE_SIZE) {
770 if (!captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid)
772 if (!captive_shared_cache_map_object->pages[now/PAGE_SIZE].dirty)
774 *dirty_foundp=TRUE; /* FIXME: stop the traversal. */
780 gboolean captive_shared_cache_map_is_any_dirty(void)
782 gboolean dirty_found;
784 CaptiveSharedCacheMapObject_hash_init();
786 g_hash_table_foreach(
787 CaptiveSharedCacheMapObject_hash, /* hash_table */
788 (GHFunc)captive_shared_cache_map_is_any_dirty_foreach, /* func */
789 &dirty_found); /* user_data */
795 typedef struct _captive_shared_cache_map_CcGetDirtyPages_foreach_param captive_shared_cache_map_CcGetDirtyPages_foreach_param;
796 struct _captive_shared_cache_map_CcGetDirtyPages_foreach_param {
797 PDIRTY_PAGE_ROUTINE DirtyPageRoutine;
803 static void captive_shared_cache_map_CcGetDirtyPages_foreach(
804 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
805 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
806 captive_shared_cache_map_CcGetDirtyPages_foreach_param *param) /* user_data */
809 CaptiveSharedCacheMapObject_page *page;
811 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
812 g_return_if_fail(captive_shared_cache_map_object->FileObject!=NULL);
813 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
814 g_return_if_fail(param!=NULL);
816 for (now=CAPTIVE_ROUND_DOWN64(captive_shared_cache_map_object->AllocationSize-1,PAGE_SIZE);now>=0;now-=PAGE_SIZE) {
817 LARGE_INTEGER now_LargeInteger,lsn_oldest_LargeInteger,lsn_newest_LargeInteger;
819 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
820 if (!page->data_valid)
824 if (page->lsn_oldest && (!param->result || param->result>page->lsn_oldest))
825 param->result=page->lsn_oldest;
827 now_LargeInteger.QuadPart=now;
828 lsn_oldest_LargeInteger.QuadPart=page->lsn_oldest;
829 lsn_newest_LargeInteger.QuadPart=page->lsn_newest;
830 (*param->DirtyPageRoutine)(
831 captive_shared_cache_map_object->FileObject, /* FileObject */
832 &now_LargeInteger, /* FileOffset */
833 PAGE_SIZE, /* Length */
834 &lsn_oldest_LargeInteger, /* OldestLsn */
835 &lsn_newest_LargeInteger, /* NewestLsn */
836 param->Context1, /* Context1 */
837 param->Context2); /* Context2 */
841 gint64 captive_shared_cache_map_CcGetDirtyPages(PDIRTY_PAGE_ROUTINE DirtyPageRoutine,VOID *Context1,VOID *Context2)
843 captive_shared_cache_map_CcGetDirtyPages_foreach_param param;
845 g_return_val_if_fail(DirtyPageRoutine!=NULL,0);
847 param.DirtyPageRoutine=DirtyPageRoutine;
848 param.Context1=Context1;
849 param.Context2=Context2;
852 CaptiveSharedCacheMapObject_hash_init();
853 g_hash_table_foreach(
854 CaptiveSharedCacheMapObject_hash, /* hash_table */
855 (GHFunc)captive_shared_cache_map_CcGetDirtyPages_foreach, /* func */
856 ¶m); /* user_data */
861 gpointer captive_shared_cache_map_get_buffer(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
863 g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),NULL);
864 g_return_val_if_fail(captive_shared_cache_map_object->buffer!=NULL,NULL);
866 return captive_shared_cache_map_object->buffer;
869 static void captive_cc_FileObject_delete_foreach(
870 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
871 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
872 FILE_OBJECT *FileObject) /* user_data */
874 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
875 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
876 g_return_if_fail(FileObject!=NULL);
878 g_assert(FileObject!=captive_shared_cache_map_object->FileObject);
881 BOOLEAN captive_cc_FileObject_delete(FILE_OBJECT *FileObject)
883 g_return_val_if_fail(FileObject!=NULL,FALSE);
885 CaptiveSharedCacheMapObject_hash_init();
886 g_hash_table_foreach(
887 CaptiveSharedCacheMapObject_hash, /* hash_table */
888 (GHFunc)captive_cc_FileObject_delete_foreach, /* func */
889 FileObject); /* user_data */
891 return FALSE; /* FIXME: remove useless return code. */