mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-01-20 22:03:45 -05:00
ITS#7361 fix Windows lock handling
This commit is contained in:
parent
cb1b9e2a3e
commit
9d5af71214
1 changed files with 103 additions and 50 deletions
|
|
@ -40,9 +40,9 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <io.h>
|
||||
#include <sys/locking.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -66,19 +66,15 @@ alock_grab_lock ( int fd, int slot )
|
|||
|
||||
res = fcntl (fd, F_SETLKW, &lock_info);
|
||||
#elif defined( _WIN32 )
|
||||
if( _lseek( fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET ) < 0 )
|
||||
return -1;
|
||||
/*
|
||||
* _lock will try for the lock once per second, returning EDEADLOCK
|
||||
* after ten tries. We just loop until we either get the lock
|
||||
* or some other error is returned.
|
||||
*/
|
||||
while((res = _locking( fd, _LK_LOCK, ALOCK_SLOT_SIZE )) < 0 ) {
|
||||
if( errno != EDEADLOCK )
|
||||
break;
|
||||
}
|
||||
OVERLAPPED ov;
|
||||
HANDLE hh = _get_osfhandle ( fd );
|
||||
ov.hEvent = 0;
|
||||
ov.Offset = ALOCK_SLOT_SIZE*slot;
|
||||
ov.OffsetHigh = 0;
|
||||
res = LockFileEx( hh, LOCKFILE_EXCLUSIVE_LOCK, 0,
|
||||
ALOCK_SLOT_SIZE, 0, &ov ) ? 0 : -1;
|
||||
#else
|
||||
# error alock needs lockf, fcntl, or _locking
|
||||
# error alock needs lockf, fcntl, or LockFile[Ex]
|
||||
#endif
|
||||
if (res == -1) {
|
||||
assert (errno != EDEADLK);
|
||||
|
|
@ -109,12 +105,54 @@ alock_release_lock ( int fd, int slot )
|
|||
res = fcntl (fd, F_SETLKW, &lock_info);
|
||||
if (res == -1) return -1;
|
||||
#elif defined( _WIN32 )
|
||||
res = _lseek (fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET);
|
||||
if (res == -1) return -1;
|
||||
res = _locking( fd, _LK_UNLCK, ALOCK_SLOT_SIZE );
|
||||
if (res == -1) return -1;
|
||||
HANDLE hh = _get_osfhandle ( fd );
|
||||
if ( !UnlockFile ( hh, ALOCK_SLOT_SIZE*slot, 0,
|
||||
ALOCK_SLOT_SIZE, 0 ))
|
||||
return -1;
|
||||
#else
|
||||
# error alock needs lockf, fcntl, or _locking
|
||||
# error alock needs lockf, fcntl, or LockFile[Ex]
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
alock_share_lock ( int fd, int slot )
|
||||
{
|
||||
int res;
|
||||
|
||||
#if defined( HAVE_LOCKF )
|
||||
res = 0; /* lockf has no shared locks */
|
||||
#elif defined ( HAVE_FCNTL )
|
||||
struct flock lock_info;
|
||||
(void) memset ((void *) &lock_info, 0, sizeof (struct flock));
|
||||
|
||||
/* The shared lock replaces the existing lock */
|
||||
lock_info.l_type = F_RDLCK;
|
||||
lock_info.l_whence = SEEK_SET;
|
||||
lock_info.l_start = (off_t) (ALOCK_SLOT_SIZE * slot);
|
||||
lock_info.l_len = (off_t) ALOCK_SLOT_SIZE;
|
||||
|
||||
res = fcntl (fd, F_SETLK, &lock_info);
|
||||
if (res == -1) return -1;
|
||||
#elif defined( _WIN32 )
|
||||
OVERLAPPED ov;
|
||||
HANDLE hh = _get_osfhandle ( fd );
|
||||
|
||||
/* Windows locks are mandatory, not advisory.
|
||||
* We must downgrade the lock to allow future
|
||||
* callers to read the slot data.
|
||||
*
|
||||
* First acquire a shared lock. Unlock will
|
||||
* release the existing exclusive lock.
|
||||
*/
|
||||
ov.hEvent = 0;
|
||||
ov.Offset = ALOCK_SLOT_SIZE*slot;
|
||||
ov.OffsetHigh = 0;
|
||||
LockFileEx (hh, 0, 0, ALOCK_SLOT_SIZE, 0, &ov);
|
||||
UnlockFile (hh, ALOCK_SLOT_SIZE*slot, 0, ALOCK_SLOT_SIZE, 0);
|
||||
#else
|
||||
# error alock needs lockf, fcntl, or LockFile[Ex]
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
@ -151,19 +189,22 @@ alock_test_lock ( int fd, int slot )
|
|||
|
||||
if (lock_info.l_type != F_UNLCK) return ALOCK_LOCKED;
|
||||
#elif defined( _WIN32 )
|
||||
res = _lseek (fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET);
|
||||
if (res == -1) return -1;
|
||||
res = _locking( fd, _LK_NBLCK, ALOCK_SLOT_SIZE );
|
||||
_locking( fd, _LK_UNLCK, ALOCK_SLOT_SIZE );
|
||||
if (res == -1) {
|
||||
if( errno == EACCES ) {
|
||||
return ALOCK_LOCKED;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
OVERLAPPED ov;
|
||||
HANDLE hh = _get_osfhandle ( fd );
|
||||
ov.hEvent = 0;
|
||||
ov.Offset = ALOCK_SLOT_SIZE*slot;
|
||||
ov.OffsetHigh = 0;
|
||||
if( !LockFileEx( hh,
|
||||
LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 0,
|
||||
ALOCK_SLOT_SIZE, 0, &ov )) {
|
||||
int err = GetLastError();
|
||||
if ( err == ERROR_LOCK_VIOLATION )
|
||||
return ALOCK_LOCKED;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
# error alock needs lockf, fcntl, or _locking
|
||||
# error alock needs lockf, fcntl, or LockFile
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
@ -364,7 +405,15 @@ alock_open ( alock_info_t * info,
|
|||
}
|
||||
ptr = lutil_strcopy(filename, envdir);
|
||||
lutil_strcopy(ptr, "/alock");
|
||||
#ifdef _WIN32
|
||||
{ HANDLE handle = CreateFile (filename, GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
info->al_fd = _open_osfhandle (handle, 0);
|
||||
}
|
||||
#else
|
||||
info->al_fd = open (filename, O_CREAT|O_RDWR, 0666);
|
||||
#endif
|
||||
ber_memfree (filename);
|
||||
if (info->al_fd < 0) {
|
||||
ber_memfree (slot_data.al_appname);
|
||||
|
|
@ -447,6 +496,7 @@ alock_open ( alock_info_t * info,
|
|||
close (info->al_fd);
|
||||
return ALOCK_UNSTABLE;
|
||||
}
|
||||
alock_share_lock (info->al_fd, info->al_slot);
|
||||
|
||||
res = alock_release_lock (info->al_fd, 0);
|
||||
if (res == -1) {
|
||||
|
|
@ -542,6 +592,12 @@ alock_close ( alock_info_t * info, int nosave )
|
|||
|
||||
res = alock_grab_lock (info->al_fd, 0);
|
||||
if (res == -1) {
|
||||
fail:
|
||||
/* Windows doesn't clean up locks immediately when a process exits.
|
||||
* Make sure we release our locks, to prevent stale locks from
|
||||
* hanging around.
|
||||
*/
|
||||
alock_release_lock (info->al_fd, 0);
|
||||
close (info->al_fd);
|
||||
return ALOCK_UNSTABLE;
|
||||
}
|
||||
|
|
@ -549,31 +605,29 @@ alock_close ( alock_info_t * info, int nosave )
|
|||
/* mark our slot as clean */
|
||||
res = alock_read_slot (info, &slot_data);
|
||||
if (res == -1) {
|
||||
close (info->al_fd);
|
||||
if (slot_data.al_appname != NULL)
|
||||
ber_memfree (slot_data.al_appname);
|
||||
return ALOCK_UNSTABLE;
|
||||
goto fail;
|
||||
}
|
||||
slot_data.al_lock = ALOCK_UNLOCKED;
|
||||
if ( nosave )
|
||||
slot_data.al_lock |= ALOCK_NOSAVE;
|
||||
/* since we have slot 0 locked, we don't need our slot lock */
|
||||
res = alock_release_lock (info->al_fd, info->al_slot);
|
||||
if (res == -1) {
|
||||
goto fail;
|
||||
}
|
||||
res = alock_write_slot (info, &slot_data);
|
||||
if (res == -1) {
|
||||
close (info->al_fd);
|
||||
if (slot_data.al_appname != NULL)
|
||||
ber_memfree (slot_data.al_appname);
|
||||
return ALOCK_UNSTABLE;
|
||||
goto fail;
|
||||
}
|
||||
if (slot_data.al_appname != NULL) {
|
||||
ber_memfree (slot_data.al_appname);
|
||||
slot_data.al_appname = NULL;
|
||||
}
|
||||
|
||||
res = alock_release_lock (info->al_fd, info->al_slot);
|
||||
if (res == -1) {
|
||||
close (info->al_fd);
|
||||
return ALOCK_UNSTABLE;
|
||||
}
|
||||
res = alock_release_lock (info->al_fd, 0);
|
||||
if (res == -1) {
|
||||
close (info->al_fd);
|
||||
|
|
@ -602,14 +656,12 @@ alock_recover ( alock_info_t * info )
|
|||
|
||||
res = alock_grab_lock (info->al_fd, 0);
|
||||
if (res == -1) {
|
||||
close (info->al_fd);
|
||||
return ALOCK_UNSTABLE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
res = fstat (info->al_fd, &statbuf);
|
||||
if (res == -1) {
|
||||
close (info->al_fd);
|
||||
return ALOCK_UNSTABLE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE;
|
||||
|
|
@ -622,23 +674,20 @@ alock_recover ( alock_info_t * info )
|
|||
if (res == ALOCK_LOCKED
|
||||
|| res == ALOCK_UNIQUE) {
|
||||
/* recovery attempt on an active db? */
|
||||
close (info->al_fd);
|
||||
return ALOCK_UNSTABLE;
|
||||
goto fail;
|
||||
|
||||
} else if (res == ALOCK_DIRTY) {
|
||||
/* mark it clean */
|
||||
res = alock_read_slot (&scan_info, &slot_data);
|
||||
if (res == -1) {
|
||||
close (info->al_fd);
|
||||
return ALOCK_UNSTABLE;
|
||||
goto fail;
|
||||
}
|
||||
slot_data.al_lock = ALOCK_UNLOCKED;
|
||||
res = alock_write_slot (&scan_info, &slot_data);
|
||||
if (res == -1) {
|
||||
close (info->al_fd);
|
||||
if (slot_data.al_appname != NULL)
|
||||
ber_memfree (slot_data.al_appname);
|
||||
return ALOCK_UNSTABLE;
|
||||
goto fail;
|
||||
}
|
||||
if (slot_data.al_appname != NULL) {
|
||||
ber_memfree (slot_data.al_appname);
|
||||
|
|
@ -646,8 +695,7 @@ alock_recover ( alock_info_t * info )
|
|||
}
|
||||
|
||||
} else if (res == -1) {
|
||||
close (info->al_fd);
|
||||
return ALOCK_UNSTABLE;
|
||||
goto fail;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -660,6 +708,11 @@ alock_recover ( alock_info_t * info )
|
|||
}
|
||||
|
||||
return ALOCK_CLEAN;
|
||||
|
||||
fail:
|
||||
alock_release_lock (info->al_fd, 0);
|
||||
close (info->al_fd);
|
||||
return ALOCK_UNSTABLE;
|
||||
}
|
||||
|
||||
#endif /* SLAPD_BDB || SLAPD_HDB */
|
||||
|
|
|
|||
Loading…
Reference in a new issue