diff options
Diffstat (limited to 'source3/locking')
-rw-r--r-- | source3/locking/brlock.c | 304 | ||||
-rw-r--r-- | source3/locking/locking.c | 87 | ||||
-rw-r--r-- | source3/locking/posix.c | 1291 |
3 files changed, 861 insertions, 821 deletions
diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index 574552e9e2..9c8a7a17ee 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -32,29 +32,6 @@ #define ZERO_ZERO 0 -/* This contains elements that differentiate locks. The smbpid is a - client supplied pid, and is essentially the locking context for - this client */ - -struct lock_context { - uint16 smbpid; - uint16 tid; - struct process_id pid; -}; - -/* The data in brlock records is an unsorted linear array of these - records. It is unnecessary to store the count as tdb provides the - size of the record */ - -struct lock_struct { - struct lock_context context; - br_off start; - br_off size; - int fnum; - enum brl_type lock_type; - enum brl_flavour lock_flav; -}; - /* The open brlock.tdb database. */ static TDB_CONTEXT *tdb; @@ -83,7 +60,7 @@ static void print_lock_struct(unsigned int i, struct lock_struct *pls) See if two locking contexts are equal. ****************************************************************************/ -static BOOL brl_same_context(const struct lock_context *ctx1, +BOOL brl_same_context(const struct lock_context *ctx1, const struct lock_context *ctx2) { return (procid_equal(&ctx1->pid, &ctx2->pid) && @@ -343,13 +320,19 @@ static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck, /* We can get the Windows lock, now see if it needs to be mapped into a lower level POSIX one, and if so can - we get it ? We tell the lower lock layer about the - lock type so it can cope with the difference between - Windows "stacking" locks and POSIX "flat" ones. */ + we get it ? */ if ((plock->lock_type != PENDING_LOCK) && lp_posix_locking(SNUM(fsp->conn))) { - if (!set_posix_lock(fsp, plock->start, plock->size, plock->lock_type, WINDOWS_LOCK)) { - if (errno == EACCES || errno == EAGAIN) { + 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)) { + if (errno_ret == EACCES || errno_ret == EAGAIN) { return NT_STATUS_FILE_LOCK_CONFLICT; } else { return map_nt_error_from_unix(errno); @@ -375,9 +358,9 @@ static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck, Cope with POSIX range splits and merges. ****************************************************************************/ -static unsigned int brlock_posix_split_merge(struct lock_struct *lck_arr, - const struct lock_struct *ex, - const struct lock_struct *plock, +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. */ BOOL *lock_was_added) { BOOL lock_types_differ = (ex->lock_type != plock->lock_type); @@ -398,26 +381,26 @@ static unsigned int brlock_posix_split_merge(struct lock_struct *lck_arr, +---------+ | ex | +---------+ - +-------+ - | plock | - +-------+ + +-------+ + | plock | + +-------+ OR.... +---------+ | ex | +---------+ **********************************************/ - if ( (ex->start >= (plock->start + plock->size)) || - (plock->start >= (ex->start + ex->size))) { + if ( (ex->start > (plock->start + plock->size)) || + (plock->start > (ex->start + ex->size))) { /* No overlap with this lock - copy existing. */ memcpy(&lck_arr[0], ex, sizeof(struct lock_struct)); return 1; } /********************************************* - +---------+ - | ex | - +---------+ + +---------------------------+ + | ex | + +---------------------------+ +---------------------------+ | plock | -> replace with plock. +---------------------------+ @@ -431,24 +414,32 @@ OR.... } /********************************************* - +---------------+ - | ex | - +---------------+ + +-----------------------+ + | ex | + +-----------------------+ +---------------+ | plock | +---------------+ +OR.... + +-------+ + | ex | + +-------+ + +---------------+ + | plock | + +---------------+ + BECOMES.... +---------------+-------+ | plock | ex | - different lock types. +---------------+-------+ -OR.... +OR.... (merge) +-----------------------+ | ex | - same lock type. +-----------------------+ **********************************************/ if ( (ex->start >= plock->start) && - (ex->start < plock->start + plock->size) && + (ex->start <= plock->start + plock->size) && (ex->start + ex->size > plock->start + plock->size) ) { *lock_was_added = True; @@ -475,9 +466,16 @@ OR.... } /********************************************* - +---------------+ - | ex | - +---------------+ + +-----------------------+ + | ex | + +-----------------------+ + +---------------+ + | plock | + +---------------+ +OR.... + +-------+ + | ex | + +-------+ +---------------+ | plock | +---------------+ @@ -486,7 +484,7 @@ BECOMES.... | ex | plock | - different lock types +-------+---------------+ -OR +OR.... (merge) +-----------------------+ | ex | - same lock type. +-----------------------+ @@ -494,7 +492,7 @@ OR **********************************************/ if ( (ex->start < plock->start) && - (ex->start + ex->size > plock->start) && + (ex->start + ex->size >= plock->start) && (ex->start + ex->size <= plock->start + plock->size) ) { *lock_was_added = True; @@ -631,20 +629,28 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck, } } + if (!lock_was_added) { + memcpy(&tp[count], plock, sizeof(struct lock_struct)); + count++; + } + /* We can get the POSIX lock, now see if it needs to be mapped into a lower level POSIX one, and if so can - we get it ? We well the lower lock layer about the - lock type so it can cope with the difference between - Windows "stacking" locks and POSIX "flat" ones. */ + we get it ? */ -#if 0 - /* FIXME - this call doesn't work correctly yet for POSIX locks... */ + if ((plock->lock_type != PENDING_LOCK) && lp_posix_locking(SNUM(br_lck->fsp->conn))) { + int errno_ret; - if ((plock->lock_type != PENDING_LOCK) && lp_posix_locking(SNUM(fsp->conn))) { - files_struct *fsp = br_lck->fsp; + /* The lower layer just needs to attempt to + get the system POSIX lock. We've weeded out + any conflicts above. */ - if (!set_posix_lock(fsp, plock->start, plock->size, plock->lock_type, POSIX_LOCK)) { - if (errno == EACCES || errno == EAGAIN) { + if (!set_posix_lock_posix_flavour(br_lck->fsp, + plock->start, + plock->size, + plock->lock_type, + &errno_ret)) { + if (errno_ret == EACCES || errno_ret == EAGAIN) { SAFE_FREE(tp); return NT_STATUS_FILE_LOCK_CONFLICT; } else { @@ -653,12 +659,6 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck, } } } -#endif - - if (!lock_was_added) { - memcpy(&tp[count], plock, sizeof(struct lock_struct)); - count++; - } /* Realloc so we don't leak entries per lock call. */ tp = (struct lock_struct *)SMB_REALLOC(tp, count * sizeof(*locks)); @@ -676,7 +676,7 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck, ****************************************************************************/ NTSTATUS brl_lock(struct byte_range_lock *br_lck, - uint16 smbpid, + uint32 smbpid, struct process_id pid, br_off start, br_off size, @@ -740,8 +740,12 @@ static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock unsigned int i, j; struct lock_struct *lock = NULL; struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data; + enum brl_type deleted_lock_type = READ_LOCK; /* shut the compiler up.... */ #if ZERO_ZERO + /* Delete write locks by preference... The lock list + is sorted in the zero zero case. */ + for (i = 0; i < br_lck->num_locks; i++) { lock = &locks[i]; @@ -753,16 +757,15 @@ static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock lock->size == plock->size) { /* found it - delete it */ - 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; - return True; + deleted_lock_type = lock->lock_type; + break; } } + + if (i != br_lck->num_locks) { + /* We found it - don't search again. */ + goto unlock_continue; + } #endif for (i = 0; i < br_lck->num_locks; i++) { @@ -774,6 +777,7 @@ static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock lock->lock_flav == WINDOWS_LOCK && lock->start == plock->start && lock->size == plock->size ) { + deleted_lock_type = lock->lock_type; break; } } @@ -783,9 +787,28 @@ static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock return False; } - /* Unlock any POSIX regions. */ +#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. */ if(lp_posix_locking(br_lck->fsp->conn->cnum)) { - release_posix_lock(br_lck->fsp, plock->start, plock->size); + release_posix_lock_windows_flavour(br_lck->fsp, + plock->start, + plock->size, + deleted_lock_type, + &plock->context, + locks, + br_lck->num_locks); } /* Send unlock messages to any pending waiters that overlap. */ @@ -810,14 +833,6 @@ static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock } } - /* 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; return True; } @@ -895,13 +910,18 @@ static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_s 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)); + if (tmp_lock[0].size != locks[i].size) { + overlap_found = True; + } } 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)); + if (tmp_lock[1].start != locks[i].start) { + overlap_found = True; + } } count++; - overlap_found = True; continue; } else { /* tmp_count == 3 - (we split a lock range in two). */ @@ -933,14 +953,15 @@ static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_s return True; } -#if 0 - /* FIXME - this call doesn't work correctly yet for POSIX locks... */ - /* Unlock any POSIX regions. */ if(lp_posix_locking(br_lck->fsp->conn->cnum)) { - release_posix_lock(br_lck->fsp, plock->start, plock->size); + release_posix_lock_posix_flavour(br_lck->fsp, + plock->start, + plock->size, + &plock->context, + tp, + count); } -#endif /* Realloc so we don't leak entries per unlock call. */ if (count) { @@ -991,7 +1012,7 @@ static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_s ****************************************************************************/ BOOL brl_unlock(struct byte_range_lock *br_lck, - uint16 smbpid, + uint32 smbpid, struct process_id pid, br_off start, br_off size, @@ -1021,7 +1042,7 @@ BOOL brl_unlock(struct byte_range_lock *br_lck, ****************************************************************************/ BOOL brl_locktest(struct byte_range_lock *br_lck, - uint16 smbpid, + uint32 smbpid, struct process_id pid, br_off start, br_off size, @@ -1079,7 +1100,7 @@ BOOL brl_locktest(struct byte_range_lock *br_lck, ****************************************************************************/ NTSTATUS brl_lockquery(struct byte_range_lock *br_lck, - uint16 *psmbpid, + uint32 *psmbpid, struct process_id pid, br_off *pstart, br_off *psize, @@ -1148,7 +1169,7 @@ NTSTATUS brl_lockquery(struct byte_range_lock *br_lck, ****************************************************************************/ BOOL brl_remove_pending_lock(struct byte_range_lock *br_lck, - uint16 smbpid, + uint32 smbpid, struct process_id pid, br_off start, br_off size, @@ -1192,18 +1213,75 @@ BOOL brl_remove_pending_lock(struct byte_range_lock *br_lck, return True; } - /**************************************************************************** Remove any locks associated with a open file. + We return True if this process owns any other Windows locks on this + fd and so we should not immediately close the fd. ****************************************************************************/ -void brl_close_fnum(struct byte_range_lock *br_lck, struct process_id pid) +void brl_close_fnum(struct byte_range_lock *br_lck) { files_struct *fsp = br_lck->fsp; uint16 tid = fsp->conn->cnum; int fnum = fsp->fnum; unsigned int i, j, dcount=0; struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data; + struct process_id pid = procid_self(); + BOOL unlock_individually = False; + + if(lp_posix_locking(fsp->conn->cnum) && !lp_posix_cifsu_locktype()) { + + /* 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; + + /* Copy the current lock array. */ + locks_copy = TALLOC_MEMDUP(br_lck, locks, br_lck->num_locks * sizeof(struct lock_struct)); + if (!locks_copy) { + DEBUG(0,("brl_close_fnum: talloc fail.\n")); + } + + for (i=0; i < br_lck->num_locks; i++) { + struct lock_struct *lock = &locks_copy[i]; + + if (lock->context.tid == tid && procid_equal(&lock->context.pid, &pid) && + (lock->fnum == fnum)) { + brl_unlock(br_lck, + 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. */ + + /* Zero any lock reference count on this dev/ino pair. */ + zero_windows_lock_ref_count(fsp); /* Remove any existing locks for this fnum (or any fnum if they're POSIX). */ @@ -1346,7 +1424,7 @@ static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *st } if (orig_num_locks != num_locks) { - dbuf.dptr = (void *)locks; + dbuf.dptr = (char *)locks; dbuf.dsize = num_locks * sizeof(*locks); if (dbuf.dsize) { @@ -1388,8 +1466,10 @@ int brl_forall(BRLOCK_FN(fn)) Unlock the record. ********************************************************************/ -int byte_range_lock_destructor(struct byte_range_lock *br_lck) +static int byte_range_lock_destructor(void *p) { + struct byte_range_lock *br_lck = + talloc_get_type_abort(p, struct byte_range_lock); TDB_DATA key; key.dptr = (char *)&br_lck->key; @@ -1406,7 +1486,7 @@ int byte_range_lock_destructor(struct byte_range_lock *br_lck) } } else { TDB_DATA data; - data.dptr = br_lck->lock_data; + data.dptr = (char *)br_lck->lock_data; data.dsize = br_lck->num_locks * sizeof(struct lock_struct); if (tdb_store(tdb, key, data, TDB_REPLACE) == -1) { @@ -1418,20 +1498,21 @@ int byte_range_lock_destructor(struct byte_range_lock *br_lck) tdb_chainunlock(tdb, key); SAFE_FREE(br_lck->lock_data); - SAFE_FREE(br_lck); return 0; } /******************************************************************* Fetch a set of byte range lock data from the database. Leave the record locked. + TALLOC_FREE(brl) will release the lock in the destructor. ********************************************************************/ -struct byte_range_lock *brl_get_locks(files_struct *fsp) +struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx, + files_struct *fsp) { TDB_DATA key; TDB_DATA data; - struct byte_range_lock *br_lck = SMB_MALLOC_P(struct byte_range_lock); + struct byte_range_lock *br_lck = TALLOC_P(mem_ctx, struct byte_range_lock); if (br_lck == NULL) { return NULL; @@ -1449,10 +1530,12 @@ struct byte_range_lock *brl_get_locks(files_struct *fsp) if (tdb_chainlock(tdb, key) != 0) { DEBUG(3, ("Could not lock byte range lock entry\n")); - SAFE_FREE(br_lck); + TALLOC_FREE(br_lck); return NULL; } + talloc_set_destructor(br_lck, byte_range_lock_destructor); + data = tdb_fetch(tdb, key); br_lck->lock_data = (void *)data.dptr; br_lck->num_locks = data.dsize / sizeof(struct lock_struct); @@ -1463,13 +1546,22 @@ struct byte_range_lock *brl_get_locks(files_struct *fsp) /* Go through and ensure all entries exist - remove any that don't. */ /* Makes the lockdb self cleaning at low cost. */ - if (!validate_lock_entries(&br_lck->num_locks, (struct lock_struct **)&br_lck->lock_data)) { - tdb_chainunlock(tdb, key); + struct lock_struct *locks = + (struct lock_struct *)br_lck->lock_data; + + if (!validate_lock_entries(&br_lck->num_locks, &locks)) { SAFE_FREE(br_lck->lock_data); - SAFE_FREE(br_lck); + TALLOC_FREE(br_lck); return NULL; } + /* + * validate_lock_entries might have changed locks. We can't + * use a direct pointer here because otherwise gcc warnes + * about strict aliasing rules being violated. + */ + br_lck->lock_data = locks; + /* Mark the lockdb as "clean" as seen from this open file. */ fsp->lockdb_clean = True; } diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 9d3ca95601..ac50c9b648 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -37,7 +37,6 @@ */ #include "includes.h" -uint16 global_smbpid; #undef DBGC_CLASS #define DBGC_CLASS DBGC_LOCKING @@ -74,6 +73,7 @@ const char *lock_flav_name(enum brl_flavour lock_flav) ****************************************************************************/ BOOL is_locked(files_struct *fsp, + uint32 smbpid, SMB_BIG_UINT count, SMB_BIG_UINT offset, enum brl_type lock_type) @@ -100,32 +100,32 @@ BOOL is_locked(files_struct *fsp, DEBUG(10,("is_locked: optimisation - level II oplock on file %s\n", fsp->fsp_name )); ret = False; } else { - struct byte_range_lock *br_lck = brl_get_locks(fsp); + struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp); if (!br_lck) { return False; } ret = !brl_locktest(br_lck, - global_smbpid, + smbpid, procid_self(), offset, count, lock_type, lock_flav); - byte_range_lock_destructor(br_lck); + TALLOC_FREE(br_lck); } } else { - struct byte_range_lock *br_lck = brl_get_locks(fsp); + struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp); if (!br_lck) { return False; } ret = !brl_locktest(br_lck, - global_smbpid, + smbpid, procid_self(), offset, count, lock_type, lock_flav); - byte_range_lock_destructor(br_lck); + TALLOC_FREE(br_lck); } DEBUG(10,("is_locked: flavour = %s brl start=%.0f len=%.0f %s for fnum %d file %s\n", @@ -141,7 +141,7 @@ BOOL is_locked(files_struct *fsp, ****************************************************************************/ NTSTATUS query_lock(files_struct *fsp, - uint16 *psmbpid, + uint32 *psmbpid, SMB_BIG_UINT *pcount, SMB_BIG_UINT *poffset, enum brl_type *plock_type, @@ -150,15 +150,15 @@ NTSTATUS query_lock(files_struct *fsp, struct byte_range_lock *br_lck = NULL; NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED; - if (!OPEN_FSP(fsp) || !fsp->can_lock) { - return NT_STATUS_INVALID_HANDLE; + if (!fsp->can_lock) { + return fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE; } if (!lp_locking(SNUM(fsp->conn))) { return NT_STATUS_OK; } - br_lck = brl_get_locks(fsp); + br_lck = brl_get_locks(NULL, fsp); if (!br_lck) { return NT_STATUS_NO_MEMORY; } @@ -171,7 +171,7 @@ NTSTATUS query_lock(files_struct *fsp, plock_type, lock_flav); - byte_range_lock_destructor(br_lck); + TALLOC_FREE(br_lck); return status; } @@ -180,7 +180,7 @@ NTSTATUS query_lock(files_struct *fsp, ****************************************************************************/ NTSTATUS do_lock(files_struct *fsp, - uint16 lock_pid, + uint32 lock_pid, SMB_BIG_UINT count, SMB_BIG_UINT offset, enum brl_type lock_type, @@ -190,8 +190,8 @@ NTSTATUS do_lock(files_struct *fsp, struct byte_range_lock *br_lck = NULL; NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED; - if (!OPEN_FSP(fsp) || !fsp->can_lock) { - return NT_STATUS_INVALID_HANDLE; + if (!fsp->can_lock) { + return fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE; } if (!lp_locking(SNUM(fsp->conn))) { @@ -204,7 +204,7 @@ NTSTATUS do_lock(files_struct *fsp, lock_flav_name(lock_flav), lock_type_name(lock_type), (double)offset, (double)count, fsp->fnum, fsp->fsp_name )); - br_lck = brl_get_locks(fsp); + br_lck = brl_get_locks(NULL, fsp); if (!br_lck) { return NT_STATUS_NO_MEMORY; } @@ -218,7 +218,7 @@ NTSTATUS do_lock(files_struct *fsp, lock_flav, my_lock_ctx); - byte_range_lock_destructor(br_lck); + TALLOC_FREE(br_lck); return status; } @@ -230,7 +230,7 @@ NTSTATUS do_lock(files_struct *fsp, ****************************************************************************/ NTSTATUS do_lock_spin(files_struct *fsp, - uint16 lock_pid, + uint32 lock_pid, SMB_BIG_UINT count, SMB_BIG_UINT offset, enum brl_type lock_type, @@ -286,7 +286,7 @@ NTSTATUS do_lock_spin(files_struct *fsp, ****************************************************************************/ NTSTATUS do_unlock(files_struct *fsp, - uint16 lock_pid, + uint32 lock_pid, SMB_BIG_UINT count, SMB_BIG_UINT offset, enum brl_flavour lock_flav) @@ -294,18 +294,18 @@ NTSTATUS do_unlock(files_struct *fsp, BOOL ok = False; struct byte_range_lock *br_lck = NULL; - if (!lp_locking(SNUM(fsp->conn))) { - return NT_STATUS_OK; + if (!fsp->can_lock) { + return fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE; } - if (!OPEN_FSP(fsp) || !fsp->can_lock) { - return NT_STATUS_INVALID_HANDLE; + if (!lp_locking(SNUM(fsp->conn))) { + return NT_STATUS_OK; } DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for fnum %d file %s\n", (double)offset, (double)count, fsp->fnum, fsp->fsp_name )); - br_lck = brl_get_locks(fsp); + br_lck = brl_get_locks(NULL, fsp); if (!br_lck) { return NT_STATUS_NO_MEMORY; } @@ -317,7 +317,7 @@ NTSTATUS do_unlock(files_struct *fsp, count, lock_flav); - byte_range_lock_destructor(br_lck); + TALLOC_FREE(br_lck); if (!ok) { DEBUG(10,("do_unlock: returning ERRlock.\n" )); @@ -334,25 +334,15 @@ NTSTATUS do_unlock(files_struct *fsp, void locking_close_file(files_struct *fsp) { struct byte_range_lock *br_lck; - struct process_id pid = procid_self(); - if (!lp_locking(SNUM(fsp->conn))) + if (!lp_locking(SNUM(fsp->conn))) { return; - - /* - * Just release all the brl locks, no need to release individually. - */ - - br_lck = brl_get_locks(fsp); - if (br_lck) { - brl_close_fnum(br_lck, pid); - byte_range_lock_destructor(br_lck); } - if(lp_posix_locking(SNUM(fsp->conn))) { - /* Release all the POSIX locks.*/ - posix_locking_close_file(fsp); - + br_lck = brl_get_locks(NULL,fsp); + if (br_lck) { + brl_close_fnum(br_lck); + TALLOC_FREE(br_lck); } } @@ -516,9 +506,10 @@ static BOOL parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) smb_panic("PANIC: parse_share_modes: buffer too short.\n"); } - lck->share_modes = talloc_memdup(lck, dbuf.dptr+sizeof(*data), - lck->num_share_modes * - sizeof(struct share_mode_entry)); + lck->share_modes = (struct share_mode_entry *) + talloc_memdup(lck, dbuf.dptr+sizeof(*data), + lck->num_share_modes * + sizeof(struct share_mode_entry)); if (lck->share_modes == NULL) { smb_panic("talloc failed\n"); @@ -635,7 +626,7 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) delete_token_size + sp_len + 1 + strlen(lck->filename) + 1; - result.dptr = talloc_size(lck, result.dsize); + result.dptr = TALLOC_ARRAY(lck, char, result.dsize); if (result.dptr == NULL) { smb_panic("talloc failed\n"); @@ -838,7 +829,7 @@ BOOL rename_share_filename(struct share_mode_lock *lck, msg_len = MSG_FILE_RENAMED_MIN_SIZE + sp_len + 1 + fn_len + 1; /* Set up the name changed message. */ - frm = TALLOC(lck, msg_len); + frm = TALLOC_ARRAY(lck, char, msg_len); if (!frm) { return False; } @@ -862,9 +853,9 @@ BOOL rename_share_filename(struct share_mode_lock *lck, continue; } - DEBUG(10,("rename_share_filename: sending rename message to pid %u " + DEBUG(10,("rename_share_filename: sending rename message to pid %s " "dev %x, inode %.0f sharepath %s newname %s\n", - (unsigned int)procid_to_pid(&se->pid), + procid_str_static(&se->pid), (unsigned int)lck->dev, (double)lck->ino, lck->servicepath, lck->filename )); @@ -1305,5 +1296,5 @@ int share_mode_forall(void (*fn)(const struct share_mode_entry *, const char *, { if (tdb == NULL) return 0; - return tdb_traverse(tdb, traverse_fn, fn); + return tdb_traverse(tdb, traverse_fn, (void *)fn); } diff --git a/source3/locking/posix.c b/source3/locking/posix.c index 4a5f59b622..59b62170e8 100644 --- a/source3/locking/posix.c +++ b/source3/locking/posix.c @@ -1,7 +1,7 @@ /* Unix SMB/CIFS implementation. Locking functions - Copyright (C) Jeremy Allison 1992-2000 + Copyright (C) Jeremy Allison 1992-2006 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 @@ -28,481 +28,17 @@ #define DBGC_CLASS DBGC_LOCKING /* - * The POSIX locking database handle. - */ - -static TDB_CONTEXT *posix_lock_tdb; - -/* * The pending close database handle. */ static TDB_CONTEXT *posix_pending_close_tdb; -/* - * The data in POSIX lock records is an unsorted linear array of these - * records. It is unnecessary to store the count as tdb provides the - * size of the record. - */ - -struct posix_lock { - int fd; - SMB_OFF_T start; - SMB_OFF_T size; - int lock_type; -}; - -/* - * The data in POSIX pending close records is an unsorted linear array of int - * records. It is unnecessary to store the count as tdb provides the - * size of the record. - */ - -/* The key used in both the POSIX databases. */ - -struct posix_lock_key { - SMB_DEV_T device; - SMB_INO_T inode; -}; - -/******************************************************************* - Form a static locking key for a dev/inode pair. -******************************************************************/ - -static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode) -{ - static struct posix_lock_key key; - TDB_DATA kbuf; - - memset(&key, '\0', sizeof(key)); - key.device = dev; - key.inode = inode; - kbuf.dptr = (char *)&key; - kbuf.dsize = sizeof(key); - return kbuf; -} - -/******************************************************************* - Convenience function to get a key from an fsp. -******************************************************************/ - -static TDB_DATA locking_key_fsp(files_struct *fsp) -{ - return locking_key(fsp->dev, fsp->inode); -} - -/**************************************************************************** - Add an fd to the pending close tdb. -****************************************************************************/ - -static BOOL add_fd_to_close_entry(files_struct *fsp) -{ - TDB_DATA kbuf = locking_key_fsp(fsp); - TDB_DATA dbuf; - - dbuf.dptr = NULL; - dbuf.dsize = 0; - - dbuf = tdb_fetch(posix_pending_close_tdb, kbuf); - - dbuf.dptr = SMB_REALLOC(dbuf.dptr, dbuf.dsize + sizeof(int)); - if (!dbuf.dptr) { - DEBUG(0,("add_fd_to_close_entry: Realloc fail !\n")); - return False; - } - - memcpy(dbuf.dptr + dbuf.dsize, &fsp->fh->fd, sizeof(int)); - dbuf.dsize += sizeof(int); - - if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) { - DEBUG(0,("add_fd_to_close_entry: tdb_store fail !\n")); - } - - SAFE_FREE(dbuf.dptr); - return True; -} - -/**************************************************************************** - Remove all fd entries for a specific dev/inode pair from the tdb. -****************************************************************************/ - -static void delete_close_entries(files_struct *fsp) -{ - TDB_DATA kbuf = locking_key_fsp(fsp); - - if (tdb_delete(posix_pending_close_tdb, kbuf) == -1) - DEBUG(0,("delete_close_entries: tdb_delete fail !\n")); -} - -/**************************************************************************** - Get the array of POSIX pending close records for an open fsp. Caller must - free. Returns number of entries. -****************************************************************************/ - -static size_t get_posix_pending_close_entries(files_struct *fsp, int **entries) -{ - TDB_DATA kbuf = locking_key_fsp(fsp); - TDB_DATA dbuf; - size_t count = 0; - - *entries = NULL; - dbuf.dptr = NULL; - - dbuf = tdb_fetch(posix_pending_close_tdb, kbuf); - - if (!dbuf.dptr) { - return 0; - } - - *entries = (int *)dbuf.dptr; - count = (size_t)(dbuf.dsize / sizeof(int)); - - return count; -} - -/**************************************************************************** - Get the array of POSIX locks for an fsp. Caller must free. Returns - number of entries. -****************************************************************************/ - -static size_t get_posix_lock_entries(files_struct *fsp, struct posix_lock **entries) -{ - TDB_DATA kbuf = locking_key_fsp(fsp); - TDB_DATA dbuf; - size_t count = 0; - - *entries = NULL; - - dbuf.dptr = NULL; - - dbuf = tdb_fetch(posix_lock_tdb, kbuf); - - if (!dbuf.dptr) { - return 0; - } - - *entries = (struct posix_lock *)dbuf.dptr; - count = (size_t)(dbuf.dsize / sizeof(struct posix_lock)); - - return count; -} - -/**************************************************************************** - Deal with pending closes needed by POSIX locking support. - Note that posix_locking_close_file() is expected to have been called - to delete all locks on this fsp before this function is called. -****************************************************************************/ - -int fd_close_posix(struct connection_struct *conn, files_struct *fsp) -{ - int saved_errno = 0; - int ret; - size_t count, i; - struct posix_lock *entries = NULL; - int *fd_array = NULL; - BOOL locks_on_other_fds = False; - - if (!lp_posix_locking(SNUM(conn))) { - /* - * No POSIX to worry about, just close. - */ - ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd); - fsp->fh->fd = -1; - return ret; - } - - /* - * Get the number of outstanding POSIX locks on this dev/inode pair. - */ - - count = get_posix_lock_entries(fsp, &entries); - - /* - * Check if there are any outstanding locks belonging to - * other fd's. This should never be the case if posix_locking_close_file() - * has been called first, but it never hurts to be *sure*. - */ - - for (i = 0; i < count; i++) { - if (entries[i].fd != fsp->fh->fd) { - locks_on_other_fds = True; - break; - } - } - - if (locks_on_other_fds) { - - /* - * There are outstanding locks on this dev/inode pair on other fds. - * Add our fd to the pending close tdb and set fsp->fh->fd to -1. - */ - - if (!add_fd_to_close_entry(fsp)) { - SAFE_FREE(entries); - return -1; - } - - SAFE_FREE(entries); - fsp->fh->fd = -1; - return 0; - } - - SAFE_FREE(entries); - - /* - * No outstanding POSIX locks. Get the pending close fd's - * from the tdb and close them all. - */ - - count = get_posix_pending_close_entries(fsp, &fd_array); - - if (count) { - DEBUG(10,("fd_close_posix: doing close on %u fd's.\n", (unsigned int)count )); - - for(i = 0; i < count; i++) { - if (SMB_VFS_CLOSE(fsp,fd_array[i]) == -1) { - saved_errno = errno; - } - } - - /* - * Delete all fd's stored in the tdb - * for this dev/inode pair. - */ - - delete_close_entries(fsp); - } - - SAFE_FREE(fd_array); - - /* - * Finally close the fd associated with this fsp. - */ - - ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd); - - if (saved_errno != 0) { - errno = saved_errno; - ret = -1; - } - - fsp->fh->fd = -1; - - return ret; -} - /**************************************************************************** - Debugging aid :-). + First - the functions that deal with the underlying system locks - these + functions are used no matter if we're mapping CIFS Windows locks or CIFS + POSIX locks onto POSIX. ****************************************************************************/ -static const char *posix_lock_type_name(int lock_type) -{ - return (lock_type == F_RDLCK) ? "READ" : "WRITE"; -} - -/**************************************************************************** - Delete a POSIX lock entry by index number. Used if the tdb add succeeds, but - then the POSIX fcntl lock fails. -****************************************************************************/ - -static BOOL delete_posix_lock_entry_by_index(files_struct *fsp, size_t entry) -{ - TDB_DATA kbuf = locking_key_fsp(fsp); - TDB_DATA dbuf; - struct posix_lock *locks; - size_t count; - - dbuf.dptr = NULL; - - dbuf = tdb_fetch(posix_lock_tdb, kbuf); - - if (!dbuf.dptr) { - DEBUG(10,("delete_posix_lock_entry_by_index: tdb_fetch failed !\n")); - goto fail; - } - - count = (size_t)(dbuf.dsize / sizeof(struct posix_lock)); - locks = (struct posix_lock *)dbuf.dptr; - - if (count == 1) { - tdb_delete(posix_lock_tdb, kbuf); - } else { - if (entry < count-1) { - memmove(&locks[entry], &locks[entry+1], sizeof(struct posix_lock)*((count-1) - entry)); - } - dbuf.dsize -= sizeof(struct posix_lock); - tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE); - } - - SAFE_FREE(dbuf.dptr); - - return True; - - fail: - - SAFE_FREE(dbuf.dptr); - return False; -} - -/**************************************************************************** - Add an entry into the POSIX locking tdb. We return the index number of the - added lock (used in case we need to delete *exactly* this entry). Returns - False on fail, True on success. -****************************************************************************/ - -static BOOL add_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T size, int lock_type, size_t *pentry_num) -{ - TDB_DATA kbuf = locking_key_fsp(fsp); - TDB_DATA dbuf; - struct posix_lock pl; - - dbuf.dptr = NULL; - dbuf.dsize = 0; - - dbuf = tdb_fetch(posix_lock_tdb, kbuf); - - *pentry_num = (size_t)(dbuf.dsize / sizeof(struct posix_lock)); - - /* - * Add new record. - */ - - pl.fd = fsp->fh->fd; - pl.start = start; - pl.size = size; - pl.lock_type = lock_type; - - dbuf.dptr = SMB_REALLOC(dbuf.dptr, dbuf.dsize + sizeof(struct posix_lock)); - if (!dbuf.dptr) { - DEBUG(0,("add_posix_lock_entry: Realloc fail !\n")); - goto fail; - } - - memcpy(dbuf.dptr + dbuf.dsize, &pl, sizeof(struct posix_lock)); - dbuf.dsize += sizeof(struct posix_lock); - - if (tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE) == -1) { - DEBUG(0,("add_posix_lock: Failed to add lock entry on file %s\n", fsp->fsp_name)); - goto fail; - } - - SAFE_FREE(dbuf.dptr); - - DEBUG(10,("add_posix_lock: File %s: type = %s: start=%.0f size=%.0f: dev=%.0f inode=%.0f\n", - fsp->fsp_name, posix_lock_type_name(lock_type), (double)start, (double)size, - (double)fsp->dev, (double)fsp->inode )); - - return True; - - fail: - - SAFE_FREE(dbuf.dptr); - return False; -} - -/**************************************************************************** - Calculate if locks have any overlap at all. -****************************************************************************/ - -static BOOL does_lock_overlap(SMB_OFF_T start1, SMB_OFF_T size1, SMB_OFF_T start2, SMB_OFF_T size2) -{ - if (start1 >= start2 && start1 <= start2 + size2) - return True; - - if (start1 < start2 && start1 + size1 > start2) - return True; - - return False; -} - -/**************************************************************************** - Delete an entry from the POSIX locking tdb. Returns a copy of the entry being - deleted and the number of records that are overlapped by this one, or -1 on error. -****************************************************************************/ - -static int delete_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T size, struct posix_lock *pl) -{ - TDB_DATA kbuf = locking_key_fsp(fsp); - TDB_DATA dbuf; - struct posix_lock *locks; - size_t i, count; - BOOL found = False; - int num_overlapping_records = 0; - - dbuf.dptr = NULL; - - dbuf = tdb_fetch(posix_lock_tdb, kbuf); - - if (!dbuf.dptr) { - DEBUG(10,("delete_posix_lock_entry: tdb_fetch failed !\n")); - goto fail; - } - - /* There are existing locks - find a match. */ - locks = (struct posix_lock *)dbuf.dptr; - count = (size_t)(dbuf.dsize / sizeof(struct posix_lock)); - - /* - * Search for and delete the first record that matches the - * unlock criteria. - */ - - for (i=0; i<count; i++) { - struct posix_lock *entry = &locks[i]; - - if (entry->fd == fsp->fh->fd && - entry->start == start && - entry->size == size) { - - /* Make a copy */ - *pl = *entry; - - /* Found it - delete it. */ - if (count == 1) { - tdb_delete(posix_lock_tdb, kbuf); - } else { - if (i < count-1) { - memmove(&locks[i], &locks[i+1], sizeof(struct posix_lock)*((count-1) - i)); - } - dbuf.dsize -= sizeof(struct posix_lock); - tdb_store(posix_lock_tdb, kbuf, dbuf, TDB_REPLACE); - } - count--; - found = True; - break; - } - } - - if (!found) - goto fail; - - /* - * Count the number of entries that are - * overlapped by this unlock request. - */ - - for (i = 0; i < count; i++) { - struct posix_lock *entry = &locks[i]; - - if (fsp->fh->fd == entry->fd && - does_lock_overlap( start, size, entry->start, entry->size)) - num_overlapping_records++; - } - - DEBUG(10,("delete_posix_lock_entry: type = %s: start=%.0f size=%.0f, num_records = %d\n", - posix_lock_type_name(pl->lock_type), (double)pl->start, (double)pl->size, - (unsigned int)num_overlapping_records )); - - SAFE_FREE(dbuf.dptr); - - return num_overlapping_records; - - fail: - - SAFE_FREE(dbuf.dptr); - return -1; -} - /**************************************************************************** Utility function to map a lock type correctly depending on the open mode of a file. @@ -519,16 +55,6 @@ static int map_posix_lock_type( files_struct *fsp, enum brl_type lock_type) DEBUG(10,("map_posix_lock_type: Downgrading write lock to read due to read-only file.\n")); return F_RDLCK; } -#if 0 - /* We no longer open files write-only. */ - else if((lock_type == READ_LOCK) && !fsp->can_read) { - /* - * Ditto for read locks on write only files. - */ - DEBUG(10,("map_posix_lock_type: Changing read lock to write due to write-only file.\n")); - return F_WRLCK; - } -#endif /* * This return should be the most normal, as we attempt @@ -539,6 +65,15 @@ static int map_posix_lock_type( files_struct *fsp, enum brl_type lock_type) } /**************************************************************************** + Debugging aid :-). +****************************************************************************/ + +static const char *posix_lock_type_name(int lock_type) +{ + return (lock_type == F_RDLCK) ? "READ" : "WRITE"; +} + +/**************************************************************************** Check to see if the given unsigned lock range is within the possible POSIX range. Modifies the given args to be in range if possible, just returns False if not. @@ -608,15 +143,17 @@ static BOOL posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out, * We must truncate the count to less than max_positive_lock_offset. */ - if (u_count & ~((SMB_BIG_UINT)max_positive_lock_offset)) + if (u_count & ~((SMB_BIG_UINT)max_positive_lock_offset)) { count = max_positive_lock_offset; + } /* * Truncate count to end at max lock offset. */ - if (offset + count < 0 || offset + count > max_positive_lock_offset) + if (offset + count < 0 || offset + count > max_positive_lock_offset) { count = max_positive_lock_offset - offset; + } /* * If we ate all the count, ignore this lock. @@ -729,7 +266,6 @@ static BOOL posix_fcntl_getlock(files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T return ret; } - /**************************************************************************** POSIX function to see if a file region is locked. Returns True if the region is locked, False otherwise. @@ -774,6 +310,411 @@ BOOL is_posix_locked(files_struct *fsp, return True; } +/**************************************************************************** + Next - the functions that deal with in memory database storing representations + of either Windows CIFS locks or POSIX CIFS locks. +****************************************************************************/ + +/* The key used in the in-memory POSIX databases. */ + +struct lock_ref_count_key { + SMB_DEV_T device; + SMB_INO_T inode; + char r; +}; + +struct fd_key { + SMB_DEV_T device; + SMB_INO_T inode; +}; + +/******************************************************************* + Form a static locking key for a dev/inode pair for the fd array. +******************************************************************/ + +static TDB_DATA fd_array_key(SMB_DEV_T dev, SMB_INO_T inode) +{ + static struct fd_key key; + TDB_DATA kbuf; + + memset(&key, '\0', sizeof(key)); + key.device = dev; + key.inode = inode; + kbuf.dptr = (char *)&key; + kbuf.dsize = sizeof(key); + return kbuf; +} + +/******************************************************************* + Form a static locking key for a dev/inode pair for the lock ref count +******************************************************************/ + +static TDB_DATA locking_ref_count_key(SMB_DEV_T dev, SMB_INO_T inode) +{ + static struct lock_ref_count_key key; + TDB_DATA kbuf; + + memset(&key, '\0', sizeof(key)); + key.device = dev; + key.inode = inode; + key.r = 'r'; + kbuf.dptr = (char *)&key; + kbuf.dsize = sizeof(key); + return kbuf; +} + +/******************************************************************* + Convenience function to get an fd_array key from an fsp. +******************************************************************/ + +static TDB_DATA fd_array_key_fsp(files_struct *fsp) +{ + return fd_array_key(fsp->dev, fsp->inode); +} + +/******************************************************************* + Convenience function to get a lock ref count key from an fsp. +******************************************************************/ + +static TDB_DATA locking_ref_count_key_fsp(files_struct *fsp) +{ + return locking_ref_count_key(fsp->dev, fsp->inode); +} + +/******************************************************************* + Create the in-memory POSIX lock databases. +********************************************************************/ + +BOOL posix_locking_init(int read_only) +{ + if (posix_pending_close_tdb) { + return True; + } + + if (!posix_pending_close_tdb) { + posix_pending_close_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL, + read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644); + } + if (!posix_pending_close_tdb) { + DEBUG(0,("Failed to open POSIX pending close database.\n")); + return False; + } + + return True; +} + +/******************************************************************* + Delete the in-memory POSIX lock databases. +********************************************************************/ + +BOOL posix_locking_end(void) +{ + if (posix_pending_close_tdb && tdb_close(posix_pending_close_tdb) != 0) { + return False; + } + return True; +} + +/**************************************************************************** + Next - the functions that deal with storing fd's that have outstanding + POSIX locks when closed. +****************************************************************************/ + +/**************************************************************************** + The records in posix_pending_close_tdb are composed of an array of ints + keyed by dev/ino pair. + The first int is a reference count of the number of outstanding locks on + all open fd's on this dev/ino pair. Any subsequent ints are the fd's that + were open on this dev/ino pair that should have been closed, but can't as + the lock ref count is non zero. +****************************************************************************/ + +/**************************************************************************** + Keep a reference count of the number of Windows locks open on this dev/ino + pair. Creates entry if it doesn't exist. +****************************************************************************/ + +static void increment_windows_lock_ref_count(files_struct *fsp) +{ + TDB_DATA kbuf = locking_ref_count_key_fsp(fsp); + TDB_DATA dbuf; + int lock_ref_count; + + dbuf = tdb_fetch(posix_pending_close_tdb, kbuf); + if (dbuf.dptr == NULL) { + dbuf.dptr = (char *)SMB_MALLOC_P(int); + if (!dbuf.dptr) { + smb_panic("increment_windows_lock_ref_count: malloc fail.\n"); + } + memset(dbuf.dptr, '\0', sizeof(int)); + dbuf.dsize = sizeof(int); + } + + memcpy(&lock_ref_count, dbuf.dptr, sizeof(int)); + lock_ref_count++; + memcpy(dbuf.dptr, &lock_ref_count, sizeof(int)); + + if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) { + smb_panic("increment_windows_lock_ref_count: tdb_store_fail.\n"); + } + SAFE_FREE(dbuf.dptr); + + DEBUG(10,("increment_windows_lock_ref_count for file now %s = %d\n", + fsp->fsp_name, lock_ref_count )); +} + +static void decrement_windows_lock_ref_count(files_struct *fsp) +{ + TDB_DATA kbuf = locking_ref_count_key_fsp(fsp); + TDB_DATA dbuf; + int lock_ref_count; + + dbuf = tdb_fetch(posix_pending_close_tdb, kbuf); + if (!dbuf.dptr) { + smb_panic("decrement_windows_lock_ref_count: logic error.\n"); + } + + memcpy(&lock_ref_count, dbuf.dptr, sizeof(int)); + lock_ref_count--; + memcpy(dbuf.dptr, &lock_ref_count, sizeof(int)); + + if (lock_ref_count < 0) { + smb_panic("decrement_windows_lock_ref_count: lock_count logic error.\n"); + } + + if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) { + smb_panic("decrement_windows_lock_ref_count: tdb_store_fail.\n"); + } + SAFE_FREE(dbuf.dptr); + + DEBUG(10,("decrement_windows_lock_ref_count for file now %s = %d\n", + fsp->fsp_name, lock_ref_count )); +} + +/**************************************************************************** + Ensure the lock ref count is zero. +****************************************************************************/ + +void zero_windows_lock_ref_count(files_struct *fsp) +{ + TDB_DATA kbuf = locking_ref_count_key_fsp(fsp); + TDB_DATA dbuf; + int lock_ref_count; + + dbuf = tdb_fetch(posix_pending_close_tdb, kbuf); + if (!dbuf.dptr) { + return; + } + + memcpy(&lock_ref_count, dbuf.dptr, sizeof(int)); + if (lock_ref_count < 0) { + smb_panic("zero_windows_lock_ref_count: lock_count logic error.\n"); + } + + lock_ref_count = 0; + memcpy(dbuf.dptr, &lock_ref_count, sizeof(int)); + + if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) { + smb_panic("zero_windows_lock_ref_count: tdb_store_fail.\n"); + } + SAFE_FREE(dbuf.dptr); + + DEBUG(10,("zero_windows_lock_ref_count for file now %s = %d\n", + fsp->fsp_name, lock_ref_count )); +} + +/**************************************************************************** + Fetch the lock ref count. +****************************************************************************/ + +static int get_windows_lock_ref_count(files_struct *fsp) +{ + TDB_DATA kbuf = locking_ref_count_key_fsp(fsp); + TDB_DATA dbuf; + int lock_ref_count; + + dbuf = tdb_fetch(posix_pending_close_tdb, kbuf); + if (!dbuf.dptr) { + lock_ref_count = 0; + } else { + memcpy(&lock_ref_count, dbuf.dptr, sizeof(int)); + } + + DEBUG(10,("get_windows_lock_count for file %s = %d\n", + fsp->fsp_name, lock_ref_count )); + return lock_ref_count; +} + +/**************************************************************************** + Delete a lock_ref_count entry. +****************************************************************************/ + +static void delete_windows_lock_ref_count(files_struct *fsp) +{ + TDB_DATA kbuf = locking_ref_count_key_fsp(fsp); + + /* Not a bug if it doesn't exist - no locks were ever granted. */ + tdb_delete(posix_pending_close_tdb, kbuf); + DEBUG(10,("delete_windows_lock_ref_count for file %s\n", fsp->fsp_name)); +} + +/**************************************************************************** + Add an fd to the pending close tdb. +****************************************************************************/ + +static void add_fd_to_close_entry(files_struct *fsp) +{ + TDB_DATA kbuf = fd_array_key_fsp(fsp); + TDB_DATA dbuf; + + dbuf.dptr = NULL; + dbuf.dsize = 0; + + dbuf = tdb_fetch(posix_pending_close_tdb, kbuf); + + dbuf.dptr = SMB_REALLOC(dbuf.dptr, dbuf.dsize + sizeof(int)); + if (!dbuf.dptr) { + smb_panic("add_fd_to_close_entry: Realloc fail !\n"); + } + + memcpy(dbuf.dptr + dbuf.dsize, &fsp->fh->fd, sizeof(int)); + dbuf.dsize += sizeof(int); + + if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) { + smb_panic("add_fd_to_close_entry: tdb_store_fail.\n"); + } + + DEBUG(10,("add_fd_to_close_entry: added fd %d file %s\n", + fsp->fh->fd, fsp->fsp_name )); + + SAFE_FREE(dbuf.dptr); +} + +/**************************************************************************** + Remove all fd entries for a specific dev/inode pair from the tdb. +****************************************************************************/ + +static void delete_close_entries(files_struct *fsp) +{ + TDB_DATA kbuf = fd_array_key_fsp(fsp); + + if (tdb_delete(posix_pending_close_tdb, kbuf) == -1) { + smb_panic("delete_close_entries: tdb_delete fail !\n"); + } +} + +/**************************************************************************** + Get the array of POSIX pending close records for an open fsp. Caller must + free. Returns number of entries. +****************************************************************************/ + +static size_t get_posix_pending_close_entries(files_struct *fsp, int **entries) +{ + TDB_DATA kbuf = fd_array_key_fsp(fsp); + TDB_DATA dbuf; + size_t count = 0; + + *entries = NULL; + dbuf.dptr = NULL; + + dbuf = tdb_fetch(posix_pending_close_tdb, kbuf); + + if (!dbuf.dptr) { + return 0; + } + + *entries = (int *)dbuf.dptr; + count = (size_t)(dbuf.dsize / sizeof(int)); + + return count; +} + +/**************************************************************************** + Deal with pending closes needed by POSIX locking support. + Note that posix_locking_close_file() is expected to have been called + to delete all locks on this fsp before this function is called. +****************************************************************************/ + +int fd_close_posix(struct connection_struct *conn, files_struct *fsp) +{ + int saved_errno = 0; + int ret; + int *fd_array = NULL; + size_t count, i; + + if (!lp_locking(SNUM(fsp->conn)) || !lp_posix_locking(SNUM(conn)) || lp_posix_cifsu_locktype()) { + /* + * No locking or POSIX to worry about or we want POSIX semantics + * which will lose all locks on all fd's open on this dev/inode, + * just close. + */ + ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd); + fsp->fh->fd = -1; + return ret; + } + + if (get_windows_lock_ref_count(fsp)) { + + /* + * There are outstanding locks on this dev/inode pair on other fds. + * Add our fd to the pending close tdb and set fsp->fh->fd to -1. + */ + + add_fd_to_close_entry(fsp); + fsp->fh->fd = -1; + return 0; + } + + /* + * No outstanding locks. Get the pending close fd's + * from the tdb and close them all. + */ + + count = get_posix_pending_close_entries(fsp, &fd_array); + + if (count) { + DEBUG(10,("fd_close_posix: doing close on %u fd's.\n", (unsigned int)count )); + + for(i = 0; i < count; i++) { + if (SMB_VFS_CLOSE(fsp,fd_array[i]) == -1) { + saved_errno = errno; + } + } + + /* + * Delete all fd's stored in the tdb + * for this dev/inode pair. + */ + + delete_close_entries(fsp); + } + + SAFE_FREE(fd_array); + + /* Don't need a lock ref count on this dev/ino anymore. */ + delete_windows_lock_ref_count(fsp); + + /* + * Finally close the fd associated with this fsp. + */ + + ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd); + + if (saved_errno != 0) { + errno = saved_errno; + ret = -1; + } + + fsp->fh->fd = -1; + + return ret; +} + +/**************************************************************************** + Next - the functions that deal with the mapping CIFS Windows locks onto + the underlying system POSIX locks. +****************************************************************************/ + /* * Structure used when splitting a lock range * into a POSIX lock range. Doubly linked list. @@ -792,22 +733,14 @@ struct lock_list { understand it :-). ****************************************************************************/ -static struct lock_list *posix_lock_list(TALLOC_CTX *ctx, struct lock_list *lhead, files_struct *fsp) +static struct lock_list *posix_lock_list(TALLOC_CTX *ctx, + struct lock_list *lhead, + const struct lock_context *lock_ctx, /* Lock context lhead belongs to. */ + files_struct *fsp, + const struct lock_struct *plocks, + int num_locks) { - TDB_DATA kbuf = locking_key_fsp(fsp); - TDB_DATA dbuf; - struct posix_lock *locks; - size_t num_locks, i; - - dbuf.dptr = NULL; - - dbuf = tdb_fetch(posix_lock_tdb, kbuf); - - if (!dbuf.dptr) - return lhead; - - locks = (struct posix_lock *)dbuf.dptr; - num_locks = (size_t)(dbuf.dsize / sizeof(struct posix_lock)); + int i; /* * Check the current lock list on this dev/inode pair. @@ -818,10 +751,19 @@ static struct lock_list *posix_lock_list(TALLOC_CTX *ctx, struct lock_list *lhea (double)lhead->start, (double)lhead->size )); for (i=0; i<num_locks && lhead; i++) { - - struct posix_lock *lock = &locks[i]; + const struct lock_struct *lock = &plocks[i]; struct lock_list *l_curr; + /* Ignore all but read/write locks. */ + if (lock->lock_type != READ_LOCK && lock->lock_type != WRITE_LOCK) { + continue; + } + + /* Ignore locks not owned by this process. */ + if (!procid_equal(&lock->context.pid, &lock_ctx->pid)) { + continue; + } + /* * Walk the lock list, checking for overlaps. Note that * the lock list can expand within this loop if the current @@ -830,13 +772,13 @@ static struct lock_list *posix_lock_list(TALLOC_CTX *ctx, struct lock_list *lhea for (l_curr = lhead; l_curr;) { - DEBUG(10,("posix_lock_list: lock: fd=%d: start=%.0f,size=%.0f:type=%s", lock->fd, + DEBUG(10,("posix_lock_list: lock: fnum=%d: start=%.0f,size=%.0f:type=%s", lock->fnum, (double)lock->start, (double)lock->size, posix_lock_type_name(lock->lock_type) )); if ( (l_curr->start >= (lock->start + lock->size)) || (lock->start >= (l_curr->start + l_curr->size))) { - /* No overlap with this lock - leave this range alone. */ + /* No overlap with existing lock - leave this range alone. */ /********************************************* +---------+ | l_curr | @@ -850,7 +792,7 @@ OR.... +---------+ **********************************************/ - DEBUG(10,("no overlap case.\n" )); + DEBUG(10,(" no overlap case.\n" )); l_curr = l_curr->next; @@ -858,8 +800,8 @@ OR.... (l_curr->start + l_curr->size <= lock->start + lock->size) ) { /* - * This unlock is completely overlapped by this existing lock range - * and thus should have no effect (not be unlocked). Delete it from the list. + * This range is completely overlapped by this existing lock range + * and thus should have no effect. Delete it from the list. */ /********************************************* +---------+ @@ -872,11 +814,12 @@ OR.... /* Save the next pointer */ struct lock_list *ul_next = l_curr->next; - DEBUG(10,("delete case.\n" )); + DEBUG(10,(" delete case.\n" )); DLIST_REMOVE(lhead, l_curr); - if(lhead == NULL) + if(lhead == NULL) { break; /* No more list... */ + } l_curr = ul_next; @@ -885,7 +828,7 @@ OR.... (l_curr->start + l_curr->size > lock->start + lock->size) ) { /* - * This unlock overlaps the existing lock range at the high end. + * This range overlaps the existing lock range at the high end. * Truncate by moving start to existing range end and reducing size. */ /********************************************* @@ -904,7 +847,7 @@ BECOMES.... l_curr->size = (l_curr->start + l_curr->size) - (lock->start + lock->size); l_curr->start = lock->start + lock->size; - DEBUG(10,("truncate high case: start=%.0f,size=%.0f\n", + DEBUG(10,(" truncate high case: start=%.0f,size=%.0f\n", (double)l_curr->start, (double)l_curr->size )); l_curr = l_curr->next; @@ -914,7 +857,7 @@ BECOMES.... (l_curr->start + l_curr->size <= lock->start + lock->size) ) { /* - * This unlock overlaps the existing lock range at the low end. + * This range overlaps the existing lock range at the low end. * Truncate by reducing size. */ /********************************************* @@ -932,7 +875,7 @@ BECOMES.... l_curr->size = lock->start - l_curr->start; - DEBUG(10,("truncate low case: start=%.0f,size=%.0f\n", + DEBUG(10,(" truncate low case: start=%.0f,size=%.0f\n", (double)l_curr->start, (double)l_curr->size )); l_curr = l_curr->next; @@ -940,10 +883,10 @@ BECOMES.... } else if ( (l_curr->start < lock->start) && (l_curr->start + l_curr->size > lock->start + lock->size) ) { /* - * Worst case scenario. Unlock request completely overlaps an existing + * Worst case scenario. Range completely overlaps an existing * lock range. Split the request into two, push the new (upper) request - * into the dlink list, and continue with the entry after ul_new (as we - * know that ul_new will not overlap with this lock). + * into the dlink list, and continue with the entry after l_new (as we + * know that l_new will not overlap with this lock). */ /********************************************* +---------------------------+ @@ -971,7 +914,7 @@ BECOMES..... /* Truncate the l_curr. */ l_curr->size = lock->start - l_curr->start; - DEBUG(10,("split case: curr: start=%.0f,size=%.0f \ + DEBUG(10,(" split case: curr: start=%.0f,size=%.0f \ new: start=%.0f,size=%.0f\n", (double)l_curr->start, (double)l_curr->size, (double)l_new->start, (double)l_new->size )); @@ -1003,34 +946,33 @@ lock: start = %.0f, size = %.0f\n", (double)l_curr->start, (double)l_curr->size, } /* end for ( l_curr = lhead; l_curr;) */ } /* end for (i=0; i<num_locks && ul_head; i++) */ - SAFE_FREE(dbuf.dptr); - return lhead; } /**************************************************************************** POSIX function to acquire a lock. Returns True if the lock could be granted, False if not. - TODO -- Fix POSIX lock flavour semantics. ****************************************************************************/ -BOOL set_posix_lock(files_struct *fsp, +BOOL set_posix_lock_windows_flavour(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type, - enum brl_flavour lock_flav) + const struct lock_context *lock_ctx, + const struct lock_struct *plocks, + int num_locks, + int *errno_ret) { SMB_OFF_T offset; SMB_OFF_T count; + int posix_lock_type = map_posix_lock_type(fsp,lock_type); BOOL ret = True; - size_t entry_num = 0; size_t lock_count; TALLOC_CTX *l_ctx = NULL; struct lock_list *llist = NULL; struct lock_list *ll = NULL; - int posix_lock_type = map_posix_lock_type(fsp,lock_type); - DEBUG(5,("set_posix_lock: File %s, offset = %.0f, count = %.0f, type = %s\n", + DEBUG(5,("set_posix_lock_windows_flavour: File %s, offset = %.0f, count = %.0f, type = %s\n", fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) )); /* @@ -1038,8 +980,9 @@ BOOL set_posix_lock(files_struct *fsp, * pretend it was successful. */ - if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) + if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) { return True; + } /* * Windows is very strange. It allows read locks to be overlayed @@ -1056,19 +999,16 @@ BOOL set_posix_lock(files_struct *fsp, * READ LOCK: start =0, len = 10 - OK * * Under POSIX, the same sequence in steps 1 and 2 would not be reference counted, but - * would leave a single read lock over the 0-14 region. In order to - * re-create Windows semantics mapped to POSIX locks, we create multiple TDB - * entries, one for each overlayed lock request. We are guarenteed by the brlock - * semantics that if a write lock is added, then it will be first in the array. + * would leave a single read lock over the 0-14 region. */ if ((l_ctx = talloc_init("set_posix_lock")) == NULL) { - DEBUG(0,("set_posix_lock: unable to init talloc context.\n")); + DEBUG(0,("set_posix_lock_windows_flavour: unable to init talloc context.\n")); return True; /* Not a fatal error. */ } if ((ll = TALLOC_P(l_ctx, struct lock_list)) == NULL) { - DEBUG(0,("set_posix_lock: unable to talloc unlock list.\n")); + DEBUG(0,("set_posix_lock_windows_flavour: unable to talloc unlock list.\n")); talloc_destroy(l_ctx); return True; /* Not a fatal error. */ } @@ -1092,19 +1032,12 @@ BOOL set_posix_lock(files_struct *fsp, * POSIX locks. */ - llist = posix_lock_list(l_ctx, llist, fsp); - - /* - * Now we have the list of ranges to lock it is safe to add the - * entry into the POSIX lock tdb. We take note of the entry we - * added here in case we have to remove it on POSIX lock fail. - */ - - if (!add_posix_lock_entry(fsp,offset,count,posix_lock_type,&entry_num)) { - DEBUG(0,("set_posix_lock: Unable to create posix lock entry !\n")); - talloc_destroy(l_ctx); - return False; - } + llist = posix_lock_list(l_ctx, + llist, + lock_ctx, /* Lock context llist belongs to. */ + fsp, + plocks, + num_locks); /* * Add the POSIX locks on the list of ranges returned. @@ -1116,11 +1049,12 @@ BOOL set_posix_lock(files_struct *fsp, offset = ll->start; count = ll->size; - DEBUG(5,("set_posix_lock: Real lock: Type = %s: offset = %.0f, count = %.0f\n", + DEBUG(5,("set_posix_lock_windows_flavour: Real lock: Type = %s: offset = %.0f, count = %.0f\n", posix_lock_type_name(posix_lock_type), (double)offset, (double)count )); if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,posix_lock_type)) { - DEBUG(5,("set_posix_lock: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n", + *errno_ret = errno; + DEBUG(5,("set_posix_lock_windows_flavour: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n", posix_lock_type_name(posix_lock_type), (double)offset, (double)count, strerror(errno) )); ret = False; break; @@ -1137,17 +1071,14 @@ BOOL set_posix_lock(files_struct *fsp, offset = ll->start; count = ll->size; - DEBUG(5,("set_posix_lock: Backing out locks: Type = %s: offset = %.0f, count = %.0f\n", + DEBUG(5,("set_posix_lock_windows_flavour: Backing out locks: Type = %s: offset = %.0f, count = %.0f\n", posix_lock_type_name(posix_lock_type), (double)offset, (double)count )); posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK); } - - /* - * Remove the tdb entry for this lock. - */ - - delete_posix_lock_entry_by_index(fsp,entry_num); + } else { + /* Remember the number of Windows locks we have on this dev/ino pair. */ + increment_windows_lock_ref_count(fsp); } talloc_destroy(l_ctx); @@ -1159,7 +1090,13 @@ BOOL set_posix_lock(files_struct *fsp, lock could be released, False if not. ****************************************************************************/ -BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count) +BOOL release_posix_lock_windows_flavour(files_struct *fsp, + SMB_BIG_UINT u_offset, + SMB_BIG_UINT u_count, + enum brl_type deleted_lock_type, + const struct lock_context *lock_ctx, + const struct lock_struct *plocks, + int num_locks) { SMB_OFF_T offset; SMB_OFF_T count; @@ -1167,10 +1104,8 @@ BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u TALLOC_CTX *ul_ctx = NULL; struct lock_list *ulist = NULL; struct lock_list *ul = NULL; - struct posix_lock deleted_lock; - int num_overlapped_entries; - DEBUG(5,("release_posix_lock: File %s, offset = %.0f, count = %.0f\n", + DEBUG(5,("release_posix_lock_windows_flavour: File %s, offset = %.0f, count = %.0f\n", fsp->fsp_name, (double)u_offset, (double)u_count )); /* @@ -1178,43 +1113,20 @@ BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u * pretend it was successful. */ - if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) + if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) { return True; - - /* - * We treat this as one unlock request for POSIX accounting purposes even - * if it may later be split into multiple smaller POSIX unlock ranges. - * num_overlapped_entries is the number of existing locks that have any - * overlap with this unlock request. - */ - - num_overlapped_entries = delete_posix_lock_entry(fsp, offset, count, &deleted_lock); - - if (num_overlapped_entries == -1) { - smb_panic("release_posix_lock: unable find entry to delete !\n"); } - /* - * If num_overlapped_entries is > 0, and the lock_type we just deleted from the tdb was - * a POSIX write lock, then before doing the unlock we need to downgrade - * the POSIX lock to a read lock. This allows any overlapping read locks - * to be atomically maintained. - */ - - if (num_overlapped_entries > 0 && deleted_lock.lock_type == F_WRLCK) { - if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_RDLCK)) { - DEBUG(0,("release_posix_lock: downgrade of lock failed with error %s !\n", strerror(errno) )); - return False; - } - } + /* Remember the number of Windows locks we have on this dev/ino pair. */ + decrement_windows_lock_ref_count(fsp); if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) { - DEBUG(0,("release_posix_lock: unable to init talloc context.\n")); + DEBUG(0,("release_posix_lock_windows_flavour: unable to init talloc context.\n")); return True; /* Not a fatal error. */ } if ((ul = TALLOC_P(ul_ctx, struct lock_list)) == NULL) { - DEBUG(0,("release_posix_lock: unable to talloc unlock list.\n")); + DEBUG(0,("release_posix_lock_windows_flavour: unable to talloc unlock list.\n")); talloc_destroy(ul_ctx); return True; /* Not a fatal error. */ } @@ -1239,7 +1151,33 @@ BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u * unlocks are performed. */ - ulist = posix_lock_list(ul_ctx, ulist, fsp); + ulist = posix_lock_list(ul_ctx, + ulist, + lock_ctx, /* Lock context ulist belongs to. */ + fsp, + plocks, + num_locks); + + /* + * If there were any overlapped entries (list is > 1 or size or start have changed), + * and the lock_type we just deleted from + * the upper layer tdb was a write lock, then before doing the unlock we need to downgrade + * the POSIX lock to a read lock. This allows any overlapping read locks + * to be atomically maintained. + */ + + if (deleted_lock_type == WRITE_LOCK && + (!ulist || ulist->next != NULL || ulist->start != offset || ulist->size != count)) { + + DEBUG(5,("release_posix_lock_windows_flavour: downgrading lock to READ: offset = %.0f, count = %.0f\n", + (double)offset, (double)count )); + + if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_RDLCK)) { + DEBUG(0,("release_posix_lock_windows_flavour: downgrade of lock failed with error %s !\n", strerror(errno) )); + talloc_destroy(ul_ctx); + return False; + } + } /* * Release the POSIX locks on the list of ranges returned. @@ -1249,129 +1187,148 @@ BOOL release_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u offset = ulist->start; count = ulist->size; - DEBUG(5,("release_posix_lock: Real unlock: offset = %.0f, count = %.0f\n", + DEBUG(5,("release_posix_lock_windows_flavour: Real unlock: offset = %.0f, count = %.0f\n", (double)offset, (double)count )); - if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK)) + if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK)) { ret = False; + } } talloc_destroy(ul_ctx); - return ret; } /**************************************************************************** - Remove all lock entries for a specific dev/inode pair from the tdb. + Next - the functions that deal with mapping CIFS POSIX locks onto + the underlying system POSIX locks. ****************************************************************************/ -static void delete_posix_lock_entries(files_struct *fsp) -{ - TDB_DATA kbuf = locking_key_fsp(fsp); - - if (tdb_delete(posix_lock_tdb, kbuf) == -1) - DEBUG(0,("delete_close_entries: tdb_delete fail !\n")); -} - /**************************************************************************** - Debug function. + POSIX function to acquire a lock. Returns True if the + lock could be granted, False if not. + As POSIX locks don't stack or conflict (they just overwrite) + we can map the requested lock directly onto a system one. We + know it doesn't conflict with locks on other contexts as the + upper layer would have refused it. ****************************************************************************/ -static void dump_entry(struct posix_lock *pl) +BOOL set_posix_lock_posix_flavour(files_struct *fsp, + SMB_BIG_UINT u_offset, + SMB_BIG_UINT u_count, + enum brl_type lock_type, + int *errno_ret) { - DEBUG(10,("entry: start=%.0f, size=%.0f, type=%d, fd=%i\n", - (double)pl->start, (double)pl->size, (int)pl->lock_type, pl->fd )); + SMB_OFF_T offset; + SMB_OFF_T count; + int posix_lock_type = map_posix_lock_type(fsp,lock_type); + + DEBUG(5,("set_posix_lock_posix_flavour: File %s, offset = %.0f, count = %.0f, type = %s\n", + fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) )); + + /* + * If the requested lock won't fit in the POSIX range, we will + * pretend it was successful. + */ + + if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) { + return True; + } + + if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,posix_lock_type)) { + *errno_ret = errno; + DEBUG(5,("set_posix_lock_posix_flavour: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n", + posix_lock_type_name(posix_lock_type), (double)offset, (double)count, strerror(errno) )); + return False; + } + return True; } /**************************************************************************** - Remove any locks on this fd. Called from file_close(). + POSIX function to release a lock. Returns True if the + lock could be released, False if not. + We are given a complete lock state from the upper layer which is what the lock + state should be after the unlock has already been done, so what + we do is punch out holes in the unlock range where locks owned by this process + have a different lock context. ****************************************************************************/ -void posix_locking_close_file(files_struct *fsp) +BOOL release_posix_lock_posix_flavour(files_struct *fsp, + SMB_BIG_UINT u_offset, + SMB_BIG_UINT u_count, + const struct lock_context *lock_ctx, + const struct lock_struct *plocks, + int num_locks) { - struct posix_lock *entries = NULL; - size_t count, i; + BOOL ret = True; + SMB_OFF_T offset; + SMB_OFF_T count; + TALLOC_CTX *ul_ctx = NULL; + struct lock_list *ulist = NULL; + struct lock_list *ul = NULL; + + DEBUG(5,("release_posix_lock_posix_flavour: File %s, offset = %.0f, count = %.0f\n", + fsp->fsp_name, (double)u_offset, (double)u_count )); /* - * Optimization for the common case where we are the only - * opener of a file. If all fd entries are our own, we don't - * need to explicitly release all the locks via the POSIX functions, - * we can just remove all the entries in the tdb and allow the - * close to remove the real locks. + * If the requested lock won't fit in the POSIX range, we will + * pretend it was successful. */ - count = get_posix_lock_entries(fsp, &entries); - - if (count == 0) { - DEBUG(10,("posix_locking_close_file: file %s has no outstanding locks.\n", fsp->fsp_name )); - return; + if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) { + return True; } - for (i = 0; i < count; i++) { - if (entries[i].fd != fsp->fh->fd ) - break; - - dump_entry(&entries[i]); + if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) { + DEBUG(0,("release_posix_lock_windows_flavour: unable to init talloc context.\n")); + return False; } - if (i == count) { - /* All locks are ours. */ - DEBUG(10,("posix_locking_close_file: file %s has %u outstanding locks, but all on one fd.\n", - fsp->fsp_name, (unsigned int)count )); - SAFE_FREE(entries); - delete_posix_lock_entries(fsp); - return; + if ((ul = TALLOC_P(ul_ctx, struct lock_list)) == NULL) { + DEBUG(0,("release_posix_lock_windows_flavour: unable to talloc unlock list.\n")); + talloc_destroy(ul_ctx); + return False; } /* - * Difficult case. We need to delete all our locks, whilst leaving - * all other POSIX locks in place. + * Create the initial list entry containing the + * lock we want to remove. */ - for (i = 0; i < count; i++) { - struct posix_lock *pl = &entries[i]; - if (pl->fd == fsp->fh->fd) - release_posix_lock(fsp, (SMB_BIG_UINT)pl->start, (SMB_BIG_UINT)pl->size ); - } - SAFE_FREE(entries); -} + ZERO_STRUCTP(ul); + ul->start = offset; + ul->size = count; -/******************************************************************* - Create the in-memory POSIX lock databases. -********************************************************************/ + DLIST_ADD(ulist, ul); -BOOL posix_locking_init(int read_only) -{ - if (posix_lock_tdb && posix_pending_close_tdb) - return True; - - if (!posix_lock_tdb) - posix_lock_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL, - read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644); - if (!posix_lock_tdb) { - DEBUG(0,("Failed to open POSIX byte range locking database.\n")); - return False; - } - if (!posix_pending_close_tdb) - posix_pending_close_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL, - read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644); - if (!posix_pending_close_tdb) { - DEBUG(0,("Failed to open POSIX pending close database.\n")); - return False; - } + /* + * Walk the given array creating a linked list + * of unlock requests. + */ - return True; -} + ulist = posix_lock_list(ul_ctx, + ulist, + lock_ctx, /* Lock context ulist belongs to. */ + fsp, + plocks, + num_locks); -/******************************************************************* - Delete the in-memory POSIX lock databases. -********************************************************************/ + /* + * Release the POSIX locks on the list of ranges returned. + */ -BOOL posix_locking_end(void) -{ - if (posix_lock_tdb && tdb_close(posix_lock_tdb) != 0) - return False; - if (posix_pending_close_tdb && tdb_close(posix_pending_close_tdb) != 0) - return False; + for(; ulist; ulist = ulist->next) { + offset = ulist->start; + count = ulist->size; + + DEBUG(5,("release_posix_lock_posix_flavour: Real unlock: offset = %.0f, count = %.0f\n", + (double)offset, (double)count )); + + if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK)) { + ret = False; + } + } + + talloc_destroy(ul_ctx); return True; } |