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