2006-07-11 22:01:26 +04:00
/*
Unix SMB / CIFS implementation .
trivial database library
Copyright ( C ) Andrew Tridgell 1999 - 2005
Copyright ( C ) Paul ` Rusty ' Russell 2000
Copyright ( C ) Jeremy Allison 2000 - 2003
* * NOTE ! The following LGPL license applies to the tdb
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
2007-07-10 05:44:42 +04:00
version 3 of the License , or ( at your option ) any later version .
2006-07-11 22:01:26 +04:00
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
2007-07-10 07:42:26 +04:00
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2006-07-11 22:01:26 +04:00
*/
# include "tdb_private.h"
2007-11-07 08:47:57 +03:00
void tdb_setalarm_sigptr ( struct tdb_context * tdb , volatile sig_atomic_t * ptr )
{
tdb - > interrupt_sig_ptr = ptr ;
}
2010-02-17 04:47:19 +03:00
static int fcntl_lock ( struct tdb_context * tdb ,
int rw , off_t off , off_t len , bool waitflag )
{
struct flock fl ;
fl . l_type = rw ;
fl . l_whence = SEEK_SET ;
fl . l_start = off ;
fl . l_len = len ;
fl . l_pid = 0 ;
if ( waitflag )
return fcntl ( tdb - > fd , F_SETLKW , & fl ) ;
else
return fcntl ( tdb - > fd , F_SETLK , & fl ) ;
}
static int fcntl_unlock ( struct tdb_context * tdb , int rw , off_t off , off_t len )
{
struct flock fl ;
#if 0 /* Check they matched up locks and unlocks correctly. */
char line [ 80 ] ;
FILE * locks ;
bool found = false ;
locks = fopen ( " /proc/locks " , " r " ) ;
while ( fgets ( line , 80 , locks ) ) {
char * p ;
int type , start , l ;
/* eg. 1: FLOCK ADVISORY WRITE 2440 08:01:2180826 0 EOF */
p = strchr ( line , ' : ' ) + 1 ;
if ( strncmp ( p , " POSIX ADVISORY " , strlen ( " POSIX ADVISORY " ) ) )
continue ;
p + = strlen ( " FLOCK ADVISORY " ) ;
if ( strncmp ( p , " READ " , strlen ( " READ " ) ) = = 0 )
type = F_RDLCK ;
else if ( strncmp ( p , " WRITE " , strlen ( " WRITE " ) ) = = 0 )
type = F_WRLCK ;
else
abort ( ) ;
p + = 6 ;
if ( atoi ( p ) ! = getpid ( ) )
continue ;
p = strchr ( strchr ( p , ' ' ) + 1 , ' ' ) + 1 ;
start = atoi ( p ) ;
p = strchr ( p , ' ' ) + 1 ;
if ( strncmp ( p , " EOF " , 3 ) = = 0 )
l = 0 ;
else
l = atoi ( p ) - start + 1 ;
if ( off = = start ) {
if ( len ! = l ) {
fprintf ( stderr , " Len %u should be %u: %s " ,
( int ) len , l , line ) ;
abort ( ) ;
}
if ( type ! = rw ) {
fprintf ( stderr , " Type %s wrong: %s " ,
rw = = F_RDLCK ? " READ " : " WRITE " , line ) ;
abort ( ) ;
}
found = true ;
break ;
}
}
if ( ! found ) {
fprintf ( stderr , " Unlock on %u@%u not found! \n " ,
( int ) off , ( int ) len ) ;
abort ( ) ;
}
fclose ( locks ) ;
# endif
fl . l_type = F_UNLCK ;
fl . l_whence = SEEK_SET ;
fl . l_start = off ;
fl . l_len = len ;
fl . l_pid = 0 ;
return fcntl ( tdb - > fd , F_SETLKW , & fl ) ;
}
2006-07-11 22:01:26 +04:00
/* a byte range locking function - return 0 on success
this functions locks / unlocks 1 byte at the specified offset .
On error , errno is also set so that errors are passed back properly
through tdb_open ( ) .
note that a len of zero means lock to end of file
*/
2010-02-17 04:47:19 +03:00
int tdb_brlock ( struct tdb_context * tdb ,
int rw_type , tdb_off_t offset , size_t len ,
enum tdb_lock_flags flags )
2006-07-11 22:01:26 +04:00
{
int ret ;
if ( tdb - > flags & TDB_NOLOCK ) {
return 0 ;
}
2010-02-17 04:47:19 +03:00
if ( flags & TDB_LOCK_MARK_ONLY ) {
return 0 ;
}
2006-07-11 22:01:26 +04:00
if ( ( rw_type = = F_WRLCK ) & & ( tdb - > read_only | | tdb - > traverse_read ) ) {
tdb - > ecode = TDB_ERR_RDONLY ;
return - 1 ;
}
do {
2010-02-17 04:47:19 +03:00
ret = fcntl_lock ( tdb , rw_type , offset , len ,
flags & TDB_LOCK_WAIT ) ;
2007-11-07 08:47:57 +03:00
/* Check for a sigalarm break. */
if ( ret = = - 1 & & errno = = EINTR & &
tdb - > interrupt_sig_ptr & &
* tdb - > interrupt_sig_ptr ) {
break ;
}
2006-07-11 22:01:26 +04:00
} while ( ret = = - 1 & & errno = = EINTR ) ;
if ( ret = = - 1 ) {
2009-10-21 17:39:43 +04:00
tdb - > ecode = TDB_ERR_LOCK ;
2006-07-11 22:01:26 +04:00
/* Generic lock error. errno set by fcntl.
* EAGAIN is an expected return from non - blocking
* locks . */
2010-02-17 04:47:19 +03:00
if ( ! ( flags & TDB_LOCK_PROBE ) & & errno ! = EAGAIN ) {
TDB_LOG ( ( tdb , TDB_DEBUG_TRACE , " tdb_brlock failed (fd=%d) at offset %d rw_type=%d flags=%d len=%d \n " ,
tdb - > fd , offset , rw_type , flags , ( int ) len ) ) ;
2006-07-11 22:01:26 +04:00
}
2009-10-21 17:39:43 +04:00
return - 1 ;
2006-07-11 22:01:26 +04:00
}
return 0 ;
}
2010-02-17 04:47:19 +03:00
int tdb_brunlock ( struct tdb_context * tdb ,
int rw_type , tdb_off_t offset , size_t len )
{
int ret ;
if ( tdb - > flags & TDB_NOLOCK ) {
return 0 ;
}
do {
ret = fcntl_unlock ( tdb , rw_type , offset , len ) ;
} while ( ret = = - 1 & & errno = = EINTR ) ;
if ( ret = = - 1 ) {
TDB_LOG ( ( tdb , TDB_DEBUG_TRACE , " tdb_brunlock failed (fd=%d) at offset %d rw_type=%d len=%d \n " ,
tdb - > fd , offset , rw_type , ( int ) len ) ) ;
}
return ret ;
}
2006-07-11 22:01:26 +04:00
/*
upgrade a read lock to a write lock . This needs to be handled in a
special way as some OSes ( such as solaris ) have too conservative
deadlock detection and claim a deadlock when progress can be
made . For those OSes we may loop for a while .
*/
int tdb_brlock_upgrade ( struct tdb_context * tdb , tdb_off_t offset , size_t len )
{
int count = 1000 ;
while ( count - - ) {
struct timeval tv ;
2010-02-17 04:47:19 +03:00
if ( tdb_brlock ( tdb , F_WRLCK , offset , len ,
TDB_LOCK_WAIT | TDB_LOCK_PROBE ) = = 0 ) {
2006-07-11 22:01:26 +04:00
return 0 ;
}
if ( errno ! = EDEADLK ) {
break ;
}
/* sleep for as short a time as we can - more portable than usleep() */
tv . tv_sec = 0 ;
tv . tv_usec = 1 ;
select ( 0 , NULL , NULL , NULL , & tv ) ;
}
2006-10-20 13:55:47 +04:00
TDB_LOG ( ( tdb , TDB_DEBUG_TRACE , " tdb_brlock_upgrade failed at offset %d \n " , offset ) ) ;
2006-07-11 22:01:26 +04:00
return - 1 ;
}
2010-02-17 04:56:13 +03:00
/* list -1 is the alloc list, otherwise a hash chain. */
static tdb_off_t lock_offset ( int list )
{
return FREELIST_TOP + 4 * list ;
}
2006-07-11 22:01:26 +04:00
2010-02-17 05:05:54 +03:00
static struct tdb_lock_type * find_nestlock ( struct tdb_context * tdb ,
tdb_off_t offset )
{
unsigned int i ;
for ( i = 0 ; i < tdb - > num_lockrecs ; i + + ) {
if ( tdb - > lockrecs [ i ] . off = = offset ) {
return & tdb - > lockrecs [ i ] ;
}
}
return NULL ;
}
2010-02-17 04:56:13 +03:00
/* lock an offset in the database. */
int tdb_nest_lock ( struct tdb_context * tdb , uint32_t offset , int ltype ,
enum tdb_lock_flags flags )
2006-07-11 22:01:26 +04:00
{
2007-02-13 02:16:02 +03:00
struct tdb_lock_type * new_lck ;
2010-02-17 04:56:13 +03:00
if ( offset > = lock_offset ( tdb - > header . hash_size ) ) {
2009-10-21 17:39:43 +04:00
tdb - > ecode = TDB_ERR_LOCK ;
2010-02-17 04:56:13 +03:00
TDB_LOG ( ( tdb , TDB_DEBUG_ERROR , " tdb_lock: invalid offset %u for ltype=%d \n " ,
offset , ltype ) ) ;
2006-07-11 22:01:26 +04:00
return - 1 ;
}
if ( tdb - > flags & TDB_NOLOCK )
return 0 ;
2010-02-17 05:05:54 +03:00
new_lck = find_nestlock ( tdb , offset ) ;
if ( new_lck ) {
/*
* Just increment the in - memory struct , posix locks
* don ' t stack .
*/
new_lck - > count + + ;
return 0 ;
2007-02-13 02:16:02 +03:00
}
new_lck = ( struct tdb_lock_type * ) realloc (
tdb - > lockrecs ,
sizeof ( * tdb - > lockrecs ) * ( tdb - > num_lockrecs + 1 ) ) ;
if ( new_lck = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
tdb - > lockrecs = new_lck ;
2006-07-11 22:01:26 +04:00
/* Since fcntl locks don't nest, we do a lock for the first one,
and simply bump the count for future ones */
2010-02-17 04:56:13 +03:00
if ( tdb - > methods - > brlock ( tdb , ltype , offset , 1 , flags ) ) {
2007-02-13 02:16:02 +03:00
return - 1 ;
2006-07-11 22:01:26 +04:00
}
2007-02-13 02:16:02 +03:00
2010-02-17 04:56:13 +03:00
tdb - > lockrecs [ tdb - > num_lockrecs ] . off = offset ;
2007-02-13 02:16:02 +03:00
tdb - > lockrecs [ tdb - > num_lockrecs ] . count = 1 ;
tdb - > lockrecs [ tdb - > num_lockrecs ] . ltype = ltype ;
2010-02-17 07:31:07 +03:00
tdb - > num_lockrecs + + ;
2007-02-13 02:16:02 +03:00
2006-07-11 22:01:26 +04:00
return 0 ;
}
2007-11-07 09:57:35 +03:00
/* lock a list in the database. list -1 is the alloc list */
int tdb_lock ( struct tdb_context * tdb , int list , int ltype )
{
int ret ;
2010-02-17 04:47:19 +03:00
2010-02-17 04:56:13 +03:00
/* a allrecord lock allows us to avoid per chain locks */
if ( tdb - > allrecord_lock . count & &
( ltype = = tdb - > allrecord_lock . ltype | | ltype = = F_RDLCK ) ) {
return 0 ;
}
if ( tdb - > allrecord_lock . count ) {
tdb - > ecode = TDB_ERR_LOCK ;
ret = - 1 ;
} else {
ret = tdb_nest_lock ( tdb , lock_offset ( list ) , ltype ,
TDB_LOCK_WAIT ) ;
}
2007-11-07 09:57:35 +03:00
if ( ret ) {
TDB_LOG ( ( tdb , TDB_DEBUG_ERROR , " tdb_lock failed on list %d "
" ltype=%d (%s) \n " , list , ltype , strerror ( errno ) ) ) ;
}
return ret ;
}
/* lock a list in the database. list -1 is the alloc list. non-blocking lock */
int tdb_lock_nonblock ( struct tdb_context * tdb , int list , int ltype )
{
2010-02-17 04:56:13 +03:00
/* a allrecord lock allows us to avoid per chain locks */
2010-02-17 04:49:47 +03:00
if ( tdb - > allrecord_lock . count & &
( ltype = = tdb - > allrecord_lock . ltype | | ltype = = F_RDLCK ) ) {
2006-10-20 13:55:47 +04:00
return 0 ;
}
2010-02-17 04:49:47 +03:00
if ( tdb - > allrecord_lock . count ) {
2009-10-21 17:39:43 +04:00
tdb - > ecode = TDB_ERR_LOCK ;
return - 1 ;
2006-10-20 13:55:47 +04:00
}
2010-02-17 04:56:13 +03:00
return tdb_nest_lock ( tdb , lock_offset ( list ) , ltype , TDB_LOCK_NOWAIT ) ;
}
int tdb_nest_unlock ( struct tdb_context * tdb , uint32_t offset , int ltype ,
bool mark_lock )
{
int ret = - 1 ;
2010-02-17 05:05:54 +03:00
struct tdb_lock_type * lck ;
2010-02-17 04:56:13 +03:00
2006-07-11 22:01:26 +04:00
if ( tdb - > flags & TDB_NOLOCK )
return 0 ;
/* Sanity checks */
2010-02-17 04:56:13 +03:00
if ( offset > = lock_offset ( tdb - > header . hash_size ) ) {
TDB_LOG ( ( tdb , TDB_DEBUG_ERROR , " tdb_unlock: offset %u invalid (%d) \n " , offset , tdb - > header . hash_size ) ) ;
2006-07-11 22:01:26 +04:00
return ret ;
}
2010-02-17 05:05:54 +03:00
lck = find_nestlock ( tdb , offset ) ;
2007-02-13 02:16:02 +03:00
if ( ( lck = = NULL ) | | ( lck - > count = = 0 ) ) {
2006-10-20 13:55:47 +04:00
TDB_LOG ( ( tdb , TDB_DEBUG_ERROR , " tdb_unlock: count is 0 \n " ) ) ;
2007-02-13 02:16:02 +03:00
return - 1 ;
}
if ( lck - > count > 1 ) {
lck - > count - - ;
return 0 ;
2006-07-11 22:01:26 +04:00
}
2007-02-13 02:16:02 +03:00
/*
* This lock has count = = 1 left , so we need to unlock it in the
* kernel . We don ' t bother with decrementing the in - memory array
* element , we ' re about to overwrite it with the last array element
* anyway .
*/
2007-11-07 09:57:35 +03:00
if ( mark_lock ) {
ret = 0 ;
} else {
2010-02-17 04:56:13 +03:00
ret = tdb - > methods - > brunlock ( tdb , ltype , offset , 1 ) ;
2007-11-07 09:57:35 +03:00
}
2007-02-13 02:16:02 +03:00
/*
* Shrink the array by overwriting the element just unlocked with the
* last array element .
*/
2010-02-17 07:31:07 +03:00
* lck = tdb - > lockrecs [ - - tdb - > num_lockrecs ] ;
2007-02-13 02:16:02 +03:00
/*
* We don ' t bother with realloc when the array shrinks , but if we have
* a completely idle tdb we should get rid of the locked array .
*/
if ( tdb - > num_lockrecs = = 0 ) {
SAFE_FREE ( tdb - > lockrecs ) ;
2006-07-11 22:01:26 +04:00
}
if ( ret )
2006-10-20 13:55:47 +04:00
TDB_LOG ( ( tdb , TDB_DEBUG_ERROR , " tdb_unlock: An error occurred unlocking! \n " ) ) ;
2006-07-11 22:01:26 +04:00
return ret ;
}
2010-02-17 04:47:19 +03:00
int tdb_unlock ( struct tdb_context * tdb , int list , int ltype )
{
2010-02-17 04:56:13 +03:00
/* a global lock allows us to avoid per chain locks */
if ( tdb - > allrecord_lock . count & &
( ltype = = tdb - > allrecord_lock . ltype | | ltype = = F_RDLCK ) ) {
return 0 ;
}
if ( tdb - > allrecord_lock . count ) {
tdb - > ecode = TDB_ERR_LOCK ;
return - 1 ;
}
return tdb_nest_unlock ( tdb , lock_offset ( list ) , ltype , false ) ;
2010-02-17 04:47:19 +03:00
}
2007-11-07 09:57:35 +03:00
/*
get the transaction lock
*/
int tdb_transaction_lock ( struct tdb_context * tdb , int ltype )
{
2010-02-17 05:07:34 +03:00
return tdb_nest_lock ( tdb , TRANSACTION_LOCK , ltype , TDB_LOCK_WAIT ) ;
2007-11-07 09:57:35 +03:00
}
/*
release the transaction lock
*/
2010-02-17 04:47:19 +03:00
int tdb_transaction_unlock ( struct tdb_context * tdb , int ltype )
2007-11-07 09:57:35 +03:00
{
2010-02-17 05:07:34 +03:00
return tdb_nest_unlock ( tdb , TRANSACTION_LOCK , ltype , false ) ;
2007-11-07 09:57:35 +03:00
}
2006-07-11 22:01:26 +04:00
/* lock/unlock entire database */
2010-02-17 04:47:19 +03:00
static int _tdb_lockall ( struct tdb_context * tdb , int ltype ,
enum tdb_lock_flags flags )
2006-07-11 22:01:26 +04:00
{
/* There are no locks on read-only dbs */
2009-10-21 17:39:43 +04:00
if ( tdb - > read_only | | tdb - > traverse_read ) {
tdb - > ecode = TDB_ERR_LOCK ;
return - 1 ;
}
2006-07-11 22:01:26 +04:00
2010-02-17 04:49:47 +03:00
if ( tdb - > allrecord_lock . count & & tdb - > allrecord_lock . ltype = = ltype ) {
tdb - > allrecord_lock . count + + ;
2006-10-20 13:55:47 +04:00
return 0 ;
}
2010-02-17 04:49:47 +03:00
if ( tdb - > allrecord_lock . count ) {
2006-10-20 13:55:47 +04:00
/* a global lock of a different type exists */
2009-10-21 17:39:43 +04:00
tdb - > ecode = TDB_ERR_LOCK ;
return - 1 ;
2006-10-20 13:55:47 +04:00
}
2010-02-17 05:04:26 +03:00
if ( tdb_have_extra_locks ( tdb ) ) {
2006-10-20 13:55:47 +04:00
/* can't combine global and chain locks */
2009-10-21 17:39:43 +04:00
tdb - > ecode = TDB_ERR_LOCK ;
return - 1 ;
2006-10-20 13:55:47 +04:00
}
2010-02-17 04:47:19 +03:00
if ( tdb - > methods - > brlock ( tdb , ltype ,
FREELIST_TOP , 4 * tdb - > header . hash_size ,
flags ) ) {
if ( flags & TDB_LOCK_WAIT ) {
2007-11-07 09:57:35 +03:00
TDB_LOG ( ( tdb , TDB_DEBUG_ERROR , " tdb_lockall failed (%s) \n " , strerror ( errno ) ) ) ;
}
2006-10-20 13:55:47 +04:00
return - 1 ;
}
2010-02-17 04:49:47 +03:00
tdb - > allrecord_lock . count = 1 ;
tdb - > allrecord_lock . ltype = ltype ;
2006-10-20 13:55:47 +04:00
return 0 ;
}
2007-11-07 09:57:35 +03:00
2006-10-20 13:55:47 +04:00
/* unlock entire db */
2010-02-17 04:47:19 +03:00
static int _tdb_unlockall ( struct tdb_context * tdb , int ltype , bool mark_lock )
2006-10-20 13:55:47 +04:00
{
/* There are no locks on read-only dbs */
if ( tdb - > read_only | | tdb - > traverse_read ) {
2009-10-21 17:39:43 +04:00
tdb - > ecode = TDB_ERR_LOCK ;
return - 1 ;
2006-10-20 13:55:47 +04:00
}
2006-07-11 22:01:26 +04:00
2010-02-17 04:49:47 +03:00
if ( tdb - > allrecord_lock . ltype ! = ltype | | tdb - > allrecord_lock . count = = 0 ) {
2009-10-21 17:39:43 +04:00
tdb - > ecode = TDB_ERR_LOCK ;
return - 1 ;
2006-10-20 13:55:47 +04:00
}
2010-02-17 04:49:47 +03:00
if ( tdb - > allrecord_lock . count > 1 ) {
tdb - > allrecord_lock . count - - ;
2006-10-20 13:55:47 +04:00
return 0 ;
2006-07-11 22:01:26 +04:00
}
2007-11-07 09:57:35 +03:00
if ( ! mark_lock & &
2010-02-17 04:47:19 +03:00
tdb - > methods - > brunlock ( tdb , ltype ,
FREELIST_TOP , 4 * tdb - > header . hash_size ) ) {
2006-10-20 13:55:47 +04:00
TDB_LOG ( ( tdb , TDB_DEBUG_ERROR , " tdb_unlockall failed (%s) \n " , strerror ( errno ) ) ) ;
return - 1 ;
}
2010-02-17 04:49:47 +03:00
tdb - > allrecord_lock . count = 0 ;
tdb - > allrecord_lock . ltype = 0 ;
2006-10-20 13:55:47 +04:00
2006-07-11 22:01:26 +04:00
return 0 ;
}
2006-10-20 13:55:47 +04:00
/* lock entire database with write lock */
int tdb_lockall ( struct tdb_context * tdb )
{
2009-10-20 05:49:41 +04:00
tdb_trace ( tdb , " tdb_lockall " ) ;
2010-02-17 04:47:19 +03:00
return _tdb_lockall ( tdb , F_WRLCK , TDB_LOCK_WAIT ) ;
2007-11-07 09:57:35 +03:00
}
/* lock entire database with write lock - mark only */
int tdb_lockall_mark ( struct tdb_context * tdb )
{
2009-10-20 05:49:41 +04:00
tdb_trace ( tdb , " tdb_lockall_mark " ) ;
2010-02-17 04:47:19 +03:00
return _tdb_lockall ( tdb , F_WRLCK , TDB_LOCK_MARK_ONLY ) ;
2007-11-07 09:57:35 +03:00
}
/* unlock entire database with write lock - unmark only */
int tdb_lockall_unmark ( struct tdb_context * tdb )
{
2009-10-20 05:49:41 +04:00
tdb_trace ( tdb , " tdb_lockall_unmark " ) ;
2010-02-17 04:47:19 +03:00
return _tdb_unlockall ( tdb , F_WRLCK , true ) ;
2007-11-07 09:57:35 +03:00
}
/* lock entire database with write lock - nonblocking varient */
int tdb_lockall_nonblock ( struct tdb_context * tdb )
{
2010-02-17 04:47:19 +03:00
int ret = _tdb_lockall ( tdb , F_WRLCK , TDB_LOCK_NOWAIT ) ;
2009-10-20 05:49:41 +04:00
tdb_trace_ret ( tdb , " tdb_lockall_nonblock " , ret ) ;
return ret ;
2006-10-20 13:55:47 +04:00
}
/* unlock entire database with write lock */
int tdb_unlockall ( struct tdb_context * tdb )
{
2009-10-20 05:49:41 +04:00
tdb_trace ( tdb , " tdb_unlockall " ) ;
2010-02-17 04:47:19 +03:00
return _tdb_unlockall ( tdb , F_WRLCK , false ) ;
2006-10-20 13:55:47 +04:00
}
/* lock entire database with read lock */
int tdb_lockall_read ( struct tdb_context * tdb )
{
2009-10-20 05:49:41 +04:00
tdb_trace ( tdb , " tdb_lockall_read " ) ;
2010-02-17 04:47:19 +03:00
return _tdb_lockall ( tdb , F_RDLCK , TDB_LOCK_WAIT ) ;
2007-11-07 09:57:35 +03:00
}
/* lock entire database with read lock - nonblock varient */
int tdb_lockall_read_nonblock ( struct tdb_context * tdb )
{
2010-02-17 04:47:19 +03:00
int ret = _tdb_lockall ( tdb , F_RDLCK , TDB_LOCK_NOWAIT ) ;
2009-10-20 05:49:41 +04:00
tdb_trace_ret ( tdb , " tdb_lockall_read_nonblock " , ret ) ;
return ret ;
2006-10-20 13:55:47 +04:00
}
/* unlock entire database with read lock */
int tdb_unlockall_read ( struct tdb_context * tdb )
2006-07-11 22:01:26 +04:00
{
2009-10-20 05:49:41 +04:00
tdb_trace ( tdb , " tdb_unlockall_read " ) ;
2010-02-17 04:47:19 +03:00
return _tdb_unlockall ( tdb , F_RDLCK , false ) ;
2006-07-11 22:01:26 +04:00
}
/* lock/unlock one hash chain. This is meant to be used to reduce
contention - it cannot guarantee how many records will be locked */
int tdb_chainlock ( struct tdb_context * tdb , TDB_DATA key )
{
2009-10-20 05:49:41 +04:00
int ret = tdb_lock ( tdb , BUCKET ( tdb - > hash_fn ( & key ) ) , F_WRLCK ) ;
tdb_trace_1rec ( tdb , " tdb_chainlock " , key ) ;
return ret ;
2006-07-11 22:01:26 +04:00
}
2007-11-07 09:57:35 +03:00
/* lock/unlock one hash chain, non-blocking. This is meant to be used
to reduce contention - it cannot guarantee how many records will be
locked */
int tdb_chainlock_nonblock ( struct tdb_context * tdb , TDB_DATA key )
{
2009-10-20 05:49:41 +04:00
int ret = tdb_lock_nonblock ( tdb , BUCKET ( tdb - > hash_fn ( & key ) ) , F_WRLCK ) ;
tdb_trace_1rec_ret ( tdb , " tdb_chainlock_nonblock " , key , ret ) ;
return ret ;
2007-11-07 09:57:35 +03:00
}
/* mark a chain as locked without actually locking it. Warning! use with great caution! */
int tdb_chainlock_mark ( struct tdb_context * tdb , TDB_DATA key )
{
2010-02-17 04:56:13 +03:00
int ret = tdb_nest_lock ( tdb , lock_offset ( BUCKET ( tdb - > hash_fn ( & key ) ) ) ,
F_WRLCK , TDB_LOCK_MARK_ONLY ) ;
2009-10-20 05:49:41 +04:00
tdb_trace_1rec ( tdb , " tdb_chainlock_mark " , key ) ;
return ret ;
2007-11-07 09:57:35 +03:00
}
/* unmark a chain as locked without actually locking it. Warning! use with great caution! */
int tdb_chainlock_unmark ( struct tdb_context * tdb , TDB_DATA key )
{
2009-10-20 05:49:41 +04:00
tdb_trace_1rec ( tdb , " tdb_chainlock_unmark " , key ) ;
2010-02-17 04:56:13 +03:00
return tdb_nest_unlock ( tdb , lock_offset ( BUCKET ( tdb - > hash_fn ( & key ) ) ) ,
F_WRLCK , true ) ;
2007-11-07 09:57:35 +03:00
}
2006-07-11 22:01:26 +04:00
int tdb_chainunlock ( struct tdb_context * tdb , TDB_DATA key )
{
2009-10-20 05:49:41 +04:00
tdb_trace_1rec ( tdb , " tdb_chainunlock " , key ) ;
2006-07-11 22:01:26 +04:00
return tdb_unlock ( tdb , BUCKET ( tdb - > hash_fn ( & key ) ) , F_WRLCK ) ;
}
int tdb_chainlock_read ( struct tdb_context * tdb , TDB_DATA key )
{
2009-10-20 05:49:41 +04:00
int ret ;
ret = tdb_lock ( tdb , BUCKET ( tdb - > hash_fn ( & key ) ) , F_RDLCK ) ;
tdb_trace_1rec ( tdb , " tdb_chainlock_read " , key ) ;
return ret ;
2006-07-11 22:01:26 +04:00
}
int tdb_chainunlock_read ( struct tdb_context * tdb , TDB_DATA key )
{
2009-10-20 05:49:41 +04:00
tdb_trace_1rec ( tdb , " tdb_chainunlock_read " , key ) ;
2006-07-11 22:01:26 +04:00
return tdb_unlock ( tdb , BUCKET ( tdb - > hash_fn ( & key ) ) , F_RDLCK ) ;
}
/* record lock stops delete underneath */
int tdb_lock_record ( struct tdb_context * tdb , tdb_off_t off )
{
2010-02-17 04:49:47 +03:00
if ( tdb - > allrecord_lock . count ) {
2008-01-12 02:08:37 +03:00
return 0 ;
}
2010-02-17 04:47:19 +03:00
return off ? tdb - > methods - > brlock ( tdb , F_RDLCK , off , 1 , TDB_LOCK_WAIT ) : 0 ;
2006-07-11 22:01:26 +04:00
}
/*
Write locks override our own fcntl readlocks , so check it here .
Note this is meant to be F_SETLK , * not * F_SETLKW , as it ' s not
an error to fail to get the lock here .
*/
int tdb_write_lock_record ( struct tdb_context * tdb , tdb_off_t off )
{
struct tdb_traverse_lock * i ;
for ( i = & tdb - > travlocks ; i ; i = i - > next )
if ( i - > off = = off )
return - 1 ;
2010-02-17 04:47:19 +03:00
return tdb - > methods - > brlock ( tdb , F_WRLCK , off , 1 , TDB_LOCK_NOWAIT | TDB_LOCK_PROBE ) ;
2006-07-11 22:01:26 +04:00
}
int tdb_write_unlock_record ( struct tdb_context * tdb , tdb_off_t off )
{
2010-02-17 04:47:19 +03:00
return tdb - > methods - > brunlock ( tdb , F_WRLCK , off , 1 ) ;
2006-07-11 22:01:26 +04:00
}
/* fcntl locks don't stack: avoid unlocking someone else's */
int tdb_unlock_record ( struct tdb_context * tdb , tdb_off_t off )
{
struct tdb_traverse_lock * i ;
2007-08-12 04:55:03 +04:00
uint32_t count = 0 ;
2006-07-11 22:01:26 +04:00
2010-02-17 04:49:47 +03:00
if ( tdb - > allrecord_lock . count ) {
2008-01-12 02:08:37 +03:00
return 0 ;
}
2006-07-11 22:01:26 +04:00
if ( off = = 0 )
return 0 ;
for ( i = & tdb - > travlocks ; i ; i = i - > next )
if ( i - > off = = off )
count + + ;
2010-02-17 04:47:19 +03:00
return ( count = = 1 ? tdb - > methods - > brunlock ( tdb , F_RDLCK , off , 1 ) : 0 ) ;
2006-07-11 22:01:26 +04:00
}
2010-02-17 05:04:26 +03:00
bool tdb_have_extra_locks ( struct tdb_context * tdb )
{
2010-02-17 05:07:34 +03:00
unsigned int extra = tdb - > num_lockrecs ;
2010-02-17 05:04:26 +03:00
if ( tdb - > allrecord_lock . count ) {
return true ;
}
2010-02-17 05:07:34 +03:00
2010-02-24 03:14:40 +03:00
/* We always hold the active lock if CLEAR_IF_FIRST. */
if ( find_nestlock ( tdb , ACTIVE_LOCK ) ) {
extra - - ;
}
2010-02-17 05:07:34 +03:00
/* In a transaction, we expect to hold the transaction lock */
if ( tdb - > transaction & & find_nestlock ( tdb , TRANSACTION_LOCK ) ) {
extra - - ;
2010-02-17 05:04:26 +03:00
}
2010-02-17 05:07:34 +03:00
return extra ;
2010-02-17 05:04:26 +03:00
}
2010-02-24 03:11:15 +03:00
2010-02-22 06:28:07 +03:00
/* The transaction code uses this to remove all locks. Note that this
may include OPEN_LOCK . */
2010-02-24 03:11:15 +03:00
void tdb_release_extra_locks ( struct tdb_context * tdb )
{
2010-02-17 05:07:34 +03:00
unsigned int i , extra = 0 ;
2010-02-24 03:11:15 +03:00
if ( tdb - > allrecord_lock . count ! = 0 ) {
tdb_brunlock ( tdb , tdb - > allrecord_lock . ltype ,
FREELIST_TOP , 4 * tdb - > header . hash_size ) ;
tdb - > allrecord_lock . count = 0 ;
}
for ( i = 0 ; i < tdb - > num_lockrecs ; i + + ) {
2010-02-17 05:07:34 +03:00
struct tdb_lock_type * lck = & tdb - > lockrecs [ i ] ;
2010-02-24 03:14:40 +03:00
/* Don't release transaction or active locks! */
2010-02-17 05:07:34 +03:00
if ( tdb - > transaction & & lck - > off = = TRANSACTION_LOCK ) {
tdb - > lockrecs [ extra + + ] = * lck ;
2010-02-24 03:14:40 +03:00
} else if ( lck - > off = = ACTIVE_LOCK ) {
tdb - > lockrecs [ extra + + ] = * lck ;
2010-02-17 05:07:34 +03:00
} else {
tdb_brunlock ( tdb , lck - > ltype , lck - > off , 1 ) ;
}
}
tdb - > num_lockrecs = extra ;
if ( tdb - > num_lockrecs = = 0 ) {
SAFE_FREE ( tdb - > lockrecs ) ;
2010-02-24 03:11:15 +03:00
}
}