got rid of USE_TDB_MMAP_FLAG as its not needed any more
[vlendec/samba-autobuild/.git] / source3 / locking / brlock.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    byte range locking code
5    Updated to handle range splits/merges.
6
7    Copyright (C) Andrew Tridgell 1992-2000
8    Copyright (C) Jeremy Allison 1992-2000
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 /* This module implements a tdb based byte range locking service,
26    replacing the fcntl() based byte range locking previously
27    used. This allows us to provide the same semantics as NT */
28
29 #include "includes.h"
30
31 extern int DEBUGLEVEL;
32
33 #define ZERO_ZERO 0
34
35 /* This contains elements that differentiate locks. The smbpid is a
36    client supplied pid, and is essentially the locking context for
37    this client */
38
39 struct lock_context {
40         uint16 smbpid;
41         uint16 tid;
42         pid_t pid;
43 };
44
45 /* The data in brlock records is an unsorted linear array of these
46    records.  It is unnecessary to store the count as tdb provides the
47    size of the record */
48
49 struct lock_struct {
50         struct lock_context context;
51         br_off start;
52         br_off size;
53         int fnum;
54         enum brl_type lock_type;
55 };
56
57 /* The key used in the brlock database. */
58
59 struct lock_key {
60         SMB_DEV_T device;
61         SMB_INO_T inode;
62 };
63
64 /* The open brlock.tdb database. */
65
66 static TDB_CONTEXT *tdb;
67
68 /****************************************************************************
69  Create a locking key - ensuring zero filled for pad purposes.
70 ****************************************************************************/
71
72 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
73 {
74         static struct lock_key key;
75         TDB_DATA kbuf;
76
77         memset(&key, '\0', sizeof(key));
78         key.device = dev;
79         key.inode = inode;
80         kbuf.dptr = (char *)&key;
81         kbuf.dsize = sizeof(key);
82         return kbuf;
83 }
84
85 /****************************************************************************
86  See if two locking contexts are equal.
87 ****************************************************************************/
88
89 static BOOL brl_same_context(struct lock_context *ctx1, 
90                              struct lock_context *ctx2)
91 {
92         return (ctx1->pid == ctx2->pid) &&
93                 (ctx1->smbpid == ctx2->smbpid) &&
94                 (ctx1->tid == ctx2->tid);
95 }
96
97 /****************************************************************************
98  See if lock2 can be added when lock1 is in place.
99 ****************************************************************************/
100
101 static BOOL brl_conflict(struct lock_struct *lck1, 
102                          struct lock_struct *lck2)
103 {
104         if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
105                 return False;
106         }
107
108         if (brl_same_context(&lck1->context, &lck2->context) &&
109             lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
110                 return False;
111         }
112
113         if (lck1->start >= (lck2->start + lck2->size) ||
114             lck2->start >= (lck1->start + lck1->size)) {
115                 return False;
116         }
117             
118         return True;
119
120
121 #if ZERO_ZERO
122 static BOOL brl_conflict1(struct lock_struct *lck1, 
123                          struct lock_struct *lck2)
124 {
125         if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
126                 return False;
127         }
128
129         if (brl_same_context(&lck1->context, &lck2->context) &&
130             lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
131                 return False;
132         }
133
134         if (lck2->start == 0 && lck2->size == 0 && lck1->size != 0) {
135                 return True;
136         }
137
138         if (lck1->start >= (lck2->start + lck2->size) ||
139             lck2->start >= (lck1->start + lck1->size)) {
140                 return False;
141         }
142             
143         return True;
144
145 #endif
146
147 /****************************************************************************
148  Check to see if this lock conflicts, but ignore our own locks on the
149  same fnum only.
150 ****************************************************************************/
151
152 static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
153 {
154         if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) 
155                 return False;
156
157         if (brl_same_context(&lck1->context, &lck2->context) &&
158                                 lck1->fnum == lck2->fnum)
159                 return False;
160
161         if (lck1->start >= (lck2->start + lck2->size) ||
162             lck2->start >= (lck1->start + lck1->size)) return False;
163             
164         return True;
165
166
167
168 /****************************************************************************
169  Delete a record if it is for a dead process, if check_self is true, then
170  delete any records belonging to this pid also (there shouldn't be any).
171 ****************************************************************************/
172
173 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
174 {
175         struct lock_struct *locks;
176         int count, i;
177         BOOL check_self = *(BOOL *)state;
178         pid_t mypid = sys_getpid();
179
180         tdb_chainlock(tdb, kbuf);
181
182         locks = (struct lock_struct *)dbuf.dptr;
183
184         count = dbuf.dsize / sizeof(*locks);
185         for (i=0; i<count; i++) {
186                 struct lock_struct *lock = &locks[i];
187
188                 /* If check_self is true we want to remove our own records. */
189                 if (check_self && (mypid == lock->context.pid)) {
190
191                         DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
192                                         (unsigned int)lock->context.pid ));
193
194                 } else if (process_exists(lock->context.pid)) {
195
196                         DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid ));
197                         continue;
198                 }
199
200                 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
201                                 (unsigned int)lock->context.pid ));
202
203                 if (count > 1 && i < count-1) {
204                         memmove(&locks[i], &locks[i+1], 
205                                 sizeof(*locks)*((count-1) - i));
206                 }
207                 count--;
208                 i--;
209         }
210
211         if (count == 0) {
212                 tdb_delete(tdb, kbuf);
213         } else if (count < (dbuf.dsize / sizeof(*locks))) {
214                 dbuf.dsize = count * sizeof(*locks);
215                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
216         }
217
218         tdb_chainunlock(tdb, kbuf);
219         return 0;
220 }
221
222 /****************************************************************************
223  Open up the brlock.tdb database.
224 ****************************************************************************/
225
226 void brl_init(int read_only)
227 {
228         BOOL check_self = False;
229
230         if (tdb)
231                 return;
232         tdb = tdb_open_log(lock_path("brlock.tdb"), 0,  TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
233                        read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
234         if (!tdb) {
235                 DEBUG(0,("Failed to open byte range locking database\n"));
236                 return;
237         }
238
239         /* delete any dead locks */
240         if (!read_only)
241                 tdb_traverse(tdb, delete_fn, &check_self);
242 }
243
244 /****************************************************************************
245  Close down the brlock.tdb database.
246 ****************************************************************************/
247
248 void brl_shutdown(int read_only)
249 {
250         BOOL check_self = True;
251
252         if (!tdb)
253                 return;
254
255         /* delete any dead locks */
256         if (!read_only)
257                 tdb_traverse(tdb, delete_fn, &check_self);
258
259         tdb_close(tdb);
260 }
261
262 #if ZERO_ZERO
263 /****************************************************************************
264 compare two locks for sorting
265 ****************************************************************************/
266 static int lock_compare(struct lock_struct *lck1, 
267                          struct lock_struct *lck2)
268 {
269         if (lck1->start != lck2->start) return (lck1->start - lck2->start);
270         if (lck2->size != lck1->size) {
271                 return ((int)lck1->size - (int)lck2->size);
272         }
273         return 0;
274 }
275 #endif
276
277 /****************************************************************************
278  Lock a range of bytes.
279 ****************************************************************************/
280
281 NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
282                   uint16 smbpid, pid_t pid, uint16 tid,
283                   br_off start, br_off size, 
284                   enum brl_type lock_type)
285 {
286         TDB_DATA kbuf, dbuf;
287         int count, i;
288         struct lock_struct lock, *locks;
289         char *tp;
290         NTSTATUS status = NT_STATUS_OK;
291
292         kbuf = locking_key(dev,ino);
293
294         dbuf.dptr = NULL;
295
296 #if !ZERO_ZERO
297         if (start == 0 && size == 0) {
298                 DEBUG(0,("client sent 0/0 lock - please report this\n"));
299                 return NT_STATUS_INVALID_PARAMETER;
300         }
301 #endif
302
303         tdb_chainlock(tdb, kbuf);
304         dbuf = tdb_fetch(tdb, kbuf);
305
306         lock.context.smbpid = smbpid;
307         lock.context.pid = pid;
308         lock.context.tid = tid;
309         lock.start = start;
310         lock.size = size;
311         lock.fnum = fnum;
312         lock.lock_type = lock_type;
313
314         if (dbuf.dptr) {
315                 /* there are existing locks - make sure they don't conflict */
316                 locks = (struct lock_struct *)dbuf.dptr;
317                 count = dbuf.dsize / sizeof(*locks);
318                 for (i=0; i<count; i++) {
319                         if (brl_conflict(&locks[i], &lock)) {
320                                 status = NT_STATUS_LOCK_NOT_GRANTED;
321                                 goto fail;
322                         }
323 #if ZERO_ZERO
324                         if (lock.start == 0 && lock.size == 0 && 
325                             locks[i].size == 0) {
326                                 break;
327                         }
328 #endif
329                 }
330         }
331
332         /* no conflicts - add it to the list of locks */
333         tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
334         if (!tp) {
335                 status = NT_STATUS_NO_MEMORY;
336                 goto fail;
337         } else {
338                 dbuf.dptr = tp;
339         }
340         memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
341         dbuf.dsize += sizeof(lock);
342
343 #if ZERO_ZERO
344         /* sort the lock list */
345         qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare);
346 #endif
347
348         tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
349
350         free(dbuf.dptr);
351         tdb_chainunlock(tdb, kbuf);
352         return NT_STATUS_OK;
353
354  fail:
355         if (dbuf.dptr) free(dbuf.dptr);
356         tdb_chainunlock(tdb, kbuf);
357         return status;
358 }
359
360 /****************************************************************************
361  Unlock a range of bytes.
362 ****************************************************************************/
363
364 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
365                 uint16 smbpid, pid_t pid, uint16 tid,
366                 br_off start, br_off size)
367 {
368         TDB_DATA kbuf, dbuf;
369         int count, i;
370         struct lock_struct *locks;
371         struct lock_context context;
372
373         kbuf = locking_key(dev,ino);
374
375         dbuf.dptr = NULL;
376
377         tdb_chainlock(tdb, kbuf);
378         dbuf = tdb_fetch(tdb, kbuf);
379
380         if (!dbuf.dptr) {
381                 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
382                 goto fail;
383         }
384
385         context.smbpid = smbpid;
386         context.pid = pid;
387         context.tid = tid;
388
389         /* there are existing locks - find a match */
390         locks = (struct lock_struct *)dbuf.dptr;
391         count = dbuf.dsize / sizeof(*locks);
392
393 #if ZERO_ZERO
394         for (i=0; i<count; i++) {
395                 struct lock_struct *lock = &locks[i];
396
397                 if (lock->lock_type == WRITE_LOCK &&
398                     brl_same_context(&lock->context, &context) &&
399                     lock->fnum == fnum &&
400                     lock->start == start &&
401                     lock->size == size) {
402                         /* found it - delete it */
403                         if (count == 1) {
404                                 tdb_delete(tdb, kbuf);
405                         } else {
406                                 if (i < count-1) {
407                                         memmove(&locks[i], &locks[i+1], 
408                                                 sizeof(*locks)*((count-1) - i));
409                                 }
410                                 dbuf.dsize -= sizeof(*locks);
411                                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
412                         }
413
414                         free(dbuf.dptr);
415                         tdb_chainunlock(tdb, kbuf);
416                         return True;
417                 }
418         }
419 #endif
420
421         locks = (struct lock_struct *)dbuf.dptr;
422         count = dbuf.dsize / sizeof(*locks);
423         for (i=0; i<count; i++) {
424                 struct lock_struct *lock = &locks[i];
425
426                 if (brl_same_context(&lock->context, &context) &&
427                     lock->fnum == fnum &&
428                     lock->start == start &&
429                     lock->size == size) {
430                         /* found it - delete it */
431                         if (count == 1) {
432                                 tdb_delete(tdb, kbuf);
433                         } else {
434                                 if (i < count-1) {
435                                         memmove(&locks[i], &locks[i+1], 
436                                                 sizeof(*locks)*((count-1) - i));
437                                 }
438                                 dbuf.dsize -= sizeof(*locks);
439                                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
440                         }
441
442                         free(dbuf.dptr);
443                         tdb_chainunlock(tdb, kbuf);
444                         return True;
445                 }
446         }
447
448         /* we didn't find it */
449
450  fail:
451         if (dbuf.dptr) free(dbuf.dptr);
452         tdb_chainunlock(tdb, kbuf);
453         return False;
454 }
455
456
457 /****************************************************************************
458  Test if we could add a lock if we wanted to.
459 ****************************************************************************/
460
461 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
462                   uint16 smbpid, pid_t pid, uint16 tid,
463                   br_off start, br_off size, 
464                   enum brl_type lock_type, int check_self)
465 {
466         TDB_DATA kbuf, dbuf;
467         int count, i;
468         struct lock_struct lock, *locks;
469
470         kbuf = locking_key(dev,ino);
471
472         dbuf.dptr = NULL;
473
474         tdb_chainlock(tdb, kbuf);
475         dbuf = tdb_fetch(tdb, kbuf);
476
477         lock.context.smbpid = smbpid;
478         lock.context.pid = pid;
479         lock.context.tid = tid;
480         lock.start = start;
481         lock.size = size;
482         lock.fnum = fnum;
483         lock.lock_type = lock_type;
484
485         if (dbuf.dptr) {
486                 /* there are existing locks - make sure they don't conflict */
487                 locks = (struct lock_struct *)dbuf.dptr;
488                 count = dbuf.dsize / sizeof(*locks);
489                 for (i=0; i<count; i++) {
490                         if (check_self) {
491                                 if (brl_conflict(&locks[i], &lock))
492                                         goto fail;
493                         } else {
494                                 /*
495                                  * Our own locks don't conflict.
496                                  */
497                                 if (brl_conflict_other(&locks[i], &lock))
498                                         goto fail;
499                         }
500                 }
501         }
502
503         /* no conflicts - we could have added it */
504         free(dbuf.dptr);
505         tdb_chainunlock(tdb, kbuf);
506         return True;
507
508  fail:
509         if (dbuf.dptr) free(dbuf.dptr);
510         tdb_chainunlock(tdb, kbuf);
511         return False;
512 }
513
514 /****************************************************************************
515  Remove any locks associated with a open file.
516 ****************************************************************************/
517
518 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
519 {
520         TDB_DATA kbuf, dbuf;
521         int count, i, dcount=0;
522         struct lock_struct *locks;
523
524         kbuf = locking_key(dev,ino);
525
526         dbuf.dptr = NULL;
527
528         tdb_chainlock(tdb, kbuf);
529         dbuf = tdb_fetch(tdb, kbuf);
530
531         if (!dbuf.dptr) goto fail;
532
533         /* there are existing locks - remove any for this fnum */
534         locks = (struct lock_struct *)dbuf.dptr;
535         count = dbuf.dsize / sizeof(*locks);
536         for (i=0; i<count; i++) {
537                 struct lock_struct *lock = &locks[i];
538
539                 if (lock->context.tid == tid &&
540                     lock->context.pid == pid &&
541                     lock->fnum == fnum) {
542                         /* found it - delete it */
543                         if (count > 1 && i < count-1) {
544                                 memmove(&locks[i], &locks[i+1], 
545                                         sizeof(*locks)*((count-1) - i));
546                         }
547                         count--;
548                         i--;
549                         dcount++;
550                 }
551         }
552
553         if (count == 0) {
554                 tdb_delete(tdb, kbuf);
555         } else if (count < (dbuf.dsize / sizeof(*locks))) {
556                 dbuf.dsize -= dcount * sizeof(*locks);
557                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
558         }
559
560         /* we didn't find it */
561  fail:
562         if (dbuf.dptr) free(dbuf.dptr);
563         tdb_chainunlock(tdb, kbuf);
564 }
565
566 /****************************************************************************
567  Traverse the whole database with this function, calling traverse_callback
568  on each lock.
569 ****************************************************************************/
570
571 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
572 {
573         struct lock_struct *locks;
574         struct lock_key *key;
575         int i;
576
577         BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
578
579         locks = (struct lock_struct *)dbuf.dptr;
580         key = (struct lock_key *)kbuf.dptr;
581
582         for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
583                 traverse_callback(key->device, key->inode,
584                                   locks[i].context.pid,
585                                   locks[i].lock_type,
586                                   locks[i].start,
587                                   locks[i].size);
588         }
589         return 0;
590 }
591
592 /*******************************************************************
593  Call the specified function on each lock in the database.
594 ********************************************************************/
595
596 int brl_forall(BRLOCK_FN(fn))
597 {
598         if (!tdb) return 0;
599         return tdb_traverse(tdb, traverse_fn, (void *)fn);
600 }