#include <unistd.h>
#include <glib/glist.h>
#include "reactos/internal/io.h" /* for IoSynchronousPageWrite() */
-#include <glib/garray.h>
#include <glib/gmain.h>
#include "captive/leave.h"
#include <glib/gtree.h>
LARGE_INTEGER FileOffset; /* always PAGE_SIZE aligned */
int shmid;
GList *privbcb_list; /* each mapped page has its one private_bcb */
+ gboolean building; /* data are not yet read; prevention for CcMapData() reentrancy */
};
/* map: (struct page_position *)pagepos -> (struct page_position *)pagepos */
IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN ULONG Flags,OUT PVOID *Bcb,OUT PVOID *Buffer)
{
PUBLIC_BCB **PublicBcbp,*PublicBcb;
-struct page_position pagepos_local,*pagepos;
+struct page_position pagepos_local;
LARGE_INTEGER FileOffset_bottom,FileOffset_top;
gpointer base_aligned;
-size_t offset,length_mapped_aligned;
+size_t length_mapped_aligned;
+gint length_pages_aligned;
+struct page_position **pagepos_array;
int errint;
gpointer errptr;
struct private_bcb *privbcb;
gboolean after_eof=FALSE; /* Did we reached the end of file already? */
-GPtrArray *read_array;
g_return_val_if_fail(FileObject!=NULL,FALSE);
g_return_val_if_fail(FileOffset!=NULL,FALSE);
FileOffset_bottom.QuadPart=CAPTIVE_ROUND_DOWN64(FileOffset->QuadPart,PAGE_SIZE);
FileOffset_top.QuadPart=CAPTIVE_ROUND_UP64(FileOffset->QuadPart+Length,PAGE_SIZE);
length_mapped_aligned=(FileOffset_top.QuadPart-FileOffset_bottom.QuadPart);
+ g_assert(0==CAPTIVE_ROUND_DOWN_EXCEEDING(length_mapped_aligned,PAGE_SIZE));
+ length_pages_aligned=length_mapped_aligned/PAGE_SIZE;
/* We can be called as full CcMapData() (e.g. CcPinRead() from fastfat.sys)
* even if such mapping for such file already exists.
/* We MUST NOT call captive_Cc_IoPageRead() inside our pagepos filling loop
* below as captive_Cc_IoPageRead() has very big consequences as it calls
* the filesystem code and we may get reentrancy.
- * Therefore we store all missing page read requests to 'read_array' and we
+ * Therefore we store all missing page read requests to 'pagepos_array' and we
* fill them when all the memory structures are in consistent state.
* We can also coalescence the requests more easily this way.
*/
- read_array=g_ptr_array_new();
+ captive_newn_alloca(pagepos_array,length_pages_aligned);
pagepos_local.FileObject=FileObject;
pagepos_local.shmid=-1;
pagepos_local.privbcb_list=NULL;
- for (
- offset=0;
- offset<length_mapped_aligned;
- offset+=PAGE_SIZE) {
+ {
+size_t offset;
+
+ for (
+ offset=0;
+ offset<length_mapped_aligned;
+ offset+=PAGE_SIZE) {
gpointer pageaddr;
+struct page_position *pagepos;
- pagepos_local.FileOffset.QuadPart=FileOffset_bottom.QuadPart+offset;
- pageaddr=(gpointer)(((char *)base_aligned)+offset);
- if (!(pagepos=g_hash_table_lookup(page_position_hash,&pagepos_local))) {
- captive_new(pagepos);
- *pagepos=pagepos_local;
- pagepos->shmid=-1;
- pagepos->privbcb_list=NULL;
- g_ptr_array_add(read_array,pagepos); /* enlist this 'pagepos' as todo read item */
- g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: read of offset %llu to new pagepos %p of pure mmap() to address %p",
- G_STRLOC,(unsigned long long)offset,pagepos,pageaddr);
- }
- else if (pagepos->privbcb_list->next==NULL) { /* exactly one item (no IPC shm yet) */
- g_assert(pagepos->shmid==-1);
- if (-1==(pagepos->shmid=shmget(IPC_PRIVATE,PAGE_SIZE,IPC_CREAT|IPC_CREAT|0600)))
- g_error("%s: Failed shmget(2), you may be out of maximum system IPC shared pages",G_STRLOC);
- g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: created shmid %d out of mmap() for offset %llu to existing pagepos %p to address %p",
- G_STRLOC,pagepos->shmid,(unsigned long long)offset,pagepos,pageaddr);
- }
- else { /* already >=2 mappings, already IPC shared mem */
- g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: already shared shmid of offset %llu by existing pagepos %p shmid %d to address %p",
- G_STRLOC,(unsigned long long)offset,pagepos,pagepos->shmid,pageaddr);
- g_assert(pagepos->shmid!=-1);
- g_assert(pagepos->privbcb_list!=NULL);
- }
- if (pagepos->privbcb_list) { /* Not the first one - some shm in use now? */
- /* It appears as shmat(2) cannot override previously mmap(2)ed memory;
- * mmap(2) is still needed to get linear block of memory assignment.
- */
- /* TODO:thread; munmap()..shmat() window */
- errint=munmap(pageaddr,PAGE_SIZE);
- g_assert(errint==0);
- errptr=shmat(pagepos->shmid,
- pageaddr, /* shmaddr */
- 0); /* shmflg; !SHM_RDONLY==r/w */
- g_assert(errptr==pageaddr);
- }
+ pagepos_local.FileOffset.QuadPart=FileOffset_bottom.QuadPart+offset;
+ pageaddr=(gpointer)(((char *)base_aligned)+offset);
+ if (!(pagepos=g_hash_table_lookup(page_position_hash,&pagepos_local))) {
+ captive_new(pagepos);
+ *pagepos=pagepos_local;
+ pagepos->shmid=-1;
+ pagepos->privbcb_list=NULL;
+ pagepos->building=TRUE;
+ g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: read of offset %llu to new pagepos %p of pure mmap() to address %p",
+ G_STRLOC,(unsigned long long)offset,pagepos,pageaddr);
+ }
+ else if (pagepos->privbcb_list->next==NULL) { /* exactly one item (no IPC shm yet) */
+ g_assert(pagepos->shmid==-1);
+ if (-1==(pagepos->shmid=shmget(IPC_PRIVATE,PAGE_SIZE,IPC_CREAT|IPC_CREAT|0600)))
+ g_error("%s: Failed shmget(2), you may be out of maximum system IPC shared pages",G_STRLOC);
+ g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: created shmid %d out of mmap() for offset %llu to existing pagepos %p to address %p",
+ G_STRLOC,pagepos->shmid,(unsigned long long)offset,pagepos,pageaddr);
+ /* Reentrancy occured? */
+ g_assert(!pagepos->building);
+ }
+ else { /* already >=2 mappings, already IPC shared mem */
+ g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: already shared shmid of offset %llu by existing pagepos %p shmid %d to address %p",
+ G_STRLOC,(unsigned long long)offset,pagepos,pagepos->shmid,pageaddr);
+ g_assert(pagepos->shmid!=-1);
+ g_assert(pagepos->privbcb_list!=NULL);
+ /* Reentrancy occured? */
+ g_assert(!pagepos->building);
+ }
+ pagepos_array[offset/PAGE_SIZE]=pagepos;
+ if (pagepos->privbcb_list) { /* Not the first one - some shm in use now? */
+ /* It appears as shmat(2) cannot override previously mmap(2)ed memory;
+ * mmap(2) is still needed to get linear block of memory assignment.
+ */
+ /* TODO:thread; munmap()..shmat() window */
+ errint=munmap(pageaddr,PAGE_SIZE);
+ g_assert(errint==0);
+ errptr=shmat(pagepos->shmid,
+ pageaddr, /* shmaddr */
+ 0); /* shmflg; !SHM_RDONLY==r/w */
+ g_assert(errptr==pageaddr);
+ }
- g_assert(g_list_find(pagepos->privbcb_list,privbcb)==NULL);
- pagepos->privbcb_list=g_list_prepend(pagepos->privbcb_list,privbcb); /* order not important */
- g_assert(g_list_find(pagepos->privbcb_list,privbcb)!=NULL);
- if (pagepos->privbcb_list->next==NULL) { /* exactly one item (we just added it now) */
+ g_assert(g_list_find(pagepos->privbcb_list,privbcb)==NULL);
+ pagepos->privbcb_list=g_list_prepend(pagepos->privbcb_list,privbcb); /* order not important */
+ g_assert(g_list_find(pagepos->privbcb_list,privbcb)!=NULL);
+ if (pagepos->privbcb_list->next==NULL) { /* exactly one item (we just added it now) */
- g_assert(pagepos->shmid==-1);
- g_hash_table_insert(page_position_hash,
- pagepos, /* key */
- pagepos); /* value */
- }
- else if (pagepos->privbcb_list->next->next==NULL) { /* second mapping - new shm */
+ g_assert(pagepos->shmid==-1);
+ g_hash_table_insert(page_position_hash,
+ pagepos, /* key */
+ pagepos); /* value */
+ }
+ else if (pagepos->privbcb_list->next->next==NULL) { /* second mapping - new shm */
struct private_bcb *privbcb_orig;
gint64 privbcb_orig_offset_relative;
gpointer mapped_orig;
- g_assert(pagepos->shmid!=-1);
- errint=shmctl(pagepos->shmid,
- IPC_RMID, /* cmd */
- NULL); /* buf */
- g_assert(errint==0);
- g_assert(pagepos->privbcb_list->data==privbcb); /* our privbcb should be the first */
- g_assert(pagepos->privbcb_list->next!=NULL); /* we have exactly two items in the list */
- g_assert(pagepos->privbcb_list->next->next==NULL); /* we have exactly two items in the list */
- privbcb_orig=pagepos->privbcb_list->next->data;
- privbcb_orig_offset_relative=pagepos->FileOffset.QuadPart-privbcb_orig->MappedFileOffset.QuadPart;
- /* privbcb_orig_offset_relative may be negative up to -PAGE_SIZE
- * as 'MappedFileOffset' and 'base' are not page-aligned.
- */
- mapped_orig=privbcb_orig->base+privbcb_orig_offset_relative;
- memcpy(pageaddr,mapped_orig,PAGE_SIZE);
- /* TODO:thread; munmap()..shmat() window */
- errint=munmap(mapped_orig,PAGE_SIZE);
- g_assert(errint==0);
- errptr=shmat(pagepos->shmid,
- mapped_orig, /* shmaddr */
- 0); /* shmflg; !SHM_RDONLY==r/w */
- g_assert(errptr==mapped_orig);
+ g_assert(pagepos->shmid!=-1);
+ errint=shmctl(pagepos->shmid,
+ IPC_RMID, /* cmd */
+ NULL); /* buf */
+ g_assert(errint==0);
+ g_assert(pagepos->privbcb_list->data==privbcb); /* our privbcb should be the first */
+ g_assert(pagepos->privbcb_list->next!=NULL); /* we have exactly two items in the list */
+ g_assert(pagepos->privbcb_list->next->next==NULL); /* we have exactly two items in the list */
+ privbcb_orig=pagepos->privbcb_list->next->data;
+ privbcb_orig_offset_relative=pagepos->FileOffset.QuadPart-privbcb_orig->MappedFileOffset.QuadPart;
+ /* privbcb_orig_offset_relative may be negative up to -PAGE_SIZE
+ * as 'MappedFileOffset' and 'base' are not page-aligned.
+ */
+ mapped_orig=privbcb_orig->base+privbcb_orig_offset_relative;
+ memcpy(pageaddr,mapped_orig,PAGE_SIZE);
+ /* TODO:thread; munmap()..shmat() window */
+ errint=munmap(mapped_orig,PAGE_SIZE);
+ g_assert(errint==0);
+ errptr=shmat(pagepos->shmid,
+ mapped_orig, /* shmaddr */
+ 0); /* shmflg; !SHM_RDONLY==r/w */
+ g_assert(errptr==mapped_orig);
+ }
+ g_assert(validate_page_position(pagepos));
}
- g_assert(validate_page_position(pagepos));
}
- /* Fill in the missing pages content todo-list stored in 'read_array': */
- while (!(Flags&MAP_NO_READ) && read_array->len && (pagepos=g_ptr_array_remove_index(read_array,
- 0))) { /* index */
-ULONG read_size;
+ /* Fill in the missing pages content todo-list by stored 'pagepos_array' '->building' flags: */
+ if (!(Flags&MAP_NO_READ)) {
+size_t offset_start,offset_end;
+
+ for (
+ offset_start=0;
+ offset_start<length_mapped_aligned;
+ offset_start=offset_end) {
+struct page_position *pagepos_start;
+size_t offset_built;
+gpointer pageaddr;
ULONG got;
-struct pagepos *pagepos_next;
-gpointer pageaddr,pageaddr_next;
-
- pageaddr=(gpointer)(((char *)base_aligned)+(pagepos->FileOffset.QuadPart-FileOffset_bottom.QuadPart));
- read_size=PAGE_SIZE;
- /* Coalescence of the requests */
- while (read_array->len) {
- pagepos_next=g_ptr_array_index(read_array,
- 0); /* index */
- pageaddr_next=(gpointer)(((char *)base_aligned)+(pagepos->FileOffset.QuadPart-FileOffset_bottom.QuadPart));
- if (pageaddr_next!=((char *)pageaddr)+read_size)
- break;
- read_size+=PAGE_SIZE;
- g_assert(pagepos_next==g_ptr_array_remove_index(read_array,
- 0)); /* index */
+
+ offset_end=offset_start+PAGE_SIZE;
+ pagepos_start=pagepos_array[offset_start/PAGE_SIZE];
+ if (!pagepos_start->building)
+ continue;
+ g_assert(offset_start==pagepos_start->FileOffset.QuadPart-FileOffset_bottom.QuadPart);
+ pageaddr=(gpointer)(((char *)base_aligned)+offset_start);
+ /* Coalescence of the requests. */
+ for (
+ offset_end=offset_start+PAGE_SIZE;
+ offset_end<length_mapped_aligned;
+ offset_end+=PAGE_SIZE) {
+struct page_position *pagepos_end;
+
+ pagepos_end=pagepos_array[offset_end/PAGE_SIZE];
+ g_assert(offset_end==pagepos_end->FileOffset.QuadPart-FileOffset_bottom.QuadPart);
+ if (!pagepos_end->building)
+ break;
+ }
+ /* Read the range content: */
+ got=captive_Cc_IoPageRead(FileObject,pageaddr,offset_end-offset_start,&pagepos_start->FileOffset);
+ if (after_eof)
+ g_assert(got==0);
+ else
+ g_assert(got<=PAGE_SIZE);
+ after_eof=(got<PAGE_SIZE);
+ /* Unmark 'building' flags. */
+ for (
+ offset_built=offset_start;
+ offset_built<offset_end;
+ offset_built+=PAGE_SIZE) {
+struct page_position *pagepos_built;
+
+ pagepos_built=pagepos_array[offset_built/PAGE_SIZE];
+ g_assert(offset_built==pagepos_built->FileOffset.QuadPart-FileOffset_bottom.QuadPart);
+ g_assert(pagepos_built->building==TRUE);
+ pagepos_built->building=FALSE;
+ }
}
- /* Read the range content: */
- got=captive_Cc_IoPageRead(FileObject,pageaddr,read_size,&pagepos->FileOffset);
- if (after_eof)
- g_assert(got==0);
- else
- g_assert(got<=PAGE_SIZE);
- after_eof=(got<PAGE_SIZE);
}
- g_ptr_array_free(read_array,
- TRUE); /* free_seg; free the array of gpointer(==struct pagepos *) items */
/* offset _into_ page, may not be PAGE_SIZE aligned: */
*Buffer=privbcb->base;