In addition to the functionality in the previous patch, this patch
includes a new function testProcessLockingBehavior(), which is
conceptually similar to testThreadLockingBehavior but using fork()
instead of pthread_create().

This might sound obvious: lock the first byte of a file, fork() a
child, and have the child attempt to lock that same byte -- this
should always fail.  Unfortunately all currently-deployed non-Linux
AFS clients will actually "grant" locks to both processes.

The added code checks for this behavior empirically before proceeding
with posixLockingStyle.  If nonsensical behavior is observed, it
automatically falls back to whole-file locks.

  - a


Index: configure.ac
===================================================================
RCS file: /sqlite/sqlite/configure.ac,v
retrieving revision 1.26
diff -B -u -b -r1.26 configure.ac
--- configure.ac        3 Jun 2006 18:02:18 -0000       1.26
+++ configure.ac        26 Dec 2006 01:25:40 -0000
@@ -318,6 +318,21 @@
 AC_SUBST(XTHREADCONNECT)
 
 ##########
+# Do we want to allow different locking styles?
+#
+AC_ARG_ENABLE(locking-style, 
+AC_HELP_STRING([--enable-locking-style],[Enable different locking 
styles]),,enable_lockingstyle=no)
+AC_MSG_CHECKING([whether to allow connections to be shared across threads])
+if test "$enable_lockingstyle" = "no"; then
+  ENABLELOCKINGSTYLE=''
+  AC_MSG_RESULT([no])
+else
+  ENABLELOCKINGSTYLE='-DSQLITE_ENABLE_LOCKING_STYLE=1'
+  AC_MSG_RESULT([yes])
+fi
+AC_SUBST(ENABLELOCKINGSTYLE)
+
+##########
 # Do we want to set threadsOverrideEachOthersLocks variable to be 1 (true) by
 # default. Normally, a test at runtime is performed to determine the
 # appropriate value of this variable. Use this option only if you're sure that
@@ -673,7 +688,35 @@
 # Redefine fdatasync as fsync on systems that lack fdatasync
 #--------------------------------------------------------------------
 
+AC_CHECK_HEADER([sys/statfs.h], [TARGET_CFLAGS="$TARGET_CFLAGS 
-DHAVE_SYS_STATFS_H=1"],)
+
 AC_CHECK_FUNC(fdatasync, [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_FDATASYNC=1"])
+AC_CHECK_FUNC(fsctl, [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_FSCTL=1"])
+
+AC_CHECK_MEMBER(struct statfs.f_flags,
+  [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_STATFS_F_FLAGS=1"],,
+  [
+    #include <sys/ioctl.h>
+    #include <sys/param.h>
+    #include <sys/mount.h>
+  ])
+
+AC_CHECK_MEMBER(struct statfs.f_type,
+  [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_STATFS_F_TYPE=1"],,
+  [
+    #include <sys/ioctl.h>
+    #include <sys/statfs.h>
+    #include <sys/param.h>
+    #include <sys/mount.h>
+  ])
+
+AC_CHECK_MEMBER(struct statfs.f_fstypename,
+  [TARGET_CFLAGS="$TARGET_CFLAGS -DHAVE_STATFS_F_FSTYPENAME=1"],,
+  [
+    #include <sys/ioctl.h>
+    #include <sys/param.h>
+    #include <sys/mount.h>
+  ])
 
 #########
 # Put out accumulated miscellaneous LIBRARIES
Index: Makefile.in
===================================================================
RCS file: /sqlite/sqlite/Makefile.in,v
retrieving revision 1.160
diff -B -u -b -r1.160 Makefile.in
--- Makefile.in 21 Dec 2006 22:38:23 -0000      1.160
+++ Makefile.in 26 Dec 2006 01:25:40 -0000
@@ -32,7 +32,7 @@
 # Omitting the define will cause extra debugging code to be inserted and
 # includes extra comments when "EXPLAIN stmt" is used.
 #
-TCC += @TARGET_DEBUG@ @XTHREADCONNECT@
+TCC += @TARGET_DEBUG@ @XTHREADCONNECT@ @ENABLELOCKINGSTYLE@
 
 # Compiler options needed for programs that use the TCL library.
 #
Index: src/os_unix.c
===================================================================
RCS file: /sqlite/sqlite/src/os_unix.c,v
retrieving revision 1.114
diff -B -u -b -r1.114 os_unix.c
--- src/os_unix.c       21 Dec 2006 01:29:23 -0000      1.114
+++ src/os_unix.c       26 Dec 2006 01:25:41 -0000
@@ -52,6 +52,9 @@
 #ifdef SQLITE_ENABLE_LOCKING_STYLE
 #include <sys/ioctl.h>
 #include <sys/param.h>
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif /* HAVE_SYS_STATFS_H */
 #include <sys/mount.h>
 #endif /* SQLITE_ENABLE_LOCKING_STYLE */
 
@@ -479,6 +482,52 @@
 #define fcntl lockTrace
 #endif /* SQLITE_LOCK_TRACE */
 
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+/**
+ *  Check to see if the OS fcntl() byte-range locking call will "lie"
+ *  to us and grant a lock that is not enforced.  This happens notably
+ *  with files in AFS (OpenAFS client <1.5.0, all OSes but Linux).
+ *
+ *  Returns zero if byte-range locks appear to work as expected.
+ */
+static int testProcessLockingBehavior(int fd_orig){
+  int fd;
+  int result;
+  struct flock lock;
+  
+  fd = dup(fd_orig);
+  if( fd<0 ) return 1;
+  memset(&lock, 0, sizeof(struct flock));
+  lock.l_type = F_WRLCK;
+  lock.l_len = 1;
+  lock.l_start = 0;
+  lock.l_whence = SEEK_SET;
+  
+  result = fcntl(fd, F_SETLK, &lock);
+  if (result) {
+    TRACE1("testProcessLockingBehavior(): initial lock in parent failed\n");
+    close(fd);
+    return 1;
+  }
+  
+  if (fork()==0) {
+    result = fcntl(fd, F_SETLK, &lock);
+    exit(result);
+    
+  } else {
+    wait(&result);
+    if (!result) {
+      TRACE1("testProcessLockingBehavior(): parent and child both got 
locks\n");
+      close(fd);
+      return 1;
+    }
+  }
+  
+  close(fd);
+  return 0;
+}
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
 /*
 ** The testThreadLockingBehavior() routine launches two separate
 ** threads on this routine.  This routine attempts to lock a file
@@ -587,15 +636,18 @@
 
 #ifdef SQLITE_FIXED_LOCKING_STYLE
   return (sqlite3LockingStyle)SQLITE_FIXED_LOCKING_STYLE;
-#else
+#else /*  SQLITE_FIXED_LOCKING_STYLE */
   struct statfs fsInfo;
 
   if (statfs(filePath, &fsInfo) == -1)
     return sqlite3TestLockingStyle(filePath, fd);
   
+#ifdef HAVE_STATFS_F_FLAGS
   if (fsInfo.f_flags & MNT_RDONLY)
     return noLockingStyle;
+#endif /* HAVE_STATFS_F_FLAGS */
   
+#ifdef HAVE_STATFS_F_FSTYPENAME
   if( (!strcmp(fsInfo.f_fstypename, "hfs")) ||
     (!strcmp(fsInfo.f_fstypename, "ufs")) )
                return posixLockingStyle;
@@ -609,14 +661,40 @@
   if(!strcmp(fsInfo.f_fstypename, "smbfs"))
     return flockLockingStyle;
   
+  if(!strcmp(fsInfo.f_fstypename, "afs"))
+    return flockLockingStyle;
+
   if(!strcmp(fsInfo.f_fstypename, "msdos"))
     return dotlockLockingStyle;
   
   if(!strcmp(fsInfo.f_fstypename, "webdav"))
     return unsupportedLockingStyle;
+#else /* HAVE_STATFS_F_FSTYPENAME */
+# ifdef HAVE_STATFS_F_TYPE
+  switch(fsInfo.f_type) {
+    case 0x4d44:     // DOS/FAT
+      return dotlockLockingStyle;
+      
+    case 0x6969:     // NFS
+    case 0x564c:     // Netware NCPFS
+      return sqlite3TestLockingStyle(filePath, fd);
+
+    case 0x517B:     // SMBFS
+    case 0x0000:     // AFS or unknown
+      return flockLockingStyle;
+      
+    case 0x00011954: // UFS
+    case 0x58465342: // XFS
+    case 0x137D:     // ext1fs
+    case 0xEF51:     // ext2fs
+    case 0xEF53:     // ext2fs
+      return posixLockingStyle;
+  }
+# endif /* HAVE_STATFS_F_TYPE */
+#endif /* HAVE_STATFS_F_FSTYPENAME */
+#endif /*  SQLITE_FIXED_LOCKING_STYLE */
   
   return sqlite3TestLockingStyle(filePath, fd);  
-#endif // SQLITE_FIXED_LOCKING_STYLE
 }
 
 #endif /* SQLITE_ENABLE_LOCKING_STYLE */
@@ -1674,6 +1752,8 @@
 
 
 #ifdef SQLITE_ENABLE_LOCKING_STYLE
+
+#ifdef HAVE_FSCTL
 #pragma mark AFP Support
 
 /*
@@ -1987,7 +2067,7 @@
   *pId = 0;
   return SQLITE_OK;
 }
-
+#endif /* HAVE_FSCTL */
 
 #pragma mark flock() style locking
 
@@ -2341,6 +2421,8 @@
 };
 
 #ifdef SQLITE_ENABLE_LOCKING_STYLE
+
+#ifdef HAVE_FSCTL
 /*
  ** This vector defines all the methods that can operate on an OsFile
  ** for unix with AFP style file locking.
@@ -2361,6 +2443,7 @@
     unixLockState,
     afpUnixCheckReservedLock,
 };
+#endif /* HAVE_FSCTL */
 
 /*
  ** This vector defines all the methods that can operate on an OsFile
@@ -2451,6 +2534,13 @@
   int rc;
 
   lockingStyle = sqlite3DetectLockingStyle(zFilename, h);
+
+  if ( lockingStyle == posixLockingStyle ) {
+    // downgrade to flock() if byte-range locks appear to work strangely
+    if (!testProcessLockingBehavior())
+      lockingStyle = flockLockingStyle;
+  }
+
   if ( lockingStyle == posixLockingStyle ) {
     sqlite3OsEnterMutex();
     rc = findLockInfo(h, &f.pLock, &f.pOpen);
@@ -2459,7 +2549,6 @@
       close(h);
       unlink(zFilename);
       return SQLITE_NOMEM;
-    }
   } else {
     //  pLock and pOpen are only used for posix advisory locking 
     f.pLock = NULL;
@@ -2486,6 +2575,7 @@
   }else{
     *pNew = f;
     switch(lockingStyle) {
+#ifdef HAVE_FSCTL
       case afpLockingStyle:
         /* afp locking uses the file path so it needs to be included in
         ** the afpLockingContext */
@@ -2498,6 +2588,7 @@
                zFilename);
         srandomdev();
         break;
+#endif /* HAVE_FSCTL */
       case flockLockingStyle:
         /* flock locking doesn't need additional lockingContext information */
         pNew->pMethod = &sqlite3FlockLockingUnixIoMethod;


-----------------------------------------------------------------------------
To unsubscribe, send email to [EMAIL PROTECTED]
-----------------------------------------------------------------------------

Reply via email to