s3:smbd: use new simplified snb_signing code in the server
[sfrench/samba-autobuild/.git] / source3 / smbd / blocking.c
index cccc5ce727af6c477ef517ed5ee3b50a175b33ee..4c61428692dc48d45ca76600d2e5cddd140f73b8 100644 (file)
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_LOCKING
 
-/****************************************************************************
- This is the structure to queue to implement blocking locks.
- notify. It consists of the requesting SMB and the expiry time.
-*****************************************************************************/
-
-typedef struct blocking_lock_record {
-       struct blocking_lock_record *next;
-       struct blocking_lock_record *prev;
-       files_struct *fsp;
-       struct timeval expire_time;
-       int lock_num;
-       uint64_t offset;
-       uint64_t count;
-       uint32_t lock_pid;
-       uint32_t blocking_pid; /* PID that blocks us. */
-       enum brl_flavour lock_flav;
-       enum brl_type lock_type;
-       struct smb_request *req;
-} blocking_lock_record;
-
 /****************************************************************************
  Determine if this is a secondary element of a chained SMB.
   **************************************************************************/
 
-static bool in_chained_smb(void)
-{
-       return (chain_size != 0);
-}
-
 static void received_unlock_msg(struct messaging_context *msg,
                                void *private_data,
                                uint32_t msg_type,
                                struct server_id server_id,
                                DATA_BLOB *data);
-static void process_blocking_lock_queue(void);
 
 static void brl_timeout_fn(struct event_context *event_ctx,
                           struct timed_event *te,
@@ -80,21 +54,21 @@ static void brl_timeout_fn(struct event_context *event_ctx,
 
 static bool recalc_brl_timeout(void)
 {
-       blocking_lock_record *brl;
+       struct blocking_lock_record *blr;
        struct timeval next_timeout;
 
        TALLOC_FREE(brl_timeout);
 
        next_timeout = timeval_zero();  
 
-       for (brl = blocking_lock_queue; brl; brl = brl->next) {
-               if (timeval_is_zero(&brl->expire_time)) {
+       for (blr = blocking_lock_queue; blr; blr = blr->next) {
+               if (timeval_is_zero(&blr->expire_time)) {
                        /*
                         * If we're blocked on pid 0xFFFFFFFF this is
                         * a POSIX lock, so calculate a timeout of
                         * 10 seconds into the future.
                         */
-                        if (brl->blocking_pid == 0xFFFFFFFF) {
+                        if (blr->blocking_pid == 0xFFFFFFFF) {
                                struct timeval psx_to = timeval_current_ofs(10, 0);
                                next_timeout = timeval_min(&next_timeout, &psx_to);
                         }
@@ -103,18 +77,28 @@ static bool recalc_brl_timeout(void)
                }
 
                if (timeval_is_zero(&next_timeout)) {
-                       next_timeout = brl->expire_time;
+                       next_timeout = blr->expire_time;
                }
                else {
                        next_timeout = timeval_min(&next_timeout,
-                                                  &brl->expire_time);
+                                                  &blr->expire_time);
                }
        }
 
        if (timeval_is_zero(&next_timeout)) {
+               DEBUG(10, ("Next timeout = Infinite.\n"));
                return True;
        }
 
+       if (DEBUGLVL(10)) {
+               struct timeval cur, from_now;
+
+               cur = timeval_current();
+               from_now = timeval_until(&cur, &next_timeout);
+               DEBUG(10, ("Next timeout = %d.%d seconds from now.\n",
+                   (int)from_now.tv_sec, (int)from_now.tv_usec));
+       }
+
        if (!(brl_timeout = event_add_timed(smbd_event_context(), NULL,
                                            next_timeout,
                                            brl_timeout_fn, NULL))) {
@@ -141,10 +125,10 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck,
                uint64_t count,
                uint32_t blocking_pid)
 {
-       blocking_lock_record *blr;
+       struct blocking_lock_record *blr;
        NTSTATUS status;
 
-       if(in_chained_smb() ) {
+       if(req_is_in_chain(req)) {
                DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n"));
                return False;
        }
@@ -178,9 +162,13 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck,
        blr->lock_type = lock_type;
        blr->offset = offset;
        blr->count = count;
+      
+       /* Specific brl_lock() implementations can fill this in. */
+       blr->blr_private = NULL;
 
        /* Add a pending lock record for this. */
-       status = brl_lock(smbd_messaging_context(), br_lck,
+       status = brl_lock(smbd_messaging_context(),
+                       br_lck,
                        lock_pid,
                        procid_self(),
                        offset,
@@ -188,18 +176,19 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck,
                        lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
                        blr->lock_flav,
                        lock_timeout ? True : False, /* blocking_lock. */
-                       NULL);
+                       NULL,
+                       blr);
 
        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);
                TALLOC_FREE(blr);
                return False;
        }
 
+       SMB_PERFCOUNT_DEFER_OP(&req->pcd, &req->pcd);
        blr->req = talloc_move(blr, &req);
 
-       DLIST_ADD_END(blocking_lock_queue, blr, blocking_lock_record *);
+       DLIST_ADD_END(blocking_lock_queue, blr, struct blocking_lock_record *);
        recalc_brl_timeout();
 
        /* Ensure we'll receive messages when this is unlocked. */
@@ -215,9 +204,6 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck,
                (unsigned int)blr->expire_time.tv_usec, lock_timeout,
                blr->fsp->fnum, blr->fsp->fsp_name ));
 
-       /* Push the MID of this packet on the signing queue. */
-       srv_defer_sign_response(blr->req->mid);
-
        return True;
 }
 
@@ -225,7 +211,7 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck,
  Return a lockingX success SMB.
 *****************************************************************************/
 
-static void reply_lockingX_success(blocking_lock_record *blr)
+static void reply_lockingX_success(struct blocking_lock_record *blr)
 {
        reply_outbuf(blr->req, 2, 0);
 
@@ -238,12 +224,6 @@ static void reply_lockingX_success(blocking_lock_record *blr)
         */
 
        chain_reply(blr->req);
-
-       if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf,
-                       IS_CONN_ENCRYPTED(blr->fsp->conn))) {
-               exit_server_cleanly("send_blocking_reply: srv_send_smb failed.");
-       }
-
        TALLOC_FREE(blr->req->outbuf);
 }
 
@@ -251,7 +231,7 @@ static void reply_lockingX_success(blocking_lock_record *blr)
  Return a generic lock fail error blocking call.
 *****************************************************************************/
 
-static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS status)
+static void generic_blocking_lock_error(struct blocking_lock_record *blr, NTSTATUS status)
 {
        /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to
           FILE_LOCK_CONFLICT! (tridge) */
@@ -277,7 +257,8 @@ static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS stat
 
        reply_nterror(blr->req, status);
        if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf,
-                         blr->req->encrypted)) {
+                         true, blr->req->seqnum+1,
+                         blr->req->encrypted, NULL)) {
                exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed.");
        }
        TALLOC_FREE(blr->req->outbuf);
@@ -288,7 +269,7 @@ static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS stat
  obtained first.
 *****************************************************************************/
 
-static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
+static void reply_lockingX_error(struct blocking_lock_record *blr, NTSTATUS status)
 {
        files_struct *fsp = blr->fsp;
        uint16 num_ulocks = SVAL(blr->req->vwv+6, 0);
@@ -340,8 +321,10 @@ static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
  Return a lock fail error.
 *****************************************************************************/
 
-static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status)
+static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS status)
 {
+       DEBUG(10, ("Replying with error=%s. BLR = %p\n", nt_errstr(status), blr));
+
        switch(blr->req->cmd) {
        case SMBlockingX:
                reply_lockingX_error(blr, status);
@@ -358,7 +341,9 @@ static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status
 
                if (!srv_send_smb(smbd_server_fd(),
                                  (char *)blr->req->outbuf,
-                                 IS_CONN_ENCRYPTED(blr->fsp->conn))) {
+                                 true, blr->req->seqnum+1,
+                                 IS_CONN_ENCRYPTED(blr->fsp->conn),
+                                 NULL)) {
                        exit_server_cleanly("blocking_lock_reply_error: "
                                            "srv_send_smb failed.");
                }
@@ -375,7 +360,7 @@ static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status
  Returns True if we want to be removed from the list.
 *****************************************************************************/
 
-static bool process_lockingX(blocking_lock_record *blr)
+static bool process_lockingX(struct blocking_lock_record *blr)
 {
        unsigned char locktype = CVAL(blr->req->vwv+3, 0);
        files_struct *fsp = blr->fsp;
@@ -418,7 +403,8 @@ static bool process_lockingX(blocking_lock_record *blr)
                                WINDOWS_LOCK,
                                True,
                                &status,
-                               &blr->blocking_pid);
+                               &blr->blocking_pid,
+                               blr);
 
                TALLOC_FREE(br_lck);
 
@@ -466,7 +452,7 @@ Waiting....\n",
  Returns True if we want to be removed from the list.
 *****************************************************************************/
 
-static bool process_trans2(blocking_lock_record *blr)
+static bool process_trans2(struct blocking_lock_record *blr)
 {
        char params[2];
        NTSTATUS status;
@@ -479,7 +465,8 @@ static bool process_trans2(blocking_lock_record *blr)
                                                blr->lock_flav,
                                                True,
                                                &status,
-                                               &blr->blocking_pid);
+                                               &blr->blocking_pid,
+                                               blr);
        TALLOC_FREE(br_lck);
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -509,7 +496,7 @@ static bool process_trans2(blocking_lock_record *blr)
  Returns True if we want to be removed from the list.
 *****************************************************************************/
 
-static bool blocking_lock_record_process(blocking_lock_record *blr)
+static bool blocking_lock_record_process(struct blocking_lock_record *blr)
 {
        switch(blr->req->cmd) {
                case SMBlockingX:
@@ -530,7 +517,7 @@ static bool blocking_lock_record_process(blocking_lock_record *blr)
 
 void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
 {
-       blocking_lock_record *blr, *next = NULL;
+       struct blocking_lock_record *blr, *blr_cancelled, *next = NULL;
 
        for(blr = blocking_lock_queue; blr; blr = next) {
                unsigned char locktype = 0;
@@ -548,14 +535,7 @@ void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lo
                           "request type %d for file %s fnum = %d\n",
                           blr->req->cmd, fsp->fsp_name, fsp->fnum));
 
-               brl_lock_cancel(br_lck,
-                               blr->lock_pid,
-                               procid_self(),
-                               blr->offset,
-                               blr->count,
-                               blr->lock_flav);
-
-               blocking_lock_cancel(fsp,
+               blr_cancelled = blocking_lock_cancel(fsp,
                                     blr->lock_pid,
                                     blr->offset,
                                     blr->count,
@@ -563,6 +543,16 @@ void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lo
                                     locktype,
                                     NT_STATUS_RANGE_NOT_LOCKED);
 
+               SMB_ASSERT(blr_cancelled == blr);
+
+               brl_lock_cancel(br_lck,
+                               blr->lock_pid,
+                               procid_self(),
+                               blr->offset,
+                               blr->count,
+                               blr->lock_flav,
+                               blr);
+
                /* We're closing the file fsp here, so ensure
                 * we don't have a dangling pointer. */
                blr->fsp = NULL;
@@ -575,7 +565,7 @@ void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lo
 
 void remove_pending_lock_requests_by_mid(int mid)
 {
-       blocking_lock_record *blr, *next = NULL;
+       struct blocking_lock_record *blr, *next = NULL;
 
        for(blr = blocking_lock_queue; blr; blr = next) {
                files_struct *fsp;
@@ -601,7 +591,8 @@ void remove_pending_lock_requests_by_mid(int mid)
                                        procid_self(),
                                        blr->offset,
                                        blr->count,
-                                       blr->lock_flav);
+                                       blr->lock_flav,
+                                       blr);
                        TALLOC_FREE(br_lck);
                }
 
@@ -617,7 +608,7 @@ void remove_pending_lock_requests_by_mid(int mid)
 
 bool blocking_lock_was_deferred(int mid)
 {
-       blocking_lock_record *blr, *next = NULL;
+       struct blocking_lock_record *blr, *next = NULL;
 
        for(blr = blocking_lock_queue; blr; blr = next) {
                next = blr->next;
@@ -646,10 +637,10 @@ static void received_unlock_msg(struct messaging_context *msg,
  Process the blocking lock queue. Note that this is only called as root.
 *****************************************************************************/
 
-static void process_blocking_lock_queue(void)
+void process_blocking_lock_queue(void)
 {
        struct timeval tv_curr = timeval_current();
-       blocking_lock_record *blr, *next = NULL;
+       struct blocking_lock_record *blr, *next = NULL;
        bool recalc_timeout = False;
 
        /*
@@ -666,17 +657,23 @@ static void process_blocking_lock_queue(void)
                 * and False if we still need to wait.
                 */
 
+               DEBUG(10, ("Processing BLR = %p\n", blr));
+
                if(blocking_lock_record_process(blr)) {
                        struct byte_range_lock *br_lck = brl_get_locks(
                                talloc_tos(), blr->fsp);
 
+                       DEBUG(10, ("BLR_process returned true: cancelling and "
+                           "removing lock. BLR = %p\n", blr));
+
                        if (br_lck) {
                                brl_lock_cancel(br_lck,
                                        blr->lock_pid,
                                        procid_self(),
                                        blr->offset,
                                        blr->count,
-                                       blr->lock_flav);
+                                       blr->lock_flav,
+                                       blr);
                                TALLOC_FREE(br_lck);
                        }
 
@@ -695,6 +692,8 @@ static void process_blocking_lock_queue(void)
                        struct byte_range_lock *br_lck = brl_get_locks(
                                talloc_tos(), blr->fsp);
 
+                       DEBUG(10, ("Lock timed out! BLR = %p\n", blr));
+
                        /*
                         * Lock expired - throw away all previously
                         * obtained locks and return lock error.
@@ -711,7 +710,8 @@ static void process_blocking_lock_queue(void)
                                        procid_self(),
                                        blr->offset,
                                        blr->count,
-                                       blr->lock_flav);
+                                       blr->lock_flav,
+                                       blr);
                                TALLOC_FREE(br_lck);
                        }
 
@@ -731,7 +731,7 @@ static void process_blocking_lock_queue(void)
  Handle a cancel message. Lock already moved onto the cancel queue.
 *****************************************************************************/
 
-#define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(blocking_lock_record *) + sizeof(NTSTATUS))
+#define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(struct blocking_lock_record *) + sizeof(NTSTATUS))
 
 static void process_blocking_lock_cancel_message(struct messaging_context *ctx,
                                                 void *private_data,
@@ -741,7 +741,7 @@ static void process_blocking_lock_cancel_message(struct messaging_context *ctx,
 {
        NTSTATUS err;
        const char *msg = (const char *)data->data;
-       blocking_lock_record *blr;
+       struct blocking_lock_record *blr;
 
        if (data->data == NULL) {
                smb_panic("process_blocking_lock_cancel_message: null msg");
@@ -766,9 +766,10 @@ static void process_blocking_lock_cancel_message(struct messaging_context *ctx,
 
 /****************************************************************************
  Send ourselves a blocking lock cancelled message. Handled asynchronously above.
+ Returns the blocking_lock_record that is being cancelled.
 *****************************************************************************/
 
-bool blocking_lock_cancel(files_struct *fsp,
+struct blocking_lock_record *blocking_lock_cancel(files_struct *fsp,
                        uint32 lock_pid,
                        uint64_t offset,
                        uint64_t count,
@@ -777,7 +778,7 @@ bool blocking_lock_cancel(files_struct *fsp,
                         NTSTATUS err)
 {
        char msg[MSG_BLOCKING_LOCK_CANCEL_SIZE];
-       blocking_lock_record *blr;
+       struct blocking_lock_record *blr;
 
        if (!blocking_lock_cancel_state) {
                /* Register our message. */
@@ -799,14 +800,14 @@ bool blocking_lock_cancel(files_struct *fsp,
        }
 
        if (!blr) {
-               return False;
+               return NULL;
        }
 
        /* Check the flags are right. */
        if (blr->req->cmd == SMBlockingX &&
                (locktype & LOCKING_ANDX_LARGE_FILES) !=
                        (CVAL(blr->req->vwv+3, 0) & LOCKING_ANDX_LARGE_FILES)) {
-               return False;
+               return NULL;
        }
 
        /* Move to cancelled queue. */
@@ -821,5 +822,5 @@ bool blocking_lock_cancel(files_struct *fsp,
                           MSG_SMB_BLOCKING_LOCK_CANCEL,
                           (uint8 *)&msg, sizeof(msg));
 
-       return True;
+       return blr;
 }