X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Fblocking.c;h=08af28ad0dd5e432deeb9d8bfdcadbb6418ba8cb;hb=988118c2358204eab5bb5907d0f5390cfece9538;hp=f489a8e96b2bf41f0c7a951ff091ceba3e420787;hpb=258a465e20e007a30043220367d17ecfc87b4f90;p=samba.git diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index f489a8e96b2..08af28ad0dd 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -2,94 +2,163 @@ Unix SMB/CIFS implementation. Blocking Locking functions 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 - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ #include "includes.h" +#include "smbd/globals.h" + #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. -*****************************************************************************/ + Determine if this is a secondary element of a chained SMB. + **************************************************************************/ -typedef struct _blocking_lock_record { - struct _blocking_lock_record *next; - struct _blocking_lock_record *prev; - int com_type; - files_struct *fsp; - struct timeval expire_time; - int lock_num; - SMB_BIG_UINT offset; - SMB_BIG_UINT count; - uint32 lock_pid; - enum brl_flavour lock_flav; - enum brl_type lock_type; - char *inbuf; - int length; -} blocking_lock_record; +static void received_unlock_msg(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data); -/* dlink list we store pending lock records on. */ -static blocking_lock_record *blocking_lock_queue; +static void brl_timeout_fn(struct event_context *event_ctx, + struct timed_event *te, + struct timeval now, + void *private_data) +{ + SMB_ASSERT(brl_timeout == te); + TALLOC_FREE(brl_timeout); -/* dlink list we move cancelled lock records onto. */ -static blocking_lock_record *blocking_lock_cancelled_queue; + change_to_root_user(); /* TODO: Possibly run all timed events as + * root */ + + process_blocking_lock_queue(); +} /**************************************************************************** - Destructor for the above structure. + We need a version of timeval_min that treats zero timval as infinite. ****************************************************************************/ -static void free_blocking_lock_record(blocking_lock_record *blr) +static struct timeval timeval_brl_min(const struct timeval *tv1, + const struct timeval *tv2) { - SAFE_FREE(blr->inbuf); - SAFE_FREE(blr); + if (timeval_is_zero(tv1)) { + return *tv2; + } + if (timeval_is_zero(tv2)) { + return *tv1; + } + return timeval_min(tv1, tv2); } /**************************************************************************** - Determine if this is a secondary element of a chained SMB. - **************************************************************************/ + After a change to blocking_lock_queue, recalculate the timed_event for the + next processing. +****************************************************************************/ -static BOOL in_chained_smb(void) +static bool recalc_brl_timeout(void) { - return (chain_size != 0); + struct blocking_lock_record *blr; + struct timeval next_timeout; + int max_brl_timeout = lp_parm_int(-1, "brl", "recalctime", 5); + + TALLOC_FREE(brl_timeout); + + next_timeout = timeval_zero(); + + 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 (blr->blocking_pid == 0xFFFFFFFF) { + struct timeval psx_to = timeval_current_ofs(10, 0); + next_timeout = timeval_brl_min(&next_timeout, &psx_to); + } + + continue; + } + + next_timeout = timeval_brl_min(&next_timeout, &blr->expire_time); + } + + if (timeval_is_zero(&next_timeout)) { + DEBUG(10, ("Next timeout = Infinite.\n")); + return True; + } + + /* + to account for unclean shutdowns by clients we need a + maximum timeout that we use for checking pending locks. If + we have any pending locks at all, then check if the pending + lock can continue at least every brl:recalctime seconds + (default 5 seconds). + + This saves us needing to do a message_send_all() in the + SIGCHLD handler in the parent daemon. That + message_send_all() caused O(n^2) work to be done when IP + failovers happened in clustered Samba, which could make the + entire system unusable for many minutes. + */ + + if (max_brl_timeout > 0) { + struct timeval min_to = timeval_current_ofs(max_brl_timeout, 0); + next_timeout = timeval_min(&next_timeout, &min_to); + } + + 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))) { + return False; + } + + return True; } -static void received_unlock_msg(int msg_type, struct process_id src, - void *buf, size_t len); /**************************************************************************** Function to push a blocking lock request onto the lock queue. ****************************************************************************/ -BOOL push_blocking_lock_request( struct byte_range_lock *br_lck, - char *inbuf, int length, +bool push_blocking_lock_request( struct byte_range_lock *br_lck, + struct smb_request *req, files_struct *fsp, int lock_timeout, int lock_num, - uint32 lock_pid, + uint32_t lock_pid, enum brl_type lock_type, enum brl_flavour lock_flav, - SMB_BIG_UINT offset, SMB_BIG_UINT count) + uint64_t offset, + uint64_t count, + uint32_t blocking_pid) { - static BOOL set_lock_msg; - 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; } @@ -99,7 +168,8 @@ BOOL push_blocking_lock_request( struct byte_range_lock *br_lck, * the expiration time here. */ - if((blr = SMB_MALLOC_P(blocking_lock_record)) == NULL) { + blr = talloc(NULL, struct blocking_lock_record); + if (blr == NULL) { DEBUG(0,("push_blocking_lock_request: Malloc fail !\n" )); return False; } @@ -107,13 +177,6 @@ BOOL push_blocking_lock_request( struct byte_range_lock *br_lck, blr->next = NULL; blr->prev = NULL; - if((blr->inbuf = (char *)SMB_MALLOC(length)) == NULL) { - DEBUG(0,("push_blocking_lock_request: Malloc fail (2)!\n" )); - SAFE_FREE(blr); - return False; - } - - blr->com_type = CVAL(inbuf,smb_com); blr->fsp = fsp; if (lock_timeout == -1) { blr->expire_time.tv_sec = 0; @@ -124,76 +187,63 @@ BOOL push_blocking_lock_request( struct byte_range_lock *br_lck, } blr->lock_num = lock_num; blr->lock_pid = lock_pid; + blr->blocking_pid = blocking_pid; blr->lock_flav = lock_flav; blr->lock_type = lock_type; blr->offset = offset; blr->count = count; - memcpy(blr->inbuf, inbuf, length); - blr->length = length; + + /* Specific brl_lock() implementations can fill this in. */ + blr->blr_private = NULL; /* Add a pending lock record for this. */ - status = brl_lock(br_lck, + status = brl_lock(smbd_messaging_context(), + br_lck, lock_pid, procid_self(), offset, count, lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK, blr->lock_flav, - lock_timeout ? True : False); /* blocking_lock. */ + True, + 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); - free_blocking_lock_record(blr); + TALLOC_FREE(blr); return False; } - DLIST_ADD_END(blocking_lock_queue, blr, blocking_lock_record *); + SMB_PERFCOUNT_DEFER_OP(&req->pcd, &req->pcd); + blr->req = talloc_move(blr, &req); + + DLIST_ADD_END(blocking_lock_queue, blr, struct blocking_lock_record *); + recalc_brl_timeout(); /* 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; + if (!blocking_lock_unlock_state) { + messaging_register(smbd_messaging_context(), NULL, + MSG_SMB_UNLOCK, received_unlock_msg); + blocking_lock_unlock_state = true; } - DEBUG(3,("push_blocking_lock_request: lock request length=%d blocked with " + DEBUG(3,("push_blocking_lock_request: lock request blocked with " "expiry time (%u sec. %u usec) (+%d msec) for fnum = %d, name = %s\n", - length, (unsigned int)blr->expire_time.tv_sec, + (unsigned int)blr->expire_time.tv_sec, (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(SVAL(inbuf,smb_mid)); + blr->fsp->fnum, fsp_str_dbg(blr->fsp))); return True; } -/**************************************************************************** - Return a smd with a given size. -*****************************************************************************/ - -static void send_blocking_reply(char *outbuf, int outsize) -{ - if(outsize > 4) - smb_setlen(outbuf,outsize - 4); - - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("send_blocking_reply: send_smb failed."); -} - /**************************************************************************** Return a lockingX success SMB. *****************************************************************************/ -static void reply_lockingX_success(blocking_lock_record *blr) +static void reply_lockingX_success(struct blocking_lock_record *blr) { - char *outbuf = get_OutBuffer(); - int bufsize = BUFFER_SIZE; - char *inbuf = blr->inbuf; - int outsize = 0; - - construct_reply_common(inbuf, outbuf); - set_message(outbuf,2,0,True); + reply_outbuf(blr->req, 2, 0); /* * As this message is a lockingX call we must handle @@ -203,23 +253,16 @@ static void reply_lockingX_success(blocking_lock_record *blr) * that here and must set up the chain info manually. */ - outsize = chain_reply(inbuf,outbuf,blr->length,bufsize); - - outsize += chain_size; - - send_blocking_reply(outbuf,outsize); + chain_reply(blr->req); + TALLOC_FREE(blr->req->outbuf); } /**************************************************************************** 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) { - char *outbuf = get_OutBuffer(); - char *inbuf = blr->inbuf; - construct_reply_common(inbuf, outbuf); - /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to FILE_LOCK_CONFLICT! (tridge) */ if (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { @@ -230,20 +273,25 @@ static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS stat /* 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; + if (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)) { - exit_server("generic_blocking_lock_error: send_smb failed."); + reply_nterror(blr->req, status); + if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf, + 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); } /**************************************************************************** @@ -251,20 +299,20 @@ 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 undo_locks_obtained(struct blocking_lock_record *blr) { - char *inbuf = blr->inbuf; files_struct *fsp = blr->fsp; - uint16 num_ulocks = SVAL(inbuf,smb_vwv6); - SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT) 0; + uint16 num_ulocks = SVAL(blr->req->vwv+6, 0); + uint64_t count = (uint64_t)0, offset = (uint64_t) 0; uint32 lock_pid; - unsigned char locktype = CVAL(inbuf,smb_vwv3); - BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES); - char *data; + unsigned char locktype = CVAL(blr->req->vwv+3, 0); + bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES); + uint8_t *data; int i; - data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks); - + data = (uint8_t *)blr->req->buf + + ((large_file_format ? 20 : 10)*num_ulocks); + /* * Data now points at the beginning of the list * of smb_lkrng structs. @@ -275,55 +323,69 @@ static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status) * as under POSIX rules, if we have a lock already there, we * will delete it (and we shouldn't) ..... */ - + for(i = blr->lock_num - 1; i >= 0; i--) { - BOOL err; - + bool err; + 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); - + /* * We know err cannot be set as if it was the lock * request would never have been queued. JRA. */ - - do_unlock(fsp, + + do_unlock(smbd_messaging_context(), + fsp, lock_pid, count, offset, WINDOWS_LOCK); } - - generic_blocking_lock_error(blr, 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) { - switch(blr->com_type) { + DEBUG(10, ("Replying with error=%s. BLR = %p\n", nt_errstr(status), blr)); + + switch(blr->req->cmd) { case SMBlockingX: - reply_lockingX_error(blr, status); - break; + /* + * This code can be called during the rundown of a + * file after it was already closed. In that case, + * blr->fsp==NULL and we do not need to undo any + * locks, they are already gone. + */ + if (blr->fsp != NULL) { + undo_locks_obtained(blr); + } + generic_blocking_lock_error(blr, status); + break; case SMBtrans2: case SMBtranss2: - { - char *outbuf = get_OutBuffer(); - char *inbuf = blr->inbuf; - construct_reply_common(inbuf, outbuf); - /* construct_reply_common has done us the favor to pre-fill the - * command field with SMBtranss2 which is wrong :-) - */ - SCVAL(outbuf,smb_com,SMBtrans2); - ERROR_NT(status); - if (!send_smb(smbd_server_fd(),outbuf)) { - exit_server("blocking_lock_reply_error: send_smb failed."); - } - break; + reply_nterror(blr->req, status); + + /* + * construct_reply_common has done us the favor to pre-fill + * the command field with SMBtranss2 which is wrong :-) + */ + SCVAL(blr->req->outbuf,smb_com,SMBtrans2); + + if (!srv_send_smb(smbd_server_fd(), + (char *)blr->req->outbuf, + true, blr->req->seqnum+1, + IS_CONN_ENCRYPTED(blr->fsp->conn), + NULL)) { + exit_server_cleanly("blocking_lock_reply_error: " + "srv_send_smb failed."); } + TALLOC_FREE(blr->req->outbuf); + break; default: DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n")); exit_server("PANIC - unknown type on blocking lock queue"); @@ -335,20 +397,20 @@ 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) { - char *inbuf = blr->inbuf; - unsigned char locktype = CVAL(inbuf,smb_vwv3); + unsigned char locktype = CVAL(blr->req->vwv+3, 0); files_struct *fsp = blr->fsp; - uint16 num_ulocks = SVAL(inbuf,smb_vwv6); - uint16 num_locks = SVAL(inbuf,smb_vwv7); - SMB_BIG_UINT count = (SMB_BIG_UINT)0, offset = (SMB_BIG_UINT)0; + uint16 num_ulocks = SVAL(blr->req->vwv+6, 0); + uint16 num_locks = SVAL(blr->req->vwv+7, 0); + uint64_t count = (uint64_t)0, offset = (uint64_t)0; uint32 lock_pid; - BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES); - char *data; + bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES); + uint8_t *data; NTSTATUS status = NT_STATUS_OK; - data = smb_buf(inbuf) + ((large_file_format ? 20 : 10)*num_ulocks); + data = (uint8_t *)blr->req->buf + + ((large_file_format ? 20 : 10)*num_ulocks); /* * Data now points at the beginning of the list @@ -357,18 +419,19 @@ static BOOL process_lockingX(blocking_lock_record *blr) for(; blr->lock_num < num_locks; blr->lock_num++) { struct byte_range_lock *br_lck = NULL; - BOOL err; + bool err; lock_pid = get_lock_pid( data, blr->lock_num, large_file_format); count = get_lock_count( data, blr->lock_num, large_file_format); offset = get_lock_offset( data, blr->lock_num, large_file_format, &err); - + /* * We know err cannot be set as if it was the lock * request would never have been queued. JRA. */ errno = 0; - br_lck = do_lock(fsp, + br_lck = do_lock(smbd_messaging_context(), + fsp, lock_pid, count, offset, @@ -376,7 +439,9 @@ static BOOL process_lockingX(blocking_lock_record *blr) READ_LOCK : WRITE_LOCK), WINDOWS_LOCK, True, - &status); + &status, + &blr->blocking_pid, + blr); TALLOC_FREE(br_lck); @@ -389,20 +454,22 @@ static BOOL process_lockingX(blocking_lock_record *blr) /* * Success - we got all the locks. */ - - DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d num_locks=%d\n", - fsp->fsp_name, fsp->fnum, (unsigned int)locktype, num_locks) ); + + DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d " + "num_locks=%d\n", fsp_str_dbg(fsp), fsp->fnum, + (unsigned int)locktype, num_locks)); reply_lockingX_success(blr); return True; - } else if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) && - !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) { - /* - * We have other than a "can't get lock" - * error. Free any locks we had and return an error. - * Return True so we get dequeued. - */ - + } + + if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) && + !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) { + /* + * We have other than a "can't get lock" + * error. Free any locks we had and return an error. + * Return True so we get dequeued. + */ blocking_lock_reply_error(blr, status); return True; } @@ -410,11 +477,11 @@ static BOOL process_lockingX(blocking_lock_record *blr) /* * Still can't get all the locks - keep waiting. */ - + DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \ Waiting....\n", - blr->lock_num, num_locks, fsp->fsp_name, fsp->fnum)); - + blr->lock_num, num_locks, fsp_str_dbg(fsp), fsp->fnum)); + return False; } @@ -423,21 +490,21 @@ 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) { - extern int max_send; - char *inbuf = blr->inbuf; - char *outbuf; char params[2]; NTSTATUS status; - struct byte_range_lock *br_lck = do_lock(blr->fsp, + struct byte_range_lock *br_lck = do_lock(smbd_messaging_context(), + blr->fsp, blr->lock_pid, blr->count, blr->offset, blr->lock_type, blr->lock_flav, True, - &status); + &status, + &blr->blocking_pid, + blr); TALLOC_FREE(br_lck); if (!NT_STATUS_IS_OK(status)) { @@ -454,12 +521,10 @@ static BOOL process_trans2(blocking_lock_record *blr) } /* We finally got the lock, return success. */ - outbuf = get_OutBuffer(); - construct_reply_common(inbuf, outbuf); - SCVAL(outbuf,smb_com,SMBtrans2); + SSVAL(params,0,0); /* Fake up max_data_bytes here - we know it fits. */ - send_trans2_replies(outbuf, max_send, params, 2, NULL, 0, 0xffff); + send_trans2_replies(blr->fsp->conn, blr->req, params, 2, NULL, 0, 0xffff); return True; } @@ -469,9 +534,9 @@ 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->com_type) { + switch(blr->req->cmd) { case SMBlockingX: return process_lockingX(blr); case SMBtrans2: @@ -490,37 +555,45 @@ 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) { - next = blr->next; - if(blr->fsp->fnum == fsp->fnum) { - 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 )); + unsigned char locktype = 0; - brl_lock_cancel(br_lck, - blr->lock_pid, - procid_self(), - blr->offset, - blr->count, - blr->lock_flav); + next = blr->next; + if (blr->fsp->fnum != fsp->fnum) { + continue; + } - blocking_lock_cancel(fsp, - blr->lock_pid, - blr->offset, - blr->count, - blr->lock_flav, - locktype, - NT_STATUS_RANGE_NOT_LOCKED); - } + if (blr->req->cmd == SMBlockingX) { + locktype = CVAL(blr->req->vwv+3, 0); } + + DEBUG(10, ("remove_pending_lock_requests_by_fid - removing " + "request type %d for file %s fnum = %d\n", + blr->req->cmd, fsp_str_dbg(fsp), fsp->fnum)); + + blr_cancelled = blocking_lock_cancel(fsp, + blr->lock_pid, + blr->offset, + blr->count, + blr->lock_flav, + 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; } } @@ -530,87 +603,72 @@ file %s fnum = %d\n", blr->com_type, fsp->fsp_name, fsp->fnum )); 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; + struct byte_range_lock *br_lck; + next = blr->next; - if(SVAL(blr->inbuf,smb_mid) == mid) { - files_struct *fsp = blr->fsp; - struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp); - if (br_lck) { - 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 )); + if (blr->req->mid != mid) { + continue; + } - brl_lock_cancel(br_lck, + fsp = blr->fsp; + br_lck = brl_get_locks(talloc_tos(), fsp); + + if (br_lck) { + DEBUG(10, ("remove_pending_lock_requests_by_mid - " + "removing request type %d for file %s fnum " + "= %d\n", blr->req->cmd, fsp_str_dbg(fsp), + fsp->fnum )); + + brl_lock_cancel(br_lck, blr->lock_pid, procid_self(), blr->offset, blr->count, - blr->lock_flav); - TALLOC_FREE(br_lck); - } - - blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); - DLIST_REMOVE(blocking_lock_queue, blr); - free_blocking_lock_record(blr); + blr->lock_flav, + blr); + TALLOC_FREE(br_lck); } + + blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); + DLIST_REMOVE(blocking_lock_queue, blr); + TALLOC_FREE(blr); } } /**************************************************************************** - Set a flag as an unlock request affects one of our pending locks. + Is this mid a blocking lock request on the queue ? *****************************************************************************/ -static void received_unlock_msg(int msg_type, struct process_id src, - void *buf, size_t len) +bool blocking_lock_was_deferred(int mid) { - DEBUG(10,("received_unlock_msg\n")); - process_blocking_lock_queue(); + struct blocking_lock_record *blr, *next = NULL; + + for(blr = blocking_lock_queue; blr; blr = next) { + next = blr->next; + if(blr->req->mid == mid) { + return True; + } + } + return False; } /**************************************************************************** - Return the number of milliseconds to the next blocking locks timeout, or default_timeout + Set a flag as an unlock request affects one of our pending locks. *****************************************************************************/ -unsigned int blocking_locks_timeout_ms(unsigned int default_timeout_ms) +static void received_unlock_msg(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data) { - unsigned int timeout_ms = default_timeout_ms; - struct timeval tv_curr; - SMB_BIG_INT min_tv_dif_us = 0x7FFFFFFF; /* A large +ve number. */ - blocking_lock_record *blr = blocking_lock_queue; - - /* note that we avoid the GetTimeOfDay() syscall if there are no blocking locks */ - if (!blr) { - return timeout_ms; - } - - tv_curr = timeval_current(); - - for (; blr; blr = blr->next) { - SMB_BIG_INT tv_dif_us; - - if (timeval_is_zero(&blr->expire_time)) { - continue; /* Never timeout. */ - } - - tv_dif_us = usec_time_diff(&blr->expire_time, &tv_curr); - min_tv_dif_us = MIN(min_tv_dif_us, tv_dif_us); - } - - if (min_tv_dif_us < 0) { - min_tv_dif_us = 0; - } - - timeout_ms = (unsigned int)(min_tv_dif_us / (SMB_BIG_INT)1000); - - if (timeout_ms < 1) { - timeout_ms = 1; - } - - DEBUG(10,("blocking_locks_timeout_ms: returning %u\n", timeout_ms)); - - return timeout_ms; + DEBUG(10,("received_unlock_msg\n")); + process_blocking_lock_queue(); } /**************************************************************************** @@ -620,158 +678,120 @@ unsigned int blocking_locks_timeout_ms(unsigned int default_timeout_ms) 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; /* * Go through the queue and see if we can get any of the locks. */ for (blr = blocking_lock_queue; blr; blr = next) { - connection_struct *conn = NULL; - uint16 vuid; - files_struct *fsp = NULL; next = blr->next; /* - * Ensure we don't have any old chain_fsp values - * sitting around.... + * Go through the remaining locks and try and obtain them. + * The call returns True if all locks were obtained successfully + * and False if we still need to wait. */ - chain_size = 0; - file_chain_reset(); - fsp = blr->fsp; - conn = conn_find(SVAL(blr->inbuf,smb_tid)); - vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : - SVAL(blr->inbuf,smb_uid); + DEBUG(10, ("Processing BLR = %p\n", blr)); - DEBUG(5,("process_blocking_lock_queue: examining pending lock fnum = %d for file %s\n", - fsp->fnum, fsp->fsp_name )); + /* We use set_current_service so connections with + * pending locks are not marked as idle. + */ - if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) { - struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp); + set_current_service(blr->fsp->conn, + SVAL(blr->req->inbuf,smb_flg), + false); - /* - * Lock expired - throw away all previously - * obtained locks and return lock error. - */ + if(blocking_lock_record_process(blr)) { + struct byte_range_lock *br_lck = brl_get_locks( + talloc_tos(), blr->fsp); - if (br_lck) { - DEBUG(5,("process_blocking_lock_queue: pending lock fnum = %d for file %s timed out.\n", - fsp->fnum, fsp->fsp_name )); + 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); } - blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); DLIST_REMOVE(blocking_lock_queue, blr); - free_blocking_lock_record(blr); + TALLOC_FREE(blr); continue; } - if(!change_to_user(conn,vuid)) { - struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp); - - /* - * Remove the entry and return an error to the client. - */ - - if (br_lck) { - brl_lock_cancel(br_lck, - blr->lock_pid, - procid_self(), - blr->offset, - blr->count, - blr->lock_flav); - TALLOC_FREE(br_lck); - } + /* + * We couldn't get the locks for this record on the list. + * If the time has expired, return a lock error. + */ - 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; - } + if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) { + struct byte_range_lock *br_lck = brl_get_locks( + talloc_tos(), blr->fsp); - if(!set_current_service(conn,SVAL(blr->inbuf,smb_flg),True)) { - struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp); + DEBUG(10, ("Lock timed out! BLR = %p\n", blr)); /* - * Remove the entry and return an error to the client. + * Lock expired - throw away all previously + * obtained locks and return lock error. */ if (br_lck) { - brl_lock_cancel(br_lck, - blr->lock_pid, - procid_self(), - blr->offset, - blr->count, - blr->lock_flav); - TALLOC_FREE(br_lck); - } - - 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; - } - - /* - * Go through the remaining locks and try and obtain them. - * The call returns True if all locks were obtained successfully - * and False if we still need to wait. - */ + DEBUG(5,("process_blocking_lock_queue: " + "pending lock fnum = %d for file %s " + "timed out.\n", blr->fsp->fnum, + fsp_str_dbg(blr->fsp))); - if(blocking_lock_record_process(blr)) { - struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp); - - 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); } + blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); DLIST_REMOVE(blocking_lock_queue, blr); - free_blocking_lock_record(blr); + TALLOC_FREE(blr); } - change_to_root_user(); } + + recalc_brl_timeout(); } /**************************************************************************** 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(int msg_type, struct process_id src, - void *buf, size_t len) +static void process_blocking_lock_cancel_message(struct messaging_context *ctx, + void *private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data) { NTSTATUS err; - const char *msg = (const char *)buf; - blocking_lock_record *blr; + const char *msg = (const char *)data->data; + struct blocking_lock_record *blr; - if (buf == NULL) { - smb_panic("process_blocking_lock_cancel_message: null msg\n"); + if (data->data == NULL) { + smb_panic("process_blocking_lock_cancel_message: null msg"); } - if (len != MSG_BLOCKING_LOCK_CANCEL_SIZE) { + if (data->length != 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"); + "Got invalid msg len %d\n", (int)data->length)); + smb_panic("process_blocking_lock_cancel_message: bad msg"); } memcpy(&blr, msg, sizeof(blr)); @@ -782,31 +802,32 @@ static void process_blocking_lock_cancel_message(int msg_type, struct process_id blocking_lock_reply_error(blr, err); DLIST_REMOVE(blocking_lock_cancelled_queue, blr); - free_blocking_lock_record(blr); + TALLOC_FREE(blr); } /**************************************************************************** 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, - SMB_BIG_UINT offset, - SMB_BIG_UINT count, + uint64_t offset, + uint64_t 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; + struct blocking_lock_record *blr; - if (!initialized) { + if (!blocking_lock_cancel_state) { /* Register our message. */ - message_register(MSG_SMB_BLOCKING_LOCK_CANCEL, - process_blocking_lock_cancel_message); + messaging_register(smbd_messaging_context(), NULL, + MSG_SMB_BLOCKING_LOCK_CANCEL, + process_blocking_lock_cancel_message); - initialized = True; + blocking_lock_cancel_state = True; } for (blr = blocking_lock_queue; blr; blr = blr->next) { @@ -820,14 +841,14 @@ BOOL blocking_lock_cancel(files_struct *fsp, } if (!blr) { - return False; + return NULL; } /* Check the flags are right. */ - if (blr->com_type == SMBlockingX && + if (blr->req->cmd == SMBlockingX && (locktype & LOCKING_ANDX_LARGE_FILES) != - (CVAL(blr->inbuf,smb_vwv3) & LOCKING_ANDX_LARGE_FILES)) { - return False; + (CVAL(blr->req->vwv+3, 0) & LOCKING_ANDX_LARGE_FILES)) { + return NULL; } /* Move to cancelled queue. */ @@ -838,9 +859,9 @@ BOOL blocking_lock_cancel(files_struct *fsp, memcpy(msg, &blr, sizeof(blr)); memcpy(&msg[sizeof(blr)], &err, sizeof(NTSTATUS)); - message_send_pid(pid_to_procid(sys_getpid()), - MSG_SMB_BLOCKING_LOCK_CANCEL, - &msg, sizeof(msg), True); + messaging_send_buf(smbd_messaging_context(), procid_self(), + MSG_SMB_BLOCKING_LOCK_CANCEL, + (uint8 *)&msg, sizeof(msg)); - return True; + return blr; }