2000-01-13 15:09:36 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-01-13 15:09:36 +03:00
byte range locking code
2000-04-26 00:30:58 +04:00
Updated to handle range splits / merges .
Copyright ( C ) Andrew Tridgell 1992 - 2000
Copyright ( C ) Jeremy Allison 1992 - 2000
2000-01-13 15:09:36 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program 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 General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2000-04-26 00:30:58 +04:00
/* This module implements a tdb based byte range locking service,
2000-01-13 15:09:36 +03:00
replacing the fcntl ( ) based byte range locking previously
used . This allows us to provide the same semantics as NT */
# include "includes.h"
2005-04-27 22:32:37 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_LOCKING
2001-08-27 12:19:43 +04:00
# define ZERO_ZERO 0
2000-04-26 00:30:58 +04:00
/* The open brlock.tdb database. */
2000-01-13 15:09:36 +03:00
2007-05-27 14:35:14 +04:00
static struct db_context * brlock_db ;
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
/****************************************************************************
Debug info at level 10 for lock struct .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void print_lock_struct ( unsigned int i , struct lock_struct * pls )
{
DEBUG ( 10 , ( " [%u]: smbpid = %u, tid = %u, pid = %u, " ,
i ,
( unsigned int ) pls - > context . smbpid ,
( unsigned int ) pls - > context . tid ,
( unsigned int ) procid_to_pid ( & pls - > context . pid ) ) ) ;
DEBUG ( 10 , ( " start = %.0f, size = %.0f, fnum = %d, %s %s \n " ,
( double ) pls - > start ,
( double ) pls - > size ,
pls - > fnum ,
lock_type_name ( pls - > lock_type ) ,
lock_flav_name ( pls - > lock_flav ) ) ) ;
}
2000-01-13 15:09:36 +03:00
/****************************************************************************
2000-04-26 00:30:58 +04:00
See if two locking contexts are equal .
2000-01-13 15:09:36 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-26 00:30:58 +04:00
2006-07-11 22:01:26 +04:00
BOOL brl_same_context ( const struct lock_context * ctx1 ,
2006-04-10 19:33:04 +04:00
const struct lock_context * ctx2 )
2000-01-13 15:09:36 +03:00
{
2005-09-30 21:13:37 +04:00
return ( procid_equal ( & ctx1 - > pid , & ctx2 - > pid ) & &
2000-01-13 15:09:36 +03:00
( ctx1 - > smbpid = = ctx2 - > smbpid ) & &
2005-09-30 21:13:37 +04:00
( ctx1 - > tid = = ctx2 - > tid ) ) ;
2000-01-13 15:09:36 +03:00
}
2004-10-19 02:01:10 +04:00
/****************************************************************************
See if lck1 and lck2 overlap .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-04-10 19:33:04 +04:00
static BOOL brl_overlap ( const struct lock_struct * lck1 ,
const struct lock_struct * lck2 )
2004-10-19 02:01:10 +04:00
{
/* this extra check is not redundent - it copes with locks
that go beyond the end of 64 bit file space */
if ( lck1 - > size ! = 0 & &
lck1 - > start = = lck2 - > start & &
lck1 - > size = = lck2 - > size ) {
return True ;
}
if ( lck1 - > start > = ( lck2 - > start + lck2 - > size ) | |
lck2 - > start > = ( lck1 - > start + lck1 - > size ) ) {
return False ;
}
return True ;
}
2000-01-13 15:09:36 +03:00
/****************************************************************************
2000-04-26 00:30:58 +04:00
See if lock2 can be added when lock1 is in place .
2000-01-13 15:09:36 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-26 00:30:58 +04:00
2006-04-10 19:33:04 +04:00
static BOOL brl_conflict ( const struct lock_struct * lck1 ,
const struct lock_struct * lck2 )
2001-08-25 01:09:38 +04:00
{
2006-04-10 19:33:04 +04:00
/* Ignore PENDING locks. */
2006-07-29 23:14:24 +04:00
if ( IS_PENDING_LOCK ( lck1 - > lock_type ) | | IS_PENDING_LOCK ( lck2 - > lock_type ) )
2003-02-27 04:04:34 +03:00
return False ;
2006-04-10 19:33:04 +04:00
/* Read locks never conflict. */
2001-08-25 01:09:38 +04:00
if ( lck1 - > lock_type = = READ_LOCK & & lck2 - > lock_type = = READ_LOCK ) {
return False ;
}
if ( brl_same_context ( & lck1 - > context , & lck2 - > context ) & &
lck2 - > lock_type = = READ_LOCK & & lck1 - > fnum = = lck2 - > fnum ) {
return False ;
}
2004-10-19 02:01:10 +04:00
return brl_overlap ( lck1 , lck2 ) ;
2001-08-25 01:09:38 +04:00
}
2006-04-10 19:33:04 +04:00
/****************************************************************************
See if lock2 can be added when lock1 is in place - when both locks are POSIX
flavour . POSIX locks ignore fnum - they only care about dev / ino which we
know already match .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL brl_conflict_posix ( const struct lock_struct * lck1 ,
const struct lock_struct * lck2 )
{
# if defined(DEVELOPER)
SMB_ASSERT ( lck1 - > lock_flav = = POSIX_LOCK ) ;
SMB_ASSERT ( lck2 - > lock_flav = = POSIX_LOCK ) ;
# endif
/* Ignore PENDING locks. */
2006-07-29 23:14:24 +04:00
if ( IS_PENDING_LOCK ( lck1 - > lock_type ) | | IS_PENDING_LOCK ( lck2 - > lock_type ) )
2006-04-10 19:33:04 +04:00
return False ;
/* Read locks never conflict. */
if ( lck1 - > lock_type = = READ_LOCK & & lck2 - > lock_type = = READ_LOCK ) {
return False ;
}
/* Locks on the same context con't conflict. Ignore fnum. */
if ( brl_same_context ( & lck1 - > context , & lck2 - > context ) ) {
return False ;
}
/* One is read, the other write, or the context is different,
do they overlap ? */
return brl_overlap ( lck1 , lck2 ) ;
}
2001-08-27 12:19:43 +04:00
# if ZERO_ZERO
2006-04-10 19:33:04 +04:00
static BOOL brl_conflict1 ( const struct lock_struct * lck1 ,
const struct lock_struct * lck2 )
2001-08-27 12:19:43 +04:00
{
2006-07-29 23:14:24 +04:00
if ( IS_PENDING_LOCK ( lck1 - > lock_type ) | | IS_PENDING_LOCK ( lck2 - > lock_type ) )
2003-02-27 04:04:34 +03:00
return False ;
2001-08-27 12:19:43 +04:00
if ( lck1 - > lock_type = = READ_LOCK & & lck2 - > lock_type = = READ_LOCK ) {
return False ;
}
if ( brl_same_context ( & lck1 - > context , & lck2 - > context ) & &
lck2 - > lock_type = = READ_LOCK & & lck1 - > fnum = = lck2 - > fnum ) {
return False ;
}
if ( lck2 - > start = = 0 & & lck2 - > size = = 0 & & lck1 - > size ! = 0 ) {
return True ;
}
if ( lck1 - > start > = ( lck2 - > start + lck2 - > size ) | |
lck2 - > start > = ( lck1 - > start + lck1 - > size ) ) {
return False ;
}
return True ;
}
# endif
2001-08-25 01:09:38 +04:00
/****************************************************************************
Check to see if this lock conflicts , but ignore our own locks on the
2006-04-10 19:33:04 +04:00
same fnum only . This is the read / write lock check code path .
This is never used in the POSIX lock case .
2001-08-25 01:09:38 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-04-10 19:33:04 +04:00
static BOOL brl_conflict_other ( const struct lock_struct * lck1 , const struct lock_struct * lck2 )
2000-01-13 15:09:36 +03:00
{
2006-07-29 23:14:24 +04:00
if ( IS_PENDING_LOCK ( lck1 - > lock_type ) | | IS_PENDING_LOCK ( lck2 - > lock_type ) )
2003-02-27 04:04:34 +03:00
return False ;
2000-01-14 11:01:44 +03:00
if ( lck1 - > lock_type = = READ_LOCK & & lck2 - > lock_type = = READ_LOCK )
return False ;
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
/* POSIX flavour locks never conflict here - this is only called
in the read / write path . */
if ( lck1 - > lock_flav = = POSIX_LOCK & & lck2 - > lock_flav = = POSIX_LOCK )
return False ;
2003-02-22 04:09:57 +03:00
/*
* Incoming WRITE locks conflict with existing READ locks even
* if the context is the same . JRA . See LOCKTEST7 in smbtorture .
*/
if ( ! ( lck2 - > lock_type = = WRITE_LOCK & & lck1 - > lock_type = = READ_LOCK ) ) {
if ( brl_same_context ( & lck1 - > context , & lck2 - > context ) & &
lck1 - > fnum = = lck2 - > fnum )
return False ;
}
2000-01-13 15:09:36 +03:00
2004-10-19 02:01:10 +04:00
return brl_overlap ( lck1 , lck2 ) ;
2000-01-13 15:09:36 +03:00
}
2006-07-29 23:14:24 +04:00
/****************************************************************************
Check if an unlock overlaps a pending lock .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL brl_pending_overlap ( const struct lock_struct * lock , const struct lock_struct * pend_lock )
{
if ( ( lock - > start < = pend_lock - > start ) & & ( lock - > start + lock - > size > pend_lock - > start ) )
return True ;
if ( ( lock - > start > = pend_lock - > start ) & & ( lock - > start < = pend_lock - > start + pend_lock - > size ) )
return True ;
return False ;
}
2004-10-19 02:01:10 +04:00
/****************************************************************************
2006-07-18 01:09:02 +04:00
Amazingly enough , w2k3 " remembers " whether the last lock failure on a fnum
2004-10-19 02:01:10 +04:00
is the same as this one and changes its error code . I wonder if any
app depends on this ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-07-18 05:05:51 +04:00
static NTSTATUS brl_lock_failed ( files_struct * fsp , const struct lock_struct * lock , BOOL blocking_lock )
2004-10-19 02:01:10 +04:00
{
2006-07-18 01:09:02 +04:00
if ( lock - > start > = 0xEF000000 & & ( lock - > start > > 63 ) = = 0 ) {
2004-10-19 02:01:10 +04:00
/* amazing the little things you learn with a test
suite . Locks beyond this offset ( as a 64 bit
number ! ) always generate the conflict error code ,
unless the top bit is set */
2006-07-18 05:05:51 +04:00
if ( ! blocking_lock ) {
2006-07-18 01:09:02 +04:00
fsp - > last_lock_failure = * lock ;
}
return NT_STATUS_FILE_LOCK_CONFLICT ;
}
if ( procid_equal ( & lock - > context . pid , & fsp - > last_lock_failure . context . pid ) & &
lock - > context . tid = = fsp - > last_lock_failure . context . tid & &
lock - > fnum = = fsp - > last_lock_failure . fnum & &
lock - > start = = fsp - > last_lock_failure . start ) {
2004-10-19 02:01:10 +04:00
return NT_STATUS_FILE_LOCK_CONFLICT ;
}
2006-07-18 01:09:02 +04:00
2006-07-18 05:05:51 +04:00
if ( ! blocking_lock ) {
2006-07-18 01:09:02 +04:00
fsp - > last_lock_failure = * lock ;
}
2004-10-19 02:01:10 +04:00
return NT_STATUS_LOCK_NOT_GRANTED ;
}
2000-01-13 15:09:36 +03:00
/****************************************************************************
2006-04-10 19:33:04 +04:00
Open up the brlock . tdb database .
2000-01-13 15:09:36 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-23 00:35:48 +04:00
2006-04-10 19:33:04 +04:00
void brl_init ( int read_only )
2000-05-03 18:29:05 +04:00
{
2007-05-27 14:35:14 +04:00
if ( brlock_db ) {
2006-04-10 19:33:04 +04:00
return ;
}
2007-05-27 14:35:14 +04:00
brlock_db = db_open ( NULL , lock_path ( " brlock.tdb " ) ,
lp_open_files_db_hash_size ( ) ,
TDB_DEFAULT
| TDB_VOLATILE
| ( read_only ? 0x0 : TDB_CLEAR_IF_FIRST ) ,
read_only ? O_RDONLY : ( O_RDWR | O_CREAT ) , 0644 ) ;
if ( ! brlock_db ) {
2006-04-10 19:33:04 +04:00
DEBUG ( 0 , ( " Failed to open byte range locking database %s \n " ,
lock_path ( " brlock.tdb " ) ) ) ;
return ;
}
}
2000-05-03 18:29:05 +04:00
2006-04-10 19:33:04 +04:00
/****************************************************************************
Close down the brlock . tdb database .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-05-03 18:29:05 +04:00
2006-04-10 19:33:04 +04:00
void brl_shutdown ( int read_only )
{
2007-05-27 14:35:14 +04:00
if ( ! brlock_db ) {
2006-04-10 19:33:04 +04:00
return ;
}
2007-05-27 14:35:14 +04:00
TALLOC_FREE ( brlock_db ) ;
2006-04-10 19:33:04 +04:00
}
2000-05-03 18:29:05 +04:00
2006-04-10 19:33:04 +04:00
# if ZERO_ZERO
/****************************************************************************
Compare two locks for sorting .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-23 00:35:48 +04:00
2006-04-10 19:33:04 +04:00
static int lock_compare ( const struct lock_struct * lck1 ,
const struct lock_struct * lck2 )
{
if ( lck1 - > start ! = lck2 - > start ) {
return ( lck1 - > start - lck2 - > start ) ;
}
if ( lck2 - > size ! = lck1 - > size ) {
return ( ( int ) lck1 - > size - ( int ) lck2 - > size ) ;
}
return 0 ;
}
# endif
2001-05-23 00:35:48 +04:00
2006-04-10 19:33:04 +04:00
/****************************************************************************
Lock a range of bytes - Windows lock semantics .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-23 00:35:48 +04:00
2006-04-10 19:33:04 +04:00
static NTSTATUS brl_lock_windows ( struct byte_range_lock * br_lck ,
2007-05-20 00:57:12 +04:00
struct lock_struct * plock , BOOL blocking_lock )
2006-04-10 19:33:04 +04:00
{
unsigned int i ;
files_struct * fsp = br_lck - > fsp ;
2007-05-06 00:43:06 +04:00
struct lock_struct * locks = br_lck - > lock_data ;
2006-04-10 19:33:04 +04:00
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
/* Do any Windows or POSIX locks conflict ? */
if ( brl_conflict ( & locks [ i ] , plock ) ) {
2007-05-20 00:57:12 +04:00
/* Remember who blocked us. */
plock - > context . smbpid = locks [ i ] . context . smbpid ;
2006-07-18 05:05:51 +04:00
return brl_lock_failed ( fsp , plock , blocking_lock ) ;
2006-04-10 19:33:04 +04:00
}
# if ZERO_ZERO
if ( plock - > start = = 0 & & plock - > size = = 0 & &
locks [ i ] . size = = 0 ) {
break ;
2001-05-23 00:35:48 +04:00
}
2006-04-10 19:33:04 +04:00
# endif
}
2001-05-23 00:35:48 +04:00
2006-04-10 19:33:04 +04:00
/* We can get the Windows lock, now see if it needs to
be mapped into a lower level POSIX one , and if so can
2006-07-11 22:01:26 +04:00
we get it ? */
2000-05-03 18:29:05 +04:00
2006-11-11 20:05:11 +03:00
if ( ! IS_PENDING_LOCK ( plock - > lock_type ) & & lp_posix_locking ( fsp - > conn - > params ) ) {
2006-07-11 22:01:26 +04:00
int errno_ret ;
if ( ! set_posix_lock_windows_flavour ( fsp ,
plock - > start ,
plock - > size ,
plock - > lock_type ,
& plock - > context ,
locks ,
br_lck - > num_locks ,
& errno_ret ) ) {
2007-05-20 00:57:12 +04:00
/* We don't know who blocked us. */
plock - > context . smbpid = 0xFFFFFFFF ;
2006-07-11 22:01:26 +04:00
if ( errno_ret = = EACCES | | errno_ret = = EAGAIN ) {
2006-04-10 19:33:04 +04:00
return NT_STATUS_FILE_LOCK_CONFLICT ;
} else {
return map_nt_error_from_unix ( errno ) ;
}
2000-05-03 18:29:05 +04:00
}
}
2000-04-26 00:30:58 +04:00
2006-04-10 19:33:04 +04:00
/* no conflicts - add it to the list of locks */
locks = ( struct lock_struct * ) SMB_REALLOC ( locks , ( br_lck - > num_locks + 1 ) * sizeof ( * locks ) ) ;
if ( ! locks ) {
return NT_STATUS_NO_MEMORY ;
2000-05-03 18:29:05 +04:00
}
2006-04-10 19:33:04 +04:00
memcpy ( & locks [ br_lck - > num_locks ] , plock , sizeof ( struct lock_struct ) ) ;
br_lck - > num_locks + = 1 ;
2007-05-06 00:43:06 +04:00
br_lck - > lock_data = locks ;
2006-04-10 19:33:04 +04:00
br_lck - > modified = True ;
return NT_STATUS_OK ;
2000-05-03 18:29:05 +04:00
}
/****************************************************************************
2006-04-10 19:33:04 +04:00
Cope with POSIX range splits and merges .
2000-05-03 18:29:05 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-23 00:35:48 +04:00
2006-07-11 22:01:26 +04:00
static unsigned int brlock_posix_split_merge ( struct lock_struct * lck_arr , /* Output array. */
const struct lock_struct * ex , /* existing lock. */
const struct lock_struct * plock , /* proposed lock. */
2006-04-10 19:33:04 +04:00
BOOL * lock_was_added )
2000-01-13 15:09:36 +03:00
{
2006-04-10 19:33:04 +04:00
BOOL lock_types_differ = ( ex - > lock_type ! = plock - > lock_type ) ;
/* We can't merge non-conflicting locks on different context - ignore fnum. */
if ( ! brl_same_context ( & ex - > context , & plock - > context ) ) {
/* Just copy. */
memcpy ( & lck_arr [ 0 ] , ex , sizeof ( struct lock_struct ) ) ;
return 1 ;
2000-05-03 18:29:05 +04:00
}
2006-04-10 19:33:04 +04:00
/* We now know we have the same context. */
/* Did we overlap ? */
/*********************************************
+ - - - - - - - - - +
| ex |
+ - - - - - - - - - +
2006-07-11 22:01:26 +04:00
+ - - - - - - - +
| plock |
+ - - - - - - - +
2006-04-10 19:33:04 +04:00
OR . . . .
+ - - - - - - - - - +
| ex |
+ - - - - - - - - - +
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-07-11 22:01:26 +04:00
if ( ( ex - > start > ( plock - > start + plock - > size ) ) | |
( plock - > start > ( ex - > start + ex - > size ) ) ) {
2006-04-10 19:33:04 +04:00
/* No overlap with this lock - copy existing. */
memcpy ( & lck_arr [ 0 ] , ex , sizeof ( struct lock_struct ) ) ;
return 1 ;
2002-07-15 14:35:28 +04:00
}
2006-04-10 19:33:04 +04:00
/*********************************************
2006-07-11 22:01:26 +04:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| ex |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-04-10 19:33:04 +04:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| plock | - > replace with plock .
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
if ( ( ex - > start > = plock - > start ) & &
( ex - > start + ex - > size < = plock - > start + plock - > size ) ) {
memcpy ( & lck_arr [ 0 ] , plock , sizeof ( struct lock_struct ) ) ;
* lock_was_added = True ;
return 1 ;
}
/*********************************************
2006-07-11 22:01:26 +04:00
+ - - - - - - - - - - - - - - - - - - - - - - - +
| ex |
+ - - - - - - - - - - - - - - - - - - - - - - - +
2006-04-10 19:33:04 +04:00
+ - - - - - - - - - - - - - - - +
| plock |
+ - - - - - - - - - - - - - - - +
2006-07-11 22:01:26 +04:00
OR . . . .
+ - - - - - - - +
| ex |
+ - - - - - - - +
+ - - - - - - - - - - - - - - - +
| plock |
+ - - - - - - - - - - - - - - - +
2006-04-10 19:33:04 +04:00
BECOMES . . . .
+ - - - - - - - - - - - - - - - + - - - - - - - +
| plock | ex | - different lock types .
+ - - - - - - - - - - - - - - - + - - - - - - - +
2006-07-11 22:01:26 +04:00
OR . . . . ( merge )
2006-04-10 19:33:04 +04:00
+ - - - - - - - - - - - - - - - - - - - - - - - +
| ex | - same lock type .
+ - - - - - - - - - - - - - - - - - - - - - - - +
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
if ( ( ex - > start > = plock - > start ) & &
2006-07-11 22:01:26 +04:00
( ex - > start < = plock - > start + plock - > size ) & &
2006-04-10 19:33:04 +04:00
( ex - > start + ex - > size > plock - > start + plock - > size ) ) {
* lock_was_added = True ;
/* If the lock types are the same, we merge, if different, we
add the new lock before the old . */
if ( lock_types_differ ) {
/* Add new. */
memcpy ( & lck_arr [ 0 ] , plock , sizeof ( struct lock_struct ) ) ;
memcpy ( & lck_arr [ 1 ] , ex , sizeof ( struct lock_struct ) ) ;
/* Adjust existing start and size. */
lck_arr [ 1 ] . start = plock - > start + plock - > size ;
lck_arr [ 1 ] . size = ( ex - > start + ex - > size ) - ( plock - > start + plock - > size ) ;
return 2 ;
} else {
/* Merge. */
memcpy ( & lck_arr [ 0 ] , plock , sizeof ( struct lock_struct ) ) ;
/* Set new start and size. */
lck_arr [ 0 ] . start = plock - > start ;
lck_arr [ 0 ] . size = ( ex - > start + ex - > size ) - plock - > start ;
return 1 ;
}
}
/*********************************************
2006-07-11 22:01:26 +04:00
+ - - - - - - - - - - - - - - - - - - - - - - - +
| ex |
+ - - - - - - - - - - - - - - - - - - - - - - - +
+ - - - - - - - - - - - - - - - +
| plock |
+ - - - - - - - - - - - - - - - +
OR . . . .
+ - - - - - - - +
| ex |
+ - - - - - - - +
2006-04-10 19:33:04 +04:00
+ - - - - - - - - - - - - - - - +
| plock |
+ - - - - - - - - - - - - - - - +
BECOMES . . . .
+ - - - - - - - + - - - - - - - - - - - - - - - +
| ex | plock | - different lock types
+ - - - - - - - + - - - - - - - - - - - - - - - +
2006-07-11 22:01:26 +04:00
OR . . . . ( merge )
2006-04-10 19:33:04 +04:00
+ - - - - - - - - - - - - - - - - - - - - - - - +
| ex | - same lock type .
+ - - - - - - - - - - - - - - - - - - - - - - - +
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
if ( ( ex - > start < plock - > start ) & &
2006-07-11 22:01:26 +04:00
( ex - > start + ex - > size > = plock - > start ) & &
2006-04-10 19:33:04 +04:00
( ex - > start + ex - > size < = plock - > start + plock - > size ) ) {
* lock_was_added = True ;
/* If the lock types are the same, we merge, if different, we
add the new lock after the old . */
if ( lock_types_differ ) {
memcpy ( & lck_arr [ 0 ] , ex , sizeof ( struct lock_struct ) ) ;
memcpy ( & lck_arr [ 1 ] , plock , sizeof ( struct lock_struct ) ) ;
/* Adjust existing size. */
lck_arr [ 0 ] . size = plock - > start - ex - > start ;
return 2 ;
} else {
/* Merge. */
memcpy ( & lck_arr [ 0 ] , ex , sizeof ( struct lock_struct ) ) ;
/* Adjust existing size. */
lck_arr [ 0 ] . size = ( plock - > start + plock - > size ) - ex - > start ;
return 1 ;
}
}
/*********************************************
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| ex |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+ - - - - - - - - - +
| plock |
+ - - - - - - - - - +
BECOMES . . . . .
+ - - - - - - - + - - - - - - - - - + - - - - - - - - - +
| ex | plock | ex | - different lock types .
+ - - - - - - - + - - - - - - - - - + - - - - - - - - - +
OR
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| ex | - same lock type .
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
if ( ( ex - > start < plock - > start ) & & ( ex - > start + ex - > size > plock - > start + plock - > size ) ) {
* lock_was_added = True ;
if ( lock_types_differ ) {
/* We have to split ex into two locks here. */
memcpy ( & lck_arr [ 0 ] , ex , sizeof ( struct lock_struct ) ) ;
memcpy ( & lck_arr [ 1 ] , plock , sizeof ( struct lock_struct ) ) ;
memcpy ( & lck_arr [ 2 ] , ex , sizeof ( struct lock_struct ) ) ;
/* Adjust first existing size. */
lck_arr [ 0 ] . size = plock - > start - ex - > start ;
/* Adjust second existing start and size. */
lck_arr [ 2 ] . start = plock - > start + plock - > size ;
lck_arr [ 2 ] . size = ( ex - > start + ex - > size ) - ( plock - > start + plock - > size ) ;
return 3 ;
} else {
/* Just eat plock. */
memcpy ( & lck_arr [ 0 ] , ex , sizeof ( struct lock_struct ) ) ;
return 1 ;
}
}
/* Never get here. */
smb_panic ( " brlock_posix_split_merge \n " ) ;
/* Notreached. */
abort ( ) ;
2006-04-26 01:36:35 +04:00
/* Keep some compilers happy. */
return 0 ;
2000-01-13 15:09:36 +03:00
}
2001-05-23 00:35:48 +04:00
/****************************************************************************
2006-04-10 19:33:04 +04:00
Lock a range of bytes - POSIX lock semantics .
We must cope with range splits and merges .
2001-05-23 00:35:48 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-14 17:01:28 +04:00
static NTSTATUS brl_lock_posix ( struct messaging_context * msg_ctx ,
struct byte_range_lock * br_lck ,
2007-05-20 00:57:12 +04:00
struct lock_struct * plock )
2001-05-23 00:35:48 +04:00
{
2006-04-10 19:33:04 +04:00
unsigned int i , count ;
2007-05-06 00:43:06 +04:00
struct lock_struct * locks = br_lck - > lock_data ;
2006-04-10 19:33:04 +04:00
struct lock_struct * tp ;
BOOL lock_was_added = False ;
2006-07-29 23:14:24 +04:00
BOOL signal_pending_read = False ;
2006-04-10 19:33:04 +04:00
/* No zero-zero locks for POSIX. */
if ( plock - > start = = 0 & & plock - > size = = 0 ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/* Don't allow 64-bit lock wrap. */
if ( plock - > start + plock - > size < plock - > start | |
plock - > start + plock - > size < plock - > size ) {
return NT_STATUS_INVALID_PARAMETER ;
}
/* The worst case scenario here is we have to split an
existing POSIX lock range into two , and add our lock ,
so we need at most 2 more entries . */
tp = SMB_MALLOC_ARRAY ( struct lock_struct , ( br_lck - > num_locks + 2 ) ) ;
if ( ! tp ) {
return NT_STATUS_NO_MEMORY ;
}
count = 0 ;
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
2006-07-29 23:14:24 +04:00
struct lock_struct * curr_lock = & locks [ i ] ;
/* If we have a pending read lock, a lock downgrade should
trigger a lock re - evaluation . */
if ( curr_lock - > lock_type = = PENDING_READ_LOCK & &
brl_pending_overlap ( plock , curr_lock ) ) {
signal_pending_read = True ;
}
if ( curr_lock - > lock_flav = = WINDOWS_LOCK ) {
2006-04-10 19:33:04 +04:00
/* Do any Windows flavour locks conflict ? */
2006-07-29 23:14:24 +04:00
if ( brl_conflict ( curr_lock , plock ) ) {
2006-04-10 19:33:04 +04:00
/* No games with error messages. */
SAFE_FREE ( tp ) ;
2007-05-20 00:57:12 +04:00
/* Remember who blocked us. */
plock - > context . smbpid = curr_lock - > context . smbpid ;
2006-04-10 19:33:04 +04:00
return NT_STATUS_FILE_LOCK_CONFLICT ;
}
/* Just copy the Windows lock into the new array. */
2006-07-29 23:14:24 +04:00
memcpy ( & tp [ count ] , curr_lock , sizeof ( struct lock_struct ) ) ;
2006-04-10 19:33:04 +04:00
count + + ;
} else {
/* POSIX conflict semantics are different. */
2006-07-29 23:14:24 +04:00
if ( brl_conflict_posix ( curr_lock , plock ) ) {
2006-04-10 19:33:04 +04:00
/* Can't block ourselves with POSIX locks. */
/* No games with error messages. */
SAFE_FREE ( tp ) ;
2007-05-20 00:57:12 +04:00
/* Remember who blocked us. */
plock - > context . smbpid = curr_lock - > context . smbpid ;
2006-04-10 19:33:04 +04:00
return NT_STATUS_FILE_LOCK_CONFLICT ;
}
/* Work out overlaps. */
2006-07-29 23:14:24 +04:00
count + = brlock_posix_split_merge ( & tp [ count ] , curr_lock , plock , & lock_was_added ) ;
2006-04-10 19:33:04 +04:00
}
}
2006-07-11 22:01:26 +04:00
if ( ! lock_was_added ) {
memcpy ( & tp [ count ] , plock , sizeof ( struct lock_struct ) ) ;
count + + ;
}
2006-04-10 19:33:04 +04:00
/* We can get the POSIX lock, now see if it needs to
be mapped into a lower level POSIX one , and if so can
2006-07-11 22:01:26 +04:00
we get it ? */
2006-04-10 19:33:04 +04:00
2006-11-11 20:05:11 +03:00
if ( ! IS_PENDING_LOCK ( plock - > lock_type ) & & lp_posix_locking ( br_lck - > fsp - > conn - > params ) ) {
2006-07-11 22:01:26 +04:00
int errno_ret ;
2001-05-23 00:35:48 +04:00
2006-07-11 22:01:26 +04:00
/* The lower layer just needs to attempt to
get the system POSIX lock . We ' ve weeded out
any conflicts above . */
2006-04-10 19:33:04 +04:00
2006-07-11 22:01:26 +04:00
if ( ! set_posix_lock_posix_flavour ( br_lck - > fsp ,
plock - > start ,
plock - > size ,
plock - > lock_type ,
& errno_ret ) ) {
2007-05-20 00:57:12 +04:00
/* We don't know who blocked us. */
plock - > context . smbpid = 0xFFFFFFFF ;
2006-07-11 22:01:26 +04:00
if ( errno_ret = = EACCES | | errno_ret = = EAGAIN ) {
2006-04-10 19:33:04 +04:00
SAFE_FREE ( tp ) ;
return NT_STATUS_FILE_LOCK_CONFLICT ;
} else {
SAFE_FREE ( tp ) ;
return map_nt_error_from_unix ( errno ) ;
}
}
2002-07-15 14:35:28 +04:00
}
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
/* Realloc so we don't leak entries per lock call. */
tp = ( struct lock_struct * ) SMB_REALLOC ( tp , count * sizeof ( * locks ) ) ;
if ( ! tp ) {
return NT_STATUS_NO_MEMORY ;
2001-08-27 12:19:43 +04:00
}
2006-04-10 19:33:04 +04:00
br_lck - > num_locks = count ;
2006-07-15 04:05:47 +04:00
SAFE_FREE ( br_lck - > lock_data ) ;
2007-05-06 00:43:06 +04:00
br_lck - > lock_data = tp ;
2006-07-29 23:14:24 +04:00
locks = tp ;
2006-04-10 19:33:04 +04:00
br_lck - > modified = True ;
2006-07-29 23:14:24 +04:00
/* A successful downgrade from write to read lock can trigger a lock
re - evalutation where waiting readers can now proceed . */
if ( signal_pending_read ) {
/* Send unlock messages to any pending read waiters that overlap. */
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
struct lock_struct * pend_lock = & locks [ i ] ;
/* Ignore non-pending locks. */
if ( ! IS_PENDING_LOCK ( pend_lock - > lock_type ) ) {
continue ;
}
if ( pend_lock - > lock_type = = PENDING_READ_LOCK & &
brl_pending_overlap ( plock , pend_lock ) ) {
DEBUG ( 10 , ( " brl_lock_posix: sending unlock message to pid %s \n " ,
procid_str_static ( & pend_lock - > context . pid ) ) ) ;
2007-05-14 17:01:28 +04:00
messaging_send ( msg_ctx , pend_lock - > context . pid ,
MSG_SMB_UNLOCK , & data_blob_null ) ;
2006-07-29 23:14:24 +04:00
}
}
}
2006-04-10 19:33:04 +04:00
return NT_STATUS_OK ;
2001-08-27 12:19:43 +04:00
}
2000-01-13 15:09:36 +03:00
/****************************************************************************
2000-04-26 00:30:58 +04:00
Lock a range of bytes .
2000-01-13 15:09:36 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-26 00:30:58 +04:00
2007-05-14 17:01:28 +04:00
NTSTATUS brl_lock ( struct messaging_context * msg_ctx ,
struct byte_range_lock * br_lck ,
2006-07-11 22:01:26 +04:00
uint32 smbpid ,
2007-05-07 13:35:35 +04:00
struct server_id pid ,
2006-04-10 19:33:04 +04:00
br_off start ,
br_off size ,
enum brl_type lock_type ,
enum brl_flavour lock_flav ,
2007-05-20 00:57:12 +04:00
BOOL blocking_lock ,
uint32 * psmbpid )
2000-01-13 15:09:36 +03:00
{
2006-04-10 19:33:04 +04:00
NTSTATUS ret ;
struct lock_struct lock ;
2000-01-13 15:09:36 +03:00
2001-08-27 12:19:43 +04:00
# if !ZERO_ZERO
2001-08-25 01:09:38 +04:00
if ( start = = 0 & & size = = 0 ) {
2001-08-27 12:19:43 +04:00
DEBUG ( 0 , ( " client sent 0/0 lock - please report this \n " ) ) ;
2001-08-25 01:09:38 +04:00
}
# endif
2000-01-13 15:09:36 +03:00
lock . context . smbpid = smbpid ;
lock . context . pid = pid ;
2006-04-10 19:33:04 +04:00
lock . context . tid = br_lck - > fsp - > conn - > cnum ;
2000-01-13 15:09:36 +03:00
lock . start = start ;
lock . size = size ;
2006-04-10 19:33:04 +04:00
lock . fnum = br_lck - > fsp - > fnum ;
2000-01-13 15:09:36 +03:00
lock . lock_type = lock_type ;
2006-04-10 19:33:04 +04:00
lock . lock_flav = lock_flav ;
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
if ( lock_flav = = WINDOWS_LOCK ) {
2006-07-18 05:05:51 +04:00
ret = brl_lock_windows ( br_lck , & lock , blocking_lock ) ;
2006-04-10 19:33:04 +04:00
} else {
2007-05-14 17:01:28 +04:00
ret = brl_lock_posix ( msg_ctx , br_lck , & lock ) ;
2000-01-13 15:09:36 +03:00
}
2001-08-27 12:19:43 +04:00
# if ZERO_ZERO
/* sort the lock list */
2006-04-10 19:33:04 +04:00
qsort ( br_lck - > lock_data , ( size_t ) br_lck - > num_locks , sizeof ( lock ) , lock_compare ) ;
2001-08-27 12:19:43 +04:00
# endif
2007-05-20 00:57:12 +04:00
/* If we're returning an error, return who blocked us. */
if ( ! NT_STATUS_IS_OK ( ret ) & & psmbpid ) {
* psmbpid = lock . context . smbpid ;
}
2006-04-10 19:33:04 +04:00
return ret ;
2000-01-13 15:09:36 +03:00
}
/****************************************************************************
2006-04-10 19:33:04 +04:00
Unlock a range of bytes - Windows semantics .
2000-01-13 15:09:36 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-26 00:30:58 +04:00
2007-05-14 17:01:28 +04:00
static BOOL brl_unlock_windows ( struct messaging_context * msg_ctx ,
struct byte_range_lock * br_lck ,
const struct lock_struct * plock )
2000-01-13 15:09:36 +03:00
{
2006-04-10 19:33:04 +04:00
unsigned int i , j ;
2007-05-06 00:43:06 +04:00
struct lock_struct * locks = br_lck - > lock_data ;
2006-07-11 22:01:26 +04:00
enum brl_type deleted_lock_type = READ_LOCK ; /* shut the compiler up.... */
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
# if ZERO_ZERO
2006-07-11 22:01:26 +04:00
/* Delete write locks by preference... The lock list
is sorted in the zero zero case . */
2006-04-10 19:33:04 +04:00
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
2006-07-15 04:34:08 +04:00
struct lock_struct * lock = & locks [ i ] ;
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
if ( lock - > lock_type = = WRITE_LOCK & &
brl_same_context ( & lock - > context , & plock - > context ) & &
lock - > fnum = = plock - > fnum & &
lock - > lock_flav = = WINDOWS_LOCK & &
lock - > start = = plock - > start & &
lock - > size = = plock - > size ) {
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
/* found it - delete it */
2006-07-11 22:01:26 +04:00
deleted_lock_type = lock - > lock_type ;
break ;
2006-04-10 19:33:04 +04:00
}
2000-04-28 02:23:04 +04:00
}
2006-07-11 22:01:26 +04:00
if ( i ! = br_lck - > num_locks ) {
/* We found it - don't search again. */
goto unlock_continue ;
}
2006-04-10 19:33:04 +04:00
# endif
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
2006-07-15 04:34:08 +04:00
struct lock_struct * lock = & locks [ i ] ;
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
/* Only remove our own locks that match in start, size, and flavour. */
if ( brl_same_context ( & lock - > context , & plock - > context ) & &
lock - > fnum = = plock - > fnum & &
lock - > lock_flav = = WINDOWS_LOCK & &
lock - > start = = plock - > start & &
lock - > size = = plock - > size ) {
2006-07-11 22:01:26 +04:00
deleted_lock_type = lock - > lock_type ;
2006-04-10 19:33:04 +04:00
break ;
}
}
2000-04-26 00:30:58 +04:00
2006-04-10 19:33:04 +04:00
if ( i = = br_lck - > num_locks ) {
/* we didn't find it */
return False ;
}
2000-04-26 00:30:58 +04:00
2006-07-11 22:01:26 +04:00
# if ZERO_ZERO
unlock_continue :
# endif
/* Actually delete the lock. */
if ( i < br_lck - > num_locks - 1 ) {
memmove ( & locks [ i ] , & locks [ i + 1 ] ,
sizeof ( * locks ) * ( ( br_lck - > num_locks - 1 ) - i ) ) ;
}
br_lck - > num_locks - = 1 ;
br_lck - > modified = True ;
/* Unlock the underlying POSIX regions. */
2006-11-11 20:05:11 +03:00
if ( lp_posix_locking ( br_lck - > fsp - > conn - > params ) ) {
2006-07-11 22:01:26 +04:00
release_posix_lock_windows_flavour ( br_lck - > fsp ,
plock - > start ,
plock - > size ,
deleted_lock_type ,
& plock - > context ,
locks ,
br_lck - > num_locks ) ;
2006-04-10 19:33:04 +04:00
}
2003-04-05 00:38:12 +04:00
2006-04-10 19:33:04 +04:00
/* Send unlock messages to any pending waiters that overlap. */
for ( j = 0 ; j < br_lck - > num_locks ; j + + ) {
struct lock_struct * pend_lock = & locks [ j ] ;
2003-04-05 00:38:12 +04:00
2006-04-10 19:33:04 +04:00
/* Ignore non-pending locks. */
2006-07-29 23:14:24 +04:00
if ( ! IS_PENDING_LOCK ( pend_lock - > lock_type ) ) {
2006-04-10 19:33:04 +04:00
continue ;
}
2000-04-28 02:23:04 +04:00
2006-04-10 19:33:04 +04:00
/* We could send specific lock info here... */
2006-07-15 04:34:08 +04:00
if ( brl_pending_overlap ( plock , pend_lock ) ) {
2006-04-10 19:33:04 +04:00
DEBUG ( 10 , ( " brl_unlock: sending unlock message to pid %s \n " ,
procid_str_static ( & pend_lock - > context . pid ) ) ) ;
2007-05-14 17:01:28 +04:00
messaging_send ( msg_ctx , pend_lock - > context . pid ,
MSG_SMB_UNLOCK , & data_blob_null ) ;
2000-04-28 02:23:04 +04:00
}
2001-08-25 01:09:38 +04:00
}
2006-04-10 19:33:04 +04:00
return True ;
}
/****************************************************************************
Unlock a range of bytes - POSIX semantics .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-02-27 04:04:34 +03:00
2007-05-14 17:01:28 +04:00
static BOOL brl_unlock_posix ( struct messaging_context * msg_ctx ,
struct byte_range_lock * br_lck ,
const struct lock_struct * plock )
2006-04-10 19:33:04 +04:00
{
unsigned int i , j , count ;
struct lock_struct * tp ;
2007-05-06 00:43:06 +04:00
struct lock_struct * locks = br_lck - > lock_data ;
2006-04-10 19:33:04 +04:00
BOOL overlap_found = False ;
/* No zero-zero locks for POSIX. */
if ( plock - > start = = 0 & & plock - > size = = 0 ) {
return False ;
}
2003-02-27 04:04:34 +03:00
2006-04-10 19:33:04 +04:00
/* Don't allow 64-bit lock wrap. */
if ( plock - > start + plock - > size < plock - > start | |
plock - > start + plock - > size < plock - > size ) {
DEBUG ( 10 , ( " brl_unlock_posix: lock wrap \n " ) ) ;
return False ;
}
2003-04-05 00:38:12 +04:00
2006-04-10 19:33:04 +04:00
/* The worst case scenario here is we have to split an
existing POSIX lock range into two , so we need at most
1 more entry . */
2003-04-05 00:38:12 +04:00
2006-04-10 19:33:04 +04:00
tp = SMB_MALLOC_ARRAY ( struct lock_struct , ( br_lck - > num_locks + 1 ) ) ;
if ( ! tp ) {
DEBUG ( 10 , ( " brl_unlock_posix: malloc fail \n " ) ) ;
return False ;
}
2003-02-27 04:04:34 +03:00
2006-04-10 19:33:04 +04:00
count = 0 ;
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
2006-07-15 04:34:08 +04:00
struct lock_struct * lock = & locks [ i ] ;
2006-04-10 19:33:04 +04:00
struct lock_struct tmp_lock [ 3 ] ;
BOOL lock_was_added = False ;
unsigned int tmp_count ;
2003-02-27 04:04:34 +03:00
2006-04-10 19:33:04 +04:00
/* Only remove our own locks - ignore fnum. */
2006-07-29 23:14:24 +04:00
if ( IS_PENDING_LOCK ( lock - > lock_type ) | |
2006-04-10 19:33:04 +04:00
! brl_same_context ( & lock - > context , & plock - > context ) ) {
memcpy ( & tp [ count ] , lock , sizeof ( struct lock_struct ) ) ;
count + + ;
continue ;
}
2003-02-27 04:04:34 +03:00
2006-04-10 19:33:04 +04:00
/* Work out overlaps. */
tmp_count = brlock_posix_split_merge ( & tmp_lock [ 0 ] , & locks [ i ] , plock , & lock_was_added ) ;
if ( tmp_count = = 1 ) {
/* Ether the locks didn't overlap, or the unlock completely
overlapped this lock . If it didn ' t overlap , then there ' s
no change in the locks . */
if ( tmp_lock [ 0 ] . lock_type ! = UNLOCK_LOCK ) {
SMB_ASSERT ( tmp_lock [ 0 ] . lock_type = = locks [ i ] . lock_type ) ;
/* No change in this lock. */
memcpy ( & tp [ count ] , & tmp_lock [ 0 ] , sizeof ( struct lock_struct ) ) ;
count + + ;
2000-01-13 15:09:36 +03:00
} else {
2006-04-10 19:33:04 +04:00
SMB_ASSERT ( tmp_lock [ 0 ] . lock_type = = UNLOCK_LOCK ) ;
overlap_found = True ;
2000-01-13 15:09:36 +03:00
}
2006-04-10 19:33:04 +04:00
continue ;
} else if ( tmp_count = = 2 ) {
/* The unlock overlapped an existing lock. Copy the truncated
lock into the lock array . */
if ( tmp_lock [ 0 ] . lock_type ! = UNLOCK_LOCK ) {
SMB_ASSERT ( tmp_lock [ 0 ] . lock_type = = locks [ i ] . lock_type ) ;
SMB_ASSERT ( tmp_lock [ 1 ] . lock_type = = UNLOCK_LOCK ) ;
memcpy ( & tp [ count ] , & tmp_lock [ 0 ] , sizeof ( struct lock_struct ) ) ;
2006-07-11 22:01:26 +04:00
if ( tmp_lock [ 0 ] . size ! = locks [ i ] . size ) {
overlap_found = True ;
}
2006-04-10 19:33:04 +04:00
} else {
SMB_ASSERT ( tmp_lock [ 0 ] . lock_type = = UNLOCK_LOCK ) ;
SMB_ASSERT ( tmp_lock [ 1 ] . lock_type = = locks [ i ] . lock_type ) ;
memcpy ( & tp [ count ] , & tmp_lock [ 1 ] , sizeof ( struct lock_struct ) ) ;
2006-07-11 22:01:26 +04:00
if ( tmp_lock [ 1 ] . start ! = locks [ i ] . start ) {
overlap_found = True ;
}
2006-04-10 19:33:04 +04:00
}
count + + ;
continue ;
} else {
/* tmp_count == 3 - (we split a lock range in two). */
SMB_ASSERT ( tmp_lock [ 0 ] . lock_type = = locks [ i ] . lock_type ) ;
SMB_ASSERT ( tmp_lock [ 1 ] . lock_type = = UNLOCK_LOCK ) ;
2006-04-26 15:02:46 +04:00
SMB_ASSERT ( tmp_lock [ 2 ] . lock_type = = locks [ i ] . lock_type ) ;
2006-04-10 19:33:04 +04:00
memcpy ( & tp [ count ] , & tmp_lock [ 0 ] , sizeof ( struct lock_struct ) ) ;
count + + ;
memcpy ( & tp [ count ] , & tmp_lock [ 2 ] , sizeof ( struct lock_struct ) ) ;
count + + ;
overlap_found = True ;
/* Optimisation... */
/* We know we're finished here as we can't overlap any
more POSIX locks . Copy the rest of the lock array . */
if ( i < br_lck - > num_locks - 1 ) {
memcpy ( & tp [ count ] , & locks [ i + 1 ] ,
sizeof ( * locks ) * ( ( br_lck - > num_locks - 1 ) - i ) ) ;
count + = ( ( br_lck - > num_locks - 1 ) - i ) ;
}
break ;
}
}
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
if ( ! overlap_found ) {
/* Just ignore - no change. */
SAFE_FREE ( tp ) ;
DEBUG ( 10 , ( " brl_unlock_posix: No overlap - unlocked. \n " ) ) ;
return True ;
}
/* Unlock any POSIX regions. */
2006-11-11 20:05:11 +03:00
if ( lp_posix_locking ( br_lck - > fsp - > conn - > params ) ) {
2006-07-11 22:01:26 +04:00
release_posix_lock_posix_flavour ( br_lck - > fsp ,
plock - > start ,
plock - > size ,
& plock - > context ,
tp ,
count ) ;
2006-04-10 19:33:04 +04:00
}
/* Realloc so we don't leak entries per unlock call. */
if ( count ) {
tp = ( struct lock_struct * ) SMB_REALLOC ( tp , count * sizeof ( * locks ) ) ;
if ( ! tp ) {
DEBUG ( 10 , ( " brl_unlock_posix: realloc fail \n " ) ) ;
return False ;
2000-01-13 15:09:36 +03:00
}
2006-04-10 19:33:04 +04:00
} else {
/* We deleted the last lock. */
SAFE_FREE ( tp ) ;
tp = NULL ;
2000-01-13 15:09:36 +03:00
}
2006-04-10 19:33:04 +04:00
br_lck - > num_locks = count ;
2006-07-15 04:05:47 +04:00
SAFE_FREE ( br_lck - > lock_data ) ;
2006-08-08 13:56:38 +04:00
locks = tp ;
2007-05-06 00:43:06 +04:00
br_lck - > lock_data = tp ;
2006-04-10 19:33:04 +04:00
br_lck - > modified = True ;
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
/* Send unlock messages to any pending waiters that overlap. */
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
for ( j = 0 ; j < br_lck - > num_locks ; j + + ) {
struct lock_struct * pend_lock = & locks [ j ] ;
/* Ignore non-pending locks. */
2006-07-29 23:14:24 +04:00
if ( ! IS_PENDING_LOCK ( pend_lock - > lock_type ) ) {
2006-04-10 19:33:04 +04:00
continue ;
}
/* We could send specific lock info here... */
2006-07-15 04:34:08 +04:00
if ( brl_pending_overlap ( plock , pend_lock ) ) {
2006-04-10 19:33:04 +04:00
DEBUG ( 10 , ( " brl_unlock: sending unlock message to pid %s \n " ,
procid_str_static ( & pend_lock - > context . pid ) ) ) ;
2007-05-14 17:01:28 +04:00
messaging_send ( msg_ctx , pend_lock - > context . pid ,
MSG_SMB_UNLOCK , & data_blob_null ) ;
2006-04-10 19:33:04 +04:00
}
}
return True ;
}
2001-06-30 05:59:48 +04:00
2000-01-13 15:09:36 +03:00
/****************************************************************************
2006-04-10 19:33:04 +04:00
Unlock a range of bytes .
2000-01-13 15:09:36 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-26 00:30:58 +04:00
2007-05-14 17:01:28 +04:00
BOOL brl_unlock ( struct messaging_context * msg_ctx ,
struct byte_range_lock * br_lck ,
2006-07-11 22:01:26 +04:00
uint32 smbpid ,
2007-05-07 13:35:35 +04:00
struct server_id pid ,
2006-04-10 19:33:04 +04:00
br_off start ,
br_off size ,
enum brl_flavour lock_flav )
2000-01-13 15:09:36 +03:00
{
2006-04-10 19:33:04 +04:00
struct lock_struct lock ;
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
lock . context . smbpid = smbpid ;
lock . context . pid = pid ;
lock . context . tid = br_lck - > fsp - > conn - > cnum ;
lock . start = start ;
lock . size = size ;
lock . fnum = br_lck - > fsp - > fnum ;
lock . lock_type = UNLOCK_LOCK ;
lock . lock_flav = lock_flav ;
if ( lock_flav = = WINDOWS_LOCK ) {
2007-05-14 17:01:28 +04:00
return brl_unlock_windows ( msg_ctx , br_lck , & lock ) ;
2006-04-10 19:33:04 +04:00
} else {
2007-05-14 17:01:28 +04:00
return brl_unlock_posix ( msg_ctx , br_lck , & lock ) ;
2006-04-10 19:33:04 +04:00
}
}
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
/****************************************************************************
Test if we could add a lock if we wanted to .
Returns True if the region required is currently unlocked , False if locked .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
BOOL brl_locktest ( struct byte_range_lock * br_lck ,
2006-07-11 22:01:26 +04:00
uint32 smbpid ,
2007-05-07 13:35:35 +04:00
struct server_id pid ,
2006-04-10 19:33:04 +04:00
br_off start ,
br_off size ,
enum brl_type lock_type ,
enum brl_flavour lock_flav )
{
BOOL ret = True ;
unsigned int i ;
struct lock_struct lock ;
2007-05-06 00:43:06 +04:00
const struct lock_struct * locks = br_lck - > lock_data ;
2006-04-10 19:33:04 +04:00
files_struct * fsp = br_lck - > fsp ;
2000-01-13 15:09:36 +03:00
lock . context . smbpid = smbpid ;
lock . context . pid = pid ;
2006-04-10 19:33:04 +04:00
lock . context . tid = br_lck - > fsp - > conn - > cnum ;
2000-01-13 15:09:36 +03:00
lock . start = start ;
lock . size = size ;
2006-04-10 19:33:04 +04:00
lock . fnum = fsp - > fnum ;
2000-01-13 15:09:36 +03:00
lock . lock_type = lock_type ;
2006-04-10 19:33:04 +04:00
lock . lock_flav = lock_flav ;
/* Make sure existing locks don't conflict */
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
/*
* Our own locks don ' t conflict .
*/
if ( brl_conflict_other ( & locks [ i ] , & lock ) ) {
return False ;
2000-01-13 15:09:36 +03:00
}
}
2006-04-10 19:33:04 +04:00
/*
* There is no lock held by an SMB daemon , check to
* see if there is a POSIX lock from a UNIX or NFS process .
* This only conflicts with Windows locks , not POSIX locks .
*/
2006-11-11 20:05:11 +03:00
if ( lp_posix_locking ( fsp - > conn - > params ) & & ( lock_flav = = WINDOWS_LOCK ) ) {
2006-04-10 19:33:04 +04:00
ret = is_posix_locked ( fsp , & start , & size , & lock_type , WINDOWS_LOCK ) ;
DEBUG ( 10 , ( " brl_locktest: posix start=%.0f len=%.0f %s for fnum %d file %s \n " ,
( double ) start , ( double ) size , ret ? " locked " : " unlocked " ,
fsp - > fnum , fsp - > fsp_name ) ) ;
/* We need to return the inverse of is_posix_locked. */
ret = ! ret ;
}
2000-01-13 15:09:36 +03:00
/* no conflicts - we could have added it */
2006-04-10 19:33:04 +04:00
return ret ;
}
2000-01-13 15:09:36 +03:00
2006-04-10 19:33:04 +04:00
/****************************************************************************
Query for existing locks .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS brl_lockquery ( struct byte_range_lock * br_lck ,
2006-07-11 22:01:26 +04:00
uint32 * psmbpid ,
2007-05-07 13:35:35 +04:00
struct server_id pid ,
2006-04-10 19:33:04 +04:00
br_off * pstart ,
br_off * psize ,
enum brl_type * plock_type ,
enum brl_flavour lock_flav )
{
unsigned int i ;
struct lock_struct lock ;
2007-05-06 00:43:06 +04:00
const struct lock_struct * locks = br_lck - > lock_data ;
2006-04-10 19:33:04 +04:00
files_struct * fsp = br_lck - > fsp ;
lock . context . smbpid = * psmbpid ;
lock . context . pid = pid ;
lock . context . tid = br_lck - > fsp - > conn - > cnum ;
lock . start = * pstart ;
lock . size = * psize ;
lock . fnum = fsp - > fnum ;
lock . lock_type = * plock_type ;
lock . lock_flav = lock_flav ;
/* Make sure existing locks don't conflict */
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
2006-07-15 04:05:47 +04:00
const struct lock_struct * exlock = & locks [ i ] ;
2006-04-10 19:33:04 +04:00
BOOL conflict = False ;
if ( exlock - > lock_flav = = WINDOWS_LOCK ) {
conflict = brl_conflict ( exlock , & lock ) ;
} else {
conflict = brl_conflict_posix ( exlock , & lock ) ;
}
if ( conflict ) {
* psmbpid = exlock - > context . smbpid ;
* pstart = exlock - > start ;
* psize = exlock - > size ;
* plock_type = exlock - > lock_type ;
return NT_STATUS_LOCK_NOT_GRANTED ;
}
}
/*
* There is no lock held by an SMB daemon , check to
* see if there is a POSIX lock from a UNIX or NFS process .
*/
2006-11-11 20:05:11 +03:00
if ( lp_posix_locking ( fsp - > conn - > params ) ) {
2006-04-10 19:33:04 +04:00
BOOL ret = is_posix_locked ( fsp , pstart , psize , plock_type , POSIX_LOCK ) ;
DEBUG ( 10 , ( " brl_lockquery: posix start=%.0f len=%.0f %s for fnum %d file %s \n " ,
( double ) * pstart , ( double ) * psize , ret ? " locked " : " unlocked " ,
fsp - > fnum , fsp - > fsp_name ) ) ;
if ( ret ) {
/* Hmmm. No clue what to set smbpid to - use -1. */
* psmbpid = 0xFFFF ;
return NT_STATUS_LOCK_NOT_GRANTED ;
}
}
return NT_STATUS_OK ;
2000-01-13 15:09:36 +03:00
}
2000-01-14 07:32:57 +03:00
/****************************************************************************
2006-04-10 19:33:04 +04:00
Remove a particular pending lock .
2000-01-14 07:32:57 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-26 00:30:58 +04:00
2006-07-18 01:09:02 +04:00
BOOL brl_lock_cancel ( struct byte_range_lock * br_lck ,
2006-07-11 22:01:26 +04:00
uint32 smbpid ,
2007-05-07 13:35:35 +04:00
struct server_id pid ,
2006-04-10 19:33:04 +04:00
br_off start ,
br_off size ,
enum brl_flavour lock_flav )
2000-01-14 07:32:57 +03:00
{
2006-04-10 19:33:04 +04:00
unsigned int i ;
2007-05-06 00:43:06 +04:00
struct lock_struct * locks = br_lck - > lock_data ;
2006-04-10 19:33:04 +04:00
struct lock_context context ;
context . smbpid = smbpid ;
context . pid = pid ;
context . tid = br_lck - > fsp - > conn - > cnum ;
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
struct lock_struct * lock = & locks [ i ] ;
/* For pending locks we *always* care about the fnum. */
if ( brl_same_context ( & lock - > context , & context ) & &
lock - > fnum = = br_lck - > fsp - > fnum & &
2006-07-29 23:14:24 +04:00
IS_PENDING_LOCK ( lock - > lock_type ) & &
2006-04-10 19:33:04 +04:00
lock - > lock_flav = = lock_flav & &
lock - > start = = start & &
lock - > size = = size ) {
break ;
}
}
2000-01-14 07:32:57 +03:00
2006-04-10 19:33:04 +04:00
if ( i = = br_lck - > num_locks ) {
/* Didn't find it. */
return False ;
}
2000-01-14 07:32:57 +03:00
2006-04-10 19:33:04 +04:00
if ( i < br_lck - > num_locks - 1 ) {
/* Found this particular pending lock - delete it */
memmove ( & locks [ i ] , & locks [ i + 1 ] ,
sizeof ( * locks ) * ( ( br_lck - > num_locks - 1 ) - i ) ) ;
}
2000-01-14 07:32:57 +03:00
2006-04-10 19:33:04 +04:00
br_lck - > num_locks - = 1 ;
br_lck - > modified = True ;
return True ;
}
2000-01-14 07:32:57 +03:00
2006-04-10 19:33:04 +04:00
/****************************************************************************
Remove any locks associated with a open file .
2006-07-11 22:01:26 +04:00
We return True if this process owns any other Windows locks on this
fd and so we should not immediately close the fd .
2006-04-10 19:33:04 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-14 17:01:28 +04:00
void brl_close_fnum ( struct messaging_context * msg_ctx ,
struct byte_range_lock * br_lck )
2006-04-10 19:33:04 +04:00
{
files_struct * fsp = br_lck - > fsp ;
uint16 tid = fsp - > conn - > cnum ;
int fnum = fsp - > fnum ;
unsigned int i , j , dcount = 0 ;
2006-07-12 20:32:02 +04:00
int num_deleted_windows_locks = 0 ;
2007-05-06 00:43:06 +04:00
struct lock_struct * locks = br_lck - > lock_data ;
2007-05-07 13:35:35 +04:00
struct server_id pid = procid_self ( ) ;
2006-07-11 22:01:26 +04:00
BOOL unlock_individually = False ;
2006-11-11 20:05:11 +03:00
if ( lp_posix_locking ( fsp - > conn - > params ) ) {
2006-07-11 22:01:26 +04:00
/* Check if there are any Windows locks associated with this dev/ino
pair that are not this fnum . If so we need to call unlock on each
one in order to release the system POSIX locks correctly . */
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
struct lock_struct * lock = & locks [ i ] ;
if ( ! procid_equal ( & lock - > context . pid , & pid ) ) {
continue ;
}
if ( lock - > lock_type ! = READ_LOCK & & lock - > lock_type ! = WRITE_LOCK ) {
continue ; /* Ignore pending. */
}
if ( lock - > context . tid ! = tid | | lock - > fnum ! = fnum ) {
unlock_individually = True ;
break ;
}
}
if ( unlock_individually ) {
struct lock_struct * locks_copy ;
2006-07-22 02:02:54 +04:00
unsigned int num_locks_copy ;
2006-07-11 22:01:26 +04:00
/* Copy the current lock array. */
2007-04-30 05:34:28 +04:00
if ( br_lck - > num_locks ) {
locks_copy = ( struct lock_struct * ) TALLOC_MEMDUP ( br_lck , locks , br_lck - > num_locks * sizeof ( struct lock_struct ) ) ;
if ( ! locks_copy ) {
smb_panic ( " brl_close_fnum: talloc fail. \n " ) ;
}
} else {
locks_copy = NULL ;
2006-07-11 22:01:26 +04:00
}
2007-04-30 05:34:28 +04:00
2006-07-22 02:02:54 +04:00
num_locks_copy = br_lck - > num_locks ;
2006-07-11 22:01:26 +04:00
2006-07-22 02:02:54 +04:00
for ( i = 0 ; i < num_locks_copy ; i + + ) {
2006-07-11 22:01:26 +04:00
struct lock_struct * lock = & locks_copy [ i ] ;
if ( lock - > context . tid = = tid & & procid_equal ( & lock - > context . pid , & pid ) & &
( lock - > fnum = = fnum ) ) {
2007-05-14 17:01:28 +04:00
brl_unlock ( msg_ctx ,
br_lck ,
2006-07-11 22:01:26 +04:00
lock - > context . smbpid ,
pid ,
lock - > start ,
lock - > size ,
lock - > lock_flav ) ;
}
}
return ;
}
}
/* We can bulk delete - any POSIX locks will be removed when the fd closes. */
2006-04-10 19:33:04 +04:00
/* Remove any existing locks for this fnum (or any fnum if they're POSIX). */
2003-02-27 04:04:34 +03:00
2006-04-10 19:33:04 +04:00
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
2000-04-26 00:30:58 +04:00
struct lock_struct * lock = & locks [ i ] ;
2006-04-10 19:33:04 +04:00
BOOL del_this_lock = False ;
2000-04-26 00:30:58 +04:00
2006-04-10 19:33:04 +04:00
if ( lock - > context . tid = = tid & & procid_equal ( & lock - > context . pid , & pid ) ) {
if ( ( lock - > lock_flav = = WINDOWS_LOCK ) & & ( lock - > fnum = = fnum ) ) {
del_this_lock = True ;
2006-07-12 20:32:02 +04:00
num_deleted_windows_locks + + ;
2006-04-10 19:33:04 +04:00
} else if ( lock - > lock_flav = = POSIX_LOCK ) {
del_this_lock = True ;
}
}
2003-02-27 04:04:34 +03:00
2006-04-10 19:33:04 +04:00
if ( del_this_lock ) {
2003-02-27 04:04:34 +03:00
/* Send unlock messages to any pending waiters that overlap. */
2006-04-10 19:33:04 +04:00
for ( j = 0 ; j < br_lck - > num_locks ; j + + ) {
2003-02-27 04:04:34 +03:00
struct lock_struct * pend_lock = & locks [ j ] ;
/* Ignore our own or non-pending locks. */
2006-07-29 23:14:24 +04:00
if ( ! IS_PENDING_LOCK ( pend_lock - > lock_type ) ) {
2003-02-27 04:04:34 +03:00
continue ;
2006-04-10 19:33:04 +04:00
}
2003-02-27 04:04:34 +03:00
2006-04-10 19:33:04 +04:00
/* Optimisation - don't send to this fnum as we're
closing it . */
2003-02-27 04:04:34 +03:00
if ( pend_lock - > context . tid = = tid & &
2005-09-30 21:13:37 +04:00
procid_equal ( & pend_lock - > context . pid , & pid ) & &
2006-04-10 19:33:04 +04:00
pend_lock - > fnum = = fnum ) {
2003-02-27 04:04:34 +03:00
continue ;
2006-04-10 19:33:04 +04:00
}
2003-02-27 04:04:34 +03:00
/* We could send specific lock info here... */
2006-04-10 19:33:04 +04:00
if ( brl_pending_overlap ( lock , pend_lock ) ) {
2007-05-14 17:01:28 +04:00
messaging_send ( msg_ctx , pend_lock - > context . pid ,
MSG_SMB_UNLOCK , & data_blob_null ) ;
2006-04-10 19:33:04 +04:00
}
2003-02-27 04:04:34 +03:00
}
2000-01-14 07:32:57 +03:00
/* found it - delete it */
2006-04-10 19:33:04 +04:00
if ( br_lck - > num_locks > 1 & & i < br_lck - > num_locks - 1 ) {
2000-01-14 07:32:57 +03:00
memmove ( & locks [ i ] , & locks [ i + 1 ] ,
2006-04-10 19:33:04 +04:00
sizeof ( * locks ) * ( ( br_lck - > num_locks - 1 ) - i ) ) ;
2000-01-14 07:32:57 +03:00
}
2006-04-10 19:33:04 +04:00
br_lck - > num_locks - - ;
br_lck - > modified = True ;
2000-01-14 07:32:57 +03:00
i - - ;
2000-05-03 18:29:05 +04:00
dcount + + ;
2000-01-14 07:32:57 +03:00
}
}
2006-07-12 10:56:43 +04:00
2006-11-11 20:05:11 +03:00
if ( lp_posix_locking ( fsp - > conn - > params ) & & num_deleted_windows_locks ) {
2006-07-27 19:23:46 +04:00
/* Reduce the Windows lock POSIX reference count on this dev/ino pair. */
2006-07-12 20:32:02 +04:00
reduce_windows_lock_ref_count ( fsp , num_deleted_windows_locks ) ;
}
2000-01-14 07:32:57 +03:00
}
2000-01-16 14:14:44 +03:00
/****************************************************************************
2006-05-03 20:07:21 +04:00
Ensure this set of lock entries is valid .
2000-01-16 14:14:44 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-26 00:30:58 +04:00
2006-05-03 20:07:21 +04:00
static BOOL validate_lock_entries ( unsigned int * pnum_entries , struct lock_struct * * pplocks )
2000-01-16 14:14:44 +03:00
{
2006-05-03 06:14:09 +04:00
unsigned int i ;
unsigned int num_valid_entries = 0 ;
2006-05-03 20:07:21 +04:00
struct lock_struct * locks = * pplocks ;
2000-01-16 14:14:44 +03:00
2006-05-03 20:07:21 +04:00
for ( i = 0 ; i < * pnum_entries ; i + + ) {
2006-05-03 06:14:09 +04:00
struct lock_struct * lock_data = & locks [ i ] ;
if ( ! process_exists ( lock_data - > context . pid ) ) {
/* This process no longer exists - mark this
entry as invalid by zeroing it . */
ZERO_STRUCTP ( lock_data ) ;
} else {
num_valid_entries + + ;
}
}
2006-05-03 20:07:21 +04:00
if ( num_valid_entries ! = * pnum_entries ) {
2006-05-03 06:14:09 +04:00
struct lock_struct * new_lock_data = NULL ;
if ( num_valid_entries ) {
new_lock_data = SMB_MALLOC_ARRAY ( struct lock_struct , num_valid_entries ) ;
if ( ! new_lock_data ) {
DEBUG ( 3 , ( " malloc fail \n " ) ) ;
2006-05-03 20:07:21 +04:00
return False ;
2006-05-03 06:14:09 +04:00
}
2006-05-03 20:07:21 +04:00
2006-05-03 06:14:09 +04:00
num_valid_entries = 0 ;
2006-05-03 20:07:21 +04:00
for ( i = 0 ; i < * pnum_entries ; i + + ) {
2006-05-03 06:14:09 +04:00
struct lock_struct * lock_data = & locks [ i ] ;
if ( lock_data - > context . smbpid & &
lock_data - > context . tid ) {
/* Valid (nonzero) entry - copy it. */
memcpy ( & new_lock_data [ num_valid_entries ] ,
lock_data , sizeof ( struct lock_struct ) ) ;
num_valid_entries + + ;
}
}
}
2006-05-03 20:07:21 +04:00
SAFE_FREE ( * pplocks ) ;
* pplocks = new_lock_data ;
* pnum_entries = num_valid_entries ;
}
return True ;
}
2007-05-29 17:26:44 +04:00
struct brl_forall_cb {
void ( * fn ) ( struct file_id id , struct server_id pid ,
enum brl_type lock_type ,
enum brl_flavour lock_flav ,
br_off start , br_off size ,
void * private_data ) ;
void * private_data ;
} ;
2006-05-03 20:07:21 +04:00
/****************************************************************************
Traverse the whole database with this function , calling traverse_callback
on each lock .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-27 14:35:14 +04:00
static int traverse_fn ( struct db_record * rec , void * state )
2006-05-03 20:07:21 +04:00
{
2007-05-29 17:26:44 +04:00
struct brl_forall_cb * cb = ( struct brl_forall_cb * ) state ;
2006-05-03 20:07:21 +04:00
struct lock_struct * locks ;
2007-05-29 13:30:34 +04:00
struct file_id * key ;
2006-05-03 20:07:21 +04:00
unsigned int i ;
unsigned int num_locks = 0 ;
unsigned int orig_num_locks = 0 ;
/* In a traverse function we must make a copy of
dbuf before modifying it . */
2007-05-27 14:35:14 +04:00
locks = ( struct lock_struct * ) memdup ( rec - > value . dptr ,
rec - > value . dsize ) ;
2006-05-03 20:07:21 +04:00
if ( ! locks ) {
return - 1 ; /* Terminate traversal. */
}
2007-05-29 13:30:34 +04:00
key = ( struct file_id * ) rec - > key . dptr ;
2007-05-27 14:35:14 +04:00
orig_num_locks = num_locks = rec - > value . dsize / sizeof ( * locks ) ;
2006-05-03 20:07:21 +04:00
/* Ensure the lock db is clean of entries from invalid processes. */
if ( ! validate_lock_entries ( & num_locks , & locks ) ) {
SAFE_FREE ( locks ) ;
return - 1 ; /* Terminate traversal */
}
if ( orig_num_locks ! = num_locks ) {
2007-05-27 21:12:08 +04:00
if ( num_locks ) {
TDB_DATA data ;
data . dptr = ( uint8_t * ) locks ;
data . dsize = num_locks * sizeof ( struct lock_struct ) ;
rec - > store ( rec , data , TDB_REPLACE ) ;
2006-05-03 06:14:09 +04:00
} else {
2007-05-27 14:35:14 +04:00
rec - > delete_rec ( rec ) ;
2006-05-03 06:14:09 +04:00
}
}
2006-05-03 20:07:21 +04:00
for ( i = 0 ; i < num_locks ; i + + ) {
2007-05-29 17:26:44 +04:00
cb - > fn ( * key ,
locks [ i ] . context . pid ,
locks [ i ] . lock_type ,
locks [ i ] . lock_flav ,
locks [ i ] . start ,
locks [ i ] . size ,
cb - > private_data ) ;
2000-01-16 14:14:44 +03:00
}
2006-05-03 20:07:21 +04:00
SAFE_FREE ( locks ) ;
2000-01-16 14:14:44 +03:00
return 0 ;
}
/*******************************************************************
2000-04-26 00:30:58 +04:00
Call the specified function on each lock in the database .
2000-01-16 14:14:44 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-26 00:30:58 +04:00
2007-05-29 17:26:44 +04:00
int brl_forall ( void ( * fn ) ( struct file_id id , struct server_id pid ,
enum brl_type lock_type ,
enum brl_flavour lock_flav ,
br_off start , br_off size ,
void * private_data ) ,
void * private_data )
2000-01-16 14:14:44 +03:00
{
2007-05-29 17:26:44 +04:00
struct brl_forall_cb cb ;
2007-05-27 14:35:14 +04:00
if ( ! brlock_db ) {
2006-04-10 19:33:04 +04:00
return 0 ;
}
2007-05-29 17:26:44 +04:00
cb . fn = fn ;
cb . private_data = private_data ;
return brlock_db - > traverse ( brlock_db , traverse_fn , & cb ) ;
2000-01-16 14:14:44 +03:00
}
2006-04-10 19:33:04 +04:00
/*******************************************************************
Store a potentially modified set of byte range lock data back into
the database .
Unlock the record .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-29 23:14:25 +04:00
static int byte_range_lock_destructor ( struct byte_range_lock * br_lck )
2006-04-10 19:33:04 +04:00
{
2006-04-13 03:00:58 +04:00
TDB_DATA key ;
2007-03-29 13:35:51 +04:00
key . dptr = ( uint8 * ) & br_lck - > key ;
2007-05-29 13:30:34 +04:00
key . dsize = sizeof ( struct file_id ) ;
2006-04-10 19:33:04 +04:00
2006-08-01 00:58:02 +04:00
if ( br_lck - > read_only ) {
SMB_ASSERT ( ! br_lck - > modified ) ;
}
2006-04-10 19:33:04 +04:00
if ( ! br_lck - > modified ) {
goto done ;
}
if ( br_lck - > num_locks = = 0 ) {
/* No locks - delete this entry. */
2007-05-27 14:35:14 +04:00
NTSTATUS status = br_lck - > record - > delete_rec ( br_lck - > record ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " delete_rec returned %s \n " ,
nt_errstr ( status ) ) ) ;
2006-04-10 19:33:04 +04:00
smb_panic ( " Could not delete byte range lock entry \n " ) ;
}
} else {
TDB_DATA data ;
2007-05-27 14:35:14 +04:00
NTSTATUS status ;
2007-03-29 13:35:51 +04:00
data . dptr = ( uint8 * ) br_lck - > lock_data ;
2006-04-10 19:33:04 +04:00
data . dsize = br_lck - > num_locks * sizeof ( struct lock_struct ) ;
2007-05-27 14:35:14 +04:00
status = br_lck - > record - > store ( br_lck - > record , data ,
TDB_REPLACE ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " store returned %s \n " , nt_errstr ( status ) ) ) ;
2006-04-10 19:33:04 +04:00
smb_panic ( " Could not store byte range mode entry \n " ) ;
}
}
done :
2006-04-13 03:00:58 +04:00
SAFE_FREE ( br_lck - > lock_data ) ;
2007-05-27 14:35:14 +04:00
TALLOC_FREE ( br_lck - > record ) ;
2006-04-10 19:33:04 +04:00
return 0 ;
}
/*******************************************************************
Fetch a set of byte range lock data from the database .
Leave the record locked .
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( brl ) will release the lock in the destructor .
2006-04-10 19:33:04 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-01 00:58:02 +04:00
static struct byte_range_lock * brl_get_locks_internal ( TALLOC_CTX * mem_ctx ,
files_struct * fsp , BOOL read_only )
2006-04-10 19:33:04 +04:00
{
2007-05-27 14:35:14 +04:00
TDB_DATA key , data ;
2006-07-11 22:01:26 +04:00
struct byte_range_lock * br_lck = TALLOC_P ( mem_ctx , struct byte_range_lock ) ;
2006-04-10 19:33:04 +04:00
if ( br_lck = = NULL ) {
return NULL ;
}
br_lck - > fsp = fsp ;
br_lck - > num_locks = 0 ;
br_lck - > modified = False ;
2007-05-29 13:30:34 +04:00
memset ( & br_lck - > key , ' \0 ' , sizeof ( struct file_id ) ) ;
br_lck - > key = fsp - > file_id ;
2006-04-13 03:00:58 +04:00
2007-03-29 13:35:51 +04:00
key . dptr = ( uint8 * ) & br_lck - > key ;
2007-05-29 13:30:34 +04:00
key . dsize = sizeof ( struct file_id ) ;
2006-04-10 19:33:04 +04:00
2006-08-01 00:58:02 +04:00
if ( ! fsp - > lockdb_clean ) {
/* We must be read/write to clean
the dead entries . */
read_only = False ;
}
if ( read_only ) {
2007-05-27 14:35:14 +04:00
if ( brlock_db - > fetch ( brlock_db , br_lck , key , & data ) = = - 1 ) {
DEBUG ( 3 , ( " Could not fetch byte range lock record \n " ) ) ;
TALLOC_FREE ( br_lck ) ;
return NULL ;
}
br_lck - > record = NULL ;
}
else {
br_lck - > record = brlock_db - > fetch_locked ( brlock_db , br_lck , key ) ;
if ( br_lck - > record = = NULL ) {
2006-08-01 00:58:02 +04:00
DEBUG ( 3 , ( " Could not lock byte range lock entry \n " ) ) ;
TALLOC_FREE ( br_lck ) ;
return NULL ;
}
2007-05-27 14:35:14 +04:00
data = br_lck - > record - > value ;
2006-04-10 19:33:04 +04:00
}
2007-05-27 14:35:14 +04:00
br_lck - > read_only = read_only ;
2006-07-11 22:01:26 +04:00
talloc_set_destructor ( br_lck , byte_range_lock_destructor ) ;
2006-04-10 19:33:04 +04:00
br_lck - > num_locks = data . dsize / sizeof ( struct lock_struct ) ;
2007-05-27 14:35:14 +04:00
br_lck - > lock_data = SMB_MALLOC_ARRAY ( struct lock_struct , br_lck - > num_locks ) ;
memcpy ( br_lck - > lock_data , data . dptr , data . dsize ) ;
2006-05-03 06:14:09 +04:00
if ( ! fsp - > lockdb_clean ) {
/* This is the first time we've accessed this. */
/* Go through and ensure all entries exist - remove any that don't. */
/* Makes the lockdb self cleaning at low cost. */
2007-05-06 00:43:06 +04:00
if ( ! validate_lock_entries ( & br_lck - > num_locks ,
& br_lck - > lock_data ) ) {
2006-05-03 06:14:09 +04:00
SAFE_FREE ( br_lck - > lock_data ) ;
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( br_lck ) ;
2006-05-03 20:07:21 +04:00
return NULL ;
2006-05-03 06:14:09 +04:00
}
/* Mark the lockdb as "clean" as seen from this open file. */
fsp - > lockdb_clean = True ;
}
2006-04-10 19:33:04 +04:00
if ( DEBUGLEVEL > = 10 ) {
unsigned int i ;
2007-05-06 00:43:06 +04:00
struct lock_struct * locks = br_lck - > lock_data ;
2007-05-29 13:30:34 +04:00
DEBUG ( 10 , ( " brl_get_locks_internal: %u current locks on file_id %s \n " ,
2006-04-10 19:33:04 +04:00
br_lck - > num_locks ,
2007-05-29 13:30:34 +04:00
file_id_static_string ( & fsp - > file_id ) ) ) ;
2006-04-10 19:33:04 +04:00
for ( i = 0 ; i < br_lck - > num_locks ; i + + ) {
print_lock_struct ( i , & locks [ i ] ) ;
}
}
return br_lck ;
}
2006-08-01 00:58:02 +04:00
struct byte_range_lock * brl_get_locks ( TALLOC_CTX * mem_ctx ,
files_struct * fsp )
{
return brl_get_locks_internal ( mem_ctx , fsp , False ) ;
}
struct byte_range_lock * brl_get_locks_readonly ( TALLOC_CTX * mem_ctx ,
files_struct * fsp )
{
return brl_get_locks_internal ( mem_ctx , fsp , True ) ;
}