source: vendor/3.6.23/source3/smbd/blocking.c

Last change on this file was 746, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated vendor to 3.6.9

File size: 27.0 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Blocking Locking functions
4 Copyright (C) Jeremy Allison 1998-2003
5
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.
10
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.
15
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/>.
18*/
19
20#include "includes.h"
21#include "smbd/smbd.h"
22#include "smbd/globals.h"
23#include "messages.h"
24
25#undef DBGC_CLASS
26#define DBGC_CLASS DBGC_LOCKING
27
28/****************************************************************************
29 Determine if this is a secondary element of a chained SMB.
30 **************************************************************************/
31
32static void received_unlock_msg(struct messaging_context *msg,
33 void *private_data,
34 uint32_t msg_type,
35 struct server_id server_id,
36 DATA_BLOB *data);
37
38void brl_timeout_fn(struct event_context *event_ctx,
39 struct timed_event *te,
40 struct timeval now,
41 void *private_data)
42{
43 struct smbd_server_connection *sconn = talloc_get_type_abort(
44 private_data, struct smbd_server_connection);
45
46 if (sconn->using_smb2) {
47 SMB_ASSERT(sconn->smb2.locks.brl_timeout == te);
48 TALLOC_FREE(sconn->smb2.locks.brl_timeout);
49 } else {
50 SMB_ASSERT(sconn->smb1.locks.brl_timeout == te);
51 TALLOC_FREE(sconn->smb1.locks.brl_timeout);
52 }
53
54 change_to_root_user(); /* TODO: Possibly run all timed events as
55 * root */
56
57 process_blocking_lock_queue(sconn);
58}
59
60/****************************************************************************
61 We need a version of timeval_min that treats zero timval as infinite.
62****************************************************************************/
63
64struct timeval timeval_brl_min(const struct timeval *tv1,
65 const struct timeval *tv2)
66{
67 if (timeval_is_zero(tv1)) {
68 return *tv2;
69 }
70 if (timeval_is_zero(tv2)) {
71 return *tv1;
72 }
73 return timeval_min(tv1, tv2);
74}
75
76/****************************************************************************
77 After a change to blocking_lock_queue, recalculate the timed_event for the
78 next processing.
79****************************************************************************/
80
81static bool recalc_brl_timeout(struct smbd_server_connection *sconn)
82{
83 struct blocking_lock_record *blr;
84 struct timeval next_timeout;
85 int max_brl_timeout = lp_parm_int(-1, "brl", "recalctime", 5);
86
87 TALLOC_FREE(sconn->smb1.locks.brl_timeout);
88
89 next_timeout = timeval_zero();
90
91 for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next) {
92 if (timeval_is_zero(&blr->expire_time)) {
93 /*
94 * If we're blocked on pid 0xFFFFFFFFFFFFFFFFLL this is
95 * a POSIX lock, so calculate a timeout of
96 * 10 seconds into the future.
97 */
98 if (blr->blocking_smblctx == 0xFFFFFFFFFFFFFFFFLL) {
99 struct timeval psx_to = timeval_current_ofs(10, 0);
100 next_timeout = timeval_brl_min(&next_timeout, &psx_to);
101 }
102
103 continue;
104 }
105
106 next_timeout = timeval_brl_min(&next_timeout, &blr->expire_time);
107 }
108
109 if (timeval_is_zero(&next_timeout)) {
110 DEBUG(10, ("Next timeout = Infinite.\n"));
111 return True;
112 }
113
114 /*
115 to account for unclean shutdowns by clients we need a
116 maximum timeout that we use for checking pending locks. If
117 we have any pending locks at all, then check if the pending
118 lock can continue at least every brl:recalctime seconds
119 (default 5 seconds).
120
121 This saves us needing to do a message_send_all() in the
122 SIGCHLD handler in the parent daemon. That
123 message_send_all() caused O(n^2) work to be done when IP
124 failovers happened in clustered Samba, which could make the
125 entire system unusable for many minutes.
126 */
127
128 if (max_brl_timeout > 0) {
129 struct timeval min_to = timeval_current_ofs(max_brl_timeout, 0);
130 next_timeout = timeval_min(&next_timeout, &min_to);
131 }
132
133 if (DEBUGLVL(10)) {
134 struct timeval cur, from_now;
135
136 cur = timeval_current();
137 from_now = timeval_until(&cur, &next_timeout);
138 DEBUG(10, ("Next timeout = %d.%d seconds from now.\n",
139 (int)from_now.tv_sec, (int)from_now.tv_usec));
140 }
141
142 sconn->smb1.locks.brl_timeout = event_add_timed(smbd_event_context(),
143 NULL, next_timeout,
144 brl_timeout_fn, sconn);
145 if (sconn->smb1.locks.brl_timeout == NULL) {
146 return False;
147 }
148
149 return True;
150}
151
152
153/****************************************************************************
154 Function to push a blocking lock request onto the lock queue.
155****************************************************************************/
156
157bool push_blocking_lock_request( struct byte_range_lock *br_lck,
158 struct smb_request *req,
159 files_struct *fsp,
160 int lock_timeout,
161 int lock_num,
162 uint64_t smblctx,
163 enum brl_type lock_type,
164 enum brl_flavour lock_flav,
165 uint64_t offset,
166 uint64_t count,
167 uint64_t blocking_smblctx)
168{
169 struct smbd_server_connection *sconn = req->sconn;
170 struct blocking_lock_record *blr;
171 NTSTATUS status;
172
173 if (req->smb2req) {
174 return push_blocking_lock_request_smb2(br_lck,
175 req,
176 fsp,
177 lock_timeout,
178 lock_num,
179 smblctx,
180 lock_type,
181 lock_flav,
182 offset,
183 count,
184 blocking_smblctx);
185 }
186
187 if(req_is_in_chain(req)) {
188 DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n"));
189 return False;
190 }
191
192 /*
193 * Now queue an entry on the blocking lock queue. We setup
194 * the expiration time here.
195 */
196
197 blr = talloc(NULL, struct blocking_lock_record);
198 if (blr == NULL) {
199 DEBUG(0,("push_blocking_lock_request: Malloc fail !\n" ));
200 return False;
201 }
202
203 blr->next = NULL;
204 blr->prev = NULL;
205
206 blr->fsp = fsp;
207 if (lock_timeout == -1) {
208 blr->expire_time.tv_sec = 0;
209 blr->expire_time.tv_usec = 0; /* Never expire. */
210 } else {
211 blr->expire_time = timeval_current_ofs(lock_timeout/1000,
212 (lock_timeout % 1000) * 1000);
213 }
214 blr->lock_num = lock_num;
215 blr->smblctx = smblctx;
216 blr->blocking_smblctx = blocking_smblctx;
217 blr->lock_flav = lock_flav;
218 blr->lock_type = lock_type;
219 blr->offset = offset;
220 blr->count = count;
221
222 /* Specific brl_lock() implementations can fill this in. */
223 blr->blr_private = NULL;
224
225 /* Add a pending lock record for this. */
226 status = brl_lock(req->sconn->msg_ctx,
227 br_lck,
228 smblctx,
229 sconn_server_id(req->sconn),
230 offset,
231 count,
232 lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
233 blr->lock_flav,
234 True,
235 NULL,
236 blr);
237
238 if (!NT_STATUS_IS_OK(status)) {
239 DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
240 TALLOC_FREE(blr);
241 return False;
242 }
243
244 SMB_PERFCOUNT_DEFER_OP(&req->pcd, &req->pcd);
245 blr->req = talloc_move(blr, &req);
246
247 DLIST_ADD_END(sconn->smb1.locks.blocking_lock_queue, blr, struct blocking_lock_record *);
248 recalc_brl_timeout(sconn);
249
250 /* Ensure we'll receive messages when this is unlocked. */
251 if (!sconn->smb1.locks.blocking_lock_unlock_state) {
252 messaging_register(sconn->msg_ctx, NULL,
253 MSG_SMB_UNLOCK, received_unlock_msg);
254 sconn->smb1.locks.blocking_lock_unlock_state = true;
255 }
256
257 DEBUG(3,("push_blocking_lock_request: lock request blocked with "
258 "expiry time (%u sec. %u usec) (+%d msec) for fnum = %d, name = %s\n",
259 (unsigned int)blr->expire_time.tv_sec,
260 (unsigned int)blr->expire_time.tv_usec, lock_timeout,
261 blr->fsp->fnum, fsp_str_dbg(blr->fsp)));
262
263 return True;
264}
265
266/****************************************************************************
267 Return a lockingX success SMB.
268*****************************************************************************/
269
270static void reply_lockingX_success(struct blocking_lock_record *blr)
271{
272 reply_outbuf(blr->req, 2, 0);
273
274 /*
275 * As this message is a lockingX call we must handle
276 * any following chained message correctly.
277 * This is normally handled in construct_reply(),
278 * but as that calls switch_message, we can't use
279 * that here and must set up the chain info manually.
280 */
281
282 chain_reply(blr->req);
283 TALLOC_FREE(blr->req->outbuf);
284}
285
286/****************************************************************************
287 Return a generic lock fail error blocking call.
288*****************************************************************************/
289
290static void generic_blocking_lock_error(struct blocking_lock_record *blr, NTSTATUS status)
291{
292 /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to
293 FILE_LOCK_CONFLICT! (tridge) */
294 if (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
295 status = NT_STATUS_FILE_LOCK_CONFLICT;
296 }
297
298 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
299 /* Store the last lock error. */
300 files_struct *fsp = blr->fsp;
301
302 if (fsp) {
303 fsp->last_lock_failure.context.smblctx = blr->smblctx;
304 fsp->last_lock_failure.context.tid = fsp->conn->cnum;
305 fsp->last_lock_failure.context.pid =
306 sconn_server_id(fsp->conn->sconn);
307 fsp->last_lock_failure.start = blr->offset;
308 fsp->last_lock_failure.size = blr->count;
309 fsp->last_lock_failure.fnum = fsp->fnum;
310 fsp->last_lock_failure.lock_type = READ_LOCK; /* Don't care. */
311 fsp->last_lock_failure.lock_flav = blr->lock_flav;
312 }
313 }
314
315 reply_nterror(blr->req, status);
316 if (!srv_send_smb(blr->req->sconn, (char *)blr->req->outbuf,
317 true, blr->req->seqnum+1,
318 blr->req->encrypted, NULL)) {
319 exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed.");
320 }
321 TALLOC_FREE(blr->req->outbuf);
322}
323
324/****************************************************************************
325 Return a lock fail error for a lockingX call. Undo all the locks we have
326 obtained first.
327*****************************************************************************/
328
329static void undo_locks_obtained(struct blocking_lock_record *blr)
330{
331 files_struct *fsp = blr->fsp;
332 uint16 num_ulocks = SVAL(blr->req->vwv+6, 0);
333 uint64_t count = (uint64_t)0, offset = (uint64_t) 0;
334 uint64_t smblctx;
335 unsigned char locktype = CVAL(blr->req->vwv+3, 0);
336 bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
337 uint8_t *data;
338 int i;
339
340 data = (uint8_t *)blr->req->buf
341 + ((large_file_format ? 20 : 10)*num_ulocks);
342
343 /*
344 * Data now points at the beginning of the list
345 * of smb_lkrng structs.
346 */
347
348 /*
349 * Ensure we don't do a remove on the lock that just failed,
350 * as under POSIX rules, if we have a lock already there, we
351 * will delete it (and we shouldn't) .....
352 */
353
354 for(i = blr->lock_num - 1; i >= 0; i--) {
355 bool err;
356
357 smblctx = get_lock_pid( data, i, large_file_format);
358 count = get_lock_count( data, i, large_file_format);
359 offset = get_lock_offset( data, i, large_file_format, &err);
360
361 /*
362 * We know err cannot be set as if it was the lock
363 * request would never have been queued. JRA.
364 */
365
366 do_unlock(fsp->conn->sconn->msg_ctx,
367 fsp,
368 smblctx,
369 count,
370 offset,
371 WINDOWS_LOCK);
372 }
373}
374
375/****************************************************************************
376 Return a lock fail error.
377*****************************************************************************/
378
379static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS status)
380{
381 DEBUG(10, ("Replying with error=%s. BLR = %p\n", nt_errstr(status), blr));
382
383 switch(blr->req->cmd) {
384 case SMBlockingX:
385 /*
386 * This code can be called during the rundown of a
387 * file after it was already closed. In that case,
388 * blr->fsp==NULL and we do not need to undo any
389 * locks, they are already gone.
390 */
391 if (blr->fsp != NULL) {
392 undo_locks_obtained(blr);
393 }
394 generic_blocking_lock_error(blr, status);
395 break;
396 case SMBtrans2:
397 case SMBtranss2:
398 reply_nterror(blr->req, status);
399
400 /*
401 * construct_reply_common has done us the favor to pre-fill
402 * the command field with SMBtranss2 which is wrong :-)
403 */
404 SCVAL(blr->req->outbuf,smb_com,SMBtrans2);
405
406 if (!srv_send_smb(blr->req->sconn,
407 (char *)blr->req->outbuf,
408 true, blr->req->seqnum+1,
409 IS_CONN_ENCRYPTED(blr->fsp->conn),
410 NULL)) {
411 exit_server_cleanly("blocking_lock_reply_error: "
412 "srv_send_smb failed.");
413 }
414 TALLOC_FREE(blr->req->outbuf);
415 break;
416 default:
417 DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n"));
418 exit_server("PANIC - unknown type on blocking lock queue");
419 }
420}
421
422/****************************************************************************
423 Attempt to finish off getting all pending blocking locks for a lockingX call.
424 Returns True if we want to be removed from the list.
425*****************************************************************************/
426
427static bool process_lockingX(struct blocking_lock_record *blr)
428{
429 unsigned char locktype = CVAL(blr->req->vwv+3, 0);
430 files_struct *fsp = blr->fsp;
431 uint16 num_ulocks = SVAL(blr->req->vwv+6, 0);
432 uint16 num_locks = SVAL(blr->req->vwv+7, 0);
433 uint64_t count = (uint64_t)0, offset = (uint64_t)0;
434 uint64_t smblctx;
435 bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
436 uint8_t *data;
437 NTSTATUS status = NT_STATUS_OK;
438
439 data = (uint8_t *)blr->req->buf
440 + ((large_file_format ? 20 : 10)*num_ulocks);
441
442 /*
443 * Data now points at the beginning of the list
444 * of smb_lkrng structs.
445 */
446
447 for(; blr->lock_num < num_locks; blr->lock_num++) {
448 struct byte_range_lock *br_lck = NULL;
449 bool err;
450
451 smblctx = get_lock_pid( data, blr->lock_num, large_file_format);
452 count = get_lock_count( data, blr->lock_num, large_file_format);
453 offset = get_lock_offset( data, blr->lock_num, large_file_format, &err);
454
455 /*
456 * We know err cannot be set as if it was the lock
457 * request would never have been queued. JRA.
458 */
459 errno = 0;
460 br_lck = do_lock(fsp->conn->sconn->msg_ctx,
461 fsp,
462 smblctx,
463 count,
464 offset,
465 ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
466 READ_LOCK : WRITE_LOCK),
467 WINDOWS_LOCK,
468 True,
469 &status,
470 &blr->blocking_smblctx,
471 blr);
472
473 TALLOC_FREE(br_lck);
474
475 if (NT_STATUS_IS_ERR(status)) {
476 break;
477 }
478 }
479
480 if(blr->lock_num == num_locks) {
481 /*
482 * Success - we got all the locks.
483 */
484
485 DEBUG(3,("process_lockingX file = %s, fnum=%d type=%d "
486 "num_locks=%d\n", fsp_str_dbg(fsp), fsp->fnum,
487 (unsigned int)locktype, num_locks));
488
489 reply_lockingX_success(blr);
490 return True;
491 }
492
493 if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
494 !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
495 /*
496 * We have other than a "can't get lock"
497 * error. Free any locks we had and return an error.
498 * Return True so we get dequeued.
499 */
500 blocking_lock_reply_error(blr, status);
501 return True;
502 }
503
504 /*
505 * Still can't get all the locks - keep waiting.
506 */
507
508 DEBUG(10,("process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \
509Waiting....\n",
510 blr->lock_num, num_locks, fsp_str_dbg(fsp), fsp->fnum));
511
512 return False;
513}
514
515/****************************************************************************
516 Attempt to get the posix lock request from a SMBtrans2 call.
517 Returns True if we want to be removed from the list.
518*****************************************************************************/
519
520static bool process_trans2(struct blocking_lock_record *blr)
521{
522 char params[2];
523 NTSTATUS status;
524 struct byte_range_lock *br_lck = do_lock(
525 blr->fsp->conn->sconn->msg_ctx,
526 blr->fsp,
527 blr->smblctx,
528 blr->count,
529 blr->offset,
530 blr->lock_type,
531 blr->lock_flav,
532 True,
533 &status,
534 &blr->blocking_smblctx,
535 blr);
536 TALLOC_FREE(br_lck);
537
538 if (!NT_STATUS_IS_OK(status)) {
539 if (ERROR_WAS_LOCK_DENIED(status)) {
540 /* Still can't get the lock, just keep waiting. */
541 return False;
542 }
543 /*
544 * We have other than a "can't get lock"
545 * error. Send an error and return True so we get dequeued.
546 */
547 blocking_lock_reply_error(blr, status);
548 return True;
549 }
550
551 /* We finally got the lock, return success. */
552
553 SSVAL(params,0,0);
554 /* Fake up max_data_bytes here - we know it fits. */
555 send_trans2_replies(blr->fsp->conn, blr->req, params, 2, NULL, 0, 0xffff);
556 return True;
557}
558
559
560/****************************************************************************
561 Process a blocking lock SMB.
562 Returns True if we want to be removed from the list.
563*****************************************************************************/
564
565static bool blocking_lock_record_process(struct blocking_lock_record *blr)
566{
567 switch(blr->req->cmd) {
568 case SMBlockingX:
569 return process_lockingX(blr);
570 case SMBtrans2:
571 case SMBtranss2:
572 return process_trans2(blr);
573 default:
574 DEBUG(0,("blocking_lock_record_process: PANIC - unknown type on blocking lock queue - exiting.!\n"));
575 exit_server("PANIC - unknown type on blocking lock queue");
576 }
577 return False; /* Keep compiler happy. */
578}
579
580/****************************************************************************
581 Cancel entries by fnum from the blocking lock pending queue.
582 Called when a file is closed.
583*****************************************************************************/
584
585void cancel_pending_lock_requests_by_fid(files_struct *fsp,
586 struct byte_range_lock *br_lck,
587 enum file_close_type close_type)
588{
589 struct smbd_server_connection *sconn = fsp->conn->sconn;
590 struct blocking_lock_record *blr, *blr_cancelled, *next = NULL;
591
592 if (sconn->using_smb2) {
593 cancel_pending_lock_requests_by_fid_smb2(fsp,
594 br_lck,
595 close_type);
596 return;
597 }
598
599 for(blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) {
600 unsigned char locktype = 0;
601
602 next = blr->next;
603 if (blr->fsp->fnum != fsp->fnum) {
604 continue;
605 }
606
607 if (blr->req->cmd == SMBlockingX) {
608 locktype = CVAL(blr->req->vwv+3, 0);
609 }
610
611 DEBUG(10, ("remove_pending_lock_requests_by_fid - removing "
612 "request type %d for file %s fnum = %d\n",
613 blr->req->cmd, fsp_str_dbg(fsp), fsp->fnum));
614
615 blr_cancelled = blocking_lock_cancel_smb1(fsp,
616 blr->smblctx,
617 blr->offset,
618 blr->count,
619 blr->lock_flav,
620 locktype,
621 NT_STATUS_RANGE_NOT_LOCKED);
622
623 SMB_ASSERT(blr_cancelled == blr);
624
625 brl_lock_cancel(br_lck,
626 blr->smblctx,
627 sconn_server_id(sconn),
628 blr->offset,
629 blr->count,
630 blr->lock_flav,
631 blr);
632
633 /* We're closing the file fsp here, so ensure
634 * we don't have a dangling pointer. */
635 blr->fsp = NULL;
636 }
637}
638
639/****************************************************************************
640 Delete entries by mid from the blocking lock pending queue. Always send reply.
641 Only called from the SMB1 cancel code.
642*****************************************************************************/
643
644void remove_pending_lock_requests_by_mid_smb1(
645 struct smbd_server_connection *sconn, uint64_t mid)
646{
647 struct blocking_lock_record *blr, *next = NULL;
648
649 for(blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) {
650 files_struct *fsp;
651 struct byte_range_lock *br_lck;
652
653 next = blr->next;
654
655 if (blr->req->mid != mid) {
656 continue;
657 }
658
659 fsp = blr->fsp;
660 br_lck = brl_get_locks(talloc_tos(), fsp);
661
662 if (br_lck) {
663 DEBUG(10, ("remove_pending_lock_requests_by_mid_smb1 - "
664 "removing request type %d for file %s fnum "
665 "= %d\n", blr->req->cmd, fsp_str_dbg(fsp),
666 fsp->fnum ));
667
668 brl_lock_cancel(br_lck,
669 blr->smblctx,
670 sconn_server_id(sconn),
671 blr->offset,
672 blr->count,
673 blr->lock_flav,
674 blr);
675 TALLOC_FREE(br_lck);
676 }
677
678 blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
679 DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
680 TALLOC_FREE(blr);
681 }
682}
683
684/****************************************************************************
685 Is this mid a blocking lock request on the queue ?
686 Currently only called from the SMB1 unix extensions POSIX lock code.
687*****************************************************************************/
688
689bool blocking_lock_was_deferred_smb1(
690 struct smbd_server_connection *sconn, uint64_t mid)
691{
692 struct blocking_lock_record *blr, *next = NULL;
693
694 for(blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) {
695 next = blr->next;
696 if(blr->req->mid == mid) {
697 return True;
698 }
699 }
700 return False;
701}
702
703/****************************************************************************
704 Set a flag as an unlock request affects one of our pending locks.
705*****************************************************************************/
706
707static void received_unlock_msg(struct messaging_context *msg,
708 void *private_data,
709 uint32_t msg_type,
710 struct server_id server_id,
711 DATA_BLOB *data)
712{
713 struct smbd_server_connection *sconn;
714
715 sconn = msg_ctx_to_sconn(msg);
716 if (sconn == NULL) {
717 DEBUG(1, ("could not find sconn\n"));
718 return;
719 }
720
721 DEBUG(10,("received_unlock_msg\n"));
722 process_blocking_lock_queue(sconn);
723}
724
725/****************************************************************************
726 Process the blocking lock queue. Note that this is only called as root.
727*****************************************************************************/
728
729void process_blocking_lock_queue(struct smbd_server_connection *sconn)
730{
731 struct timeval tv_curr = timeval_current();
732 struct blocking_lock_record *blr, *next = NULL;
733
734 if (sconn->using_smb2) {
735 process_blocking_lock_queue_smb2(sconn, tv_curr);
736 return;
737 }
738
739 /*
740 * Go through the queue and see if we can get any of the locks.
741 */
742
743 for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) {
744
745 next = blr->next;
746
747 /*
748 * Go through the remaining locks and try and obtain them.
749 * The call returns True if all locks were obtained successfully
750 * and False if we still need to wait.
751 */
752
753 DEBUG(10, ("Processing BLR = %p\n", blr));
754
755 /* We use set_current_service so connections with
756 * pending locks are not marked as idle.
757 */
758
759 set_current_service(blr->fsp->conn,
760 SVAL(blr->req->inbuf,smb_flg),
761 false);
762
763 if(blocking_lock_record_process(blr)) {
764 struct byte_range_lock *br_lck = brl_get_locks(
765 talloc_tos(), blr->fsp);
766
767 DEBUG(10, ("BLR_process returned true: cancelling and "
768 "removing lock. BLR = %p\n", blr));
769
770 if (br_lck) {
771 brl_lock_cancel(br_lck,
772 blr->smblctx,
773 sconn_server_id(sconn),
774 blr->offset,
775 blr->count,
776 blr->lock_flav,
777 blr);
778 TALLOC_FREE(br_lck);
779 }
780
781 DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
782 TALLOC_FREE(blr);
783 continue;
784 }
785
786 /*
787 * We couldn't get the locks for this record on the list.
788 * If the time has expired, return a lock error.
789 */
790
791 if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) {
792 struct byte_range_lock *br_lck = brl_get_locks(
793 talloc_tos(), blr->fsp);
794
795 DEBUG(10, ("Lock timed out! BLR = %p\n", blr));
796
797 /*
798 * Lock expired - throw away all previously
799 * obtained locks and return lock error.
800 */
801
802 if (br_lck) {
803 DEBUG(5,("process_blocking_lock_queue: "
804 "pending lock fnum = %d for file %s "
805 "timed out.\n", blr->fsp->fnum,
806 fsp_str_dbg(blr->fsp)));
807
808 brl_lock_cancel(br_lck,
809 blr->smblctx,
810 sconn_server_id(sconn),
811 blr->offset,
812 blr->count,
813 blr->lock_flav,
814 blr);
815 TALLOC_FREE(br_lck);
816 }
817
818 blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
819 DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
820 TALLOC_FREE(blr);
821 }
822 }
823
824 recalc_brl_timeout(sconn);
825}
826
827/****************************************************************************
828 Handle a cancel message. Lock already moved onto the cancel queue.
829*****************************************************************************/
830
831#define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(struct blocking_lock_record *) + sizeof(NTSTATUS))
832
833static void process_blocking_lock_cancel_message(struct messaging_context *ctx,
834 void *private_data,
835 uint32_t msg_type,
836 struct server_id server_id,
837 DATA_BLOB *data)
838{
839 struct smbd_server_connection *sconn;
840 NTSTATUS err;
841 const char *msg = (const char *)data->data;
842 struct blocking_lock_record *blr;
843
844 if (data->data == NULL) {
845 smb_panic("process_blocking_lock_cancel_message: null msg");
846 }
847
848 if (data->length != MSG_BLOCKING_LOCK_CANCEL_SIZE) {
849 DEBUG(0, ("process_blocking_lock_cancel_message: "
850 "Got invalid msg len %d\n", (int)data->length));
851 smb_panic("process_blocking_lock_cancel_message: bad msg");
852 }
853
854 sconn = msg_ctx_to_sconn(ctx);
855 if (sconn == NULL) {
856 DEBUG(1, ("could not find sconn\n"));
857 return;
858 }
859
860 memcpy(&blr, msg, sizeof(blr));
861 memcpy(&err, &msg[sizeof(blr)], sizeof(NTSTATUS));
862
863 DEBUG(10,("process_blocking_lock_cancel_message: returning error %s\n",
864 nt_errstr(err) ));
865
866 blocking_lock_reply_error(blr, err);
867 DLIST_REMOVE(sconn->smb1.locks.blocking_lock_cancelled_queue, blr);
868 TALLOC_FREE(blr);
869}
870
871/****************************************************************************
872 Send ourselves a blocking lock cancelled message. Handled asynchronously above.
873 Returns the blocking_lock_record that is being cancelled.
874 Only called from the SMB1 code.
875*****************************************************************************/
876
877struct blocking_lock_record *blocking_lock_cancel_smb1(files_struct *fsp,
878 uint64_t smblctx,
879 uint64_t offset,
880 uint64_t count,
881 enum brl_flavour lock_flav,
882 unsigned char locktype,
883 NTSTATUS err)
884{
885 struct smbd_server_connection *sconn = fsp->conn->sconn;
886 char msg[MSG_BLOCKING_LOCK_CANCEL_SIZE];
887 struct blocking_lock_record *blr;
888
889 if (!sconn->smb1.locks.blocking_lock_cancel_state) {
890 /* Register our message. */
891 messaging_register(sconn->msg_ctx, NULL,
892 MSG_SMB_BLOCKING_LOCK_CANCEL,
893 process_blocking_lock_cancel_message);
894
895 sconn->smb1.locks.blocking_lock_cancel_state = True;
896 }
897
898 for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next) {
899 if (fsp == blr->fsp &&
900 smblctx == blr->smblctx &&
901 offset == blr->offset &&
902 count == blr->count &&
903 lock_flav == blr->lock_flav) {
904 break;
905 }
906 }
907
908 if (!blr) {
909 return NULL;
910 }
911
912 /* Check the flags are right. */
913 if (blr->req->cmd == SMBlockingX &&
914 (locktype & LOCKING_ANDX_LARGE_FILES) !=
915 (CVAL(blr->req->vwv+3, 0) & LOCKING_ANDX_LARGE_FILES)) {
916 return NULL;
917 }
918
919 /* Move to cancelled queue. */
920 DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
921 DLIST_ADD(sconn->smb1.locks.blocking_lock_cancelled_queue, blr);
922
923 /* Create the message. */
924 memcpy(msg, &blr, sizeof(blr));
925 memcpy(&msg[sizeof(blr)], &err, sizeof(NTSTATUS));
926
927 messaging_send_buf(sconn->msg_ctx, sconn_server_id(sconn),
928 MSG_SMB_BLOCKING_LOCK_CANCEL,
929 (uint8 *)&msg, sizeof(msg));
930
931 return blr;
932}
Note: See TracBrowser for help on using the repository browser.