From 954674ddf8cb6807501e23ba7da706c72d465162 Mon Sep 17 00:00:00 2001 From: Michael Phipps Date: Mon, 6 Jan 2003 04:49:58 +0000 Subject: [PATCH] Changes to mmap to make COPY and SHARED work correctly (I hope) git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2358 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kernel/vm2/area.C | 8 ++++---- src/kernel/vm2/area.h | 4 ++-- src/kernel/vm2/areaManager.C | 14 +++++++++++--- src/kernel/vm2/vm.h | 2 ++ src/kernel/vm2/vpage.C | 35 +++++++++++++++++++++++++---------- src/kernel/vm2/vpage.h | 2 +- 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/kernel/vm2/area.C b/src/kernel/vm2/area.C index b1a797e904..9e93367275 100644 --- a/src/kernel/vm2/area.C +++ b/src/kernel/vm2/area.C @@ -53,7 +53,7 @@ unsigned long area::mapAddressSpecToAddress(addressSpec type,void * req,int page } // This is the really interesting part of creating an area -status_t area::createAreaGuts( char *inName, int pageCount, void **address, addressSpec type, pageState inState, protectType protect, bool inFinalWrite, int fd, size_t offset, area *originalArea=NULL /* For clone only*/) { +status_t area::createAreaGuts( char *inName, int pageCount, void **address, addressSpec type, pageState inState, protectType protect, bool inFinalWrite, int fd, size_t offset, area *originalArea /* For clone only*/, mmapSharing share) { error ("area::createAreaGuts : name = %s, pageCount = %d, address = %lx, addressSpec = %d, pageState = %d, protection = %d, inFinalWrite = %d, fd = %d, offset = %d,originalArea=%ld\n", inName,pageCount,address,type,inState,protect,inFinalWrite,fd,offset,originalArea); vpage *newPage; @@ -78,7 +78,7 @@ status_t area::createAreaGuts( char *inName, int pageCount, void **address, addr newVnode.fd=fd; newVnode.offset=offset; // vmBlock->vnodeManager->addVNode(newVnode,newPage); - newPage->setup(base+PAGE_SIZE*i,&newVnode,NULL,protect,inState); + newPage->setup(base+PAGE_SIZE*i,&newVnode,NULL,protect,inState,share); } else newPage->setup(base+PAGE_SIZE*i,NULL,NULL,protect,inState); @@ -99,8 +99,8 @@ status_t area::createAreaGuts( char *inName, int pageCount, void **address, addr return B_OK; } -status_t area::createAreaMappingFile(char *inName, int pageCount,void **address, addressSpec type,pageState inState,protectType protect,int fd,size_t offset) { - return createAreaGuts(inName,pageCount,address,type,inState,protect,true,fd,offset); +status_t area::createAreaMappingFile(char *inName, int pageCount,void **address, addressSpec type,pageState inState,protectType protect,int fd,size_t offset, mmapSharing share) { + return createAreaGuts(inName,pageCount,address,type,inState,protect,true,fd,offset,NULL,share); } status_t area::createArea(char *inName, int pageCount,void **address, addressSpec type,pageState inState,protectType protect) { diff --git a/src/kernel/vm2/area.h b/src/kernel/vm2/area.h index b7c3e5fe27..580f508f43 100644 --- a/src/kernel/vm2/area.h +++ b/src/kernel/vm2/area.h @@ -29,8 +29,8 @@ class area : public node area(void); void setup(areaManager *myManager); void freeArea(void); - status_t createAreaGuts( char *inName, int pageCount, void **address, addressSpec type, pageState inState, protectType protect, bool inFinalWrite, int fd, size_t offset, area *originalArea=NULL /* For clone only*/); - status_t createAreaMappingFile(char *name, int pageCount,void **address, addressSpec type,pageState state,protectType protect,int fd,size_t offset); + status_t createAreaGuts( char *inName, int pageCount, void **address, addressSpec type, pageState inState, protectType protect, bool inFinalWrite, int fd, size_t offset, area *originalArea=NULL,mmapSharing share=CLONEAREA /* For clone only*/); + status_t createAreaMappingFile(char *name, int pageCount,void **address, addressSpec type,pageState state,protectType protect,int fd,size_t offset, mmapSharing share=CLONEAREA); status_t createArea (char *name, int pageCount,void **address, addressSpec type,pageState state,protectType protect); status_t cloneArea(area *area, char *inName, void **address, addressSpec type,pageState inState,protectType protect); unsigned long mapAddressSpecToAddress(addressSpec type,void *requested,int pageCount); diff --git a/src/kernel/vm2/areaManager.C b/src/kernel/vm2/areaManager.C index 03c2563a77..72d3aa2156 100644 --- a/src/kernel/vm2/areaManager.C +++ b/src/kernel/vm2/areaManager.C @@ -285,8 +285,9 @@ void *areaManager::mmap(void *addr, size_t len, int prot, int flags, int fd, off strcpy( name,"mmap - need to include fileName"); addressSpec addType=((flags&MAP_FIXED)?EXACT:ANY); - protectType protType=(prot&PROT_WRITE)?writable:(prot&PROT_READ)?readable:none; - // Not doing anything with MAP_SHARED and MAP_COPY - needs to be done + + protectType protType; + protType=(flags&PROT_WRITE)?writable:(flags&(PROT_READ|PROT_EXEC))?readable:none; //error ("flags = %x, anon = %x\n",flags,MAP_ANON); lock(); if (flags & MAP_ANON) { @@ -294,10 +295,17 @@ void *areaManager::mmap(void *addr, size_t len, int prot, int flags, int fd, off return addr; } + int shareCount=0; + mmapSharing share; + if (flags & MAP_SHARED) { share=SHARED;shareCount++;} + if (flags & MAP_PRIVATE) { share=PRIVATE;shareCount++;} + if (flags & MAP_COPY){ share=COPY;shareCount++;} + if (shareCount!=1) + return NULL; area *newArea = new (vmBlock->areaPool->get()) area; newArea->setup(this); //error ("area = %x, start = %x\n",newArea, newArea->getStartAddress()); - newArea->createAreaMappingFile(name,(int)((len+PAGE_SIZE-1)/PAGE_SIZE),&addr,addType,LAZY,protType,fd,offset); + newArea->createAreaMappingFile(name,(int)((len+PAGE_SIZE-1)/PAGE_SIZE),&addr,addType,LAZY,protType,fd,offset,share); atomic_add(&nextAreaID,1); newArea->setAreaID(nextAreaID); addArea(newArea); diff --git a/src/kernel/vm2/vm.h b/src/kernel/vm2/vm.h index 807ecbd600..cd6a4ed72f 100644 --- a/src/kernel/vm2/vm.h +++ b/src/kernel/vm2/vm.h @@ -47,6 +47,8 @@ enum pageState {FULL,CONTIGUOUS,LAZY,NO_LOCK,LOMEM}; #define B_DMA_IO 0x00000001 #define B_READ_DEVICE 0x00000002 +enum mmapSharing {CLONEAREA,SHARED,PRIVATE,COPY}; + struct physical_entry {void *address; ulong size; }; diff --git a/src/kernel/vm2/vpage.C b/src/kernel/vm2/vpage.C index c09574fbb5..3c383dc99e 100644 --- a/src/kernel/vm2/vpage.C +++ b/src/kernel/vm2/vpage.C @@ -40,7 +40,7 @@ vpage::vpage(void) : physPage(NULL),backingNode(NULL),protection(none),dirty(fal // Does the real setup work for making a vpage. // backing and/or physMem can be NULL/0. -void vpage::setup(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state) { +void vpage::setup(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state, mmapSharing share) { // Basic setup from parameters vpage *clonedPage; // This is the page that this page is to be the clone of... error ("vpage::setup: start = %x, vnode.fd=%d, vnode.offset=%d, physMem = %x\n",start,((backing)?backing->fd:0),((backing)?backing->offset:0), ((physMem)?(physMem->getAddress()):0)); @@ -53,21 +53,35 @@ void vpage::setup(unsigned long start,vnode *backing, page *physMem,protectType end_address=start+PAGE_SIZE-1; // Set up the backing store. If one is specified, use it; if not, get a swap file page. - if (backingNode) { - clonedPage=vmBlock->vnodeMan->addVnode(*backingNode,*this); // Use the reference version which will make a new one if this one is not found - if (clonedPage) { - physPage=clonedPage->physPage; - protection=(protection<=readable)?protection: copyOnWrite; - if (clonedPage->getProtection()<=readable) - clonedPage->setProtection(copyOnWrite); + if (backingNode) { // This is an mmapped file (or a cloned area) + switch (share) { + case CLONE: // This is a cloned area + case SHARED: // This is a shared mmap + clonedPage=vmBlock->vnodeMan->addVnode(*backingNode,*this); // Use the reference version which will make a new one if this one is not found + if (clonedPage) physPage=clonedPage->physPage; + break; + case PRIVATE: // This is a one way share - we get others changes (until we make a change) but no one gets our changes + clonedPage=vmBlock->vnodeMan->addVnode(*backingNode,*this); // Use the reference version which will make a new one if this one is not found + if (clonedPage) physPage=clonedPage->physPage; + protection=(protection<=readable)?protection: copyOnWrite; + break; + case COPY: // This is not shared - get a fresh page and fresh swap file space and copy the original page + physPage=vmBlock->pageMan->getPage(); + clonedPage=vmBlock->vnodeMan->findVnode(*backing); // Find out if the page we are copying is in memory already... + if (clonedPage && clonedPage->physPage) // If it is in memory, copy its values + memcpy((void *)(physPage->getAddress()),(void *)(clonedPage->physPage->getAddress()),PAGE_SIZE); + else + refresh(); // otherwise, get a copy from disk... + backingNode=&(vmBlock->swapMan->findNode()); // Now get swap space (since we don't want to be backed by the file... + clonedPage=vmBlock->vnodeMan->addVnode(backingNode,*this); // Add this vnode to the vnode keeper + break; } } else { // Going to swap file. backingNode=&(vmBlock->swapMan->findNode()); clonedPage=vmBlock->vnodeMan->addVnode(backingNode,*this); // Use the pointer version which will use this one. Should always return NULL } - - // If there is no physical page already and we can't wait to get one, then get one now +// If there is no physical page already and we can't wait to get one, then get one now if (!physPage && (state!=LAZY) && (state!=NO_LOCK)) { physPage=vmBlock->pageMan->getPage(); error ("vpage::setup, state = %d, allocated page %x\n",state,physPage); @@ -76,6 +90,7 @@ void vpage::setup(unsigned long start,vnode *backing, page *physMem,protectType if (physPage) atomic_add(&(physPage->count),1); } + error ("vpage::setup: ended : start = %x, vnode.fd=%d, vnode.offset=%d, physMem = %x\n",start,((backing)?backing->fd:0),((backing)?backing->offset:0), ((physMem)?(physMem->getAddress()):0)); } diff --git a/src/kernel/vm2/vpage.h b/src/kernel/vm2/vpage.h index 2ccefff5f2..26bf125d3e 100644 --- a/src/kernel/vm2/vpage.h +++ b/src/kernel/vm2/vpage.h @@ -21,7 +21,7 @@ class vpage : public node vpage(void); vpage(unsigned long address) {start_address=address-address%PAGE_SIZE;end_address=start_address+PAGE_SIZE-1;} // Only for lookups // Setup should now only be called by the vpage manager... - void setup(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state); // backing and/or physMem can be NULL/0. + void setup(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state, mmapSharing share=CLONEAREA); // backing and/or physMem can be NULL/0. void cleanup(void); // Mutators