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"
34 static GHashTable *CaptiveSharedCacheMapObject_hash;
36 static void CaptiveSharedCacheMapObject_hash_init(void)
38 if (CaptiveSharedCacheMapObject_hash)
40 CaptiveSharedCacheMapObject_hash=g_hash_table_new(
41 g_direct_hash, /* hash_func */
42 g_direct_equal); /* key_equal_func */
46 static gpointer captive_shared_cache_map_object_parent_class=NULL;
49 static void captive_shared_cache_map_object_finalize(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
51 static const CC_FILE_SIZES FileSizes_zero;
54 CaptiveSharedCacheMapObject_page *page;
56 g_return_if_fail(captive_shared_cache_map_object!=NULL);
58 for (offset=0;offset<CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE);offset+=PAGE_SIZE) {
59 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
60 if (!page->data_valid)
62 g_assert(!page->dirty); /* FIXME: Is it allowed by W32? */
65 CaptiveSharedCacheMapObject_hash_init();
66 errbool=g_hash_table_remove(CaptiveSharedCacheMapObject_hash,captive_shared_cache_map_object);
67 g_assert(errbool==TRUE);
69 captive_shared_cache_map_FileSizes_set(captive_shared_cache_map_object,&FileSizes_zero);
70 g_assert(captive_shared_cache_map_object->buffer==NULL);
71 g_assert(captive_shared_cache_map_object->pages==NULL);
73 if (captive_shared_cache_map_object->pin_hash) {
74 captive_private_bcb_pin_object_hash_destroy(captive_shared_cache_map_object->pin_hash);
75 captive_shared_cache_map_object->pin_hash=NULL;
77 g_assert(captive_shared_cache_map_object->map==NULL);
78 if (captive_shared_cache_map_object->SectionObjectPointer) {
79 g_assert(captive_shared_cache_map_object==captive_shared_cache_map_object->SectionObjectPointer->SharedCacheMap);
80 captive_shared_cache_map_object->SectionObjectPointer->SharedCacheMap=NULL;
83 if (captive_shared_cache_map_object->FileObject) {
84 /* W32 dereferences twice. */
85 ObDereferenceObject(captive_shared_cache_map_object->FileObject);
86 captive_shared_cache_map_object->FileObject=NULL;
89 G_OBJECT_CLASS(captive_shared_cache_map_object_parent_class)->finalize((GObject *)captive_shared_cache_map_object);
92 static guint FileSizes_changed_signal;
93 static guint purge_signal;
95 static void captive_shared_cache_map_object_FileSizes_changed(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
96 guint64 AllocationSize,guint64 FileSize,guint64 ValidDataLength);
97 static void captive_shared_cache_map_object_purge(CaptiveSharedCacheMapObject *captive_shared_cache_map_object);
99 static void captive_shared_cache_map_object_class_init(CaptiveSharedCacheMapObjectClass *class)
101 GObjectClass *gobject_class=G_OBJECT_CLASS(class);
103 captive_shared_cache_map_object_parent_class=g_type_class_ref(g_type_parent(G_TYPE_FROM_CLASS(class)));
104 gobject_class->finalize=(void (*)(GObject *object))captive_shared_cache_map_object_finalize;
106 class->FileSizes_changed=captive_shared_cache_map_object_FileSizes_changed;
107 class->purge=captive_shared_cache_map_object_purge;
109 FileSizes_changed_signal=g_signal_new("FileSizes_changed",
110 G_TYPE_FROM_CLASS(gobject_class),
112 G_STRUCT_OFFSET(CaptiveSharedCacheMapObjectClass,FileSizes_changed),
114 captive_cc_VOID__UINT64_UINT64_UINT64,
115 G_TYPE_NONE,3,G_TYPE_UINT64,G_TYPE_UINT64,G_TYPE_UINT64);
116 purge_signal=g_signal_new("purge",
117 G_TYPE_FROM_CLASS(gobject_class),
119 G_STRUCT_OFFSET(CaptiveSharedCacheMapObjectClass,purge),
121 captive_cc_VOID__VOID,
126 static void captive_shared_cache_map_object_init(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
128 captive_shared_cache_map_object->pin_hash=captive_private_bcb_pin_object_hash_new();
130 captive_shared_cache_map_w32_ref(captive_shared_cache_map_object);
131 g_object_unref(captive_shared_cache_map_object); /* ==sink */
133 CaptiveSharedCacheMapObject_hash_init();
134 g_hash_table_insert(CaptiveSharedCacheMapObject_hash,
135 captive_shared_cache_map_object,captive_shared_cache_map_object);
139 GType captive_shared_cache_map_object_get_type(void)
141 static GType captive_shared_cache_map_object_type=0;
143 if (!captive_shared_cache_map_object_type) {
144 static const GTypeInfo captive_shared_cache_map_object_info={
145 sizeof(CaptiveSharedCacheMapObjectClass),
146 NULL, /* base_init */
147 NULL, /* base_finalize */
148 (GClassInitFunc)captive_shared_cache_map_object_class_init,
149 NULL, /* class_finalize */
150 NULL, /* class_data */
151 sizeof(CaptiveSharedCacheMapObject),
153 (GInstanceInitFunc)captive_shared_cache_map_object_init,
156 captive_shared_cache_map_object_type=g_type_register_static(G_TYPE_OBJECT,
157 "CaptiveSharedCacheMapObject",&captive_shared_cache_map_object_info,0);
160 return captive_shared_cache_map_object_type;
163 static void captive_shared_cache_map_object_FileSizes_changed(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
164 guint64 AllocationSize,guint64 FileSize,guint64 ValidDataLength)
166 size_t size_old,size_new;
167 guint64 size64_old,size64_new;
169 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
171 g_assert((!captive_shared_cache_map_object->buffer)==(!captive_shared_cache_map_object->AllocationSize));
172 g_assert((!captive_shared_cache_map_object->pages)==(!captive_shared_cache_map_object->AllocationSize));
174 size64_old=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE);
176 g_assert(size_old==size64_old);
177 size64_new=CAPTIVE_ROUND_UP64(AllocationSize,PAGE_SIZE);
179 if (size_new!=size64_new) {
181 g_error("Mapped size %" G_GUINT64_FORMAT " is too big; FIXME: non-mmap(2)-able areas not yet supported",size64_new);
182 g_assert_not_reached();
185 if (size_old!=size_new) {
186 /* ntfs.sys of NT-5.1sp1 may extend StreamFileObject while dirty pins exist.
187 * How to extend SharedCacheMap size without changing the memory location?
188 * I hope ntfs.sys does not expect long-term absolute position of its
191 if (!(captive_shared_cache_map_object->FileObject->Flags&FO_STREAM_FILE)) {
192 /* These two assertions should be already catched by pin/map signal handlers. */
193 g_assert(!captive_shared_cache_map_object->map);
194 g_assert(!g_hash_table_size(captive_shared_cache_map_object->pin_hash));
198 if (!size_new || size_new > captive_shared_cache_map_object->alloc_length) {
203 alloc64_new=CAPTIVE_ROUND_UP64((!size64_new ? 0 : MAX(size64_new*2,0x10000)),PAGE_SIZE);
204 alloc_new=alloc64_new;
205 if (alloc_new!=alloc64_new)
216 PAGE_SIZE+alloc_new+PAGE_SIZE, /* length; leading and trailing boundary check pages */
217 PROT_READ|PROT_WRITE, /* prot; read/write must be possible although write is not guaranteed to be flushed yet */
218 MAP_PRIVATE|MAP_ANONYMOUS /* flags */
219 |MAP_NORESERVE, /* At least ext2fsd maps the whole disk. */
220 -1, /* fd; ignored due to MAP_ANONYMOUS */
221 0); /* offset; ignored due to MAP_ANONYMOUS */
222 if (base==MAP_FAILED)
224 g_assert(base!=NULL);
227 errint=munmap(base-PAGE_SIZE,PAGE_SIZE); /* unmap leading boundary check page */
229 errint=munmap(base+alloc_new,PAGE_SIZE); /* unmap trailing boundary check page */
235 memcpy(buffer_new,captive_shared_cache_map_object->buffer,
236 MIN(AllocationSize,captive_shared_cache_map_object->AllocationSize));
238 if (captive_shared_cache_map_object->alloc_length) {
241 errint=munmap(captive_shared_cache_map_object->buffer,captive_shared_cache_map_object->alloc_length);
245 captive_shared_cache_map_object->buffer=buffer_new;
247 #if 0 /* It appears it is valid to squeeze out 'dirty' blocks. FIXME: Flush them? */
248 /* FIXME: The code may be no longer valid with the 'alloc_new' introduction! */
249 if (size_old>size_new) {
252 for (now=size_new;now<size_old;now+=PAGE_SIZE) {
253 if (!captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid)
255 g_assert(!captive_shared_cache_map_object->pages[now/PAGE_SIZE].dirty);
260 captive_shared_cache_map_object->pages=g_realloc(captive_shared_cache_map_object->pages,
261 alloc_new/PAGE_SIZE*sizeof(*captive_shared_cache_map_object->pages));
263 captive_shared_cache_map_object->alloc_length=alloc_new;
266 if (size_new>size_old) /* prevent 'size_new-size_old' as it is unsigned! */
267 memset(captive_shared_cache_map_object->pages+(size_old/PAGE_SIZE),0,
268 (size_new-size_old)/PAGE_SIZE*sizeof(*captive_shared_cache_map_object->pages));
270 captive_shared_cache_map_object->AllocationSize=AllocationSize;
271 captive_shared_cache_map_object->FileSize=FileSize;
272 captive_shared_cache_map_object->ValidDataLength=ValidDataLength;
274 g_assert((!captive_shared_cache_map_object->buffer)==(!captive_shared_cache_map_object->AllocationSize));
275 g_assert((!captive_shared_cache_map_object->pages)==(!captive_shared_cache_map_object->AllocationSize));
278 static void captive_shared_cache_map_object_purge(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
280 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
282 /* NOP; just to provide slot for checking by Bcbs */
285 CaptiveSharedCacheMapObject *captive_shared_cache_map_get_ref(FILE_OBJECT *FileObject,
286 const CC_FILE_SIZES *FileSizes,BOOLEAN PinAccess,const CACHE_MANAGER_CALLBACKS *CallBacks,VOID *LazyWriterContext)
288 CaptiveSharedCacheMapObject *captive_shared_cache_map_object;
290 g_return_val_if_fail(FileObject!=NULL,NULL);
291 g_return_val_if_fail(FileObject->SectionObjectPointer!=NULL,NULL);
292 g_return_val_if_fail(FileSizes!=NULL,NULL);
293 g_return_val_if_fail(CallBacks!=NULL,NULL);
295 if ((captive_shared_cache_map_object=FileObject->SectionObjectPointer->SharedCacheMap)) {
296 captive_shared_cache_map_w32_ref(captive_shared_cache_map_object);
299 captive_shared_cache_map_object=g_object_new(
300 CAPTIVE_SHARED_CACHE_MAP_TYPE_OBJECT, /* object_type */
301 NULL); /* first_property_name; FIXME: support properties */
303 /* FIXME: When to drop SharedCacheMap?
304 * Currently we never close it.
305 * Fix also CcZeroData() workaround.
307 g_object_ref(captive_shared_cache_map_object);
309 /* W32 references twice. */
310 ObReferenceObject(FileObject);
311 captive_shared_cache_map_object->FileObject=FileObject;
312 captive_shared_cache_map_object->SectionObjectPointer=FileObject->SectionObjectPointer;
313 captive_shared_cache_map_object->AllocationSize=0;
314 captive_shared_cache_map_object->FileSize=0;
315 captive_shared_cache_map_object->ValidDataLength=0;
316 captive_shared_cache_map_object->PinAccess=PinAccess;
317 captive_shared_cache_map_object->CallBacks=*CallBacks;
318 captive_shared_cache_map_object->LazyWriterContext=LazyWriterContext;
320 FileObject->SectionObjectPointer->SharedCacheMap=captive_shared_cache_map_object;
323 g_assert(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
324 /* FileObject may differ - we can have a different reference to the same FCB. */
325 g_assert(FileObject->SectionObjectPointer==captive_shared_cache_map_object->SectionObjectPointer);
326 g_assert(PinAccess==captive_shared_cache_map_object->PinAccess);
327 g_assert(CallBacks->AcquireForLazyWrite==captive_shared_cache_map_object->CallBacks.AcquireForLazyWrite);
328 g_assert(CallBacks->ReleaseFromLazyWrite==captive_shared_cache_map_object->CallBacks.ReleaseFromLazyWrite);
329 g_assert(CallBacks->AcquireForReadAhead==captive_shared_cache_map_object->CallBacks.AcquireForReadAhead);
330 g_assert(CallBacks->ReleaseFromReadAhead==captive_shared_cache_map_object->CallBacks.ReleaseFromReadAhead);
331 g_assert(LazyWriterContext==captive_shared_cache_map_object->LazyWriterContext);
333 captive_shared_cache_map_FileSizes_set(captive_shared_cache_map_object,FileSizes);
335 return captive_shared_cache_map_object;
338 void captive_shared_cache_map_FileSizes_set(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
339 const CC_FILE_SIZES *FileSizes)
341 guint64 AllocationSize,FileSize,ValidDataLength;
343 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
344 g_return_if_fail(FileSizes!=NULL);
346 AllocationSize=FileSizes->AllocationSize.QuadPart;
347 FileSize=FileSizes->FileSize.QuadPart;
348 ValidDataLength=FileSizes->ValidDataLength.QuadPart;
350 /* Do not: if (ValidDataLength==G_MAXINT64)
351 * ValidDataLength=FileSize;
352 * In some cases (during NTFS mount) there may be also invalid 'ValidDataLength' at all:
353 * CcSetFileSizes(AllocationSize=0x1000000,FileSize=0xf80208,ValidDataLength=0x23b801a0)
355 ValidDataLength=FileSize;
357 g_assert(AllocationSize>=0);
358 g_assert(FileSize>=0);
359 g_assert(ValidDataLength>=0);
361 g_assert(ValidDataLength<=FileSize);
362 /* Do not: g_assert(0==(AllocationSize%0x200));
363 * as it is true for ntfs.sys of NT-5.1sp1 but it fails for fastfat.sys of NT-5.1sp1.
365 /* AllocationSize can be much higher: */
366 g_assert(FileSize<=AllocationSize);
368 /* Prevent signalling if not needed. */
370 || captive_shared_cache_map_object->AllocationSize!=AllocationSize
371 || captive_shared_cache_map_object->FileSize!=FileSize
372 || captive_shared_cache_map_object->ValidDataLength!=ValidDataLength) {
373 /* Signalling is forbidden in captive_shared_cache_map_object_finalize(). */
374 if (G_OBJECT(captive_shared_cache_map_object)->ref_count==0) {
375 (*CAPTIVE_SHARED_CACHE_MAP_OBJECT_GET_CLASS(captive_shared_cache_map_object)->FileSizes_changed)
376 (captive_shared_cache_map_object,AllocationSize,FileSize,ValidDataLength);
379 g_signal_emit(captive_shared_cache_map_object,FileSizes_changed_signal,0,
380 AllocationSize,FileSize,ValidDataLength);
384 g_assert(captive_shared_cache_map_object->AllocationSize==AllocationSize);
385 g_assert(captive_shared_cache_map_object->FileSize==FileSize);
386 g_assert(captive_shared_cache_map_object->ValidDataLength==ValidDataLength);
389 CaptiveSharedCacheMapObject *captive_SectionObjectPointers_to_SharedCacheMap(SECTION_OBJECT_POINTERS *SectionObjectPointers)
391 g_return_val_if_fail(SectionObjectPointers!=NULL,NULL);
392 g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(SectionObjectPointers->SharedCacheMap),NULL);
394 return SectionObjectPointers->SharedCacheMap;
397 CaptiveSharedCacheMapObject *captive_FileObject_to_SharedCacheMap(FILE_OBJECT *FileObject)
399 g_return_val_if_fail(FileObject!=NULL,NULL);
401 return captive_SectionObjectPointers_to_SharedCacheMap(FileObject->SectionObjectPointer);
404 void captive_shared_cache_map_w32_ref(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
406 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
408 g_object_ref(captive_shared_cache_map_object);
409 captive_shared_cache_map_object->w32_ref_count++;
412 void captive_shared_cache_map_w32_unref(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
414 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
415 g_return_if_fail(G_OBJECT(captive_shared_cache_map_object)->ref_count>0);
417 captive_shared_cache_map_object->w32_ref_count--;
418 g_object_unref(captive_shared_cache_map_object);
421 gint captive_shared_cache_map_query_w32_ref(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
423 g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),0);
425 return captive_shared_cache_map_object->w32_ref_count;
428 void captive_shared_cache_map_data_validate_read(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
429 FILE_OBJECT *FileObject,guint64 start,guint64 end)
432 gboolean after_eof=FALSE; /* Did we reached the end of file already? */
434 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
435 g_return_if_fail(captive_shared_cache_map_object==captive_FileObject_to_SharedCacheMap(FileObject));
436 g_return_if_fail(start<=end);
437 g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
439 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
440 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
442 for (now=start;now<end;now+=PAGE_SIZE) {
443 LARGE_INTEGER now_LargeInteger;
446 if (captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid)
448 now_LargeInteger.QuadPart=now;
449 got=captive_Cc_IoPageRead(FileObject,captive_shared_cache_map_object->buffer+now,PAGE_SIZE,&now_LargeInteger);
453 g_assert(got<=PAGE_SIZE);
454 after_eof=(got<PAGE_SIZE);
455 captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid=TRUE;
456 captive_shared_cache_map_object->pages[now/PAGE_SIZE].dirty=FALSE;
460 void captive_shared_cache_map_data_validate_noread(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
461 guint64 start,guint64 end)
465 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
466 g_return_if_fail(start<=end);
467 g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
469 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
470 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
472 for (now=start;now<end;now+=PAGE_SIZE) {
473 g_assert(captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid);
477 void captive_shared_cache_map_set_data_valid(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
478 guint64 start,guint64 end)
482 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
483 g_return_if_fail(start<=end);
484 g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
486 start=CAPTIVE_ROUND_UP64(start,PAGE_SIZE);
487 if (end<captive_shared_cache_map_object->FileSize)
488 end=CAPTIVE_ROUND_DOWN64(end,PAGE_SIZE);
490 /* We can validate the last page of the file
491 * even if it does not end on PAGE_SIZE boundary.
493 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
495 /* We may get end<start here - it is valid to not to validate anything. */
497 for (now=start;now<end;now+=PAGE_SIZE) {
498 captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid=TRUE;
499 /* .dirty is undefined */
503 void captive_shared_cache_map_set_data_invalid(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
504 guint64 start,guint64 end)
508 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
509 g_return_if_fail(start<=end);
510 g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
512 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
513 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
515 for (now=start;now<end;now+=PAGE_SIZE) {
516 captive_shared_cache_map_object->pages[now/PAGE_SIZE].data_valid=FALSE;
520 void captive_shared_cache_map_set_dirty(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
521 guint64 start,guint64 end)
524 CaptiveSharedCacheMapObject_page *page;
526 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
527 g_return_if_fail(end<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
529 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
530 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
532 for (now=start;now<end;now+=PAGE_SIZE) {
533 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
534 g_assert(page->data_valid);
543 typedef struct _captive_shared_cache_map_memory_range_set_dirty_param
544 captive_shared_cache_map_memory_range_set_dirty_param;
545 struct _captive_shared_cache_map_memory_range_set_dirty_param {
546 gpointer address_start;
547 gpointer address_end;
551 static void captive_shared_cache_map_memory_range_set_dirty_foreach(
552 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
553 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
554 captive_shared_cache_map_memory_range_set_dirty_param *param) /* user_data */
556 gpointer address_start_local,address_end_local;
558 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
559 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
560 g_return_if_fail(param!=NULL);
562 address_start_local=MAX(param->address_start,captive_shared_cache_map_object->buffer);
563 address_end_local=MIN(param->address_end,captive_shared_cache_map_object->buffer+captive_shared_cache_map_object->AllocationSize);
565 if (address_start_local>address_end_local)
568 captive_shared_cache_map_set_dirty(captive_shared_cache_map_object,
569 address_start_local-captive_shared_cache_map_object->buffer, /* start */
570 address_end_local -captive_shared_cache_map_object->buffer); /* end */
572 param->bytes_set+=(address_end_local-address_start_local);
575 guint64 captive_shared_cache_map_memory_range_set_dirty(gpointer address_start,gpointer address_end)
577 captive_shared_cache_map_memory_range_set_dirty_param set_dirty_param;
579 g_return_val_if_fail(address_start!=NULL,0);
580 g_return_val_if_fail(address_end!=NULL,0);
581 g_return_val_if_fail(address_start<=address_end,0);
583 address_start=CAPTIVE_ROUND_DOWN(address_start,PAGE_SIZE);
584 address_end=CAPTIVE_ROUND_UP(address_end,PAGE_SIZE);
586 CaptiveSharedCacheMapObject_hash_init();
587 set_dirty_param.address_start=address_start;
588 set_dirty_param.address_end=address_end;
589 set_dirty_param.bytes_set=0;
590 g_hash_table_foreach(
591 CaptiveSharedCacheMapObject_hash, /* hash_table */
592 (GHFunc)captive_shared_cache_map_memory_range_set_dirty_foreach, /* func */
593 &set_dirty_param); /* user_data */
595 return set_dirty_param.bytes_set;
598 gboolean captive_shared_cache_map_is_page_dirty(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
601 CaptiveSharedCacheMapObject_page *page;
603 g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),FALSE);
604 g_return_val_if_fail(offset<CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE),FALSE);
605 g_return_val_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(offset,PAGE_SIZE),FALSE);
606 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
607 g_return_val_if_fail(page->data_valid,FALSE);
612 void captive_shared_cache_map_page_set_lsn(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
613 guint64 offset,gint64 lsn)
615 CaptiveSharedCacheMapObject_page *page;
617 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
618 g_return_if_fail(offset<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
619 g_return_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(offset,PAGE_SIZE));
620 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
621 g_return_if_fail(page->data_valid);
622 g_return_if_fail(page->dirty);
623 g_return_if_fail(page->lsn_oldest<=page->lsn_newest);
624 g_return_if_fail(!page->lsn_newest || lsn>=page->lsn_newest);
625 g_return_if_fail(captive_shared_cache_map_object->LogHandle_set);
626 g_return_if_fail(captive_shared_cache_map_object->FlushToLsnRoutine_set);
628 if (!page->lsn_oldest)
629 page->lsn_oldest=lsn;
630 page->lsn_newest=lsn;
633 void captive_shared_cache_map_purge(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
636 CaptiveSharedCacheMapObject_page *page;
638 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
640 g_signal_emit(captive_shared_cache_map_object,purge_signal,0);
642 /* Needed by fastfat.sys of NT-5.1sp1 during FAT32 unmount
643 * otherwise it fails on: g_assert(!page->dirty);
644 * It corrupts the disk if the buffer is dropped instead.
646 captive_shared_cache_map_flush(captive_shared_cache_map_object,
647 0,CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
649 for (offset=0;offset<CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE);offset+=PAGE_SIZE) {
650 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
651 if (!page->data_valid)
653 g_assert(!page->dirty);
654 page->data_valid=FALSE;
658 static VOID *captive_LogHandle;
659 static PFLUSH_TO_LSN captive_FlushToLsnRoutine;
661 void captive_shared_cache_map_set_LogHandle(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,VOID *LogHandle)
663 g_return_if_fail(!captive_shared_cache_map_object || CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
664 /* FIXME: 'captive_shared_cache_map_object->LogHandle_set' may be set.
665 * Does it mean 'LogHandle_set' is 'FileObject'-based instead of 'SharedCacheMap'-based?
668 /* Do not: if (!LogHandle)
670 * See CcGetDirtyPages()/"W32 undocumented: What does mean LogHandle==NULL?"
672 g_assert(!captive_LogHandle || !LogHandle || captive_LogHandle==LogHandle);
673 captive_LogHandle=LogHandle;
674 if (captive_shared_cache_map_object)
675 captive_shared_cache_map_object->LogHandle_set=!!LogHandle;
678 void captive_shared_cache_map_set_FlushToLsnRoutine
679 (CaptiveSharedCacheMapObject *captive_shared_cache_map_object,PFLUSH_TO_LSN FlushToLsnRoutine)
681 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
682 /* FIXME: 'captive_shared_cache_map_object->FlushToLsnRoutine_set' may be set.
683 * Does it mean 'FlushToLsnRoutine_set' is 'FileObject'-based instead of 'SharedCacheMap'-based?
686 if (!FlushToLsnRoutine)
688 g_assert(!captive_FlushToLsnRoutine || captive_FlushToLsnRoutine==FlushToLsnRoutine);
689 captive_FlushToLsnRoutine=FlushToLsnRoutine;
690 if (FlushToLsnRoutine)
691 captive_shared_cache_map_object->FlushToLsnRoutine_set=TRUE;
694 static void captive_shared_cache_map_page_write(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
697 LARGE_INTEGER offset_LargeInteger;
698 static gint64 lsn_last;
699 CaptiveSharedCacheMapObject_page *page;
701 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
702 g_return_if_fail(captive_shared_cache_map_object->FileObject!=NULL);
703 g_return_if_fail(offset<=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
704 g_return_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(offset,PAGE_SIZE));
705 page=captive_shared_cache_map_object->pages+offset/PAGE_SIZE;
706 g_return_if_fail(page->data_valid);
707 g_return_if_fail(page->dirty);
709 if (page->lsn_newest) {
711 g_assert(!lsn_last || lsn_last<=page->lsn_newest);
712 lsn_last=page->lsn_newest;
714 captive_stdcall_call_12((CaptiveStdCallFunc12)captive_FlushToLsnRoutine,
716 (gpointer)(guint32)(page->lsn_newest>> 0U), /* 'LARGE_INTEGER' argument */
717 (gpointer)(guint32)(page->lsn_newest>>32U));
720 offset_LargeInteger.QuadPart=offset;
721 captive_Cc_IoPageWrite(captive_shared_cache_map_object->FileObject,
722 captive_shared_cache_map_object->buffer+offset,PAGE_SIZE,&offset_LargeInteger);
729 typedef struct _captive_shared_cache_map_flush_lsn_sort captive_shared_cache_map_flush_lsn_sort;
730 struct _captive_shared_cache_map_flush_lsn_sort {
732 CaptiveSharedCacheMapObject *captive_shared_cache_map_object;
736 typedef struct _captive_shared_cache_map_flush_lsn_pages_foreach_param
737 captive_shared_cache_map_flush_lsn_pages_foreach_param;
738 struct _captive_shared_cache_map_flush_lsn_pages_foreach_param {
740 guint lsn_pages_count;
741 captive_shared_cache_map_flush_lsn_sort *lsn_pages_pointer; /* Not filled in if NULL */
744 static void captive_shared_cache_map_flush_lsn_pages_foreach(
745 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
746 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
747 captive_shared_cache_map_flush_lsn_pages_foreach_param *param) /* user_data */
750 CaptiveSharedCacheMapObject_page *page;
752 #if 0 /* acceleration */
753 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
754 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
755 g_return_if_fail(param!=NULL);
758 for (now=0;now<captive_shared_cache_map_object->AllocationSize;now+=PAGE_SIZE) {
759 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
760 if (!page->data_valid)
764 if (!page->lsn_newest)
766 if (page->lsn_newest>param->lsn_target)
768 param->lsn_pages_count++;
769 if (!param->lsn_pages_pointer)
771 param->lsn_pages_pointer->lsn=page->lsn_newest;
772 param->lsn_pages_pointer->captive_shared_cache_map_object=captive_shared_cache_map_object;
773 param->lsn_pages_pointer->offset=now;
774 param->lsn_pages_pointer++;
778 static int captive_shared_cache_map_flush_lsn_pages_compar
779 (const captive_shared_cache_map_flush_lsn_sort *a,const captive_shared_cache_map_flush_lsn_sort *b)
781 #if 0 /* acceleration */
782 g_return_val_if_fail(a!=NULL,0);
783 g_return_val_if_fail(b!=NULL,0);
786 return (a->lsn>b->lsn)-(b->lsn>a->lsn);
789 guint64 captive_shared_cache_map_flush(CaptiveSharedCacheMapObject *captive_shared_cache_map_object,
790 guint64 start,guint64 end)
795 captive_shared_cache_map_flush_lsn_pages_foreach_param lsn_pages_foreach_param;
796 captive_shared_cache_map_flush_lsn_sort *lsn_pages_pointer;
797 const captive_shared_cache_map_flush_lsn_sort *lsn_page;
798 guint lsn_pages_count;
800 g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),0);
801 g_return_val_if_fail(start<=end,0);
803 end=MIN(end,CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE));
805 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
806 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
809 for (now=start;now<end;now+=PAGE_SIZE) {
810 CaptiveSharedCacheMapObject_page *page;
812 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
813 if (!page->data_valid)
817 if (!page->lsn_newest)
819 if (!lsn_target || lsn_target<page->lsn_newest)
820 lsn_target=page->lsn_newest;
823 CaptiveSharedCacheMapObject_hash_init();
825 lsn_pages_foreach_param.lsn_target=lsn_target;
826 lsn_pages_foreach_param.lsn_pages_count=0;
827 lsn_pages_foreach_param.lsn_pages_pointer=NULL; /* Not yet filling */
828 g_hash_table_foreach(
829 CaptiveSharedCacheMapObject_hash, /* hash_table */
830 (GHFunc)captive_shared_cache_map_flush_lsn_pages_foreach, /* func */
831 &lsn_pages_foreach_param); /* user_data */
833 lsn_pages_count=lsn_pages_foreach_param.lsn_pages_count;
834 captive_newn(lsn_pages_pointer,lsn_pages_count);
835 g_assert(lsn_pages_foreach_param.lsn_target==lsn_target);
836 lsn_pages_foreach_param.lsn_pages_count=0;
837 lsn_pages_foreach_param.lsn_pages_pointer=lsn_pages_pointer;
838 g_hash_table_foreach(
839 CaptiveSharedCacheMapObject_hash, /* hash_table */
840 (GHFunc)captive_shared_cache_map_flush_lsn_pages_foreach, /* func */
841 &lsn_pages_foreach_param); /* user_data */
843 g_assert(lsn_pages_foreach_param.lsn_target==lsn_target);
844 g_assert(lsn_pages_foreach_param.lsn_pages_count==lsn_pages_count);
845 g_assert(lsn_pages_foreach_param.lsn_pages_pointer==lsn_pages_pointer+lsn_pages_count);
847 qsort(lsn_pages_pointer,lsn_pages_count,sizeof(*lsn_pages_pointer),
848 (int (*)(const void *,const void *))captive_shared_cache_map_flush_lsn_pages_compar);
852 for (lsn_page=lsn_pages_pointer;lsn_page<lsn_pages_pointer+lsn_pages_count;lsn_page++) {
853 captive_shared_cache_map_page_write(lsn_page->captive_shared_cache_map_object,lsn_page->offset);
854 if (lsn_page->captive_shared_cache_map_object==captive_shared_cache_map_object
855 && lsn_page->offset>=start && lsn_page->offset<end)
859 g_free(lsn_pages_pointer);
861 for (now=start;now<end;now+=PAGE_SIZE) {
862 CaptiveSharedCacheMapObject_page *page;
864 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
865 if (!page->data_valid)
869 captive_shared_cache_map_page_write(captive_shared_cache_map_object,now);
873 /* We were calling W32 code - recheck our task completion. */
874 for (now=start;now<end;now+=PAGE_SIZE) {
875 CaptiveSharedCacheMapObject_page *page;
877 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
878 if (!page->data_valid)
880 g_assert(!page->dirty);
886 static void captive_shared_cache_map_flush_all_foreach_flush(
887 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
888 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
889 gboolean user_data) /* unused */
891 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
892 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
894 captive_shared_cache_map_flush(captive_shared_cache_map_object,0,G_MAXUINT64-1); /* '-1' for overflow safety */
897 static void captive_shared_cache_map_flush_all_foreach_check(
898 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
899 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
900 gboolean user_data) /* unused */
905 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
906 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
909 end=CAPTIVE_ROUND_UP64(captive_shared_cache_map_object->AllocationSize,PAGE_SIZE);
911 start=CAPTIVE_ROUND_DOWN64(start,PAGE_SIZE);
912 end=CAPTIVE_ROUND_UP64(end,PAGE_SIZE);
914 /* We were calling W32 code - recheck our task completion. */
915 for (now=start;now<end;now+=PAGE_SIZE) {
916 CaptiveSharedCacheMapObject_page *page;
918 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
919 if (!page->data_valid)
921 g_assert(!page->dirty);
925 void captive_shared_cache_map_flush_all(void)
927 CaptiveSharedCacheMapObject_hash_init();
928 g_hash_table_foreach(
929 CaptiveSharedCacheMapObject_hash, /* hash_table */
930 (GHFunc)captive_shared_cache_map_flush_all_foreach_flush, /* func */
931 NULL); /* user_data; unused */
932 g_hash_table_foreach(
933 CaptiveSharedCacheMapObject_hash, /* hash_table */
934 (GHFunc)captive_shared_cache_map_flush_all_foreach_check, /* func */
935 NULL); /* user_data; unused */
938 static void captive_shared_cache_map_is_any_dirty_foreach(
939 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
940 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
941 gboolean *dirty_foundp) /* user_data */
945 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
946 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
947 g_return_if_fail(dirty_foundp!=NULL);
949 for (now=0;now<captive_shared_cache_map_object->AllocationSize;now+=PAGE_SIZE) {
950 CaptiveSharedCacheMapObject_page *page;
952 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
953 if (!page->data_valid)
957 *dirty_foundp=TRUE; /* FIXME: stop the traversal. */
963 gboolean captive_shared_cache_map_is_any_dirty(void)
965 gboolean dirty_found;
967 CaptiveSharedCacheMapObject_hash_init();
969 g_hash_table_foreach(
970 CaptiveSharedCacheMapObject_hash, /* hash_table */
971 (GHFunc)captive_shared_cache_map_is_any_dirty_foreach, /* func */
972 &dirty_found); /* user_data */
978 typedef struct _captive_shared_cache_map_CcGetDirtyPages_foreach_param captive_shared_cache_map_CcGetDirtyPages_foreach_param;
979 struct _captive_shared_cache_map_CcGetDirtyPages_foreach_param {
980 PDIRTY_PAGE_ROUTINE DirtyPageRoutine;
986 static void captive_shared_cache_map_CcGetDirtyPages_foreach(
987 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
988 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
989 captive_shared_cache_map_CcGetDirtyPages_foreach_param *param) /* user_data */
992 CaptiveSharedCacheMapObject_page *page;
994 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
995 g_return_if_fail(captive_shared_cache_map_object->FileObject!=NULL);
996 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
997 g_return_if_fail(param!=NULL);
999 for (now=CAPTIVE_ROUND_DOWN64(captive_shared_cache_map_object->AllocationSize-1,PAGE_SIZE);now>=0;now-=PAGE_SIZE) {
1000 LARGE_INTEGER now_LargeInteger,lsn_oldest_LargeInteger,lsn_newest_LargeInteger;
1002 page=captive_shared_cache_map_object->pages+now/PAGE_SIZE;
1003 if (!page->data_valid)
1007 if (page->lsn_oldest && (!param->result || param->result>page->lsn_oldest))
1008 param->result=page->lsn_oldest;
1010 now_LargeInteger.QuadPart=now;
1011 lsn_oldest_LargeInteger.QuadPart=page->lsn_oldest;
1012 lsn_newest_LargeInteger.QuadPart=page->lsn_newest;
1013 (*param->DirtyPageRoutine)(
1014 captive_shared_cache_map_object->FileObject, /* FileObject */
1015 &now_LargeInteger, /* FileOffset */
1016 PAGE_SIZE, /* Length */
1017 &lsn_oldest_LargeInteger, /* OldestLsn */
1018 &lsn_newest_LargeInteger, /* NewestLsn */
1019 param->Context1, /* Context1 */
1020 param->Context2); /* Context2 */
1024 gint64 captive_shared_cache_map_CcGetDirtyPages(PDIRTY_PAGE_ROUTINE DirtyPageRoutine,VOID *Context1,VOID *Context2)
1026 captive_shared_cache_map_CcGetDirtyPages_foreach_param param;
1028 g_return_val_if_fail(DirtyPageRoutine!=NULL,0);
1030 param.DirtyPageRoutine=DirtyPageRoutine;
1031 param.Context1=Context1;
1032 param.Context2=Context2;
1035 CaptiveSharedCacheMapObject_hash_init();
1036 g_hash_table_foreach(
1037 CaptiveSharedCacheMapObject_hash, /* hash_table */
1038 (GHFunc)captive_shared_cache_map_CcGetDirtyPages_foreach, /* func */
1039 ¶m); /* user_data */
1041 return param.result;
1044 gpointer captive_shared_cache_map_get_buffer(CaptiveSharedCacheMapObject *captive_shared_cache_map_object)
1046 g_return_val_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object),NULL);
1047 g_return_val_if_fail(captive_shared_cache_map_object->buffer!=NULL,NULL);
1049 return captive_shared_cache_map_object->buffer;
1052 static void captive_cc_FileObject_delete_foreach(
1053 CaptiveSharedCacheMapObject *captive_shared_cache_map_object, /* key */
1054 CaptiveSharedCacheMapObject *captive_shared_cache_map_object_value, /* value */
1055 FILE_OBJECT *FileObject) /* user_data */
1057 g_return_if_fail(CAPTIVE_SHARED_CACHE_MAP_IS_OBJECT(captive_shared_cache_map_object));
1058 g_return_if_fail(captive_shared_cache_map_object==captive_shared_cache_map_object_value);
1059 g_return_if_fail(FileObject!=NULL);
1061 g_assert(FileObject!=captive_shared_cache_map_object->FileObject);
1064 BOOLEAN captive_cc_FileObject_delete(FILE_OBJECT *FileObject)
1066 g_return_val_if_fail(FileObject!=NULL,FALSE);
1068 CaptiveSharedCacheMapObject_hash_init();
1069 g_hash_table_foreach(
1070 CaptiveSharedCacheMapObject_hash, /* hash_table */
1071 (GHFunc)captive_cc_FileObject_delete_foreach, /* func */
1072 FileObject); /* user_data */
1074 return FALSE; /* FIXME: remove useless return code. */