r4348: syncing up for 3.0.11pre1
[Samba.git] / source / locking / brlock.c
blob3451b0cc1ab07592f0d866c4d99dd0ff768614e4
1 /*
2 Unix SMB/CIFS implementation.
3 byte range locking code
4 Updated to handle range splits/merges.
6 Copyright (C) Andrew Tridgell 1992-2000
7 Copyright (C) Jeremy Allison 1992-2000
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.
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.
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.
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 */
28 #include "includes.h"
30 #define ZERO_ZERO 0
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 */
36 struct lock_context {
37 uint16 smbpid;
38 uint16 tid;
39 pid_t pid;
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 */
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;
54 /* The key used in the brlock database. */
56 struct lock_key {
57 SMB_DEV_T device;
58 SMB_INO_T inode;
61 /* The open brlock.tdb database. */
63 static TDB_CONTEXT *tdb;
65 /****************************************************************************
66 Create a locking key - ensuring zero filled for pad purposes.
67 ****************************************************************************/
69 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
71 static struct lock_key key;
72 TDB_DATA kbuf;
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;
82 /****************************************************************************
83 See if two locking contexts are equal.
84 ****************************************************************************/
86 static BOOL brl_same_context(struct lock_context *ctx1,
87 struct lock_context *ctx2)
89 return (ctx1->pid == ctx2->pid) &&
90 (ctx1->smbpid == ctx2->smbpid) &&
91 (ctx1->tid == ctx2->tid);
94 /****************************************************************************
95 See if lck1 and lck2 overlap.
96 ****************************************************************************/
98 static BOOL brl_overlap(struct lock_struct *lck1,
99 struct lock_struct *lck2)
101 /* this extra check is not redundent - it copes with locks
102 that go beyond the end of 64 bit file space */
103 if (lck1->size != 0 &&
104 lck1->start == lck2->start &&
105 lck1->size == lck2->size) {
106 return True;
109 if (lck1->start >= (lck2->start+lck2->size) ||
110 lck2->start >= (lck1->start+lck1->size)) {
111 return False;
113 return True;
116 /****************************************************************************
117 See if lock2 can be added when lock1 is in place.
118 ****************************************************************************/
120 static BOOL brl_conflict(struct lock_struct *lck1,
121 struct lock_struct *lck2)
123 if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
124 return False;
126 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
127 return False;
130 if (brl_same_context(&lck1->context, &lck2->context) &&
131 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
132 return False;
135 if (lck1->start >= (lck2->start + lck2->size) ||
136 lck2->start >= (lck1->start + lck1->size)) {
137 return False;
140 return brl_overlap(lck1, lck2);
143 #if ZERO_ZERO
144 static BOOL brl_conflict1(struct lock_struct *lck1,
145 struct lock_struct *lck2)
147 if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
148 return False;
150 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
151 return False;
154 if (brl_same_context(&lck1->context, &lck2->context) &&
155 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
156 return False;
159 if (lck2->start == 0 && lck2->size == 0 && lck1->size != 0) {
160 return True;
163 if (lck1->start >= (lck2->start + lck2->size) ||
164 lck2->start >= (lck1->start + lck1->size)) {
165 return False;
168 return True;
170 #endif
172 /****************************************************************************
173 Check to see if this lock conflicts, but ignore our own locks on the
174 same fnum only.
175 ****************************************************************************/
177 static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
179 if (lck1->lock_type == PENDING_LOCK || lck2->lock_type == PENDING_LOCK )
180 return False;
182 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
183 return False;
186 * Incoming WRITE locks conflict with existing READ locks even
187 * if the context is the same. JRA. See LOCKTEST7 in smbtorture.
190 if (!(lck2->lock_type == WRITE_LOCK && lck1->lock_type == READ_LOCK)) {
191 if (brl_same_context(&lck1->context, &lck2->context) &&
192 lck1->fnum == lck2->fnum)
193 return False;
196 if (lck1->start >= (lck2->start + lck2->size) ||
197 lck2->start >= (lck1->start + lck1->size))
198 return False;
200 return brl_overlap(lck1, lck2);
203 /****************************************************************************
204 Amazingly enough, w2k3 "remembers" whether the last lock failure
205 is the same as this one and changes its error code. I wonder if any
206 app depends on this ?
207 ****************************************************************************/
209 static NTSTATUS brl_lock_failed(struct lock_struct *lock)
211 static struct lock_struct last_lock_failure;
213 if (brl_same_context(&lock->context, &last_lock_failure.context) &&
214 lock->fnum == last_lock_failure.fnum &&
215 lock->start == last_lock_failure.start &&
216 lock->size == last_lock_failure.size) {
217 return NT_STATUS_FILE_LOCK_CONFLICT;
219 last_lock_failure = *lock;
220 if (lock->start >= 0xEF000000 &&
221 (lock->start >> 63) == 0) {
222 /* amazing the little things you learn with a test
223 suite. Locks beyond this offset (as a 64 bit
224 number!) always generate the conflict error code,
225 unless the top bit is set */
226 return NT_STATUS_FILE_LOCK_CONFLICT;
228 return NT_STATUS_LOCK_NOT_GRANTED;
231 #if DONT_DO_THIS
232 /* doing this traversal could kill solaris machines under high load (tridge) */
233 /* delete any dead locks */
235 /****************************************************************************
236 Delete a record if it is for a dead process, if check_self is true, then
237 delete any records belonging to this pid also (there shouldn't be any).
238 ****************************************************************************/
240 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
242 struct lock_struct *locks;
243 int count, i;
244 BOOL check_self = *(BOOL *)state;
245 pid_t mypid = sys_getpid();
247 tdb_chainlock(tdb, kbuf);
249 locks = (struct lock_struct *)dbuf.dptr;
251 count = dbuf.dsize / sizeof(*locks);
252 for (i=0; i<count; i++) {
253 struct lock_struct *lock = &locks[i];
255 /* If check_self is true we want to remove our own records. */
256 if (check_self && (mypid == lock->context.pid)) {
258 DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
259 (unsigned int)lock->context.pid ));
261 } else if (process_exists(lock->context.pid)) {
263 DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid ));
264 continue;
267 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
268 (unsigned int)lock->context.pid ));
270 if (count > 1 && i < count-1) {
271 memmove(&locks[i], &locks[i+1],
272 sizeof(*locks)*((count-1) - i));
274 count--;
275 i--;
278 if (count == 0) {
279 tdb_delete(tdb, kbuf);
280 } else if (count < (dbuf.dsize / sizeof(*locks))) {
281 dbuf.dsize = count * sizeof(*locks);
282 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
285 tdb_chainunlock(tdb, kbuf);
286 return 0;
288 #endif
290 /****************************************************************************
291 Open up the brlock.tdb database.
292 ****************************************************************************/
294 void brl_init(int read_only)
296 if (tdb)
297 return;
298 tdb = tdb_open_log(lock_path("brlock.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
299 read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 );
300 if (!tdb) {
301 DEBUG(0,("Failed to open byte range locking database\n"));
302 return;
305 #if DONT_DO_THIS
306 /* doing this traversal could kill solaris machines under high load (tridge) */
307 /* delete any dead locks */
308 if (!read_only) {
309 BOOL check_self = False;
310 tdb_traverse(tdb, delete_fn, &check_self);
312 #endif
315 /****************************************************************************
316 Close down the brlock.tdb database.
317 ****************************************************************************/
319 void brl_shutdown(int read_only)
321 if (!tdb)
322 return;
324 #if DONT_DO_THIS
325 /* doing this traversal could kill solaris machines under high load (tridge) */
326 /* delete any dead locks */
327 if (!read_only) {
328 BOOL check_self = True;
329 tdb_traverse(tdb, delete_fn, &check_self);
331 #endif
333 tdb_close(tdb);
336 #if ZERO_ZERO
337 /****************************************************************************
338 compare two locks for sorting
339 ****************************************************************************/
340 static int lock_compare(struct lock_struct *lck1,
341 struct lock_struct *lck2)
343 if (lck1->start != lck2->start) return (lck1->start - lck2->start);
344 if (lck2->size != lck1->size) {
345 return ((int)lck1->size - (int)lck2->size);
347 return 0;
349 #endif
351 /****************************************************************************
352 Lock a range of bytes.
353 ****************************************************************************/
355 NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
356 uint16 smbpid, pid_t pid, uint16 tid,
357 br_off start, br_off size,
358 enum brl_type lock_type, BOOL *my_lock_ctx)
360 TDB_DATA kbuf, dbuf;
361 int count, i;
362 struct lock_struct lock, *locks;
363 char *tp;
364 NTSTATUS status = NT_STATUS_OK;
366 *my_lock_ctx = False;
367 kbuf = locking_key(dev,ino);
369 dbuf.dptr = NULL;
371 #if !ZERO_ZERO
372 if (start == 0 && size == 0) {
373 DEBUG(0,("client sent 0/0 lock - please report this\n"));
375 #endif
377 tdb_chainlock(tdb, kbuf);
378 dbuf = tdb_fetch(tdb, kbuf);
380 lock.context.smbpid = smbpid;
381 lock.context.pid = pid;
382 lock.context.tid = tid;
383 lock.start = start;
384 lock.size = size;
385 lock.fnum = fnum;
386 lock.lock_type = lock_type;
388 if (dbuf.dptr) {
389 /* there are existing locks - make sure they don't conflict */
390 locks = (struct lock_struct *)dbuf.dptr;
391 count = dbuf.dsize / sizeof(*locks);
392 for (i=0; i<count; i++) {
393 if (brl_conflict(&locks[i], &lock)) {
394 status = brl_lock_failed(&lock);;
395 /* Did we block ourselves ? */
396 if (brl_same_context(&locks[i].context, &lock.context))
397 *my_lock_ctx = True;
398 goto fail;
400 #if ZERO_ZERO
401 if (lock.start == 0 && lock.size == 0 &&
402 locks[i].size == 0) {
403 break;
405 #endif
409 /* no conflicts - add it to the list of locks */
410 tp = SMB_REALLOC(dbuf.dptr, dbuf.dsize + sizeof(*locks));
411 if (!tp) {
412 status = NT_STATUS_NO_MEMORY;
413 goto fail;
414 } else {
415 dbuf.dptr = tp;
417 memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
418 dbuf.dsize += sizeof(lock);
420 #if ZERO_ZERO
421 /* sort the lock list */
422 qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare);
423 #endif
425 if (tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) != 0) {
426 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
427 goto fail;
430 SAFE_FREE(dbuf.dptr);
431 tdb_chainunlock(tdb, kbuf);
432 return NT_STATUS_OK;
434 fail:
436 SAFE_FREE(dbuf.dptr);
437 tdb_chainunlock(tdb, kbuf);
438 return status;
441 /****************************************************************************
442 Check if an unlock overlaps a pending lock.
443 ****************************************************************************/
445 static BOOL brl_pending_overlap(struct lock_struct *lock, struct lock_struct *pend_lock)
447 if ((lock->start <= pend_lock->start) && (lock->start + lock->size > pend_lock->start))
448 return True;
449 if ((lock->start >= pend_lock->start) && (lock->start <= pend_lock->start + pend_lock->size))
450 return True;
451 return False;
454 /****************************************************************************
455 Unlock a range of bytes.
456 ****************************************************************************/
458 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
459 uint16 smbpid, pid_t pid, uint16 tid,
460 br_off start, br_off size,
461 BOOL remove_pending_locks_only,
462 void (*pre_unlock_fn)(void *),
463 void *pre_unlock_data)
465 TDB_DATA kbuf, dbuf;
466 int count, i, j;
467 struct lock_struct *locks;
468 struct lock_context context;
470 kbuf = locking_key(dev,ino);
472 dbuf.dptr = NULL;
474 tdb_chainlock(tdb, kbuf);
475 dbuf = tdb_fetch(tdb, kbuf);
477 if (!dbuf.dptr) {
478 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
479 goto fail;
482 context.smbpid = smbpid;
483 context.pid = pid;
484 context.tid = tid;
486 /* there are existing locks - find a match */
487 locks = (struct lock_struct *)dbuf.dptr;
488 count = dbuf.dsize / sizeof(*locks);
490 #if ZERO_ZERO
491 for (i=0; i<count; i++) {
492 struct lock_struct *lock = &locks[i];
494 if (lock->lock_type == WRITE_LOCK &&
495 brl_same_context(&lock->context, &context) &&
496 lock->fnum == fnum &&
497 lock->start == start &&
498 lock->size == size) {
500 if (pre_unlock_fn)
501 (*pre_unlock_fn)(pre_unlock_data);
503 /* found it - delete it */
504 if (count == 1) {
505 tdb_delete(tdb, kbuf);
506 } else {
507 if (i < count-1) {
508 memmove(&locks[i], &locks[i+1],
509 sizeof(*locks)*((count-1) - i));
511 dbuf.dsize -= sizeof(*locks);
512 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
515 SAFE_FREE(dbuf.dptr);
516 tdb_chainunlock(tdb, kbuf);
517 return True;
520 #endif
522 locks = (struct lock_struct *)dbuf.dptr;
523 count = dbuf.dsize / sizeof(*locks);
524 for (i=0; i<count; i++) {
525 struct lock_struct *lock = &locks[i];
527 if (brl_same_context(&lock->context, &context) &&
528 lock->fnum == fnum &&
529 lock->start == start &&
530 lock->size == size) {
532 if (remove_pending_locks_only && lock->lock_type != PENDING_LOCK)
533 continue;
535 if (lock->lock_type != PENDING_LOCK) {
537 /* Do any POSIX unlocks needed. */
538 if (pre_unlock_fn)
539 (*pre_unlock_fn)(pre_unlock_data);
541 /* Send unlock messages to any pending waiters that overlap. */
542 for (j=0; j<count; j++) {
543 struct lock_struct *pend_lock = &locks[j];
545 /* Ignore non-pending locks. */
546 if (pend_lock->lock_type != PENDING_LOCK)
547 continue;
549 /* We could send specific lock info here... */
550 if (brl_pending_overlap(lock, pend_lock)) {
551 DEBUG(10,("brl_unlock: sending unlock message to pid %u\n",
552 (unsigned int)pend_lock->context.pid ));
554 message_send_pid(pend_lock->context.pid,
555 MSG_SMB_UNLOCK,
556 NULL, 0, True);
561 /* found it - delete it */
562 if (count == 1) {
563 tdb_delete(tdb, kbuf);
564 } else {
565 if (i < count-1) {
566 memmove(&locks[i], &locks[i+1],
567 sizeof(*locks)*((count-1) - i));
569 dbuf.dsize -= sizeof(*locks);
570 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
573 SAFE_FREE(dbuf.dptr);
574 tdb_chainunlock(tdb, kbuf);
575 return True;
579 /* we didn't find it */
581 fail:
582 SAFE_FREE(dbuf.dptr);
583 tdb_chainunlock(tdb, kbuf);
584 return False;
588 /****************************************************************************
589 Test if we could add a lock if we wanted to.
590 ****************************************************************************/
592 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
593 uint16 smbpid, pid_t pid, uint16 tid,
594 br_off start, br_off size,
595 enum brl_type lock_type)
597 TDB_DATA kbuf, dbuf;
598 int count, i;
599 struct lock_struct lock, *locks;
601 kbuf = locking_key(dev,ino);
603 dbuf.dptr = NULL;
605 dbuf = tdb_fetch(tdb, kbuf);
607 lock.context.smbpid = smbpid;
608 lock.context.pid = pid;
609 lock.context.tid = tid;
610 lock.start = start;
611 lock.size = size;
612 lock.fnum = fnum;
613 lock.lock_type = lock_type;
615 if (dbuf.dptr) {
616 /* there are existing locks - make sure they don't conflict */
617 locks = (struct lock_struct *)dbuf.dptr;
618 count = dbuf.dsize / sizeof(*locks);
619 for (i=0; i<count; i++) {
621 * Our own locks don't conflict.
623 if (brl_conflict_other(&locks[i], &lock))
624 goto fail;
628 /* no conflicts - we could have added it */
629 SAFE_FREE(dbuf.dptr);
630 return True;
632 fail:
633 SAFE_FREE(dbuf.dptr);
634 return False;
637 /****************************************************************************
638 Remove any locks associated with a open file.
639 ****************************************************************************/
641 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
643 TDB_DATA kbuf, dbuf;
644 int count, i, j, dcount=0;
645 struct lock_struct *locks;
647 kbuf = locking_key(dev,ino);
649 dbuf.dptr = NULL;
651 tdb_chainlock(tdb, kbuf);
652 dbuf = tdb_fetch(tdb, kbuf);
654 if (!dbuf.dptr) goto fail;
656 /* there are existing locks - remove any for this fnum */
657 locks = (struct lock_struct *)dbuf.dptr;
658 count = dbuf.dsize / sizeof(*locks);
660 for (i=0; i<count; i++) {
661 struct lock_struct *lock = &locks[i];
663 if (lock->context.tid == tid &&
664 lock->context.pid == pid &&
665 lock->fnum == fnum) {
667 /* Send unlock messages to any pending waiters that overlap. */
668 for (j=0; j<count; j++) {
669 struct lock_struct *pend_lock = &locks[j];
671 /* Ignore our own or non-pending locks. */
672 if (pend_lock->lock_type != PENDING_LOCK)
673 continue;
675 if (pend_lock->context.tid == tid &&
676 pend_lock->context.pid == pid &&
677 pend_lock->fnum == fnum)
678 continue;
680 /* We could send specific lock info here... */
681 if (brl_pending_overlap(lock, pend_lock))
682 message_send_pid(pend_lock->context.pid,
683 MSG_SMB_UNLOCK,
684 NULL, 0, True);
687 /* found it - delete it */
688 if (count > 1 && i < count-1) {
689 memmove(&locks[i], &locks[i+1],
690 sizeof(*locks)*((count-1) - i));
692 count--;
693 i--;
694 dcount++;
698 if (count == 0) {
699 tdb_delete(tdb, kbuf);
700 } else if (count < (dbuf.dsize / sizeof(*locks))) {
701 dbuf.dsize -= dcount * sizeof(*locks);
702 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
705 /* we didn't find it */
706 fail:
707 SAFE_FREE(dbuf.dptr);
708 tdb_chainunlock(tdb, kbuf);
711 /****************************************************************************
712 Traverse the whole database with this function, calling traverse_callback
713 on each lock.
714 ****************************************************************************/
716 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
718 struct lock_struct *locks;
719 struct lock_key *key;
720 int i;
722 BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
724 locks = (struct lock_struct *)dbuf.dptr;
725 key = (struct lock_key *)kbuf.dptr;
727 for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
728 traverse_callback(key->device, key->inode,
729 locks[i].context.pid,
730 locks[i].lock_type,
731 locks[i].start,
732 locks[i].size);
734 return 0;
737 /*******************************************************************
738 Call the specified function on each lock in the database.
739 ********************************************************************/
741 int brl_forall(BRLOCK_FN(fn))
743 if (!tdb) return 0;
744 return tdb_traverse(tdb, traverse_fn, (void *)fn);