r22846: Chunk one to replace message_send_pid with messaging_send: Deep inside
[sfrench/samba-autobuild/.git] / source / locking / brlock.c
index 5ce8a3730b23ddbcf4e3b29388e324c8f0fdeec7..d48c746161daf181bba70c37da641debeabce626 100644 (file)
@@ -98,7 +98,7 @@ static BOOL brl_conflict(const struct lock_struct *lck1,
                         const struct lock_struct *lck2)
 {
        /* Ignore PENDING locks. */
-       if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
+       if (IS_PENDING_LOCK(lck1->lock_type) || IS_PENDING_LOCK(lck2->lock_type))
                return False;
 
        /* Read locks never conflict. */
@@ -129,7 +129,7 @@ static BOOL brl_conflict_posix(const struct lock_struct *lck1,
 #endif
 
        /* Ignore PENDING locks. */
-       if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
+       if (IS_PENDING_LOCK(lck1->lock_type) || IS_PENDING_LOCK(lck2->lock_type))
                return False;
 
        /* Read locks never conflict. */
@@ -151,7 +151,7 @@ static BOOL brl_conflict_posix(const struct lock_struct *lck1,
 static BOOL brl_conflict1(const struct lock_struct *lck1, 
                         const struct lock_struct *lck2)
 {
-       if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
+       if (IS_PENDING_LOCK(lck1->lock_type) || IS_PENDING_LOCK(lck2->lock_type))
                return False;
 
        if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
@@ -184,7 +184,7 @@ static BOOL brl_conflict1(const struct lock_struct *lck1,
 
 static BOOL brl_conflict_other(const struct lock_struct *lck1, const struct lock_struct *lck2)
 {
-       if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
+       if (IS_PENDING_LOCK(lck1->lock_type) || IS_PENDING_LOCK(lck2->lock_type))
                return False;
 
        if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) 
@@ -210,6 +210,19 @@ static BOOL brl_conflict_other(const struct lock_struct *lck1, const struct lock
        return brl_overlap(lck1, lck2);
 } 
 
+/****************************************************************************
+ 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;
+}
+
 /****************************************************************************
  Amazingly enough, w2k3 "remembers" whether the last lock failure on a fnum
  is the same as this one and changes its error code. I wonder if any
@@ -260,6 +273,9 @@ void brl_init(int read_only)
                        lock_path("brlock.tdb")));
                return;
        }
+
+       /* Activate the per-hashchain freelist */
+       tdb_set_max_dead(tdb, 5);
 }
 
 /****************************************************************************
@@ -301,7 +317,7 @@ static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
 {
        unsigned int i;
        files_struct *fsp = br_lck->fsp;
-       struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+       struct lock_struct *locks = br_lck->lock_data;
 
        for (i=0; i < br_lck->num_locks; i++) {
                /* Do any Windows or POSIX locks conflict ? */
@@ -320,7 +336,7 @@ static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
           be mapped into a lower level POSIX one, and if so can
           we get it ? */
 
-       if ((plock->lock_type != PENDING_LOCK) && lp_posix_locking(SNUM(fsp->conn))) {
+       if (!IS_PENDING_LOCK(plock->lock_type) && lp_posix_locking(fsp->conn->params)) {
                int errno_ret;
                if (!set_posix_lock_windows_flavour(fsp,
                                plock->start,
@@ -346,7 +362,7 @@ static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
 
        memcpy(&locks[br_lck->num_locks], plock, sizeof(struct lock_struct));
        br_lck->num_locks += 1;
-       br_lck->lock_data = (void *)locks;
+       br_lck->lock_data = locks;
        br_lck->modified = True;
 
        return NT_STATUS_OK;
@@ -568,13 +584,15 @@ OR
  We must cope with range splits and merges.
 ****************************************************************************/
 
-static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
-                       const struct lock_struct *plock)
+static NTSTATUS brl_lock_posix(struct messaging_context *msg_ctx,
+                              struct byte_range_lock *br_lck,
+                              const struct lock_struct *plock)
 {
        unsigned int i, count;
-       struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+       struct lock_struct *locks = br_lck->lock_data;
        struct lock_struct *tp;
        BOOL lock_was_added = False;
+       BOOL signal_pending_read = False;
 
        /* No zero-zero locks for POSIX. */
        if (plock->start == 0 && plock->size == 0) {
@@ -598,19 +616,28 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
        
        count = 0;
        for (i=0; i < br_lck->num_locks; i++) {
-               if (locks[i].lock_flav == WINDOWS_LOCK) {
+               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) {
                        /* Do any Windows flavour locks conflict ? */
-                       if (brl_conflict(&locks[i], plock)) {
+                       if (brl_conflict(curr_lock, plock)) {
                                /* No games with error messages. */
                                SAFE_FREE(tp);
                                return NT_STATUS_FILE_LOCK_CONFLICT;
                        }
                        /* Just copy the Windows lock into the new array. */
-                       memcpy(&tp[count], &locks[i], sizeof(struct lock_struct));
+                       memcpy(&tp[count], curr_lock, sizeof(struct lock_struct));
                        count++;
                } else {
                        /* POSIX conflict semantics are different. */
-                       if (brl_conflict_posix(&locks[i], plock)) {
+                       if (brl_conflict_posix(curr_lock, plock)) {
                                /* Can't block ourselves with POSIX locks. */
                                /* No games with error messages. */
                                SAFE_FREE(tp);
@@ -618,7 +645,7 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
                        }
 
                        /* Work out overlaps. */
-                       count += brlock_posix_split_merge(&tp[count], &locks[i], plock, &lock_was_added);
+                       count += brlock_posix_split_merge(&tp[count], curr_lock, plock, &lock_was_added);
                }
        }
 
@@ -631,7 +658,7 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
           be mapped into a lower level POSIX one, and if so can
           we get it ? */
 
-       if ((plock->lock_type != PENDING_LOCK) && lp_posix_locking(SNUM(br_lck->fsp->conn))) {
+       if (!IS_PENDING_LOCK(plock->lock_type) && lp_posix_locking(br_lck->fsp->conn->params)) {
                int errno_ret;
 
                /* The lower layer just needs to attempt to
@@ -660,8 +687,34 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
        }
        br_lck->num_locks = count;
        SAFE_FREE(br_lck->lock_data);
-       br_lck->lock_data = (void *)tp;
+       br_lck->lock_data = tp;
+       locks = tp;
        br_lck->modified = True;
+
+       /* 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 )));
+
+                               messaging_send(msg_ctx, pend_lock->context.pid,
+                                              MSG_SMB_UNLOCK, &data_blob_null);
+                       }
+               }
+       }
+
        return NT_STATUS_OK;
 }
 
@@ -669,9 +722,10 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
  Lock a range of bytes.
 ****************************************************************************/
 
-NTSTATUS brl_lock(struct byte_range_lock *br_lck,
+NTSTATUS brl_lock(struct messaging_context *msg_ctx,
+               struct byte_range_lock *br_lck,
                uint32 smbpid,
-               struct process_id pid,
+               struct server_id pid,
                br_off start,
                br_off size, 
                enum brl_type lock_type,
@@ -699,7 +753,7 @@ NTSTATUS brl_lock(struct byte_range_lock *br_lck,
        if (lock_flav == WINDOWS_LOCK) {
                ret = brl_lock_windows(br_lck, &lock, blocking_lock);
        } else {
-               ret = brl_lock_posix(br_lck, &lock);
+               ret = brl_lock_posix(msg_ctx, br_lck, &lock);
        }
 
 #if ZERO_ZERO
@@ -710,27 +764,16 @@ NTSTATUS brl_lock(struct byte_range_lock *br_lck,
        return ret;
 }
 
-/****************************************************************************
- 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;
-}
-
 /****************************************************************************
  Unlock a range of bytes - Windows semantics.
 ****************************************************************************/
 
-static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock_struct *plock)
+static BOOL brl_unlock_windows(struct messaging_context *msg_ctx,
+                              struct byte_range_lock *br_lck,
+                              const struct lock_struct *plock)
 {
        unsigned int i, j;
-       struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+       struct lock_struct *locks = br_lck->lock_data;
        enum brl_type deleted_lock_type = READ_LOCK; /* shut the compiler up.... */
 
 #if ZERO_ZERO
@@ -792,7 +835,7 @@ static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock
        br_lck->modified = True;
 
        /* Unlock the underlying POSIX regions. */
-       if(lp_posix_locking(br_lck->fsp->conn->cnum)) {
+       if(lp_posix_locking(br_lck->fsp->conn->params)) {
                release_posix_lock_windows_flavour(br_lck->fsp,
                                plock->start,
                                plock->size,
@@ -807,7 +850,7 @@ static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock
                struct lock_struct *pend_lock = &locks[j];
 
                /* Ignore non-pending locks. */
-               if (pend_lock->lock_type != PENDING_LOCK) {
+               if (!IS_PENDING_LOCK(pend_lock->lock_type)) {
                        continue;
                }
 
@@ -816,11 +859,8 @@ static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock
                        DEBUG(10,("brl_unlock: sending unlock message to pid %s\n",
                                procid_str_static(&pend_lock->context.pid )));
 
-                       become_root();
-                       message_send_pid(pend_lock->context.pid,
-                                       MSG_SMB_UNLOCK,
-                                       NULL, 0, True);
-                       unbecome_root();
+                       messaging_send(msg_ctx, pend_lock->context.pid,
+                                      MSG_SMB_UNLOCK, &data_blob_null);
                }
        }
 
@@ -831,11 +871,13 @@ static BOOL brl_unlock_windows(struct byte_range_lock *br_lck, const struct lock
  Unlock a range of bytes - POSIX semantics.
 ****************************************************************************/
 
-static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_struct *plock)
+static BOOL brl_unlock_posix(struct messaging_context *msg_ctx,
+                            struct byte_range_lock *br_lck,
+                            const struct lock_struct *plock)
 {
        unsigned int i, j, count;
        struct lock_struct *tp;
-       struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+       struct lock_struct *locks = br_lck->lock_data;
        BOOL overlap_found = False;
 
        /* No zero-zero locks for POSIX. */
@@ -868,7 +910,7 @@ static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_s
                unsigned int tmp_count;
 
                /* Only remove our own locks - ignore fnum. */
-               if (lock->lock_type == PENDING_LOCK ||
+               if (IS_PENDING_LOCK(lock->lock_type) ||
                                !brl_same_context(&lock->context, &plock->context)) {
                        memcpy(&tp[count], lock, sizeof(struct lock_struct));
                        count++;
@@ -943,7 +985,7 @@ static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_s
        }
 
        /* Unlock any POSIX regions. */
-       if(lp_posix_locking(br_lck->fsp->conn->cnum)) {
+       if(lp_posix_locking(br_lck->fsp->conn->params)) {
                release_posix_lock_posix_flavour(br_lck->fsp,
                                                plock->start,
                                                plock->size,
@@ -967,7 +1009,8 @@ static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_s
 
        br_lck->num_locks = count;
        SAFE_FREE(br_lck->lock_data);
-       locks = br_lck->lock_data = (void *)tp;
+       locks = tp;
+       br_lck->lock_data = tp;
        br_lck->modified = True;
 
        /* Send unlock messages to any pending waiters that overlap. */
@@ -976,7 +1019,7 @@ static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_s
                struct lock_struct *pend_lock = &locks[j];
 
                /* Ignore non-pending locks. */
-               if (pend_lock->lock_type != PENDING_LOCK) {
+               if (!IS_PENDING_LOCK(pend_lock->lock_type)) {
                        continue;
                }
 
@@ -985,11 +1028,8 @@ static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_s
                        DEBUG(10,("brl_unlock: sending unlock message to pid %s\n",
                                procid_str_static(&pend_lock->context.pid )));
 
-                       become_root();
-                       message_send_pid(pend_lock->context.pid,
-                                       MSG_SMB_UNLOCK,
-                                       NULL, 0, True);
-                       unbecome_root();
+                       messaging_send(msg_ctx, pend_lock->context.pid,
+                                      MSG_SMB_UNLOCK, &data_blob_null);
                }
        }
 
@@ -1000,9 +1040,10 @@ static BOOL brl_unlock_posix(struct byte_range_lock *br_lck, const struct lock_s
  Unlock a range of bytes.
 ****************************************************************************/
 
-BOOL brl_unlock(struct byte_range_lock *br_lck,
+BOOL brl_unlock(struct messaging_context *msg_ctx,
+               struct byte_range_lock *br_lck,
                uint32 smbpid,
-               struct process_id pid,
+               struct server_id pid,
                br_off start,
                br_off size,
                enum brl_flavour lock_flav)
@@ -1019,9 +1060,9 @@ BOOL brl_unlock(struct byte_range_lock *br_lck,
        lock.lock_flav = lock_flav;
 
        if (lock_flav == WINDOWS_LOCK) {
-               return brl_unlock_windows(br_lck, &lock);
+               return brl_unlock_windows(msg_ctx, br_lck, &lock);
        } else {
-               return brl_unlock_posix(br_lck, &lock);
+               return brl_unlock_posix(msg_ctx, br_lck, &lock);
        }
 }
 
@@ -1032,7 +1073,7 @@ BOOL brl_unlock(struct byte_range_lock *br_lck,
 
 BOOL brl_locktest(struct byte_range_lock *br_lck,
                uint32 smbpid,
-               struct process_id pid,
+               struct server_id pid,
                br_off start,
                br_off size, 
                enum brl_type lock_type,
@@ -1041,7 +1082,7 @@ BOOL brl_locktest(struct byte_range_lock *br_lck,
        BOOL ret = True;
        unsigned int i;
        struct lock_struct lock;
-       const struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+       const struct lock_struct *locks = br_lck->lock_data;
        files_struct *fsp = br_lck->fsp;
 
        lock.context.smbpid = smbpid;
@@ -1069,7 +1110,7 @@ BOOL brl_locktest(struct byte_range_lock *br_lck,
         * This only conflicts with Windows locks, not POSIX locks.
         */
 
-       if(lp_posix_locking(fsp->conn->cnum) && (lock_flav == WINDOWS_LOCK)) {
+       if(lp_posix_locking(fsp->conn->params) && (lock_flav == WINDOWS_LOCK)) {
                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",
@@ -1090,7 +1131,7 @@ BOOL brl_locktest(struct byte_range_lock *br_lck,
 
 NTSTATUS brl_lockquery(struct byte_range_lock *br_lck,
                uint32 *psmbpid,
-               struct process_id pid,
+               struct server_id pid,
                br_off *pstart,
                br_off *psize, 
                enum brl_type *plock_type,
@@ -1098,7 +1139,7 @@ NTSTATUS brl_lockquery(struct byte_range_lock *br_lck,
 {
        unsigned int i;
        struct lock_struct lock;
-       const struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+       const struct lock_struct *locks = br_lck->lock_data;
        files_struct *fsp = br_lck->fsp;
 
        lock.context.smbpid = *psmbpid;
@@ -1135,7 +1176,7 @@ NTSTATUS brl_lockquery(struct byte_range_lock *br_lck,
         * see if there is a POSIX lock from a UNIX or NFS process.
         */
 
-       if(lp_posix_locking(fsp->conn->cnum)) {
+       if(lp_posix_locking(fsp->conn->params)) {
                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",
@@ -1158,13 +1199,13 @@ NTSTATUS brl_lockquery(struct byte_range_lock *br_lck,
 
 BOOL brl_lock_cancel(struct byte_range_lock *br_lck,
                uint32 smbpid,
-               struct process_id pid,
+               struct server_id pid,
                br_off start,
                br_off size,
                enum brl_flavour lock_flav)
 {
        unsigned int i;
-       struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
+       struct lock_struct *locks = br_lck->lock_data;
        struct lock_context context;
 
        context.smbpid = smbpid;
@@ -1177,7 +1218,7 @@ BOOL brl_lock_cancel(struct byte_range_lock *br_lck,
                /* For pending locks we *always* care about the fnum. */
                if (brl_same_context(&lock->context, &context) &&
                                lock->fnum == br_lck->fsp->fnum &&
-                               lock->lock_type == PENDING_LOCK &&
+                               IS_PENDING_LOCK(lock->lock_type) &&
                                lock->lock_flav == lock_flav &&
                                lock->start == start &&
                                lock->size == size) {
@@ -1207,18 +1248,19 @@ BOOL brl_lock_cancel(struct byte_range_lock *br_lck,
  fd and so we should not immediately close the fd.
 ****************************************************************************/
 
-void brl_close_fnum(struct byte_range_lock *br_lck)
+void brl_close_fnum(struct messaging_context *msg_ctx,
+                   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;
        int num_deleted_windows_locks = 0;
-       struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
-       struct process_id pid = procid_self();
+       struct lock_struct *locks = br_lck->lock_data;
+       struct server_id pid = procid_self();
        BOOL unlock_individually = False;
 
-       if(lp_posix_locking(fsp->conn->cnum)) {
+       if(lp_posix_locking(fsp->conn->params)) {
 
                /* 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
@@ -1246,10 +1288,15 @@ void brl_close_fnum(struct byte_range_lock *br_lck)
                        unsigned int num_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) {
-                               smb_panic("brl_close_fnum: talloc fail.\n");
+                       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;
                        }
+
                        num_locks_copy = br_lck->num_locks;
 
                        for (i=0; i < num_locks_copy; i++) {
@@ -1257,7 +1304,8 @@ void brl_close_fnum(struct byte_range_lock *br_lck)
 
                                if (lock->context.tid == tid && procid_equal(&lock->context.pid, &pid) &&
                                                (lock->fnum == fnum)) {
-                                       brl_unlock(br_lck,
+                                       brl_unlock(msg_ctx,
+                                               br_lck,
                                                lock->context.smbpid,
                                                pid,
                                                lock->start,
@@ -1292,7 +1340,7 @@ void brl_close_fnum(struct byte_range_lock *br_lck)
                                struct lock_struct *pend_lock = &locks[j];
 
                                /* Ignore our own or non-pending locks. */
-                               if (pend_lock->lock_type != PENDING_LOCK) {
+                               if (!IS_PENDING_LOCK(pend_lock->lock_type)) {
                                        continue;
                                }
 
@@ -1306,11 +1354,8 @@ void brl_close_fnum(struct byte_range_lock *br_lck)
 
                                /* We could send specific lock info here... */
                                if (brl_pending_overlap(lock, pend_lock)) {
-                                       become_root();
-                                       message_send_pid(pend_lock->context.pid,
-                                                       MSG_SMB_UNLOCK,
-                                                       NULL, 0, True);
-                                       unbecome_root();
+                                       messaging_send(msg_ctx, pend_lock->context.pid,
+                                                      MSG_SMB_UNLOCK, &data_blob_null);
                                }
                        }
 
@@ -1326,7 +1371,7 @@ void brl_close_fnum(struct byte_range_lock *br_lck)
                }
        }
 
-       if(lp_posix_locking(fsp->conn->cnum) && num_deleted_windows_locks) {
+       if(lp_posix_locking(fsp->conn->params) && num_deleted_windows_locks) {
                /* Reduce the Windows lock POSIX reference count on this dev/ino pair. */
                reduce_windows_lock_ref_count(fsp, num_deleted_windows_locks);
        }
@@ -1418,7 +1463,7 @@ static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *st
        }
 
        if (orig_num_locks != num_locks) {
-               dbuf.dptr = (char *)locks;
+               dbuf.dptr = (uint8 *)locks;
                dbuf.dsize = num_locks * sizeof(*locks);
 
                if (dbuf.dsize) {
@@ -1460,15 +1505,17 @@ int brl_forall(BRLOCK_FN(fn))
  Unlock the record.
 ********************************************************************/
 
-static int byte_range_lock_destructor(void *p)
+static int byte_range_lock_destructor(struct byte_range_lock *br_lck)
 {
-       struct byte_range_lock *br_lck =
-               talloc_get_type_abort(p, struct byte_range_lock);
        TDB_DATA key;
 
-       key.dptr = (char *)&br_lck->key;
+       key.dptr = (uint8 *)&br_lck->key;
        key.dsize = sizeof(struct lock_key);
 
+       if (br_lck->read_only) {
+               SMB_ASSERT(!br_lck->modified);
+       }
+
        if (!br_lck->modified) {
                goto done;
        }
@@ -1480,7 +1527,7 @@ static int byte_range_lock_destructor(void *p)
                }
        } else {
                TDB_DATA data;
-               data.dptr = (char *)br_lck->lock_data;
+               data.dptr = (uint8 *)br_lck->lock_data;
                data.dsize = br_lck->num_locks * sizeof(struct lock_struct);
 
                if (tdb_store(tdb, key, data, TDB_REPLACE) == -1) {
@@ -1490,7 +1537,9 @@ static int byte_range_lock_destructor(void *p)
 
  done:
 
-       tdb_chainunlock(tdb, key);
+       if (!br_lck->read_only) {
+               tdb_chainunlock(tdb, key);
+       }
        SAFE_FREE(br_lck->lock_data);
        return 0;
 }
@@ -1501,8 +1550,8 @@ static int byte_range_lock_destructor(void *p)
  TALLOC_FREE(brl) will release the lock in the destructor.
 ********************************************************************/
 
-struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
-                                       files_struct *fsp)
+static struct byte_range_lock *brl_get_locks_internal(TALLOC_CTX *mem_ctx,
+                                       files_struct *fsp, BOOL read_only)
 {
        TDB_DATA key;
        TDB_DATA data;
@@ -1519,19 +1568,30 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
        br_lck->key.device = fsp->dev;
        br_lck->key.inode = fsp->inode;
 
-       key.dptr = (char *)&br_lck->key;
+       key.dptr = (uint8 *)&br_lck->key;
        key.dsize = sizeof(struct lock_key);
 
-       if (tdb_chainlock(tdb, key) != 0) {
-               DEBUG(3, ("Could not lock byte range lock entry\n"));
-               TALLOC_FREE(br_lck);
-               return NULL;
+       if (!fsp->lockdb_clean) {
+               /* We must be read/write to clean
+                  the dead entries. */
+               read_only = False;
+       }
+
+       if (read_only) {
+               br_lck->read_only = True;
+       } else {
+               if (tdb_chainlock(tdb, key) != 0) {
+                       DEBUG(3, ("Could not lock byte range lock entry\n"));
+                       TALLOC_FREE(br_lck);
+                       return NULL;
+               }
+               br_lck->read_only = False;
        }
 
        talloc_set_destructor(br_lck, byte_range_lock_destructor);
 
        data = tdb_fetch(tdb, key);
-       br_lck->lock_data = (void *)data.dptr;
+       br_lck->lock_data = (struct lock_struct *)data.dptr;
        br_lck->num_locks = data.dsize / sizeof(struct lock_struct);
 
        if (!fsp->lockdb_clean) {
@@ -1540,30 +1600,21 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
                /* Go through and ensure all entries exist - remove any that don't. */
                /* Makes the lockdb self cleaning at low cost. */
 
-               struct lock_struct *locks =
-                       (struct lock_struct *)br_lck->lock_data;
-
-               if (!validate_lock_entries(&br_lck->num_locks, &locks)) {
+               if (!validate_lock_entries(&br_lck->num_locks,
+                                          &br_lck->lock_data)) {
                        SAFE_FREE(br_lck->lock_data);
                        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;
        }
 
        if (DEBUGLEVEL >= 10) {
                unsigned int i;
-               struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
-               DEBUG(10,("brl_get_locks: %u current locks on dev=%.0f, inode=%.0f\n",
+               struct lock_struct *locks = br_lck->lock_data;
+               DEBUG(10,("brl_get_locks_internal: %u current locks on dev=%.0f, inode=%.0f\n",
                        br_lck->num_locks,
                        (double)fsp->dev, (double)fsp->inode ));
                for( i = 0; i < br_lck->num_locks; i++) {
@@ -1572,3 +1623,15 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx,
        }
        return br_lck;
 }
+
+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);
+}