This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.
[kai/samba-autobuild/.git] / source / 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 /****************************************************************************
166  Delete a record if it is for a dead process, if check_self is true, then
167  delete any records belonging to this pid also (there shouldn't be any).
168 ****************************************************************************/
169
170 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
171 {
172         struct lock_struct *locks;
173         int count, i;
174         BOOL check_self = *(BOOL *)state;
175         pid_t mypid = sys_getpid();
176
177         tdb_chainlock(tdb, kbuf);
178
179         locks = (struct lock_struct *)dbuf.dptr;
180
181         count = dbuf.dsize / sizeof(*locks);
182         for (i=0; i<count; i++) {
183                 struct lock_struct *lock = &locks[i];
184
185                 /* If check_self is true we want to remove our own records. */
186                 if (check_self && (mypid == lock->context.pid)) {
187
188                         DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
189                                         (unsigned int)lock->context.pid ));
190
191                 } else if (process_exists(lock->context.pid)) {
192
193                         DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid ));
194                         continue;
195                 }
196
197                 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
198                                 (unsigned int)lock->context.pid ));
199
200                 if (count > 1 && i < count-1) {
201                         memmove(&locks[i], &locks[i+1], 
202                                 sizeof(*locks)*((count-1) - i));
203                 }
204                 count--;
205                 i--;
206         }
207
208         if (count == 0) {
209                 tdb_delete(tdb, kbuf);
210         } else if (count < (dbuf.dsize / sizeof(*locks))) {
211                 dbuf.dsize = count * sizeof(*locks);
212                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
213         }
214
215         tdb_chainunlock(tdb, kbuf);
216         return 0;
217 }
218
219 /****************************************************************************
220  Open up the brlock.tdb database.
221 ****************************************************************************/
222
223 void brl_init(int read_only)
224 {
225         BOOL check_self = False;
226
227         if (tdb)
228                 return;
229         tdb = tdb_open_log(lock_path("brlock.tdb"), 0,  TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
230                        read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
231         if (!tdb) {
232                 DEBUG(0,("Failed to open byte range locking database\n"));
233                 return;
234         }
235
236         /* delete any dead locks */
237         if (!read_only)
238                 tdb_traverse(tdb, delete_fn, &check_self);
239 }
240
241 /****************************************************************************
242  Close down the brlock.tdb database.
243 ****************************************************************************/
244
245 void brl_shutdown(int read_only)
246 {
247         BOOL check_self = True;
248
249         if (!tdb)
250                 return;
251
252         /* delete any dead locks */
253         if (!read_only)
254                 tdb_traverse(tdb, delete_fn, &check_self);
255
256         tdb_close(tdb);
257 }
258
259 #if ZERO_ZERO
260 /****************************************************************************
261 compare two locks for sorting
262 ****************************************************************************/
263 static int lock_compare(struct lock_struct *lck1, 
264                          struct lock_struct *lck2)
265 {
266         if (lck1->start != lck2->start) return (lck1->start - lck2->start);
267         if (lck2->size != lck1->size) {
268                 return ((int)lck1->size - (int)lck2->size);
269         }
270         return 0;
271 }
272 #endif
273
274 /****************************************************************************
275  Lock a range of bytes.
276 ****************************************************************************/
277
278 NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
279                   uint16 smbpid, pid_t pid, uint16 tid,
280                   br_off start, br_off size, 
281                   enum brl_type lock_type)
282 {
283         TDB_DATA kbuf, dbuf;
284         int count, i;
285         struct lock_struct lock, *locks;
286         char *tp;
287         NTSTATUS status = NT_STATUS_OK;
288         static int last_failed = -1;
289         static br_off last_failed_start;
290
291         kbuf = locking_key(dev,ino);
292
293         dbuf.dptr = NULL;
294
295 #if !ZERO_ZERO
296         if (start == 0 && size == 0) {
297                 DEBUG(0,("client sent 0/0 lock - please report this\n"));
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         /* this is a nasty hack to try to simulate the lock result cache code in w2k.
354            It isn't completely accurate as I haven't yet worked out the correct
355            semantics (tridge)
356         */
357         if (last_failed == fnum &&
358             last_failed_start == start &&
359             NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
360                 status = NT_STATUS_FILE_LOCK_CONFLICT;
361         }
362         last_failed = fnum;
363         last_failed_start = start;
364
365         SAFE_FREE(dbuf.dptr);
366         tdb_chainunlock(tdb, kbuf);
367         return status;
368 }
369
370 /****************************************************************************
371  Unlock a range of bytes.
372 ****************************************************************************/
373
374 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
375                 uint16 smbpid, pid_t pid, uint16 tid,
376                 br_off start, br_off size)
377 {
378         TDB_DATA kbuf, dbuf;
379         int count, i;
380         struct lock_struct *locks;
381         struct lock_context context;
382
383         kbuf = locking_key(dev,ino);
384
385         dbuf.dptr = NULL;
386
387         tdb_chainlock(tdb, kbuf);
388         dbuf = tdb_fetch(tdb, kbuf);
389
390         if (!dbuf.dptr) {
391                 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
392                 goto fail;
393         }
394
395         context.smbpid = smbpid;
396         context.pid = pid;
397         context.tid = 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 #if ZERO_ZERO
404         for (i=0; i<count; i++) {
405                 struct lock_struct *lock = &locks[i];
406
407                 if (lock->lock_type == WRITE_LOCK &&
408                     brl_same_context(&lock->context, &context) &&
409                     lock->fnum == fnum &&
410                     lock->start == start &&
411                     lock->size == size) {
412                         /* found it - delete it */
413                         if (count == 1) {
414                                 tdb_delete(tdb, kbuf);
415                         } else {
416                                 if (i < count-1) {
417                                         memmove(&locks[i], &locks[i+1], 
418                                                 sizeof(*locks)*((count-1) - i));
419                                 }
420                                 dbuf.dsize -= sizeof(*locks);
421                                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
422                         }
423
424                         SAFE_FREE(dbuf.dptr);
425                         tdb_chainunlock(tdb, kbuf);
426                         return True;
427                 }
428         }
429 #endif
430
431         locks = (struct lock_struct *)dbuf.dptr;
432         count = dbuf.dsize / sizeof(*locks);
433         for (i=0; i<count; i++) {
434                 struct lock_struct *lock = &locks[i];
435
436                 if (brl_same_context(&lock->context, &context) &&
437                     lock->fnum == fnum &&
438                     lock->start == start &&
439                     lock->size == size) {
440                         /* found it - delete it */
441                         if (count == 1) {
442                                 tdb_delete(tdb, kbuf);
443                         } else {
444                                 if (i < count-1) {
445                                         memmove(&locks[i], &locks[i+1], 
446                                                 sizeof(*locks)*((count-1) - i));
447                                 }
448                                 dbuf.dsize -= sizeof(*locks);
449                                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
450                         }
451
452                         SAFE_FREE(dbuf.dptr);
453                         tdb_chainunlock(tdb, kbuf);
454                         return True;
455                 }
456         }
457
458         /* we didn't find it */
459
460  fail:
461         SAFE_FREE(dbuf.dptr);
462         tdb_chainunlock(tdb, kbuf);
463         return False;
464 }
465
466
467 /****************************************************************************
468  Test if we could add a lock if we wanted to.
469 ****************************************************************************/
470
471 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
472                   uint16 smbpid, pid_t pid, uint16 tid,
473                   br_off start, br_off size, 
474                   enum brl_type lock_type, int check_self)
475 {
476         TDB_DATA kbuf, dbuf;
477         int count, i;
478         struct lock_struct lock, *locks;
479
480         kbuf = locking_key(dev,ino);
481
482         dbuf.dptr = NULL;
483
484         tdb_chainlock(tdb, kbuf);
485         dbuf = tdb_fetch(tdb, kbuf);
486
487         lock.context.smbpid = smbpid;
488         lock.context.pid = pid;
489         lock.context.tid = tid;
490         lock.start = start;
491         lock.size = size;
492         lock.fnum = fnum;
493         lock.lock_type = lock_type;
494
495         if (dbuf.dptr) {
496                 /* there are existing locks - make sure they don't conflict */
497                 locks = (struct lock_struct *)dbuf.dptr;
498                 count = dbuf.dsize / sizeof(*locks);
499                 for (i=0; i<count; i++) {
500                         if (check_self) {
501                                 if (brl_conflict(&locks[i], &lock))
502                                         goto fail;
503                         } else {
504                                 /*
505                                  * Our own locks don't conflict.
506                                  */
507                                 if (brl_conflict_other(&locks[i], &lock))
508                                         goto fail;
509                         }
510                 }
511         }
512
513         /* no conflicts - we could have added it */
514         SAFE_FREE(dbuf.dptr);
515         tdb_chainunlock(tdb, kbuf);
516         return True;
517
518  fail:
519         SAFE_FREE(dbuf.dptr);
520         tdb_chainunlock(tdb, kbuf);
521         return False;
522 }
523
524 /****************************************************************************
525  Remove any locks associated with a open file.
526 ****************************************************************************/
527
528 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
529 {
530         TDB_DATA kbuf, dbuf;
531         int count, i, dcount=0;
532         struct lock_struct *locks;
533
534         kbuf = locking_key(dev,ino);
535
536         dbuf.dptr = NULL;
537
538         tdb_chainlock(tdb, kbuf);
539         dbuf = tdb_fetch(tdb, kbuf);
540
541         if (!dbuf.dptr) goto fail;
542
543         /* there are existing locks - remove any for this fnum */
544         locks = (struct lock_struct *)dbuf.dptr;
545         count = dbuf.dsize / sizeof(*locks);
546         for (i=0; i<count; i++) {
547                 struct lock_struct *lock = &locks[i];
548
549                 if (lock->context.tid == tid &&
550                     lock->context.pid == pid &&
551                     lock->fnum == fnum) {
552                         /* found it - delete it */
553                         if (count > 1 && i < count-1) {
554                                 memmove(&locks[i], &locks[i+1], 
555                                         sizeof(*locks)*((count-1) - i));
556                         }
557                         count--;
558                         i--;
559                         dcount++;
560                 }
561         }
562
563         if (count == 0) {
564                 tdb_delete(tdb, kbuf);
565         } else if (count < (dbuf.dsize / sizeof(*locks))) {
566                 dbuf.dsize -= dcount * sizeof(*locks);
567                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
568         }
569
570         /* we didn't find it */
571  fail:
572         SAFE_FREE(dbuf.dptr);
573         tdb_chainunlock(tdb, kbuf);
574 }
575
576 /****************************************************************************
577  Traverse the whole database with this function, calling traverse_callback
578  on each lock.
579 ****************************************************************************/
580
581 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
582 {
583         struct lock_struct *locks;
584         struct lock_key *key;
585         int i;
586
587         BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
588
589         locks = (struct lock_struct *)dbuf.dptr;
590         key = (struct lock_key *)kbuf.dptr;
591
592         for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
593                 traverse_callback(key->device, key->inode,
594                                   locks[i].context.pid,
595                                   locks[i].lock_type,
596                                   locks[i].start,
597                                   locks[i].size);
598         }
599         return 0;
600 }
601
602 /*******************************************************************
603  Call the specified function on each lock in the database.
604 ********************************************************************/
605
606 int brl_forall(BRLOCK_FN(fn))
607 {
608         if (!tdb) return 0;
609         return tdb_traverse(tdb, traverse_fn, (void *)fn);
610 }