CcMapData(): +protection agains function reentrancy (pagepos 'building' flag)
authorshort <>
Sun, 13 Jul 2003 22:00:26 +0000 (22:00 +0000)
committershort <>
Sun, 13 Jul 2003 22:00:26 +0000 (22:00 +0000)
 - currently not reentrant, probably cured by MAP_NO_READ implementation

src/libcaptive/cc/map.c

index 057b065..570edab 100644 (file)
@@ -33,7 +33,6 @@
 #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>
@@ -227,6 +226,7 @@ struct page_position {
        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 */
@@ -826,15 +826,16 @@ BOOLEAN CcMapData(IN PFILE_OBJECT FileObject,
                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);
@@ -879,6 +880,8 @@ GPtrArray *read_array;
        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.
@@ -938,130 +941,161 @@ GPtrArray *read_array;
        /* 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;