/ Check-in [e3d2be3b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add a test to ensure os_unix.c works with 64KiB OS pages.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | shm-mapping-fix
Files: files | file ages | folders
SHA1: e3d2be3ba47cdaafd26347620ae3bc2813203f16
User & Date: dan 2014-03-20 09:42:09
Context
2014-03-24
11:23
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. check-in: db7d62c8 user: dan tags: trunk
2014-03-20
09:42
Add a test to ensure os_unix.c works with 64KiB OS pages. Closed-Leaf check-in: e3d2be3b user: dan tags: shm-mapping-fix
08:59
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. check-in: 6f3a5c24 user: dan tags: shm-mapping-fix
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

   319    319   */
   320    320   static int posixFchown(int fd, uid_t uid, gid_t gid){
   321    321     return geteuid() ? 0 : fchown(fd,uid,gid);
   322    322   }
   323    323   
   324    324   /* Forward reference */
   325    325   static int openDirectory(const char*, int*);
          326  +static int unixGetpagesize(void);
   326    327   
   327    328   /*
   328    329   ** Many system calls are accessed through pointer-to-functions so that
   329    330   ** they may be overridden at runtime to facilitate fault injection during
   330    331   ** testing and sandboxing.  The following array holds the names and pointers
   331    332   ** to all overrideable system calls.
   332    333   */
................................................................................
   441    442   #if HAVE_MREMAP
   442    443     { "mremap",       (sqlite3_syscall_ptr)mremap,          0 },
   443    444   #else
   444    445     { "mremap",       (sqlite3_syscall_ptr)0,               0 },
   445    446   #endif
   446    447   #define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
   447    448   #endif
          449  +
          450  +  { "getpagesize",  (sqlite3_syscall_ptr)unixGetpagesize, 0 },
          451  +#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
   448    452   
   449    453   }; /* End of the overrideable system calls */
   450    454   
   451    455   /*
   452    456   ** This is the xSetSystemCall() method of sqlite3_vfs for all of the
   453    457   ** "unix" VFSes.  Return SQLITE_OK opon successfully updating the
   454    458   ** system call pointer, or SQLITE_NOTFOUND if there is no configurable
................................................................................
  4103   4107   #endif
  4104   4108   
  4105   4109     return rc;        
  4106   4110   }
  4107   4111   
  4108   4112   /*
  4109   4113   ** Return the system page size.
         4114  +**
         4115  +** This function should not be called directly by other code in this file. 
         4116  +** Instead, it should be called via macro osGetpagesize().
  4110   4117   */
  4111         -static int unixGetPagesize(void){
         4118  +static int unixGetpagesize(void){
  4112   4119   #if defined(_BSD_SOURCE)
  4113   4120     return getpagesize();
  4114   4121   #else
  4115   4122     return (int)sysconf(_SC_PAGESIZE);
  4116   4123   #endif
  4117   4124   }
  4118   4125   
................................................................................
  4123   4130   **
  4124   4131   ** Usually, this is 1. The exception seems to be systems that are configured
  4125   4132   ** to use 64KB pages - in this case each mapping must cover at least two
  4126   4133   ** shm regions.
  4127   4134   */
  4128   4135   static int unixShmRegionPerMap(void){
  4129   4136     int shmsz = 32*1024;            /* SHM region size */
  4130         -  int pgsz = unixGetPagesize();   /* System page size */
         4137  +  int pgsz = osGetpagesize();   /* System page size */
  4131   4138     assert( ((pgsz-1)&pgsz)==0 );   /* Page size must be a power of 2 */
  4132   4139     if( pgsz<shmsz ) return 1;
  4133   4140     return pgsz/shmsz;
  4134   4141   }
  4135   4142   
  4136   4143   /*
  4137   4144   ** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
................................................................................
  4706   4713   
  4707   4714     if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
  4708   4715   
  4709   4716     if( pOrig ){
  4710   4717   #if HAVE_MREMAP
  4711   4718       i64 nReuse = pFd->mmapSize;
  4712   4719   #else
  4713         -    const int szSyspage = unixGetPagesize();
         4720  +    const int szSyspage = osGetpagesize();
  4714   4721       i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
  4715   4722   #endif
  4716   4723       u8 *pReq = &pOrig[nReuse];
  4717   4724   
  4718   4725       /* Unmap any pages of the existing mapping that cannot be reused. */
  4719   4726       if( nReuse!=nOrig ){
  4720   4727         osMunmap(pReq, nOrig-nReuse);
................................................................................
  7454   7461       UNIXVFS("unix-proxy",    proxyIoFinder ),
  7455   7462   #endif
  7456   7463     };
  7457   7464     unsigned int i;          /* Loop counter */
  7458   7465   
  7459   7466     /* Double-check that the aSyscall[] array has been constructed
  7460   7467     ** correctly.  See ticket [bb3a86e890c8e96ab] */
  7461         -  assert( ArraySize(aSyscall)==24 );
         7468  +  assert( ArraySize(aSyscall)==25 );
  7462   7469   
  7463   7470     /* Register all VFSes defined in the aVfs[] array */
  7464   7471     for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
  7465   7472       sqlite3_vfs_register(&aVfs[i], i==0);
  7466   7473     }
  7467   7474     return SQLITE_OK; 
  7468   7475   }

Changes to src/test_syscall.c.

    63     63   **
    64     64   **   test_syscall exists SYSTEM-CALL
    65     65   **     Return true if the named system call exists. Or false otherwise.
    66     66   **
    67     67   **   test_syscall list
    68     68   **     Return a list of all system calls. The list is constructed using
    69     69   **     the xNextSystemCall() VFS method.
           70  +**
           71  +**   test_syscall pagesize PGSZ
           72  +**     If PGSZ is a power of two greater than 256, install a wrapper around
           73  +**     OS function getpagesize() that reports the system page size as PGSZ.
           74  +**     Or, if PGSZ is less than zero, remove any wrapper already installed.
    70     75   */
    71     76   
    72     77   #include "sqliteInt.h"
    73     78   #include "sqlite3.h"
    74     79   #include "tcl.h"
    75     80   #include <stdlib.h>
    76     81   #include <string.h>
................................................................................
    85     90   #include <sys/types.h>
    86     91   #include <errno.h>
    87     92   
    88     93   static struct TestSyscallGlobal {
    89     94     int bPersist;                   /* 1 for persistent errors, 0 for transient */
    90     95     int nCount;                     /* Fail after this many more calls */
    91     96     int nFail;                      /* Number of failures that have occurred */
    92         -} gSyscall = { 0, 0 };
           97  +  int pgsz;
           98  +  sqlite3_syscall_ptr orig_getpagesize;
           99  +} gSyscall = { 0, 0, 0, 0, 0 };
    93    100   
    94    101   static int ts_open(const char *, int, int);
    95    102   static int ts_close(int fd);
    96    103   static int ts_access(const char *zPath, int mode);
    97    104   static char *ts_getcwd(char *zPath, size_t nPath);
    98    105   static int ts_stat(const char *zPath, struct stat *p);
    99    106   static int ts_fstat(int fd, struct stat *p);
................................................................................
   645    652       return TCL_ERROR;
   646    653     }
   647    654   
   648    655     pVfs = sqlite3_vfs_find(0);
   649    656     Tcl_SetObjResult(interp, Tcl_NewStringObj(pVfs->zName, -1));
   650    657     return TCL_OK;
   651    658   }
          659  +
          660  +static int ts_getpagesize(void){
          661  +  return gSyscall.pgsz;
          662  +}
          663  +
          664  +static int test_syscall_pagesize(
          665  +  void * clientData,
          666  +  Tcl_Interp *interp,
          667  +  int objc,
          668  +  Tcl_Obj *CONST objv[]
          669  +){
          670  +  sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
          671  +  int pgsz;
          672  +  if( objc!=3 ){
          673  +    Tcl_WrongNumArgs(interp, 2, objv, "PGSZ");
          674  +    return TCL_ERROR;
          675  +  }
          676  +  if( Tcl_GetIntFromObj(interp, objv[2], &pgsz) ){
          677  +    return TCL_ERROR;
          678  +  }
          679  +
          680  +  if( pgsz<0 ){
          681  +    if( gSyscall.orig_getpagesize ){
          682  +      pVfs->xSetSystemCall(pVfs, "getpagesize", gSyscall.orig_getpagesize);
          683  +    }
          684  +  }else{
          685  +    if( pgsz<512 || (pgsz & (pgsz-1)) ){
          686  +      Tcl_AppendResult(interp, "pgsz out of range", 0);
          687  +      return TCL_ERROR;
          688  +    }
          689  +    gSyscall.orig_getpagesize = pVfs->xGetSystemCall(pVfs, "getpagesize");
          690  +    gSyscall.pgsz = pgsz;
          691  +    pVfs->xSetSystemCall(
          692  +        pVfs, "getpagesize", (sqlite3_syscall_ptr)ts_getpagesize
          693  +    );
          694  +  }
          695  +
          696  +  return TCL_OK;
          697  +}
   652    698   
   653    699   static int test_syscall(
   654    700     void * clientData,
   655    701     Tcl_Interp *interp,
   656    702     int objc,
   657    703     Tcl_Obj *CONST objv[]
   658    704   ){
................................................................................
   664    710       { "install",    test_syscall_install },
   665    711       { "uninstall",  test_syscall_uninstall },
   666    712       { "reset",      test_syscall_reset },
   667    713       { "errno",      test_syscall_errno },
   668    714       { "exists",     test_syscall_exists },
   669    715       { "list",       test_syscall_list },
   670    716       { "defaultvfs", test_syscall_defaultvfs },
          717  +    { "pagesize",   test_syscall_pagesize },
   671    718       { 0, 0 }
   672    719     };
   673    720     int iCmd;
   674    721     int rc;
   675    722   
   676    723     if( objc<2 ){
   677    724       Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");

Changes to test/syscall.test.

    57     57   # Tests for the xNextSystemCall method.
    58     58   #
    59     59   foreach s {
    60     60       open close access getcwd stat fstat ftruncate
    61     61       fcntl read pread write pwrite fchmod fallocate
    62     62       pread64 pwrite64 unlink openDirectory mkdir rmdir 
    63     63       statvfs fchown umask mmap munmap mremap
           64  +    getpagesize
    64     65   } {
    65     66     if {[test_syscall exists $s]} {lappend syscall_list $s}
    66     67   }
    67     68   do_test 3.1 { lsort [test_syscall list] } [lsort $syscall_list]
    68     69   
    69     70   #-------------------------------------------------------------------------
    70     71   # This test verifies that if a call to open() fails and errno is set to

Added test/wal64k.test.

            1  +# 2010 April 13
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this file is testing the operation of the library in
           13  +# "PRAGMA journal_mode=WAL" mode.
           14  +#
           15  +
           16  +set testdir [file dirname $argv0]
           17  +source $testdir/tester.tcl
           18  +set testprefix wal64k
           19  +
           20  +ifcapable !wal {finish_test ; return }
           21  +
           22  +db close
           23  +test_syscall pagesize 65536
           24  +sqlite3 db test.db
           25  +
           26  +do_execsql_test 1.0 { 
           27  +  PRAGMA journal_mode = WAL;
           28  +  CREATE TABLE t1(x);
           29  +  CREATE INDEX i1 ON t1(x);
           30  +} {wal}
           31  +do_test 1.1 { file size test.db-shm } {65536}
           32  +
           33  +do_test 1.2 {
           34  +  execsql BEGIN
           35  +  while {[file size test.db-shm]==65536} {
           36  +    execsql { INSERT INTO t1 VALUES( randstr(900,1100) ) }
           37  +  }
           38  +  execsql COMMIT
           39  +  file size test.db-shm
           40  +} {131072}
           41  +
           42  +integrity_check 1.3
           43  +
           44  +db close
           45  +test_syscall pagesize -1
           46  +finish_test
           47  +