guix-play/gnu/packages/patches/sqlite-large-page-size-fix.patch
Mark H Weaver 8ead71b4b0 gnu: sqlite: Fix sqlite on systems with page size larger than 32K.
Based on a patch by Dan Kennedy <danielk1977@gmail.com>.

* gnu/packages/patches/sqlite-large-page-size-fix.patch: New file.
* gnu/packages/sqlite.scm (sqlite): Add it.
* gnu-system.am (dist_patch_DATA): Add it.
2014-04-02 15:31:28 -04:00

181 lines
5.4 KiB
Diff

Add an experimental fix to avoid attempting to mmap memory from an
offset that is not a multiple of the system page size on systems with
page sizes larger than 32KB.
Patch by Dan Kennedy <danielk1977@gmail.com>.
--- sqlite-autoconf/sqlite3.c.orig 2014-03-22 23:44:47.055908203 -0400
+++ sqlite-autoconf/sqlite3.c 2014-03-22 23:44:06.716552734 -0400
@@ -24010,6 +24010,7 @@
/* Forward reference */
static int openDirectory(const char*, int*);
+static int unixGetpagesize(void);
/*
** Many system calls are accessed through pointer-to-functions so that
@@ -24133,6 +24134,9 @@
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
#endif
+ { "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
+#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
+
}; /* End of the overrideable system calls */
/*
@@ -27792,6 +27796,36 @@
return rc;
}
+/*
+** Return the system page size.
+**
+** This function should not be called directly by other code in this file.
+** Instead, it should be called via macro osGetpagesize().
+*/
+static int unixGetpagesize(void){
+#if defined(_BSD_SOURCE)
+ return getpagesize();
+#else
+ return (int)sysconf(_SC_PAGESIZE);
+#endif
+}
+
+/*
+** Return the minimum number of 32KB shm regions that should be mapped at
+** a time, assuming that each mapping must be an integer multiple of the
+** current system page-size.
+**
+** Usually, this is 1. The exception seems to be systems that are configured
+** to use 64KB pages - in this case each mapping must cover at least two
+** shm regions.
+*/
+static int unixShmRegionPerMap(void){
+ int shmsz = 32*1024; /* SHM region size */
+ int pgsz = osGetpagesize(); /* System page size */
+ assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */
+ if( pgsz<shmsz ) return 1;
+ return pgsz/shmsz;
+}
/*
** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
@@ -27803,10 +27837,11 @@
unixShmNode *p = pFd->pInode->pShmNode;
assert( unixMutexHeld() );
if( p && p->nRef==0 ){
+ int nShmPerMap = unixShmRegionPerMap();
int i;
assert( p->pInode==pFd->pInode );
sqlite3_mutex_free(p->mutex);
- for(i=0; i<p->nRegion; i++){
+ for(i=0; i<p->nRegion; i+=nShmPerMap){
if( p->h>=0 ){
osMunmap(p->apRegion[i], p->szRegion);
}else{
@@ -28013,6 +28048,8 @@
unixShm *p;
unixShmNode *pShmNode;
int rc = SQLITE_OK;
+ int nShmPerMap = unixShmRegionPerMap();
+ int nReqRegion;
/* If the shared-memory file has not yet been opened, open it now. */
if( pDbFd->pShm==0 ){
@@ -28028,9 +28065,12 @@
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
- if( pShmNode->nRegion<=iRegion ){
+ /* Minimum number of regions required to be mapped. */
+ nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
+
+ if( pShmNode->nRegion<nReqRegion ){
char **apNew; /* New apRegion[] array */
- int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
+ int nByte = nReqRegion*szRegion; /* Minimum required file size */
struct stat sStat; /* Used by fstat() */
pShmNode->szRegion = szRegion;
@@ -28079,17 +28119,19 @@
/* Map the requested memory region into this processes address space. */
apNew = (char **)sqlite3_realloc(
- pShmNode->apRegion, (iRegion+1)*sizeof(char *)
+ pShmNode->apRegion, nReqRegion*sizeof(char *)
);
if( !apNew ){
rc = SQLITE_IOERR_NOMEM;
goto shmpage_out;
}
pShmNode->apRegion = apNew;
- while(pShmNode->nRegion<=iRegion){
+ while( pShmNode->nRegion<nReqRegion ){
+ int nMap = szRegion*nShmPerMap;
+ int i;
void *pMem;
if( pShmNode->h>=0 ){
- pMem = osMmap(0, szRegion,
+ pMem = osMmap(0, nMap,
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
);
@@ -28105,8 +28147,11 @@
}
memset(pMem, 0, szRegion);
}
- pShmNode->apRegion[pShmNode->nRegion] = pMem;
- pShmNode->nRegion++;
+
+ for(i=0; i<nShmPerMap; i++){
+ pShmNode->apRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i];
+ }
+ pShmNode->nRegion += nShmPerMap;
}
}
@@ -28321,19 +28366,6 @@
}
/*
-** Return the system page size.
-*/
-static int unixGetPagesize(void){
-#if HAVE_MREMAP
- return 512;
-#elif defined(_BSD_SOURCE)
- return getpagesize();
-#else
- return (int)sysconf(_SC_PAGESIZE);
-#endif
-}
-
-/*
** Attempt to set the size of the memory mapping maintained by file
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
**
@@ -28369,8 +28401,12 @@
if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
if( pOrig ){
- const int szSyspage = unixGetPagesize();
+#if HAVE_MREMAP
+ i64 nReuse = pFd->mmapSize;
+#else
+ const int szSyspage = osGetpagesize();
i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
+#endif
u8 *pReq = &pOrig[nReuse];
/* Unmap any pages of the existing mapping that cannot be reused. */
@@ -31116,7 +31152,7 @@
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==24 );
+ assert( ArraySize(aSyscall)==25 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){