2da32891fbad3c746456b924ea4433ef96dcc391
[gd/samba-autobuild/.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         void *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 void *brl_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid, 
75                void *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 (void *)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(void *brl_ctx,
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         struct brl_context *brl = brl_ctx;
231         TDB_DATA kbuf, dbuf;
232         int count, i;
233         struct lock_struct lock, *locks;
234         char *tp;
235         NTSTATUS status;
236
237         kbuf.dptr = file_key->data;
238         kbuf.dsize = file_key->length;
239
240         if (tdb_chainlock(brl->w->tdb, kbuf) != 0) {
241                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
242         }
243
244         /* if this is a pending lock, then with the chainlock held we
245            try to get the real lock. If we succeed then we don't need
246            to make it pending. This prevents a possible race condition
247            where the pending lock gets created after the lock that is
248            preventing the real lock gets removed */
249         if (lock_type >= PENDING_READ_LOCK) {
250                 enum brl_type rw = (lock_type==PENDING_READ_LOCK? READ_LOCK : WRITE_LOCK);
251                 status = brl_lock(brl_ctx, file_key, smbpid, fnum, start, size, rw, NULL);
252                 if (NT_STATUS_IS_OK(status)) {
253                         tdb_chainunlock(brl->w->tdb, kbuf);
254                         return NT_STATUS_OK;
255                 }
256         }
257
258         dbuf = tdb_fetch(brl->w->tdb, kbuf);
259
260         lock.context.smbpid = smbpid;
261         lock.context.server = brl->server;
262         lock.context.tid = brl->tid;
263         lock.start = start;
264         lock.size = size;
265         lock.fnum = fnum;
266         lock.lock_type = lock_type;
267         lock.notify_ptr = notify_ptr;
268
269         if (dbuf.dptr) {
270                 /* there are existing locks - make sure they don't conflict */
271                 locks = (struct lock_struct *)dbuf.dptr;
272                 count = dbuf.dsize / sizeof(*locks);
273                 for (i=0; i<count; i++) {
274                         if (brl_conflict(&locks[i], &lock)) {
275                                 status = brl_lock_failed(brl, &lock);
276                                 goto fail;
277                         }
278                 }
279         }
280
281         /* no conflicts - add it to the list of locks */
282         tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
283         if (!tp) {
284                 status = NT_STATUS_NO_MEMORY;
285                 goto fail;
286         } else {
287                 dbuf.dptr = tp;
288         }
289         memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
290         dbuf.dsize += sizeof(lock);
291
292         if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
293                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
294                 goto fail;
295         }
296
297         free(dbuf.dptr);
298         tdb_chainunlock(brl->w->tdb, kbuf);
299
300         /* the caller needs to know if the real lock was granted. If
301            we have reached here then it must be a pending lock that
302            was granted, so tell them the lock failed */
303         if (lock_type >= PENDING_READ_LOCK) {
304                 return brl_lock_failed(brl, &lock);
305         }
306
307         return NT_STATUS_OK;
308
309  fail:
310
311         free(dbuf.dptr);
312         tdb_chainunlock(brl->w->tdb, kbuf);
313         return status;
314 }
315
316
317 /*
318   we are removing a lock that might be holding up a pending lock. Scan for pending
319   locks that cover this range and if we find any then notify the server that it should
320   retry the lock
321 */
322 static void brl_notify_unlock(struct brl_context *brl,
323                               struct lock_struct *locks, int count, 
324                               struct lock_struct *removed_lock)
325 {
326         int i, last_notice;
327
328         /* the last_notice logic is to prevent stampeding on a lock
329            range. It prevents us sending hundreds of notifies on the
330            same range of bytes. It doesn't prevent all possible
331            stampedes, but it does prevent the most common problem */
332         last_notice = -1;
333
334         for (i=0;i<count;i++) {
335                 if (locks[i].lock_type >= PENDING_READ_LOCK &&
336                     brl_overlap(&locks[i], removed_lock)) {
337                         DATA_BLOB data;
338
339                         if (last_notice != -1 && brl_overlap(&locks[i], &locks[last_notice])) {
340                                 continue;
341                         }
342                         last_notice = i;
343                         data.data = (void *)&locks[i].notify_ptr;
344                         data.length = sizeof(void *);
345                         messaging_send(brl->messaging_ctx, locks[i].context.server, MSG_BRL_RETRY, &data);
346                 }
347         }
348 }
349
350
351 /*
352   send notifications for all pending locks - the file is being closed by this
353   user
354 */
355 static void brl_notify_all(struct brl_context *brl,
356                            struct lock_struct *locks, int count)
357 {
358         int i;
359         for (i=0;i<count;i++) {
360                 if (locks->lock_type >= PENDING_READ_LOCK) {
361                         brl_notify_unlock(brl, locks, count, &locks[i]);
362                 }
363         }
364 }
365
366
367
368 /*
369  Unlock a range of bytes.
370 */
371 NTSTATUS brl_unlock(void *brl_ctx,
372                     DATA_BLOB *file_key, 
373                     uint16_t smbpid,
374                     uint16_t fnum,
375                     uint64_t start, uint64_t size)
376 {
377         struct brl_context *brl = brl_ctx;
378         TDB_DATA kbuf, dbuf;
379         int count, i;
380         struct lock_struct *locks;
381         struct lock_context context;
382         NTSTATUS status;
383
384         kbuf.dptr = file_key->data;
385         kbuf.dsize = file_key->length;
386
387         if (tdb_chainlock(brl->w->tdb, kbuf) != 0) {
388                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
389         }
390
391         dbuf = tdb_fetch(brl->w->tdb, kbuf);
392         if (!dbuf.dptr) {
393                 tdb_chainunlock(brl->w->tdb, kbuf);
394                 return NT_STATUS_RANGE_NOT_LOCKED;
395         }
396
397         context.smbpid = smbpid;
398         context.server = brl->server;
399         context.tid = brl->tid;
400
401         /* there are existing locks - find a match */
402         locks = (struct lock_struct *)dbuf.dptr;
403         count = dbuf.dsize / sizeof(*locks);
404
405         for (i=0; i<count; i++) {
406                 struct lock_struct *lock = &locks[i];
407                 
408                 if (brl_same_context(&lock->context, &context) &&
409                     lock->fnum == fnum &&
410                     lock->start == start &&
411                     lock->size == size &&
412                     lock->notify_ptr == NULL) {
413                         /* found it - delete it */
414                         if (count == 1) {
415                                 if (tdb_delete(brl->w->tdb, kbuf) != 0) {
416                                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
417                                         goto fail;
418                                 }
419                         } else {
420                                 struct lock_struct removed_lock = *lock;
421                                 if (i < count-1) {
422                                         memmove(&locks[i], &locks[i+1], 
423                                                 sizeof(*locks)*((count-1) - i));
424                                 }
425                                 count--;
426
427                                 /* send notifications for any relevant pending locks */
428                                 brl_notify_unlock(brl, locks, count, &removed_lock);
429
430                                 dbuf.dsize = count * sizeof(*locks);
431
432                                 if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
433                                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
434                                         goto fail;
435                                 }
436                         }
437                         
438                         free(dbuf.dptr);
439                         tdb_chainunlock(brl->w->tdb, kbuf);
440                         return NT_STATUS_OK;
441                 }
442         }
443         
444         /* we didn't find it */
445         status = NT_STATUS_RANGE_NOT_LOCKED;
446
447  fail:
448         free(dbuf.dptr);
449         tdb_chainunlock(brl->w->tdb, kbuf);
450         return status;
451 }
452
453
454 /*
455   remove a pending lock. This is called when the caller has either
456   given up trying to establish a lock or when they have succeeded in
457   getting it. In either case they no longer need to be notified.
458 */
459 NTSTATUS brl_remove_pending(void *brl_ctx,
460                             DATA_BLOB *file_key, 
461                             void *notify_ptr)
462 {
463         struct brl_context *brl = brl_ctx;
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->notify_ptr == notify_ptr &&
490                     lock->context.server == brl->server) {
491                         /* found it - delete it */
492                         if (count == 1) {
493                                 if (tdb_delete(brl->w->tdb, kbuf) != 0) {
494                                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
495                                         goto fail;
496                                 }
497                         } else {
498                                 if (i < count-1) {
499                                         memmove(&locks[i], &locks[i+1], 
500                                                 sizeof(*locks)*((count-1) - i));
501                                 }
502                                 count--;
503                                 dbuf.dsize = count * sizeof(*locks);
504                                 if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
505                                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
506                                         goto fail;
507                                 }
508                         }
509                         
510                         free(dbuf.dptr);
511                         tdb_chainunlock(brl->w->tdb, kbuf);
512                         return NT_STATUS_OK;
513                 }
514         }
515         
516         /* we didn't find it */
517         status = NT_STATUS_RANGE_NOT_LOCKED;
518
519  fail:
520         free(dbuf.dptr);
521         tdb_chainunlock(brl->w->tdb, kbuf);
522         return status;
523 }
524
525
526 /*
527   Test if we are allowed to perform IO on a region of an open file
528 */
529 NTSTATUS brl_locktest(void *brl_ctx,
530                       DATA_BLOB *file_key, 
531                       uint16_t fnum,
532                       uint16 smbpid, 
533                       uint64_t start, uint64_t size, 
534                       enum brl_type lock_type)
535 {
536         struct brl_context *brl = brl_ctx;
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.tid = brl->tid;
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(void *brl_ctx,
577                    DATA_BLOB *file_key, int fnum)
578 {
579         struct brl_context *brl = brl_ctx;
580         TDB_DATA kbuf, dbuf;
581         int count, i, dcount=0;
582         struct lock_struct *locks;
583         NTSTATUS status;
584
585         kbuf.dptr = file_key->data;
586         kbuf.dsize = file_key->length;
587
588         if (tdb_chainlock(brl->w->tdb, kbuf) != 0) {
589                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
590         }
591
592         dbuf = tdb_fetch(brl->w->tdb, kbuf);
593         if (!dbuf.dptr) {
594                 tdb_chainunlock(brl->w->tdb, kbuf);
595                 return NT_STATUS_OK;
596         }
597
598         /* there are existing locks - remove any for this fnum */
599         locks = (struct lock_struct *)dbuf.dptr;
600         count = dbuf.dsize / sizeof(*locks);
601
602         for (i=0; i<count; i++) {
603                 struct lock_struct *lock = &locks[i];
604
605                 if (lock->context.tid == brl->tid &&
606                     lock->context.server == brl->server &&
607                     lock->fnum == fnum) {
608                         /* found it - delete it */
609                         if (count > 1 && i < count-1) {
610                                 memmove(&locks[i], &locks[i+1], 
611                                         sizeof(*locks)*((count-1) - i));
612                         }
613                         count--;
614                         i--;
615                         dcount++;
616                 }
617         }
618
619         status = NT_STATUS_OK;
620
621         if (count == 0) {
622                 if (tdb_delete(brl->w->tdb, kbuf) != 0) {
623                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
624                 }
625         } else if (dcount != 0) {
626                 /* tell all pending lock holders for this file that
627                    they have a chance now. This is a bit indiscriminant,
628                    but works OK */
629                 brl_notify_all(brl, locks, count);
630
631                 dbuf.dsize = count * sizeof(*locks);
632
633                 if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
634                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
635                 }
636         }
637
638         free(dbuf.dptr);
639         tdb_chainunlock(brl->w->tdb, kbuf);
640
641         return status;
642 }
643