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