Fix to allow blocking lock notification to be done rapidly (no wait
authorJeremy Allison <jra@samba.org>
Thu, 27 Feb 2003 01:04:34 +0000 (01:04 +0000)
committerJeremy Allison <jra@samba.org>
Thu, 27 Feb 2003 01:04:34 +0000 (01:04 +0000)
for smb -> smb lock release). Adds new PENDING_LOCK type to lockdb
(does not interfere with existing locks).
Jeremy.
(This used to be commit 766928bbba1e597c9c2b12458dd8d37e6080593e)

source3/include/messages.h
source3/include/smb.h
source3/locking/brlock.c
source3/locking/locking.c
source3/smbd/blocking.c
source3/smbd/process.c
source3/smbd/reply.c

index 2b8ca8bbe97b830fa1cb872e03cf8de308573b01..ce167a772d307bb5d67fa6017990cefb0df462ca 100644 (file)
@@ -62,6 +62,7 @@
 #define MSG_SMB_FORCE_TDIS   3002
 #define MSG_SMB_SAM_SYNC     3003
 #define MSG_SMB_SAM_REPL     3004
+#define MSG_SMB_UNLOCK       3005
 
 /* Flags to classify messages - used in message_send_all() */
 /* Sender will filter by flag. */
index f96a19954a24770b395f273224e6b339bdd33526..e96d664bd31c60a2f82a00dadeded5e4f541cdf6 100644 (file)
@@ -772,7 +772,7 @@ typedef enum
 } parm_class;
 
 /* passed to br lock code */
-enum brl_type {READ_LOCK, WRITE_LOCK};
+enum brl_type {READ_LOCK, WRITE_LOCK, PENDING_LOCK};
 
 struct enum_list {
        int value;
index 9902c7bbd7b6c7e00504624e99e3e71c0aa0484e..4cd885f1a6507d4345742bb581efd5535ee08bc6 100644 (file)
@@ -98,6 +98,9 @@ static BOOL brl_same_context(struct lock_context *ctx1,
 static BOOL brl_conflict(struct lock_struct *lck1, 
                         struct lock_struct *lck2)
 {
+       if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
+               return False;
+
        if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
                return False;
        }
@@ -119,6 +122,9 @@ static BOOL brl_conflict(struct lock_struct *lck1,
 static BOOL brl_conflict1(struct lock_struct *lck1, 
                         struct lock_struct *lck2)
 {
+       if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
+               return False;
+
        if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
                return False;
        }
@@ -148,6 +154,9 @@ static BOOL brl_conflict1(struct lock_struct *lck1,
 
 static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
 {
+       if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
+               return False;
+
        if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) 
                return False;
 
@@ -385,16 +394,30 @@ NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
        return status;
 }
 
+/****************************************************************************
+ Check if an unlock overlaps a pending lock.
+****************************************************************************/
+
+static BOOL brl_pending_overlap(struct lock_struct *lock, 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.
 ****************************************************************************/
 
 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
                uint16 smbpid, pid_t pid, uint16 tid,
-               br_off start, br_off size)
+               br_off start, br_off size,
+               BOOL remove_pending_locks_only)
 {
        TDB_DATA kbuf, dbuf;
-       int count, i;
+       int count, i, j;
        struct lock_struct *locks;
        struct lock_context context;
 
@@ -452,9 +475,34 @@ BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
                struct lock_struct *lock = &locks[i];
 
                if (brl_same_context(&lock->context, &context) &&
-                   lock->fnum == fnum &&
-                   lock->start == start &&
-                   lock->size == size) {
+                               lock->fnum == fnum &&
+                               lock->start == start &&
+                               lock->size == size) {
+
+                       if (remove_pending_locks_only && lock->lock_type != PENDING_LOCK)
+                               continue;
+
+                       if (lock->lock_type != PENDING_LOCK) {
+                               /* Send unlock messages to any pending waiters that overlap. */
+                               for (j=0; j<count; j++) {
+                                       struct lock_struct *pend_lock = &locks[j];
+
+                                       /* Ignore non-pending locks. */
+                                       if (pend_lock->lock_type != PENDING_LOCK)
+                                               continue;
+
+                                       /* We could send specific lock info here... */
+                                       if (brl_pending_overlap(lock, pend_lock)) {
+                                               DEBUG(10,("brl_unlock: sending unlock message to pid %u\n",
+                                                                       (unsigned int)pend_lock->context.pid ));
+
+                                               message_send_pid(pend_lock->context.pid,
+                                                               MSG_SMB_UNLOCK,
+                                                               NULL, 0, True);
+                                       }
+                               }
+                       }
+
                        /* found it - delete it */
                        if (count == 1) {
                                tdb_delete(tdb, kbuf);
@@ -546,7 +594,7 @@ BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
 {
        TDB_DATA kbuf, dbuf;
-       int count, i, dcount=0;
+       int count, i, j, dcount=0;
        struct lock_struct *locks;
 
        kbuf = locking_key(dev,ino);
@@ -561,12 +609,34 @@ void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
        /* there are existing locks - remove any for this fnum */
        locks = (struct lock_struct *)dbuf.dptr;
        count = dbuf.dsize / sizeof(*locks);
+
        for (i=0; i<count; i++) {
                struct lock_struct *lock = &locks[i];
 
                if (lock->context.tid == tid &&
                    lock->context.pid == pid &&
                    lock->fnum == fnum) {
+
+                       /* Send unlock messages to any pending waiters that overlap. */
+                       for (j=0; j<count; j++) {
+                               struct lock_struct *pend_lock = &locks[j];
+
+                               /* Ignore our own or non-pending locks. */
+                               if (pend_lock->lock_type != PENDING_LOCK)
+                                       continue;
+
+                               if (pend_lock->context.tid == tid &&
+                                   pend_lock->context.pid == pid &&
+                                   pend_lock->fnum == fnum)
+                                       continue;
+
+                               /* We could send specific lock info here... */
+                               if (brl_pending_overlap(lock, pend_lock))
+                                       message_send_pid(pend_lock->context.pid,
+                                                       MSG_SMB_UNLOCK,
+                                                       NULL, 0, True);
+                       }
+
                        /* found it - delete it */
                        if (count > 1 && i < count-1) {
                                memmove(&locks[i], &locks[i+1], 
index fdfd4d661c6d0d5d2f31d6afc41514234a3fe6d1..651f905e15de6b4ff7071413ebfd63e9654bdfe7 100644 (file)
@@ -132,7 +132,7 @@ static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_p
                                 */
                                (void)brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
                                                                lock_pid, sys_getpid(), conn->cnum, 
-                                                               offset, count);
+                                                               offset, count, False);
                        }
                }
        }
@@ -201,7 +201,7 @@ NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
         */
 
        ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
-                       lock_pid, sys_getpid(), conn->cnum, offset, count);
+                       lock_pid, sys_getpid(), conn->cnum, offset, count, False);
    
        if (!ok) {
                DEBUG(10,("do_unlock: returning ERRlock.\n" ));
index 14239272c291fc76d27970504a2788003022f10b..581ce43f9118e7ac000bd664a57d7d359955d284 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Unix SMB/CIFS implementation.
    Blocking Locking functions
-   Copyright (C) Jeremy Allison 1998
+   Copyright (C) Jeremy Allison 1998-2003
    
    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
@@ -33,6 +33,9 @@ typedef struct {
   files_struct *fsp;
   time_t expire_time;
   int lock_num;
+  SMB_BIG_UINT offset;
+  SMB_BIG_UINT count;
+  uint16 lock_pid;
   char *inbuf;
   int length;
 } blocking_lock_record;
@@ -77,13 +80,18 @@ static BOOL in_chained_smb(void)
   return (chain_size != 0);
 }
 
+static void received_unlock_msg(int msg_type, pid_t src, void *buf, size_t len);
+
 /****************************************************************************
  Function to push a blocking lock request onto the lock queue.
 ****************************************************************************/
 
-BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int lock_num)
+BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout,
+               int lock_num, uint16 lock_pid, SMB_BIG_UINT offset, SMB_BIG_UINT count)
 {
+  static BOOL set_lock_msg;
   blocking_lock_record *blr;
+  NTSTATUS status;
 
   if(in_chained_smb() ) {
     DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n"));
@@ -110,11 +118,31 @@ BOOL push_blocking_lock_request( char *inbuf, int length, int lock_timeout, int
   blr->fsp = get_fsp_from_pkt(inbuf);
   blr->expire_time = (lock_timeout == -1) ? (time_t)-1 : time(NULL) + (time_t)lock_timeout;
   blr->lock_num = lock_num;
+  blr->lock_pid = lock_pid;
+  blr->offset = offset;
+  blr->count = count;
   memcpy(blr->inbuf, inbuf, length);
   blr->length = length;
 
+  /* Add a pending lock record for this. */
+  status = brl_lock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
+               lock_pid, sys_getpid(), blr->fsp->conn->cnum,
+               offset, count,
+               PENDING_LOCK);
+
+  if (!NT_STATUS_IS_OK(status)) {
+       DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
+       free_blocking_lock_record(blr);
+       return False;
+  }
+
   ubi_slAddTail(&blocking_lock_queue, blr);
 
+  /* Ensure we'll receive messages when this is unlocked. */
+  if (!set_lock_msg) {
+         message_register(MSG_SMB_UNLOCK, received_unlock_msg);
+         set_lock_msg = True;
+  }
 
   DEBUG(3,("push_blocking_lock_request: lock request length=%d blocked with expiry time %d (+%d) \
 for fnum = %d, name = %s\n", length, (int)blr->expire_time, lock_timeout,
@@ -493,6 +521,10 @@ void remove_pending_lock_requests_by_fid(files_struct *fsp)
       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_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
+               blr->lock_pid, sys_getpid(), blr->fsp->conn->cnum,
+               blr->offset, blr->count, True);
+
       free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
       blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
       continue;
@@ -520,6 +552,9 @@ void remove_pending_lock_requests_by_mid(int mid)
 file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
 
       blocking_lock_reply_error(blr,NT_STATUS_CANCELLED);
+      brl_unlock(blr->fsp->dev, blr->fsp->inode, blr->fsp->fnum,
+               blr->lock_pid, sys_getpid(), blr->fsp->conn->cnum,
+               blr->offset, blr->count, True);
       free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
       blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
       continue;
@@ -530,9 +565,20 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum ));
   }
 }
 
+/****************************************************************************
+  Set a flag as an unlock request affects one of our pending locks.
+*****************************************************************************/
+
+static void received_unlock_msg(int msg_type, pid_t src, void *buf, size_t len)
+{
+       DEBUG(10,("received_unlock_msg\n"));
+       process_blocking_lock_queue(time(NULL));
+}
+
 /****************************************************************************
  Return the number of seconds to the next blocking locks timeout, or default_timeout
 *****************************************************************************/
+
 unsigned blocking_locks_timeout(unsigned default_timeout)
 {
        unsigned timeout = default_timeout;
@@ -540,22 +586,21 @@ unsigned blocking_locks_timeout(unsigned default_timeout)
        blocking_lock_record *blr = (blocking_lock_record *)ubi_slFirst(&blocking_lock_queue);
 
        /* note that we avoid the time() syscall if there are no blocking locks */
-       if (!blr) {
+       if (!blr)
                return timeout;
-       }
 
        t = time(NULL);
 
        while (blr) {
-               if (timeout > (blr->expire_time - t)) {
+               if ((blr->expire_time != (time_t)-1) &&
+                                       (timeout > (blr->expire_time - t))) {
                        timeout = blr->expire_time - t;
                }
                blr = (blocking_lock_record *)ubi_slNext(blr);
        }
 
-       if (timeout < 1) {
+       if (timeout < 1)
                timeout = 1;
-       }
 
        return timeout;
 }
@@ -604,6 +649,10 @@ 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_unlock(fsp->dev, fsp->inode, fsp->fnum,
+               blr->lock_pid, sys_getpid(), conn->cnum,
+               blr->offset, blr->count, True);
+
       blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
       free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
       blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
@@ -617,6 +666,11 @@ void process_blocking_lock_queue(time_t t)
        * Remove the entry and return an error to the client.
        */
       blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
+
+      brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
+               blr->lock_pid, sys_getpid(), conn->cnum,
+               blr->offset, blr->count, True);
+
       free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
       blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
       continue;
@@ -628,6 +682,11 @@ void process_blocking_lock_queue(time_t t)
        * Remove the entry and return an error to the client.
        */
       blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
+
+      brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
+               blr->lock_pid, sys_getpid(), conn->cnum,
+               blr->offset, blr->count, True);
+
       free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
       blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
       change_to_root_user();
@@ -641,6 +700,11 @@ void process_blocking_lock_queue(time_t t)
      */
 
     if(blocking_lock_record_process(blr)) {
+
+      brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
+               blr->lock_pid, sys_getpid(), conn->cnum,
+               blr->offset, blr->count, True);
+
       free_blocking_lock_record((blocking_lock_record *)ubi_slRemNext( &blocking_lock_queue, prev));
       blr = (blocking_lock_record *)(prev ? ubi_slNext(prev) : ubi_slFirst(&blocking_lock_queue));
       change_to_root_user();
index c002abad162ecf365dc20678030cf5716b95f9a8..57bc236eef583b9a255b358a4716d536775d8356 100644 (file)
@@ -1271,6 +1271,13 @@ void smbd_process(void)
                lp_talloc_free();
                main_loop_talloc_free();
 
+               /* Did someone ask for immediate checks on things like blocking locks ? */
+               if (select_timeout == 0) {
+                       if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
+                               return;
+                       num_smbs = 0; /* Reset smb counter. */
+               }
+
                while (!receive_message_or_smb(InBuffer,BUFFER_SIZE+LARGE_WRITEX_HDR_SIZE,select_timeout)) {
                        if(!timeout_processing( deadtime, &select_timeout, &last_timeout_processing_time))
                                return;
index 580878fe3205597b8d96a36ab0c952044d496fa1..71e880476cf69583ad7a37c1cffade7a2dfd46d2 100644 (file)
@@ -1609,7 +1609,8 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
                         * this smb into a queued request and push it
                         * onto the blocking lock queue.
                         */
-                       if(push_blocking_lock_request(inbuf, length, -1, 0)) {
+                       if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)startpos,
+                                                               (SMB_BIG_UINT)numtoread)) {
                                END_PROFILE(SMBlockread);
                                return -1;
                        }
@@ -2514,7 +2515,7 @@ int reply_lock(connection_struct *conn,
                         * this smb into a queued request and push it
                         * onto the blocking lock queue.
                         */
-                       if(push_blocking_lock_request(inbuf, length, -1, 0)) {
+                       if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), offset, count)) {
                                END_PROFILE(SMBlock);
                                return -1;
                        }
@@ -3955,7 +3956,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
                                 * this smb into a queued request and push it
                                 * onto the blocking lock queue.
                                 */
-                               if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) {
+                               if(push_blocking_lock_request(inbuf, length, lock_timeout, i, lock_pid, offset, count)) {
                                        END_PROFILE(SMBlockingX);
                                        return -1;
                                }