2 Unix SMB/CIFS implementation.
3 Blocking Locking functions
4 Copyright (C) Jeremy Allison 1998-2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "smbd/globals.h"
24 #define DBGC_CLASS DBGC_LOCKING
26 /****************************************************************************
27 Determine if this is a secondary element of a chained SMB.
28 **************************************************************************/
30 static void received_unlock_msg(struct messaging_context *msg,
33 struct server_id server_id,
36 void brl_timeout_fn(struct event_context *event_ctx,
37 struct timed_event *te,
41 struct smbd_server_connection *sconn = smbd_server_conn;
43 if (sconn->allow_smb2) {
44 SMB_ASSERT(sconn->smb2.locks.brl_timeout == te);
45 TALLOC_FREE(sconn->smb2.locks.brl_timeout);
47 SMB_ASSERT(sconn->smb1.locks.brl_timeout == te);
48 TALLOC_FREE(sconn->smb1.locks.brl_timeout);
51 change_to_root_user(); /* TODO: Possibly run all timed events as
54 process_blocking_lock_queue();
57 /****************************************************************************
58 We need a version of timeval_min that treats zero timval as infinite.
59 ****************************************************************************/
61 struct timeval timeval_brl_min(const struct timeval *tv1,
62 const struct timeval *tv2)
64 if (timeval_is_zero(tv1)) {
67 if (timeval_is_zero(tv2)) {
70 return timeval_min(tv1, tv2);
73 /****************************************************************************
74 After a change to blocking_lock_queue, recalculate the timed_event for the
76 ****************************************************************************/
78 static bool recalc_brl_timeout(void)
80 struct smbd_server_connection *sconn = smbd_server_conn;
81 struct blocking_lock_record *blr;
82 struct timeval next_timeout;
83 int max_brl_timeout = lp_parm_int(-1, "brl", "recalctime", 5);
85 TALLOC_FREE(sconn->smb1.locks.brl_timeout);
87 next_timeout = timeval_zero();
89 for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next) {
90 if (timeval_is_zero(&blr->expire_time)) {
92 * If we're blocked on pid 0xFFFFFFFF this is
93 * a POSIX lock, so calculate a timeout of
94 * 10 seconds into the future.
96 if (blr->blocking_pid == 0xFFFFFFFF) {
97 struct timeval psx_to = timeval_current_ofs(10, 0);
98 next_timeout = timeval_brl_min(&next_timeout, &psx_to);
104 next_timeout = timeval_brl_min(&next_timeout, &blr->expire_time);
107 if (timeval_is_zero(&next_timeout)) {
108 DEBUG(10, ("Next timeout = Infinite.\n"));
113 to account for unclean shutdowns by clients we need a
114 maximum timeout that we use for checking pending locks. If
115 we have any pending locks at all, then check if the pending
116 lock can continue at least every brl:recalctime seconds
119 This saves us needing to do a message_send_all() in the
120 SIGCHLD handler in the parent daemon. That
121 message_send_all() caused O(n^2) work to be done when IP
122 failovers happened in clustered Samba, which could make the
123 entire system unusable for many minutes.
126 if (max_brl_timeout > 0) {
127 struct timeval min_to = timeval_current_ofs(max_brl_timeout, 0);
128 next_timeout = timeval_min(&next_timeout, &min_to);
132 struct timeval cur, from_now;
134 cur = timeval_current();
135 from_now = timeval_until(&cur, &next_timeout);
136 DEBUG(10, ("Next timeout = %d.%d seconds from now.\n",
137 (int)from_now.tv_sec, (int)from_now.tv_usec));
140 if (!(sconn->smb1.locks.brl_timeout = event_add_timed(smbd_event_context(), NULL,
142 brl_timeout_fn, NULL))) {
150 /****************************************************************************
151 Function to push a blocking lock request onto the lock queue.
152 ****************************************************************************/
154 bool push_blocking_lock_request( struct byte_range_lock *br_lck,
155 struct smb_request *req,
160 enum brl_type lock_type,
161 enum brl_flavour lock_flav,
164 uint32_t blocking_pid)
166 struct smbd_server_connection *sconn = smbd_server_conn;
167 struct blocking_lock_record *blr;
171 return push_blocking_lock_request_smb2(br_lck,
184 if(req_is_in_chain(req)) {
185 DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n"));
190 * Now queue an entry on the blocking lock queue. We setup
191 * the expiration time here.
194 blr = talloc(NULL, struct blocking_lock_record);
196 DEBUG(0,("push_blocking_lock_request: Malloc fail !\n" ));
204 if (lock_timeout == -1) {
205 blr->expire_time.tv_sec = 0;
206 blr->expire_time.tv_usec = 0; /* Never expire. */
208 blr->expire_time = timeval_current_ofs(lock_timeout/1000,
209 (lock_timeout % 1000) * 1000);
211 blr->lock_num = lock_num;
212 blr->lock_pid = lock_pid;
213 blr->blocking_pid = blocking_pid;
214 blr->lock_flav = lock_flav;
215 blr->lock_type = lock_type;
216 blr->offset = offset;
219 /* Specific brl_lock() implementations can fill this in. */
220 blr->blr_private = NULL;
222 /* Add a pending lock record for this. */
223 status = brl_lock(smbd_messaging_context(),
229 lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
235 if (!NT_STATUS_IS_OK(status)) {
236 DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
241 SMB_PERFCOUNT_DEFER_OP(&req->pcd, &req->pcd);
242 blr->req = talloc_move(blr, &req);
244 DLIST_ADD_END(sconn->smb1.locks.blocking_lock_queue, blr, struct blocking_lock_record *);
245 recalc_brl_timeout();
247 /* Ensure we'll receive messages when this is unlocked. */
248 if (!sconn->smb1.locks.blocking_lock_unlock_state) {
249 messaging_register(smbd_messaging_context(), NULL,
250 MSG_SMB_UNLOCK, received_unlock_msg);
251 sconn->smb1.locks.blocking_lock_unlock_state = true;
254 DEBUG(3,("push_blocking_lock_request: lock request blocked with "
255 "expiry time (%u sec. %u usec) (+%d msec) for fnum = %d, name = %s\n",
256 (unsigned int)blr->expire_time.tv_sec,
257 (unsigned int)blr->expire_time.tv_usec, lock_timeout,
258 blr->fsp->fnum, fsp_str_dbg(blr->fsp)));
263 /****************************************************************************
264 Return a lockingX success SMB.
265 *****************************************************************************/
267 static void reply_lockingX_success(struct blocking_lock_record *blr)
269 reply_outbuf(blr->req, 2, 0);
272 * As this message is a lockingX call we must handle
273 * any following chained message correctly.
274 * This is normally handled in construct_reply(),
275 * but as that calls switch_message, we can't use
276 * that here and must set up the chain info manually.
279 chain_reply(blr->req);
280 TALLOC_FREE(blr->req->outbuf);
283 /****************************************************************************
284 Return a generic lock fail error blocking call.
285 *****************************************************************************/
287 static void generic_blocking_lock_error(struct blocking_lock_record *blr, NTSTATUS status)
289 /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to
290 FILE_LOCK_CONFLICT! (tridge) */
291 if (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
292 status = NT_STATUS_FILE_LOCK_CONFLICT;
295 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
296 /* Store the last lock error. */
297 files_struct *fsp = blr->fsp;
300 fsp->last_lock_failure.context.smbpid = blr->lock_pid;
301 fsp->last_lock_failure.context.tid = fsp->conn->cnum;
302 fsp->last_lock_failure.context.pid = procid_self();
303 fsp->last_lock_failure.start = blr->offset;
304 fsp->last_lock_failure.size = blr->count;
305 fsp->last_lock_failure.fnum = fsp->fnum;
306 fsp->last_lock_failure.lock_type = READ_LOCK; /* Don't care. */
307 fsp->last_lock_failure.lock_flav = blr->lock_flav;
311 reply_nterror(blr->req, status);
312 if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf,
313 true, blr->req->seqnum+1,
314 blr->req->encrypted, NULL)) {
315 exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed.");
317 TALLOC_FREE(blr->req->outbuf);
320 /****************************************************************************
321 Return a lock fail error for a lockingX call. Undo all the locks we have
323 *****************************************************************************/
325 static void reply_lockingX_error(struct blocking_lock_record *blr, NTSTATUS status)
327 files_struct *fsp = blr->fsp;
328 uint16 num_ulocks = SVAL(blr->req->vwv+6, 0);
329 uint64_t count = (uint64_t)0, offset = (uint64_t) 0;
331 unsigned char locktype = CVAL(blr->req->vwv+3, 0);
332 bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
336 data = (uint8_t *)blr->req->buf
337 + ((large_file_format ? 20 : 10)*num_ulocks);
340 * Data now points at the beginning of the list
341 * of smb_lkrng structs.
345 * Ensure we don't do a remove on the lock that just failed,
346 * as under POSIX rules, if we have a lock already there, we
347 * will delete it (and we shouldn't) .....
350 for(i = blr->lock_num - 1; i >= 0; i--) {
353 lock_pid = get_lock_pid( data, i, large_file_format);
354 count = get_lock_count( data, i, large_file_format);
355 offset = get_lock_offset( data, i, large_file_format, &err);
358 * We know err cannot be set as if it was the lock
359 * request would never have been queued. JRA.
362 do_unlock(smbd_messaging_context(),
370 generic_blocking_lock_error(blr, status);
373 /****************************************************************************
374 Return a lock fail error.
375 *****************************************************************************/
377 static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS status)
379 DEBUG(10, ("Replying with error=%s. BLR = %p\n", nt_errstr(status), blr));
381 switch(blr->req->cmd) {
383 reply_lockingX_error(blr, status);
387 reply_nterror(blr->req, status);
390 * construct_reply_common has done us the favor to pre-fill
391 * the command field with SMBtranss2 which is wrong :-)
393 SCVAL(blr->req->outbuf,smb_com,SMBtrans2);
395 if (!srv_send_smb(smbd_server_fd(),
396 (char *)blr->req->outbuf,
397 true, blr->req->seqnum+1,
398 IS_CONN_ENCRYPTED(blr->fsp->conn),
400 exit_server_cleanly("blocking_lock_reply_error: "
401 "srv_send_smb failed.");
403 TALLOC_FREE(blr->req->outbuf);
406 DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n"));
407 exit_server("PANIC - unknown type on blocking lock queue");
411 /****************************************************************************
412 Attempt to finish off getting all pending blocking locks for a lockingX call.
413 Returns True if we want to be removed from the list.
414 *****************************************************************************/
416 static bool process_lockingX(struct blocking_lock_record *blr)
418 unsigned char locktype = CVAL(blr->req->vwv+3, 0);
419 files_struct *fsp = blr->fsp;
420 uint16 num_ulocks = SVAL(blr->req->vwv+6, 0);
421 uint16 num_locks = SVAL(blr->req->vwv+7, 0);
422 uint64_t count = (uint64_t)0, offset = (uint64_t)0;
424 bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
426 NTSTATUS status = NT_STATUS_OK;
428 data = (uint8_t *)blr->req->buf
429 + ((large_file_format ? 20 : 10)*num_ulocks);
432 * Data now points at the beginning of the list
433 * of smb_lkrng structs.
436 for(; blr->lock_num < num_locks; blr->lock_num++) {
437 struct byte_range_lock *br_lck = NULL;
440 lock_pid = get_lock_pid( data, blr->lock_num, large_file_format);
441 count = get_lock_count( data, blr->lock_num, large_file_format);
442 offset = get_lock_offset( data, blr->lock_num, large_file_format, &err);
445 * We know err cannot be set as if it was the lock
446 * request would never have been queued. JRA.
449 br_lck = do_lock(smbd_messaging_context(),
454 ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
455 READ_LOCK : WRITE_LOCK),
464 if (NT_STATUS_IS_ERR(status)) {
469 if(blr->lock_num == num_locks) {
471 * Success - we got all the locks.
474 DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d "
475 "num_locks=%d\n", fsp_str_dbg(fsp), fsp->fnum,
476 (unsigned int)locktype, num_locks));
478 reply_lockingX_success(blr);
482 if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
483 !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
485 * We have other than a "can't get lock"
486 * error. Free any locks we had and return an error.
487 * Return True so we get dequeued.
489 blocking_lock_reply_error(blr, status);
494 * Still can't get all the locks - keep waiting.
497 DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \
499 blr->lock_num, num_locks, fsp_str_dbg(fsp), fsp->fnum));
504 /****************************************************************************
505 Attempt to get the posix lock request from a SMBtrans2 call.
506 Returns True if we want to be removed from the list.
507 *****************************************************************************/
509 static bool process_trans2(struct blocking_lock_record *blr)
513 struct byte_range_lock *br_lck = do_lock(smbd_messaging_context(),
526 if (!NT_STATUS_IS_OK(status)) {
527 if (ERROR_WAS_LOCK_DENIED(status)) {
528 /* Still can't get the lock, just keep waiting. */
532 * We have other than a "can't get lock"
533 * error. Send an error and return True so we get dequeued.
535 blocking_lock_reply_error(blr, status);
539 /* We finally got the lock, return success. */
542 /* Fake up max_data_bytes here - we know it fits. */
543 send_trans2_replies(blr->fsp->conn, blr->req, params, 2, NULL, 0, 0xffff);
548 /****************************************************************************
549 Process a blocking lock SMB.
550 Returns True if we want to be removed from the list.
551 *****************************************************************************/
553 static bool blocking_lock_record_process(struct blocking_lock_record *blr)
555 switch(blr->req->cmd) {
557 return process_lockingX(blr);
560 return process_trans2(blr);
562 DEBUG(0,("blocking_lock_record_process: PANIC - unknown type on blocking lock queue - exiting.!\n"));
563 exit_server("PANIC - unknown type on blocking lock queue");
565 return False; /* Keep compiler happy. */
568 /****************************************************************************
569 Cancel entries by fnum from the blocking lock pending queue.
570 Called when a file is closed.
571 *****************************************************************************/
573 void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
575 struct smbd_server_connection *sconn = smbd_server_conn;
576 struct blocking_lock_record *blr, *blr_cancelled, *next = NULL;
578 if (sconn->allow_smb2) {
579 cancel_pending_lock_requests_by_fid_smb2(fsp, br_lck);
583 for(blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) {
584 unsigned char locktype = 0;
587 if (blr->fsp->fnum != fsp->fnum) {
591 if (blr->req->cmd == SMBlockingX) {
592 locktype = CVAL(blr->req->vwv+3, 0);
595 DEBUG(10, ("remove_pending_lock_requests_by_fid - removing "
596 "request type %d for file %s fnum = %d\n",
597 blr->req->cmd, fsp_str_dbg(fsp), fsp->fnum));
599 blr_cancelled = blocking_lock_cancel_smb1(fsp,
605 NT_STATUS_RANGE_NOT_LOCKED);
607 SMB_ASSERT(blr_cancelled == blr);
609 brl_lock_cancel(br_lck,
617 /* We're closing the file fsp here, so ensure
618 * we don't have a dangling pointer. */
623 /****************************************************************************
624 Delete entries by mid from the blocking lock pending queue. Always send reply.
625 Only called from the SMB1 cancel code.
626 *****************************************************************************/
628 void remove_pending_lock_requests_by_mid_smb1(uint64_t mid)
630 struct smbd_server_connection *sconn = smbd_server_conn;
631 struct blocking_lock_record *blr, *next = NULL;
633 for(blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) {
635 struct byte_range_lock *br_lck;
639 if (blr->req->mid != mid) {
644 br_lck = brl_get_locks(talloc_tos(), fsp);
647 DEBUG(10, ("remove_pending_lock_requests_by_mid_smb1 - "
648 "removing request type %d for file %s fnum "
649 "= %d\n", blr->req->cmd, fsp_str_dbg(fsp),
652 brl_lock_cancel(br_lck,
662 blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
663 DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
668 /****************************************************************************
669 Is this mid a blocking lock request on the queue ?
670 Currently only called from the SMB1 unix extensions POSIX lock code.
671 *****************************************************************************/
673 bool blocking_lock_was_deferred_smb1(uint64_t mid)
675 struct smbd_server_connection *sconn = smbd_server_conn;
676 struct blocking_lock_record *blr, *next = NULL;
678 for(blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) {
680 if(blr->req->mid == mid) {
687 /****************************************************************************
688 Set a flag as an unlock request affects one of our pending locks.
689 *****************************************************************************/
691 static void received_unlock_msg(struct messaging_context *msg,
694 struct server_id server_id,
697 DEBUG(10,("received_unlock_msg\n"));
698 process_blocking_lock_queue();
701 /****************************************************************************
702 Process the blocking lock queue. Note that this is only called as root.
703 *****************************************************************************/
705 void process_blocking_lock_queue(void)
707 struct smbd_server_connection *sconn = smbd_server_conn;
708 struct timeval tv_curr;
709 struct blocking_lock_record *blr, *next = NULL;
711 if (sconn->allow_smb2) {
712 process_blocking_lock_queue_smb2();
716 tv_curr = timeval_current();
718 * Go through the queue and see if we can get any of the locks.
721 for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) {
726 * Go through the remaining locks and try and obtain them.
727 * The call returns True if all locks were obtained successfully
728 * and False if we still need to wait.
731 DEBUG(10, ("Processing BLR = %p\n", blr));
733 /* We use set_current_service so connections with
734 * pending locks are not marked as idle.
737 set_current_service(blr->fsp->conn,
738 SVAL(blr->req->inbuf,smb_flg),
741 if(blocking_lock_record_process(blr)) {
742 struct byte_range_lock *br_lck = brl_get_locks(
743 talloc_tos(), blr->fsp);
745 DEBUG(10, ("BLR_process returned true: cancelling and "
746 "removing lock. BLR = %p\n", blr));
749 brl_lock_cancel(br_lck,
759 DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
765 * We couldn't get the locks for this record on the list.
766 * If the time has expired, return a lock error.
769 if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) {
770 struct byte_range_lock *br_lck = brl_get_locks(
771 talloc_tos(), blr->fsp);
773 DEBUG(10, ("Lock timed out! BLR = %p\n", blr));
776 * Lock expired - throw away all previously
777 * obtained locks and return lock error.
781 DEBUG(5,("process_blocking_lock_queue: "
782 "pending lock fnum = %d for file %s "
783 "timed out.\n", blr->fsp->fnum,
784 fsp_str_dbg(blr->fsp)));
786 brl_lock_cancel(br_lck,
796 blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
797 DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
802 recalc_brl_timeout();
805 /****************************************************************************
806 Handle a cancel message. Lock already moved onto the cancel queue.
807 *****************************************************************************/
809 #define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(struct blocking_lock_record *) + sizeof(NTSTATUS))
811 static void process_blocking_lock_cancel_message(struct messaging_context *ctx,
814 struct server_id server_id,
817 struct smbd_server_connection *sconn = smbd_server_conn;
819 const char *msg = (const char *)data->data;
820 struct blocking_lock_record *blr;
822 if (data->data == NULL) {
823 smb_panic("process_blocking_lock_cancel_message: null msg");
826 if (data->length != MSG_BLOCKING_LOCK_CANCEL_SIZE) {
827 DEBUG(0, ("process_blocking_lock_cancel_message: "
828 "Got invalid msg len %d\n", (int)data->length));
829 smb_panic("process_blocking_lock_cancel_message: bad msg");
832 memcpy(&blr, msg, sizeof(blr));
833 memcpy(&err, &msg[sizeof(blr)], sizeof(NTSTATUS));
835 DEBUG(10,("process_blocking_lock_cancel_message: returning error %s\n",
838 blocking_lock_reply_error(blr, err);
839 DLIST_REMOVE(sconn->smb1.locks.blocking_lock_cancelled_queue, blr);
843 /****************************************************************************
844 Send ourselves a blocking lock cancelled message. Handled asynchronously above.
845 Returns the blocking_lock_record that is being cancelled.
846 Only called from the SMB1 code.
847 *****************************************************************************/
849 struct blocking_lock_record *blocking_lock_cancel_smb1(files_struct *fsp,
853 enum brl_flavour lock_flav,
854 unsigned char locktype,
857 struct smbd_server_connection *sconn = smbd_server_conn;
858 char msg[MSG_BLOCKING_LOCK_CANCEL_SIZE];
859 struct blocking_lock_record *blr;
861 if (!sconn->smb1.locks.blocking_lock_cancel_state) {
862 /* Register our message. */
863 messaging_register(smbd_messaging_context(), NULL,
864 MSG_SMB_BLOCKING_LOCK_CANCEL,
865 process_blocking_lock_cancel_message);
867 sconn->smb1.locks.blocking_lock_cancel_state = True;
870 for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next) {
871 if (fsp == blr->fsp &&
872 lock_pid == blr->lock_pid &&
873 offset == blr->offset &&
874 count == blr->count &&
875 lock_flav == blr->lock_flav) {
884 /* Check the flags are right. */
885 if (blr->req->cmd == SMBlockingX &&
886 (locktype & LOCKING_ANDX_LARGE_FILES) !=
887 (CVAL(blr->req->vwv+3, 0) & LOCKING_ANDX_LARGE_FILES)) {
891 /* Move to cancelled queue. */
892 DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
893 DLIST_ADD(sconn->smb1.locks.blocking_lock_cancelled_queue, blr);
895 /* Create the message. */
896 memcpy(msg, &blr, sizeof(blr));
897 memcpy(&msg[sizeof(blr)], &err, sizeof(NTSTATUS));
899 messaging_send_buf(smbd_messaging_context(), procid_self(),
900 MSG_SMB_BLOCKING_LOCK_CANCEL,
901 (uint8 *)&msg, sizeof(msg));