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