r17098: Samba3 now cleanly passes Samba4 RAW-LOCK torture
authorJeremy Allison <jra@samba.org>
Mon, 17 Jul 2006 21:09:02 +0000 (21:09 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:38:11 +0000 (11:38 -0500)
test. Phew - that was painful :-). But what it means
is that we now implement lock cancels and I can add
lock cancels into POSIX lock handling which will fix
the fast/slow system call issue with cifsfs !
Jeremy.

source/include/includes.h
source/include/locking.h
source/include/messages.h
source/include/smb.h
source/lib/dummysmbd.c
source/locking/brlock.c
source/locking/locking.c
source/smbd/blocking.c
source/smbd/close.c
source/smbd/reply.c
source/smbd/trans2.c

index ab2f6a96410e4736f453db44313c00e637e574c8..86d7f069cda8bc97b41d17d6e1a750b7fd13823a 100644 (file)
@@ -936,6 +936,7 @@ extern int errno;
 #include "debugparse.h"
 #include "version.h"
 #include "privileges.h"
+#include "locking.h"
 #include "smb.h"
 #include "ads_cldap.h"
 #include "nameserv.h"
index 983d59a853fffded14b08687e44c8058483a1fa7..8eabb305f7f6e6c9a14666e3f3b97ac7762e7bbe 100644 (file)
@@ -45,8 +45,10 @@ struct lock_key {
        SMB_INO_T inode;
 };
 
+struct files_struct;
+
 struct byte_range_lock {
-       files_struct *fsp;
+       struct files_struct *fsp;
        unsigned int num_locks;
        BOOL modified;
        struct lock_key key;
index e246123ea9ffd397a23e1e420a2bef540485c49a..b0305373c0d244b6470b78bf7f1e7092cf26b80f 100644 (file)
@@ -70,6 +70,7 @@
 #define MSG_SMB_KERNEL_BREAK 3010
 #define MSG_SMB_FILE_RENAME  3011
 #define MSG_SMB_INJECT_FAULT 3012
+#define MSG_SMB_BLOCKING_LOCK_CANCEL 3013
 
 /* winbind messages */
 #define MSG_WINBIND_FINISHED     4001
index 39a7897581cf47d249f457493ede0f7adcec947d..1a55bef4287ccbbc93efe4770fb246f7ce162239 100644 (file)
@@ -440,6 +440,7 @@ typedef struct files_struct {
        int oplock_type;
        int sent_oplock_break;
        struct timed_event *oplock_timeout;
+       struct lock_struct last_lock_failure;
 
        struct share_mode_entry *pending_break_messages;
        int num_pending_break_messages;
@@ -861,8 +862,6 @@ struct parm_struct {
 #define FLAG_HIDE      0x2000 /* options that should be hidden in SWAT */
 #define FLAG_DOS_STRING 0x4000 /* convert from UNIX to DOS codepage when reading this string. */
 
-#include "locking.h"
-
 struct bitmap {
        uint32 *b;
        unsigned int n;
index 9b587224e3e8b19624061ed92081ebbedc3e6030..087de2fe253f20540ad82c896aee88f6cc003a62 100644 (file)
@@ -38,3 +38,7 @@ BOOL conn_snum_used(int snum)
 {
        return False;
 }
+
+void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
+{
+}
index 9edac7203b95dfa46fce38041ef75c220fdd6af4..f251ff57ec794f355be79289387fbf3e3e312fc2 100644 (file)
@@ -211,30 +211,34 @@ static BOOL brl_conflict_other(const struct lock_struct *lck1, const struct lock
 } 
 
 /****************************************************************************
- Amazingly enough, w2k3 "remembers" whether the last lock failure
+ 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
  app depends on this ?
 ****************************************************************************/
 
-static NTSTATUS brl_lock_failed(const struct lock_struct *lock)
+static NTSTATUS brl_lock_failed(files_struct *fsp, const struct lock_struct *lock, int32 lock_timeout)
 {
-       static struct lock_struct last_lock_failure;
-
-       if (brl_same_context(&lock->context, &last_lock_failure.context) &&
-                       lock->fnum == last_lock_failure.fnum &&
-                       lock->start == last_lock_failure.start &&
-                       lock->size == last_lock_failure.size) {
-               return NT_STATUS_FILE_LOCK_CONFLICT;
-       }
-       last_lock_failure = *lock;
-       if (lock->start >= 0xEF000000 &&
-                       (lock->start >> 63) == 0) {
+       if (lock->start >= 0xEF000000 && (lock->start >> 63) == 0) {
                /* amazing the little things you learn with a test
                   suite. Locks beyond this offset (as a 64 bit
                   number!) always generate the conflict error code,
                   unless the top bit is set */
+               if (lock_timeout == 0) {
+                       fsp->last_lock_failure = *lock;
+               }
+               return NT_STATUS_FILE_LOCK_CONFLICT;
+       }
+
+       if (procid_equal(&lock->context.pid, &fsp->last_lock_failure.context.pid) &&
+                       lock->context.tid == fsp->last_lock_failure.context.tid &&
+                       lock->fnum == fsp->last_lock_failure.fnum &&
+                       lock->start == fsp->last_lock_failure.start) {
                return NT_STATUS_FILE_LOCK_CONFLICT;
        }
+
+       if (lock_timeout == 0) {
+               fsp->last_lock_failure = *lock;
+       }
        return NT_STATUS_LOCK_NOT_GRANTED;
 }
 
@@ -293,8 +297,7 @@ static int lock_compare(const struct lock_struct *lck1,
 ****************************************************************************/
 
 static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
-                       const struct lock_struct *plock,
-                       BOOL *my_lock_ctx)
+                       const struct lock_struct *plock, int32 lock_timeout)
 {
        unsigned int i;
        files_struct *fsp = br_lck->fsp;
@@ -303,12 +306,7 @@ static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
        for (i=0; i < br_lck->num_locks; i++) {
                /* Do any Windows or POSIX locks conflict ? */
                if (brl_conflict(&locks[i], plock)) {
-                       NTSTATUS status = brl_lock_failed(plock);;
-                       /* Did we block ourselves ? */
-                       if (brl_same_context(&locks[i].context, &plock->context)) {
-                               *my_lock_ctx = True;
-                       }
-                       return status;
+                       return brl_lock_failed(fsp,plock,lock_timeout);
                }
 #if ZERO_ZERO
                if (plock->start == 0 && plock->size == 0 && 
@@ -571,8 +569,7 @@ OR
 ****************************************************************************/
 
 static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
-                       const struct lock_struct *plock,
-                       BOOL *my_lock_ctx)
+                       const struct lock_struct *plock)
 {
        unsigned int i, count;
        struct lock_struct *locks = (struct lock_struct *)br_lck->lock_data;
@@ -604,10 +601,6 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck,
                if (locks[i].lock_flav == WINDOWS_LOCK) {
                        /* Do any Windows flavour locks conflict ? */
                        if (brl_conflict(&locks[i], plock)) {
-                               /* Did we block ourselves ? */
-                               if (brl_same_context(&locks[i].context, &plock->context)) {
-                                       *my_lock_ctx = True;
-                               }
                                /* No games with error messages. */
                                SAFE_FREE(tp);
                                return NT_STATUS_FILE_LOCK_CONFLICT;
@@ -683,13 +676,11 @@ NTSTATUS brl_lock(struct byte_range_lock *br_lck,
                br_off size, 
                enum brl_type lock_type,
                enum brl_flavour lock_flav,
-               BOOL *my_lock_ctx)
+               int32 lock_timeout)
 {
        NTSTATUS ret;
        struct lock_struct lock;
 
-       *my_lock_ctx = False;
-
 #if !ZERO_ZERO
        if (start == 0 && size == 0) {
                DEBUG(0,("client sent 0/0 lock - please report this\n"));
@@ -706,9 +697,9 @@ NTSTATUS brl_lock(struct byte_range_lock *br_lck,
        lock.lock_flav = lock_flav;
 
        if (lock_flav == WINDOWS_LOCK) {
-               ret = brl_lock_windows(br_lck, &lock, my_lock_ctx);
+               ret = brl_lock_windows(br_lck, &lock, lock_timeout);
        } else {
-               ret = brl_lock_posix(br_lck, &lock, my_lock_ctx);
+               ret = brl_lock_posix(br_lck, &lock);
        }
 
 #if ZERO_ZERO
@@ -1165,7 +1156,7 @@ NTSTATUS brl_lockquery(struct byte_range_lock *br_lck,
  Remove a particular pending lock.
 ****************************************************************************/
 
-BOOL brl_remove_pending_lock(struct byte_range_lock *br_lck,
+BOOL brl_lock_cancel(struct byte_range_lock *br_lck,
                uint32 smbpid,
                struct process_id pid,
                br_off start,
index ac50c9b648fdb7be9eb938ae82a9c5d38c5176f8..cd1d9547f3d32207f488d13f11ce611cb7e17a3d 100644 (file)
@@ -185,7 +185,7 @@ NTSTATUS do_lock(files_struct *fsp,
                        SMB_BIG_UINT offset,
                        enum brl_type lock_type,
                        enum brl_flavour lock_flav,
-                       BOOL *my_lock_ctx)
+                       int32 lock_timeout)
 {
        struct byte_range_lock *br_lck = NULL;
        NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED;
@@ -216,76 +216,63 @@ NTSTATUS do_lock(files_struct *fsp,
                        count, 
                        lock_type,
                        lock_flav,
-                       my_lock_ctx);
+                       lock_timeout);
 
        TALLOC_FREE(br_lck);
        return status;
 }
 
 /****************************************************************************
- Utility function called by locking requests. This is *DISGUSTING*. It also
- appears to be "What Windows Does" (tm). Andrew, ever wonder why Windows 2000
- is so slow on the locking tests...... ? This is the reason. Much though I hate
- it, we need this. JRA.
+ Utility function called by unlocking requests.
 ****************************************************************************/
 
-NTSTATUS do_lock_spin(files_struct *fsp,
+NTSTATUS do_unlock(files_struct *fsp,
                        uint32 lock_pid,
                        SMB_BIG_UINT count,
                        SMB_BIG_UINT offset,
-                       enum brl_type lock_type,
-                       enum brl_flavour lock_flav,
-                       BOOL *my_lock_ctx)
+                       enum brl_flavour lock_flav)
 {
-       int j, maxj = lp_lock_spin_count();
-       int sleeptime = lp_lock_sleep_time();
-       NTSTATUS status, ret;
-
-       if (maxj <= 0) {
-               maxj = 1;
+       BOOL ok = False;
+       struct byte_range_lock *br_lck = NULL;
+       
+       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;
+       }
+       
+       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 ));
 
-       ret = NT_STATUS_OK; /* to keep dumb compilers happy */
-
-       for (j = 0; j < maxj; j++) {
-               status = do_lock(fsp,
-                               lock_pid,
-                               count,
-                               offset,
-                               lock_type,
-                               lock_flav,
-                               my_lock_ctx);
-
-               if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED) &&
-                   !NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
-                       return status;
-               }
-               /* if we do fail then return the first error code we got */
-               if (j == 0) {
-                       ret = status;
-                       /* Don't spin if we blocked ourselves. */
-                       if (*my_lock_ctx) {
-                               return ret;
-                       }
+       br_lck = brl_get_locks(NULL, fsp);
+       if (!br_lck) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
-                       /* Only spin for Windows locks. */
-                       if (lock_flav == POSIX_LOCK) {
-                               return ret;
-                       }
-               }
+       ok = brl_unlock(br_lck,
+                       lock_pid,
+                       procid_self(),
+                       offset,
+                       count,
+                       lock_flav);
+   
+       TALLOC_FREE(br_lck);
 
-               if (sleeptime) {
-                       sys_usleep(sleeptime);
-               }
+       if (!ok) {
+               DEBUG(10,("do_unlock: returning ERRlock.\n" ));
+               return NT_STATUS_RANGE_NOT_LOCKED;
        }
-       return ret;
+
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
Utility function called by unlocking requests.
Cancel any pending blocked locks.
 ****************************************************************************/
 
-NTSTATUS do_unlock(files_struct *fsp,
+NTSTATUS do_lock_cancel(files_struct *fsp,
                        uint32 lock_pid,
                        SMB_BIG_UINT count,
                        SMB_BIG_UINT offset,
@@ -295,14 +282,15 @@ NTSTATUS do_unlock(files_struct *fsp,
        struct byte_range_lock *br_lck = NULL;
        
        if (!fsp->can_lock) {
-               return fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE;
+               return fsp->is_directory ?
+                       NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE;
        }
        
        if (!lp_locking(SNUM(fsp->conn))) {
-               return NT_STATUS_OK;
+               return NT_STATUS_DOS(ERRDOS, ERRcancelviolation);
        }
-       
-       DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for fnum %d file %s\n",
+
+       DEBUG(10,("do_lock_cancel: cancel 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(NULL, fsp);
@@ -310,7 +298,7 @@ NTSTATUS do_unlock(files_struct *fsp,
                return NT_STATUS_NO_MEMORY;
        }
 
-       ok = brl_unlock(br_lck,
+       ok = brl_lock_cancel(br_lck,
                        lock_pid,
                        procid_self(),
                        offset,
@@ -320,8 +308,8 @@ NTSTATUS do_unlock(files_struct *fsp,
        TALLOC_FREE(br_lck);
 
        if (!ok) {
-               DEBUG(10,("do_unlock: returning ERRlock.\n" ));
-               return NT_STATUS_RANGE_NOT_LOCKED;
+               DEBUG(10,("do_lock_cancel: returning ERRcancelviolation.\n" ));
+               return NT_STATUS_DOS(ERRDOS, ERRcancelviolation);
        }
 
        return NT_STATUS_OK;
@@ -340,7 +328,9 @@ void locking_close_file(files_struct *fsp)
        }
 
        br_lck = brl_get_locks(NULL,fsp);
+
        if (br_lck) {
+               cancel_pending_lock_requests_by_fid(fsp, br_lck);
                brl_close_fnum(br_lck);
                TALLOC_FREE(br_lck);
        }
index 04ab01eb664fef7e2fec9ed2b2388d82223b80ac..941e87d3ad70b9098f54afe2c0c3b4cefa68924c 100644 (file)
@@ -19,6 +19,8 @@
 */
 
 #include "includes.h"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_LOCKING
 
 /****************************************************************************
  This is the structure to queue to implement blocking locks.
@@ -41,15 +43,18 @@ typedef struct _blocking_lock_record {
        int length;
 } blocking_lock_record;
 
+/* dlink list we store pending lock records on. */
 static blocking_lock_record *blocking_lock_queue;
 
+/* dlink list we move cancelled lock records onto. */
+static blocking_lock_record *blocking_lock_cancelled_queue;
+
 /****************************************************************************
  Destructor for the above structure.
 ****************************************************************************/
 
 static void free_blocking_lock_record(blocking_lock_record *blr)
 {
-       DLIST_REMOVE(blocking_lock_queue, blr);
        SAFE_FREE(blr->inbuf);
        SAFE_FREE(blr);
 }
@@ -81,7 +86,6 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
 {
        static BOOL set_lock_msg;
        blocking_lock_record *blr, *tmp;
-       BOOL my_lock_ctx = False;
        struct byte_range_lock *br_lck = NULL;
        NTSTATUS status;
 
@@ -123,6 +127,7 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
 
        br_lck = brl_get_locks(NULL, blr->fsp);
        if (!br_lck) {
+               DLIST_REMOVE(blocking_lock_queue, blr);
                free_blocking_lock_record(blr);
                return False;
        }
@@ -135,11 +140,12 @@ BOOL push_blocking_lock_request( char *inbuf, int length,
                        count,
                        PENDING_LOCK,
                        blr->lock_flav,
-                       &my_lock_ctx);
+                       lock_timeout);
        TALLOC_FREE(br_lck);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
+               DLIST_REMOVE(blocking_lock_queue, blr);
                free_blocking_lock_record(blr);
                return False;
        }
@@ -220,9 +226,24 @@ static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS stat
                status = NT_STATUS_FILE_LOCK_CONFLICT;
        }
 
+       if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
+               /* Store the last lock error. */
+               files_struct *fsp = blr->fsp;
+
+               fsp->last_lock_failure.context.smbpid = blr->lock_pid;
+               fsp->last_lock_failure.context.tid = fsp->conn->cnum;
+               fsp->last_lock_failure.context.pid = procid_self();
+               fsp->last_lock_failure.start = blr->offset;
+               fsp->last_lock_failure.size = blr->count;
+               fsp->last_lock_failure.fnum = fsp->fnum;
+               fsp->last_lock_failure.lock_type = READ_LOCK; /* Don't care. */
+               fsp->last_lock_failure.lock_flav = blr->lock_flav;
+       }
+
        ERROR_NT(status);
-       if (!send_smb(smbd_server_fd(),outbuf))
+       if (!send_smb(smbd_server_fd(),outbuf)) {
                exit_server("generic_blocking_lock_error: send_smb failed.");
+       }
 }
 
 /****************************************************************************
@@ -335,7 +356,6 @@ static BOOL process_lockread(blocking_lock_record *blr)
        size_t numtoread;
        NTSTATUS status;
        files_struct *fsp = blr->fsp;
-       BOOL my_lock_ctx = False;
 
        numtoread = SVAL(inbuf,smb_vwv1);
        startpos = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv2);
@@ -343,13 +363,13 @@ static BOOL process_lockread(blocking_lock_record *blr)
        numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
        data = smb_buf(outbuf) + 3;
  
-       status = do_lock_spin(fsp,
-                               (uint32)SVAL(inbuf,smb_pid),
-                               (SMB_BIG_UINT)numtoread,
-                               startpos,
-                               READ_LOCK,
-                               WINDOWS_LOCK,
-                               &my_lock_ctx);
+       status = do_lock(fsp,
+                       (uint32)SVAL(inbuf,smb_pid),
+                       (SMB_BIG_UINT)numtoread,
+                       startpos,
+                       READ_LOCK,
+                       WINDOWS_LOCK,
+                       (int32)-1);
 
        if (NT_STATUS_V(status)) {
                if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
@@ -410,19 +430,18 @@ static BOOL process_lock(blocking_lock_record *blr)
        SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0;
        NTSTATUS status;
        files_struct *fsp = blr->fsp;
-       BOOL my_lock_ctx = False;
 
        count = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
        offset = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
 
        errno = 0;
-       status = do_lock_spin(fsp,
-                               (uint32)SVAL(inbuf,smb_pid),
-                               count,
-                               offset,
-                               WRITE_LOCK,
-                               WINDOWS_LOCK,
-                               &my_lock_ctx);
+       status = do_lock(fsp,
+                       (uint32)SVAL(inbuf,smb_pid),
+                       count,
+                       offset,
+                       WRITE_LOCK,
+                       WINDOWS_LOCK,
+                       (int32)-1);
 
        if (NT_STATUS_IS_ERR(status)) {
                if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
@@ -474,7 +493,6 @@ static BOOL process_lockingX(blocking_lock_record *blr)
        uint32 lock_pid;
        BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
        char *data;
-       BOOL my_lock_ctx = False;
        NTSTATUS status = NT_STATUS_OK;
 
        data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks);
@@ -496,13 +514,14 @@ static BOOL process_lockingX(blocking_lock_record *blr)
                 * request would never have been queued. JRA.
                 */
                errno = 0;
-               status = do_lock_spin(fsp,
+               status = do_lock(fsp,
                                lock_pid,
                                count,
                                offset, 
-                               ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
+                               ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
+                                       READ_LOCK : WRITE_LOCK),
                                WINDOWS_LOCK,
-                               &my_lock_ctx);
+                               (int32)-1);
 
                if (NT_STATUS_IS_ERR(status)) {
                        break;
@@ -552,7 +571,6 @@ static BOOL process_trans2(blocking_lock_record *blr)
        extern int max_send;
        char *inbuf = blr->inbuf;
        char *outbuf;
-       BOOL my_lock_ctx = False;
        char params[2];
        NTSTATUS status;
 
@@ -562,7 +580,7 @@ static BOOL process_trans2(blocking_lock_record *blr)
                        blr->offset,
                        blr->lock_type,
                        blr->lock_flav,
-                       &my_lock_ctx);
+                       (int32)-1);
 
        if (!NT_STATUS_IS_OK(status)) {
                if (ERROR_WAS_LOCK_DENIED(status)) {
@@ -615,33 +633,41 @@ static BOOL blocking_lock_record_process(blocking_lock_record *blr)
 }
 
 /****************************************************************************
Delete entries by fnum from the blocking lock pending queue.
Cancel entries by fnum from the blocking lock pending queue.
 *****************************************************************************/
 
-void remove_pending_lock_requests_by_fid(files_struct *fsp)
+void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
 {
        blocking_lock_record *blr, *next = NULL;
 
        for(blr = blocking_lock_queue; blr; blr = next) {
                next = blr->next;
                if(blr->fsp->fnum == fsp->fnum) {
-                       struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
+                       unsigned char locktype = 0;
+
+                       if (blr->com_type == SMBlockingX) {
+                               locktype = CVAL(blr->inbuf,smb_vwv3);
+                       }
 
                        if (br_lck) {
                                DEBUG(10,("remove_pending_lock_requests_by_fid - removing request type %d for \
 file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
 
-                               brl_remove_pending_lock(br_lck,
+                               brl_lock_cancel(br_lck,
                                        blr->lock_pid,
                                        procid_self(),
                                        blr->offset,
                                        blr->count,
                                        blr->lock_flav);
-                               TALLOC_FREE(br_lck);
 
+                               blocking_lock_cancel(fsp,
+                                       blr->lock_pid,
+                                       blr->offset,
+                                       blr->count,
+                                       blr->lock_flav,
+                                       locktype,
+                                       NT_STATUS_RANGE_NOT_LOCKED);
                        }
-
-                       free_blocking_lock_record(blr);
                }
        }
 }
@@ -664,7 +690,7 @@ void remove_pending_lock_requests_by_mid(int mid)
                                DEBUG(10,("remove_pending_lock_requests_by_mid - removing request type %d for \
 file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
 
-                               brl_remove_pending_lock(br_lck,
+                               brl_lock_cancel(br_lck,
                                        blr->lock_pid,
                                        procid_self(),
                                        blr->offset,
@@ -674,6 +700,7 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
                        }
 
                        blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
+                       DLIST_REMOVE(blocking_lock_queue, blr);
                        free_blocking_lock_record(blr);
                }
        }
@@ -765,7 +792,7 @@ void process_blocking_lock_queue(time_t t)
                                DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n",
                                        fsp->fnum, fsp->fsp_name ));
 
-                               brl_remove_pending_lock(br_lck,
+                               brl_lock_cancel(br_lck,
                                        blr->lock_pid,
                                        procid_self(),
                                        blr->offset,
@@ -775,6 +802,7 @@ void process_blocking_lock_queue(time_t t)
                        }
 
                        blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
+                       DLIST_REMOVE(blocking_lock_queue, blr);
                        free_blocking_lock_record(blr);
                        continue;
                }
@@ -787,7 +815,7 @@ void process_blocking_lock_queue(time_t t)
                         */
 
                        if (br_lck) {
-                               brl_remove_pending_lock(br_lck,
+                               brl_lock_cancel(br_lck,
                                        blr->lock_pid,
                                        procid_self(),
                                        blr->offset,
@@ -799,6 +827,7 @@ void process_blocking_lock_queue(time_t t)
                        DEBUG(0,("process_blocking_lock_queue: Unable to become user vuid=%d.\n",
                                vuid ));
                        blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
+                       DLIST_REMOVE(blocking_lock_queue, blr);
                        free_blocking_lock_record(blr);
                        continue;
                }
@@ -811,7 +840,7 @@ void process_blocking_lock_queue(time_t t)
                         */
 
                        if (br_lck) {
-                               brl_remove_pending_lock(br_lck,
+                               brl_lock_cancel(br_lck,
                                        blr->lock_pid,
                                        procid_self(),
                                        blr->offset,
@@ -822,6 +851,7 @@ void process_blocking_lock_queue(time_t t)
 
                        DEBUG(0,("process_blocking_lock_queue: Unable to become service Error was %s.\n", strerror(errno) ));
                        blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
+                       DLIST_REMOVE(blocking_lock_queue, blr);
                        free_blocking_lock_record(blr);
                        change_to_root_user();
                        continue;
@@ -837,7 +867,7 @@ void process_blocking_lock_queue(time_t t)
                        struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp);
 
                        if (br_lck) {
-                               brl_remove_pending_lock(br_lck,
+                               brl_lock_cancel(br_lck,
                                        blr->lock_pid,
                                        procid_self(),
                                        blr->offset,
@@ -846,8 +876,106 @@ void process_blocking_lock_queue(time_t t)
                                TALLOC_FREE(br_lck);
                        }
 
+                       DLIST_REMOVE(blocking_lock_queue, blr);
                        free_blocking_lock_record(blr);
                }
                change_to_root_user();
        }
 }
+
+/****************************************************************************
+ Handle a cancel message. Lock already moved onto the cancel queue.
+*****************************************************************************/
+
+#define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(blocking_lock_record *) + sizeof(NTSTATUS))
+
+static void process_blocking_lock_cancel_message(int msg_type, struct process_id src,
+                                         void *buf, size_t len)
+{
+       NTSTATUS err;
+       const char *msg = (const char *)buf;
+       blocking_lock_record *blr;
+
+       if (buf == NULL) {
+               smb_panic("process_blocking_lock_cancel_message: null msg\n");
+       }
+
+       if (len != MSG_BLOCKING_LOCK_CANCEL_SIZE) {
+               DEBUG(0, ("process_blocking_lock_cancel_message: "
+                       "Got invalid msg len %d\n", (int)len));
+               smb_panic("process_blocking_lock_cancel_message: bad msg\n");
+        }
+
+       memcpy(&blr, msg, sizeof(blr));
+       memcpy(&err, &msg[sizeof(blr)], sizeof(NTSTATUS));
+
+       DEBUG(10,("process_blocking_lock_cancel_message: returning error %s\n",
+               nt_errstr(err) ));
+
+       blocking_lock_reply_error(blr, err);
+       DLIST_REMOVE(blocking_lock_cancelled_queue, blr);
+       free_blocking_lock_record(blr);
+}
+
+/****************************************************************************
+ Send ourselves a blocking lock cancelled message. Handled asynchronously above.
+*****************************************************************************/
+
+BOOL blocking_lock_cancel(files_struct *fsp,
+                       uint32 lock_pid,
+                       SMB_BIG_UINT offset,
+                       SMB_BIG_UINT count,
+                       enum brl_flavour lock_flav,
+                       unsigned char locktype,
+                        NTSTATUS err)
+{
+       static BOOL initialized;
+       char msg[MSG_BLOCKING_LOCK_CANCEL_SIZE];
+       blocking_lock_record *blr;
+
+       if (!initialized) {
+               /* Register our message. */
+               message_register(MSG_SMB_BLOCKING_LOCK_CANCEL,
+                               process_blocking_lock_cancel_message);
+
+               initialized = True;
+       }
+
+       for (blr = blocking_lock_queue; blr; blr = blr->next) {
+               if (fsp == blr->fsp &&
+                               lock_pid == blr->lock_pid &&
+                               offset == blr->offset &&
+                               count == blr->count &&
+                               lock_flav == blr->lock_flav) {
+                       break;
+               }
+       }
+
+       if (!blr) {
+               return False;
+       }
+
+       /* Check the flags are right. */
+       if (blr->com_type == SMBlockingX &&
+               (locktype & LOCKING_ANDX_LARGE_FILES) !=
+                       (CVAL(blr->inbuf,smb_vwv3) & LOCKING_ANDX_LARGE_FILES)) {
+               return False;
+       }
+
+       /* Move to cancelled queue. */
+       DLIST_REMOVE(blocking_lock_queue, blr);
+       DLIST_ADD(blocking_lock_cancelled_queue, blr);
+
+       /* Create the message. */
+       memcpy(msg, &blr, sizeof(blr));
+       memcpy(&msg[sizeof(blr)], &err, sizeof(NTSTATUS));
+
+       /* Don't need to be root here as we're only ever
+               sending to ourselves. */
+
+       message_send_pid(pid_to_procid(sys_getpid()),
+                       MSG_SMB_BLOCKING_LOCK_CANCEL,
+                       &msg, sizeof(msg), True);
+
+       return True;
+}
index 8a63d3b227b318dd0c30e898cf10d38df100ec7a..08e4a24a56288a2bd366a89b1bcf3cf12f13e4f5 100644 (file)
@@ -268,8 +268,6 @@ static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
        int err = 0;
        int err1 = 0;
 
-       remove_pending_lock_requests_by_fid(fsp);
-
        if (fsp->aio_write_behind) {
                /*
                 * If we're finishing write behind on a close we can get a write
index ff3c6832e4f33c1cd1eb047e8285166858b5dabf..ec618db3f854b6aa934b90030e76837ad5810647 100644 (file)
@@ -2371,7 +2371,6 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
        size_t numtoread;
        NTSTATUS status;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-       BOOL my_lock_ctx = False;
        START_PROFILE(SMBlockread);
 
        CHECK_FSP(fsp,conn);
@@ -2396,13 +2395,13 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
         * Note that the requested lock size is unaffected by max_recv.
         */
        
-       status = do_lock_spin(fsp,
-                               (uint32)SVAL(inbuf,smb_pid), 
-                               (SMB_BIG_UINT)numtoread,
-                               (SMB_BIG_UINT)startpos,
-                               WRITE_LOCK,
-                               WINDOWS_LOCK,
-                               &my_lock_ctx);
+       status = do_lock(fsp,
+                       (uint32)SVAL(inbuf,smb_pid), 
+                       (SMB_BIG_UINT)numtoread,
+                       (SMB_BIG_UINT)startpos,
+                       WRITE_LOCK,
+                       WINDOWS_LOCK,
+                       0 /* zero timeout. */);
 
        if (NT_STATUS_V(status)) {
 #if 0
@@ -2412,7 +2411,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
                 * tester. JRA.
                 */
 
-               if (lp_blocking_locks(SNUM(conn)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) {
+               if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
                        /*
                         * A blocking lock was requested. Package up
                         * this smb into a queued request and push it
@@ -3418,7 +3417,6 @@ int reply_lock(connection_struct *conn,
        SMB_BIG_UINT count,offset;
        NTSTATUS status;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
-       BOOL my_lock_ctx = False;
 
        START_PROFILE(SMBlock);
 
@@ -3432,17 +3430,18 @@ int reply_lock(connection_struct *conn,
        DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
                 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
 
-       status = do_lock_spin(fsp,
-                               (uint32)SVAL(inbuf,smb_pid),
-                               count,
-                               offset,
-                               WRITE_LOCK,
-                               WINDOWS_LOCK,
-                               &my_lock_ctx);
+       status = do_lock(fsp,
+                       (uint32)SVAL(inbuf,smb_pid),
+                       count,
+                       offset,
+                       WRITE_LOCK,
+                       WINDOWS_LOCK,
+                       0 /* zero timeout. */);
+
        if (NT_STATUS_V(status)) {
 #if 0
                /* Tests using Samba4 against W2K show this call never creates a blocking lock. */
-               if (lp_blocking_locks(SNUM(conn)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) {
+               if (lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
                        /*
                         * A blocking lock was requested. Package up
                         * this smb into a queued request and push it
@@ -5228,7 +5227,6 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
        BOOL large_file_format =
                (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
        BOOL err;
-       BOOL my_lock_ctx = False;
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 
        START_PROFILE(SMBlockingX);
@@ -5244,11 +5242,6 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
        }
        
-       if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
-               /* Need to make this like a cancel.... JRA. */
-               return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
-       }
-       
        /* Check if this is an oplock break on a file
           we have granted an oplock on.
        */
@@ -5360,7 +5353,11 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
 
        /* Setup the timeout in seconds. */
 
-       lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000);
+       if (lp_blocking_locks(SNUM(conn))) {
+               lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000);
+       } else {
+               lock_timeout = 0;
+       }
        
        /* Now do any requested locks */
        data += ((large_file_format ? 20 : 10)*num_ulocks);
@@ -5369,7 +5366,8 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
           of smb_lkrng structs */
        
        for(i = 0; i < (int)num_locks; i++) {
-               enum brl_type lock_type = ((locktype & 1) ? READ_LOCK:WRITE_LOCK);
+               enum brl_type lock_type = ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
+                               READ_LOCK:WRITE_LOCK);
                lock_pid = get_lock_pid( data, i, large_file_format);
                count = get_lock_count( data, i, large_file_format);
                offset = get_lock_offset( data, i, large_file_format, &err);
@@ -5387,31 +5385,54 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                          (double)count, (unsigned int)lock_pid,
                          fsp->fsp_name, (int)lock_timeout ));
                
-               status = do_lock_spin(fsp,
+               if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
+                       if (lp_blocking_locks(SNUM(conn))) {
+
+                               /* Schedule a message to ourselves to
+                                  remove the blocking lock record and
+                                  return the right error. */
+
+                               if (!blocking_lock_cancel(fsp,
+                                               lock_pid,
+                                               offset,
+                                               count,
+                                               WINDOWS_LOCK,
+                                               locktype,
+                                               NT_STATUS_FILE_LOCK_CONFLICT)) {
+                                       END_PROFILE(SMBlockingX);
+                                       return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
+                               }
+                       }
+                       /* Remove a matching pending lock. */
+                       status = do_lock_cancel(fsp,
+                                               lock_pid,
+                                               count,
+                                               offset,
+                                               WINDOWS_LOCK);
+               } else {
+                       status = do_lock(fsp,
                                        lock_pid,
                                        count,
                                        offset, 
                                        lock_type,
                                        WINDOWS_LOCK,
-                                       &my_lock_ctx);
+                                       lock_timeout);
 
-               if (NT_STATUS_V(status)) {
-                       /*
-                        * Interesting fact found by IFSTEST /t
-                        * LockOverlappedTest...  Even if it's our own lock
-                        * context, we need to wait here as there may be an
-                        * unlock on the way.  So I removed a "&&
-                        * !my_lock_ctx" from the following if statement. JRA.
-                        */
-                       if ((lock_timeout != 0) &&
-                           lp_blocking_locks(SNUM(conn)) &&
-                           ERROR_WAS_LOCK_DENIED(status)) {
+                       if (NT_STATUS_V(status)) {
                                /*
-                                * A blocking lock was requested. Package up
-                                * this smb into a queued request and push it
-                                * onto the blocking lock queue.
+                                * Interesting fact found by IFSTEST /t
+                                * LockOverlappedTest...  Even if it's our own lock
+                                * context, we need to wait here as there may be an
+                                * unlock on the way. JRA.
                                 */
-                               if(push_blocking_lock_request(inbuf, length,
+                               if ((lock_timeout != 0) &&
+                                   ERROR_WAS_LOCK_DENIED(status)) {
+                                       /*
+                                        * A blocking lock was requested. Package up
+                                        * this smb into a queued request and push it
+                                        * onto the blocking lock queue.
+                                        */
+                                       if(push_blocking_lock_request(inbuf, length,
                                                              fsp,
                                                              lock_timeout,
                                                              i,
@@ -5420,17 +5441,25 @@ int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
                                                              WINDOWS_LOCK,
                                                              offset,
                                                              count)) {
-                                       END_PROFILE(SMBlockingX);
-                                       return -1;
+                                               END_PROFILE(SMBlockingX);
+                                               return -1;
+                                       }
                                }
                        }
-                       break;
+               }
+
+               if (NT_STATUS_V(status)) {
+                       END_PROFILE(SMBlockingX);
+                       return ERROR_NT(status);
                }
        }
        
        /* If any of the above locks failed, then we must unlock
           all of the previous locks (X/Open spec). */
-       if (i != num_locks && num_locks != 0) {
+
+       if (!(locktype & LOCKING_ANDX_CANCEL_LOCK) &&
+                       (i != num_locks) &&
+                       (num_locks != 0)) {
                /*
                 * Ensure we don't do a remove on the lock that just failed,
                 * as under POSIX rules, if we have a lock already there, we
index 43437469d7e5277219e76df183c38ac6365549a2..329d5bb0a52b26bf29faf03b4a3b638bc4e185ea 100644 (file)
@@ -4505,7 +4505,6 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        uint32 lock_pid;
                        BOOL lock_blocking;
                        enum brl_type lock_type;
-                       BOOL my_lock_ctx;
 
                        if (fsp == NULL || fsp->fh->fd == -1) {
                                return ERROR_NT(NT_STATUS_INVALID_HANDLE);
@@ -4564,8 +4563,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                                count,
                                                offset,
                                                lock_type,
-                                               POSIX_LOCK,
-                                               &my_lock_ctx);
+                                               POSIX_LOCK);
 
                                if (lock_blocking && lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
                                        /*