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