r15613: the snum doesn't identify the tcon, but the brl_context pointer does
[kai/samba.git] / source4 / ntvfs / common / brlock.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    generic byte range locking code
5
6    Copyright (C) Andrew Tridgell 1992-2004
7    Copyright (C) Jeremy Allison 1992-2000
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 /* This module implements a tdb based byte range locking service,
25    replacing the fcntl() based byte range locking previously
26    used. This allows us to provide the same semantics as NT */
27
28 #include "includes.h"
29 #include "system/filesys.h"
30 #include "lib/tdb/include/tdb.h"
31 #include "messaging/messaging.h"
32 #include "db_wrap.h"
33 #include "lib/messaging/irpc.h"
34 #include "libcli/libcli.h"
35
36 /*
37   in this module a "DATA_BLOB *file_key" is a blob that uniquely identifies
38   a file. For a local posix filesystem this will usually be a combination
39   of the device and inode numbers of the file, but it can be anything 
40   that uniquely idetifies a file for locking purposes, as long
41   as it is applied consistently.
42 */
43
44 struct brl_context;
45 /*
46   the lock context contains the elements that define whether one
47   lock is the same as another lock
48 */
49 struct lock_context {
50         uint32_t server;
51         uint16_t smbpid;
52         struct brl_context *ctx;
53 };
54
55 /* The data in brlock records is an unsorted linear array of these
56    records.  It is unnecessary to store the count as tdb provides the
57    size of the record */
58 struct lock_struct {
59         struct lock_context context;
60         uint64_t start;
61         uint64_t size;
62         uint16_t fnum;
63         enum brl_type lock_type;
64         void *notify_ptr;
65 };
66
67 struct brl_context {
68         struct tdb_wrap *w;
69         uint32_t server;
70         struct messaging_context *messaging_ctx;
71         struct lock_struct last_lock;
72 };
73
74
75 /*
76   Open up the brlock.tdb database. Close it down using
77   talloc_free(). We need the messaging_ctx to allow for
78   pending lock notifications.
79 */
80 struct brl_context *brl_init(TALLOC_CTX *mem_ctx, uint32_t server, 
81                              struct messaging_context *messaging_ctx)
82 {
83         char *path;
84         struct brl_context *brl;
85
86         brl = talloc(mem_ctx, struct brl_context);
87         if (brl == NULL) {
88                 return NULL;
89         }
90
91         path = smbd_tmp_path(brl, "brlock.tdb");
92         brl->w = tdb_wrap_open(brl, path, 0,  
93                                TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
94         talloc_free(path);
95         if (brl->w == NULL) {
96                 talloc_free(brl);
97                 return NULL;
98         }
99
100         brl->server = server;
101         brl->messaging_ctx = messaging_ctx;
102         ZERO_STRUCT(brl->last_lock);
103
104         return brl;
105 }
106
107
108 /*
109   see if two locking contexts are equal
110 */
111 static BOOL brl_same_context(struct lock_context *ctx1, struct lock_context *ctx2)
112 {
113         return (ctx1->server == ctx2->server &&
114                 ctx1->smbpid == ctx2->smbpid &&
115                 ctx1->ctx == ctx2->ctx);
116 }
117
118 /*
119   see if lck1 and lck2 overlap
120 */
121 static BOOL brl_overlap(struct lock_struct *lck1, 
122                         struct lock_struct *lck2)
123 {
124         /* this extra check is not redundent - it copes with locks
125            that go beyond the end of 64 bit file space */
126         if (lck1->size != 0 &&
127             lck1->start == lck2->start &&
128             lck1->size == lck2->size) {
129                 return True;
130         }
131             
132         if (lck1->start >= (lck2->start+lck2->size) ||
133             lck2->start >= (lck1->start+lck1->size)) {
134                 return False;
135         }
136         return True;
137
138
139 /*
140  See if lock2 can be added when lock1 is in place.
141 */
142 static BOOL brl_conflict(struct lock_struct *lck1, 
143                          struct lock_struct *lck2)
144 {
145         /* pending locks don't conflict with anything */
146         if (lck1->lock_type >= PENDING_READ_LOCK ||
147             lck2->lock_type >= PENDING_READ_LOCK) {
148                 return False;
149         }
150
151         if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
152                 return False;
153         }
154
155         if (brl_same_context(&lck1->context, &lck2->context) &&
156             lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
157                 return False;
158         }
159
160         return brl_overlap(lck1, lck2);
161
162
163
164 /*
165  Check to see if this lock conflicts, but ignore our own locks on the
166  same fnum only.
167 */
168 static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
169 {
170         /* pending locks don't conflict with anything */
171         if (lck1->lock_type >= PENDING_READ_LOCK ||
172             lck2->lock_type >= PENDING_READ_LOCK) {
173                 return False;
174         }
175
176         if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) 
177                 return False;
178
179         /*
180          * note that incoming write calls conflict with existing READ
181          * locks even if the context is the same. JRA. See LOCKTEST7
182          * in smbtorture.
183          */
184         if (brl_same_context(&lck1->context, &lck2->context) &&
185             lck1->fnum == lck2->fnum &&
186             (lck2->lock_type == READ_LOCK || lck1->lock_type == WRITE_LOCK)) {
187                 return False;
188         }
189
190         return brl_overlap(lck1, lck2);
191
192
193
194 /*
195   amazingly enough, w2k3 "remembers" whether the last lock failure
196   is the same as this one and changes its error code. I wonder if any
197   app depends on this?
198 */
199 static NTSTATUS brl_lock_failed(struct brl_context *brl, struct lock_struct *lock)
200 {
201         if (lock->context.server == brl->last_lock.context.server &&
202             lock->context.ctx == brl->last_lock.context.ctx &&
203             lock->fnum == brl->last_lock.fnum &&
204             lock->start == brl->last_lock.start &&
205             lock->size == brl->last_lock.size) {
206                 return NT_STATUS_FILE_LOCK_CONFLICT;
207         }
208         brl->last_lock = *lock;
209         if (lock->start >= 0xEF000000 && 
210             (lock->start >> 63) == 0) {
211                 /* amazing the little things you learn with a test
212                    suite. Locks beyond this offset (as a 64 bit
213                    number!) always generate the conflict error code,
214                    unless the top bit is set */
215                 return NT_STATUS_FILE_LOCK_CONFLICT;
216         }
217         return NT_STATUS_LOCK_NOT_GRANTED;
218 }
219
220 /*
221   Lock a range of bytes.  The lock_type can be a PENDING_*_LOCK, in
222   which case a real lock is first tried, and if that fails then a
223   pending lock is created. When the pending lock is triggered (by
224   someone else closing an overlapping lock range) a messaging
225   notification is sent, identified by the notify_ptr
226 */
227 NTSTATUS brl_lock(struct brl_context *brl,
228                   DATA_BLOB *file_key, 
229                   uint16_t smbpid,
230                   uint16_t fnum, 
231                   uint64_t start, uint64_t size, 
232                   enum brl_type lock_type,
233                   void *notify_ptr)
234 {
235         TDB_DATA kbuf, dbuf;
236         int count=0, i;
237         struct lock_struct lock, *locks=NULL;
238         NTSTATUS status;
239
240         kbuf.dptr = file_key->data;
241         kbuf.dsize = file_key->length;
242
243         if (tdb_chainlock(brl->w->tdb, kbuf) != 0) {
244                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
245         }
246
247         /* if this is a pending lock, then with the chainlock held we
248            try to get the real lock. If we succeed then we don't need
249            to make it pending. This prevents a possible race condition
250            where the pending lock gets created after the lock that is
251            preventing the real lock gets removed */
252         if (lock_type >= PENDING_READ_LOCK) {
253                 enum brl_type rw = (lock_type==PENDING_READ_LOCK? READ_LOCK : WRITE_LOCK);
254                 status = brl_lock(brl, file_key, smbpid, fnum, start, size, rw, NULL);
255                 if (NT_STATUS_IS_OK(status)) {
256                         tdb_chainunlock(brl->w->tdb, kbuf);
257                         return NT_STATUS_OK;
258                 }
259         }
260
261         dbuf = tdb_fetch(brl->w->tdb, kbuf);
262
263         lock.context.smbpid = smbpid;
264         lock.context.server = brl->server;
265         lock.context.ctx = brl;
266         lock.start = start;
267         lock.size = size;
268         lock.fnum = fnum;
269         lock.lock_type = lock_type;
270         lock.notify_ptr = notify_ptr;
271
272         if (dbuf.dptr) {
273                 /* there are existing locks - make sure they don't conflict */
274                 locks = (struct lock_struct *)dbuf.dptr;
275                 count = dbuf.dsize / sizeof(*locks);
276                 for (i=0; i<count; i++) {
277                         if (brl_conflict(&locks[i], &lock)) {
278                                 status = brl_lock_failed(brl, &lock);
279                                 goto fail;
280                         }
281                 }
282         }
283
284         /* no conflicts - add it to the list of locks */
285         locks = realloc_p(locks, struct lock_struct, count+1);
286         if (!locks) {
287                 status = NT_STATUS_NO_MEMORY;
288                 goto fail;
289         } else {
290                 dbuf.dptr = (uint8_t *)locks;
291         }
292         locks[count] = lock;
293         dbuf.dsize += sizeof(lock);
294
295         if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
296                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
297                 goto fail;
298         }
299
300         free(dbuf.dptr);
301         tdb_chainunlock(brl->w->tdb, kbuf);
302
303         /* the caller needs to know if the real lock was granted. If
304            we have reached here then it must be a pending lock that
305            was granted, so tell them the lock failed */
306         if (lock_type >= PENDING_READ_LOCK) {
307                 return brl_lock_failed(brl, &lock);
308         }
309
310         return NT_STATUS_OK;
311
312  fail:
313
314         free(dbuf.dptr);
315         tdb_chainunlock(brl->w->tdb, kbuf);
316         return status;
317 }
318
319
320 /*
321   we are removing a lock that might be holding up a pending lock. Scan for pending
322   locks that cover this range and if we find any then notify the server that it should
323   retry the lock
324 */
325 static void brl_notify_unlock(struct brl_context *brl,
326                               struct lock_struct *locks, int count, 
327                               struct lock_struct *removed_lock)
328 {
329         int i, last_notice;
330
331         /* the last_notice logic is to prevent stampeding on a lock
332            range. It prevents us sending hundreds of notifies on the
333            same range of bytes. It doesn't prevent all possible
334            stampedes, but it does prevent the most common problem */
335         last_notice = -1;
336
337         for (i=0;i<count;i++) {
338                 if (locks[i].lock_type >= PENDING_READ_LOCK &&
339                     brl_overlap(&locks[i], removed_lock)) {
340                         if (last_notice != -1 && brl_overlap(&locks[i], &locks[last_notice])) {
341                                 continue;
342                         }
343                         if (locks[i].lock_type == PENDING_WRITE_LOCK) {
344                                 last_notice = i;
345                         }
346                         messaging_send_ptr(brl->messaging_ctx, locks[i].context.server, 
347                                            MSG_BRL_RETRY, locks[i].notify_ptr);
348                 }
349         }
350 }
351
352
353 /*
354   send notifications for all pending locks - the file is being closed by this
355   user
356 */
357 static void brl_notify_all(struct brl_context *brl,
358                            struct lock_struct *locks, int count)
359 {
360         int i;
361         for (i=0;i<count;i++) {
362                 if (locks->lock_type >= PENDING_READ_LOCK) {
363                         brl_notify_unlock(brl, locks, count, &locks[i]);
364                 }
365         }
366 }
367
368
369
370 /*
371  Unlock a range of bytes.
372 */
373 NTSTATUS brl_unlock(struct brl_context *brl,
374                     DATA_BLOB *file_key, 
375                     uint16_t smbpid,
376                     uint16_t fnum,
377                     uint64_t start, uint64_t size)
378 {
379         TDB_DATA kbuf, dbuf;
380         int count, i;
381         struct lock_struct *locks;
382         struct lock_context context;
383         NTSTATUS status;
384
385         kbuf.dptr = file_key->data;
386         kbuf.dsize = file_key->length;
387
388         if (tdb_chainlock(brl->w->tdb, kbuf) != 0) {
389                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
390         }
391
392         dbuf = tdb_fetch(brl->w->tdb, kbuf);
393         if (!dbuf.dptr) {
394                 tdb_chainunlock(brl->w->tdb, kbuf);
395                 return NT_STATUS_RANGE_NOT_LOCKED;
396         }
397
398         context.smbpid = smbpid;
399         context.server = brl->server;
400         context.ctx = brl;
401
402         /* there are existing locks - find a match */
403         locks = (struct lock_struct *)dbuf.dptr;
404         count = dbuf.dsize / sizeof(*locks);
405
406         for (i=0; i<count; i++) {
407                 struct lock_struct *lock = &locks[i];
408                 
409                 if (brl_same_context(&lock->context, &context) &&
410                     lock->fnum == fnum &&
411                     lock->start == start &&
412                     lock->size == size &&
413                     lock->lock_type < PENDING_READ_LOCK) {
414                         /* found it - delete it */
415                         if (count == 1) {
416                                 if (tdb_delete(brl->w->tdb, kbuf) != 0) {
417                                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
418                                         goto fail;
419                                 }
420                         } else {
421                                 struct lock_struct removed_lock = *lock;
422                                 if (i < count-1) {
423                                         memmove(&locks[i], &locks[i+1], 
424                                                 sizeof(*locks)*((count-1) - i));
425                                 }
426                                 count--;
427
428                                 /* send notifications for any relevant pending locks */
429                                 brl_notify_unlock(brl, locks, count, &removed_lock);
430
431                                 dbuf.dsize = count * sizeof(*locks);
432
433                                 if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
434                                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
435                                         goto fail;
436                                 }
437                         }
438                         
439                         free(dbuf.dptr);
440                         tdb_chainunlock(brl->w->tdb, kbuf);
441                         return NT_STATUS_OK;
442                 }
443         }
444         
445         /* we didn't find it */
446         status = NT_STATUS_RANGE_NOT_LOCKED;
447
448  fail:
449         free(dbuf.dptr);
450         tdb_chainunlock(brl->w->tdb, kbuf);
451         return status;
452 }
453
454
455 /*
456   remove a pending lock. This is called when the caller has either
457   given up trying to establish a lock or when they have succeeded in
458   getting it. In either case they no longer need to be notified.
459 */
460 NTSTATUS brl_remove_pending(struct brl_context *brl,
461                             DATA_BLOB *file_key, 
462                             void *notify_ptr)
463 {
464         TDB_DATA kbuf, dbuf;
465         int count, i;
466         struct lock_struct *locks;
467         NTSTATUS status;
468
469         kbuf.dptr = file_key->data;
470         kbuf.dsize = file_key->length;
471
472         if (tdb_chainlock(brl->w->tdb, kbuf) != 0) {
473                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
474         }
475
476         dbuf = tdb_fetch(brl->w->tdb, kbuf);
477         if (!dbuf.dptr) {
478                 tdb_chainunlock(brl->w->tdb, kbuf);
479                 return NT_STATUS_RANGE_NOT_LOCKED;
480         }
481
482         /* there are existing locks - find a match */
483         locks = (struct lock_struct *)dbuf.dptr;
484         count = dbuf.dsize / sizeof(*locks);
485
486         for (i=0; i<count; i++) {
487                 struct lock_struct *lock = &locks[i];
488                 
489                 if (lock->lock_type >= PENDING_READ_LOCK &&
490                     lock->notify_ptr == notify_ptr &&
491                     lock->context.server == brl->server) {
492                         /* found it - delete it */
493                         if (count == 1) {
494                                 if (tdb_delete(brl->w->tdb, kbuf) != 0) {
495                                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
496                                         goto fail;
497                                 }
498                         } else {
499                                 if (i < count-1) {
500                                         memmove(&locks[i], &locks[i+1], 
501                                                 sizeof(*locks)*((count-1) - i));
502                                 }
503                                 count--;
504                                 dbuf.dsize = count * sizeof(*locks);
505                                 if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
506                                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
507                                         goto fail;
508                                 }
509                         }
510                         
511                         free(dbuf.dptr);
512                         tdb_chainunlock(brl->w->tdb, kbuf);
513                         return NT_STATUS_OK;
514                 }
515         }
516         
517         /* we didn't find it */
518         status = NT_STATUS_RANGE_NOT_LOCKED;
519
520  fail:
521         free(dbuf.dptr);
522         tdb_chainunlock(brl->w->tdb, kbuf);
523         return status;
524 }
525
526
527 /*
528   Test if we are allowed to perform IO on a region of an open file
529 */
530 NTSTATUS brl_locktest(struct brl_context *brl,
531                       DATA_BLOB *file_key, 
532                       uint16_t fnum,
533                       uint16_t smbpid, 
534                       uint64_t start, uint64_t size, 
535                       enum brl_type lock_type)
536 {
537         TDB_DATA kbuf, dbuf;
538         int count, i;
539         struct lock_struct lock, *locks;
540
541         kbuf.dptr = file_key->data;
542         kbuf.dsize = file_key->length;
543
544         dbuf = tdb_fetch(brl->w->tdb, kbuf);
545         if (dbuf.dptr == NULL) {
546                 return NT_STATUS_OK;
547         }
548
549         lock.context.smbpid = smbpid;
550         lock.context.server = brl->server;
551         lock.context.ctx = brl;
552         lock.start = start;
553         lock.size = size;
554         lock.fnum = fnum;
555         lock.lock_type = lock_type;
556
557         /* there are existing locks - make sure they don't conflict */
558         locks = (struct lock_struct *)dbuf.dptr;
559         count = dbuf.dsize / sizeof(*locks);
560
561         for (i=0; i<count; i++) {
562                 if (brl_conflict_other(&locks[i], &lock)) {
563                         free(dbuf.dptr);
564                         return NT_STATUS_FILE_LOCK_CONFLICT;
565                 }
566         }
567
568         free(dbuf.dptr);
569         return NT_STATUS_OK;
570 }
571
572
573 /*
574  Remove any locks associated with a open file.
575 */
576 NTSTATUS brl_close(struct brl_context *brl,
577                    DATA_BLOB *file_key, int fnum)
578 {
579         TDB_DATA kbuf, dbuf;
580         int count, i, dcount=0;
581         struct lock_struct *locks;
582         NTSTATUS status;
583
584         kbuf.dptr = file_key->data;
585         kbuf.dsize = file_key->length;
586
587         if (tdb_chainlock(brl->w->tdb, kbuf) != 0) {
588                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
589         }
590
591         dbuf = tdb_fetch(brl->w->tdb, kbuf);
592         if (!dbuf.dptr) {
593                 tdb_chainunlock(brl->w->tdb, kbuf);
594                 return NT_STATUS_OK;
595         }
596
597         /* there are existing locks - remove any for this fnum */
598         locks = (struct lock_struct *)dbuf.dptr;
599         count = dbuf.dsize / sizeof(*locks);
600
601         for (i=0; i<count; i++) {
602                 struct lock_struct *lock = &locks[i];
603
604                 if (lock->context.ctx == brl &&
605                     lock->context.server == brl->server &&
606                     lock->fnum == fnum) {
607                         /* found it - delete it */
608                         if (count > 1 && i < count-1) {
609                                 memmove(&locks[i], &locks[i+1], 
610                                         sizeof(*locks)*((count-1) - i));
611                         }
612                         count--;
613                         i--;
614                         dcount++;
615                 }
616         }
617
618         status = NT_STATUS_OK;
619
620         if (count == 0) {
621                 if (tdb_delete(brl->w->tdb, kbuf) != 0) {
622                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
623                 }
624         } else if (dcount != 0) {
625                 /* tell all pending lock holders for this file that
626                    they have a chance now. This is a bit indiscriminant,
627                    but works OK */
628                 brl_notify_all(brl, locks, count);
629
630                 dbuf.dsize = count * sizeof(*locks);
631
632                 if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
633                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
634                 }
635         }
636
637         free(dbuf.dptr);
638         tdb_chainunlock(brl->w->tdb, kbuf);
639
640         return status;
641 }
642