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 */
32 /* This contains elements that differentiate locks. The smbpid is a
33 client supplied pid, and is essentially the locking context for
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
47 struct lock_context context
;
51 enum brl_type lock_type
;
54 /* The key used in the brlock database. */
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
;
74 memset(&key
, '\0', sizeof(key
));
77 kbuf
.dptr
= (char *)&key
;
78 kbuf
.dsize
= sizeof(key
);
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 lock2 can be added when lock1 is in place.
96 ****************************************************************************/
98 static BOOL
brl_conflict(struct lock_struct
*lck1
,
99 struct lock_struct
*lck2
)
101 if (lck1
->lock_type
== PENDING_LOCK
|| lck2
->lock_type
== PENDING_LOCK
)
104 if (lck1
->lock_type
== READ_LOCK
&& lck2
->lock_type
== READ_LOCK
) {
108 if (brl_same_context(&lck1
->context
, &lck2
->context
) &&
109 lck2
->lock_type
== READ_LOCK
&& lck1
->fnum
== lck2
->fnum
) {
113 if (lck1
->start
>= (lck2
->start
+ lck2
->size
) ||
114 lck2
->start
>= (lck1
->start
+ lck1
->size
)) {
122 static BOOL
brl_conflict1(struct lock_struct
*lck1
,
123 struct lock_struct
*lck2
)
125 if (lck1
->lock_type
== PENDING_LOCK
|| lck2
->lock_type
== PENDING_LOCK
)
128 if (lck1
->lock_type
== READ_LOCK
&& lck2
->lock_type
== READ_LOCK
) {
132 if (brl_same_context(&lck1
->context
, &lck2
->context
) &&
133 lck2
->lock_type
== READ_LOCK
&& lck1
->fnum
== lck2
->fnum
) {
137 if (lck2
->start
== 0 && lck2
->size
== 0 && lck1
->size
!= 0) {
141 if (lck1
->start
>= (lck2
->start
+ lck2
->size
) ||
142 lck2
->start
>= (lck1
->start
+ lck1
->size
)) {
150 /****************************************************************************
151 Check to see if this lock conflicts, but ignore our own locks on the
153 ****************************************************************************/
155 static BOOL
brl_conflict_other(struct lock_struct
*lck1
, struct lock_struct
*lck2
)
157 if (lck1
->lock_type
== PENDING_LOCK
|| lck2
->lock_type
== PENDING_LOCK
)
160 if (lck1
->lock_type
== READ_LOCK
&& lck2
->lock_type
== READ_LOCK
)
164 * Incoming WRITE locks conflict with existing READ locks even
165 * if the context is the same. JRA. See LOCKTEST7 in smbtorture.
168 if (!(lck2
->lock_type
== WRITE_LOCK
&& lck1
->lock_type
== READ_LOCK
)) {
169 if (brl_same_context(&lck1
->context
, &lck2
->context
) &&
170 lck1
->fnum
== lck2
->fnum
)
174 if (lck1
->start
>= (lck2
->start
+ lck2
->size
) ||
175 lck2
->start
>= (lck1
->start
+ lck1
->size
)) return False
;
182 /* doing this traversal could kill solaris machines under high load (tridge) */
183 /* delete any dead locks */
185 /****************************************************************************
186 Delete a record if it is for a dead process, if check_self is true, then
187 delete any records belonging to this pid also (there shouldn't be any).
188 ****************************************************************************/
190 static int delete_fn(TDB_CONTEXT
*ttdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
192 struct lock_struct
*locks
;
194 BOOL check_self
= *(BOOL
*)state
;
195 pid_t mypid
= sys_getpid();
197 tdb_chainlock(tdb
, kbuf
);
199 locks
= (struct lock_struct
*)dbuf
.dptr
;
201 count
= dbuf
.dsize
/ sizeof(*locks
);
202 for (i
=0; i
<count
; i
++) {
203 struct lock_struct
*lock
= &locks
[i
];
205 /* If check_self is true we want to remove our own records. */
206 if (check_self
&& (mypid
== lock
->context
.pid
)) {
208 DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
209 (unsigned int)lock
->context
.pid
));
211 } else if (process_exists(lock
->context
.pid
)) {
213 DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock
->context
.pid
));
217 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
218 (unsigned int)lock
->context
.pid
));
220 if (count
> 1 && i
< count
-1) {
221 memmove(&locks
[i
], &locks
[i
+1],
222 sizeof(*locks
)*((count
-1) - i
));
229 tdb_delete(tdb
, kbuf
);
230 } else if (count
< (dbuf
.dsize
/ sizeof(*locks
))) {
231 dbuf
.dsize
= count
* sizeof(*locks
);
232 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
235 tdb_chainunlock(tdb
, kbuf
);
240 /****************************************************************************
241 Open up the brlock.tdb database.
242 ****************************************************************************/
244 void brl_init(int read_only
)
248 tdb
= tdb_open_log(lock_path("brlock.tdb"), 0, TDB_DEFAULT
|(read_only
?0x0:TDB_CLEAR_IF_FIRST
),
249 read_only
?O_RDONLY
:(O_RDWR
|O_CREAT
), 0644);
251 DEBUG(0,("Failed to open byte range locking database\n"));
256 /* doing this traversal could kill solaris machines under high load (tridge) */
257 /* delete any dead locks */
259 BOOL check_self
= False
;
260 tdb_traverse(tdb
, delete_fn
, &check_self
);
265 /****************************************************************************
266 Close down the brlock.tdb database.
267 ****************************************************************************/
269 void brl_shutdown(int read_only
)
275 /* doing this traversal could kill solaris machines under high load (tridge) */
276 /* delete any dead locks */
278 BOOL check_self
= True
;
279 tdb_traverse(tdb
, delete_fn
, &check_self
);
287 /****************************************************************************
288 compare two locks for sorting
289 ****************************************************************************/
290 static int lock_compare(struct lock_struct
*lck1
,
291 struct lock_struct
*lck2
)
293 if (lck1
->start
!= lck2
->start
) return (lck1
->start
- lck2
->start
);
294 if (lck2
->size
!= lck1
->size
) {
295 return ((int)lck1
->size
- (int)lck2
->size
);
301 /****************************************************************************
302 Lock a range of bytes.
303 ****************************************************************************/
305 NTSTATUS
brl_lock(SMB_DEV_T dev
, SMB_INO_T ino
, int fnum
,
306 uint16 smbpid
, pid_t pid
, uint16 tid
,
307 br_off start
, br_off size
,
308 enum brl_type lock_type
)
312 struct lock_struct lock
, *locks
;
314 NTSTATUS status
= NT_STATUS_OK
;
315 static int last_failed
= -1;
316 static br_off last_failed_start
;
318 kbuf
= locking_key(dev
,ino
);
323 if (start
== 0 && size
== 0) {
324 DEBUG(0,("client sent 0/0 lock - please report this\n"));
328 tdb_chainlock(tdb
, kbuf
);
329 dbuf
= tdb_fetch(tdb
, kbuf
);
331 lock
.context
.smbpid
= smbpid
;
332 lock
.context
.pid
= pid
;
333 lock
.context
.tid
= tid
;
337 lock
.lock_type
= lock_type
;
340 /* there are existing locks - make sure they don't conflict */
341 locks
= (struct lock_struct
*)dbuf
.dptr
;
342 count
= dbuf
.dsize
/ sizeof(*locks
);
343 for (i
=0; i
<count
; i
++) {
344 if (brl_conflict(&locks
[i
], &lock
)) {
345 status
= NT_STATUS_LOCK_NOT_GRANTED
;
349 if (lock
.start
== 0 && lock
.size
== 0 &&
350 locks
[i
].size
== 0) {
357 /* no conflicts - add it to the list of locks */
358 tp
= Realloc(dbuf
.dptr
, dbuf
.dsize
+ sizeof(*locks
));
360 status
= NT_STATUS_NO_MEMORY
;
365 memcpy(dbuf
.dptr
+ dbuf
.dsize
, &lock
, sizeof(lock
));
366 dbuf
.dsize
+= sizeof(lock
);
369 /* sort the lock list */
370 qsort(dbuf
.dptr
, dbuf
.dsize
/sizeof(lock
), sizeof(lock
), lock_compare
);
373 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
375 SAFE_FREE(dbuf
.dptr
);
376 tdb_chainunlock(tdb
, kbuf
);
380 /* this is a nasty hack to try to simulate the lock result cache code in w2k.
381 It isn't completely accurate as I haven't yet worked out the correct
384 if (last_failed
== fnum
&&
385 last_failed_start
== start
&&
386 NT_STATUS_EQUAL(status
, NT_STATUS_LOCK_NOT_GRANTED
)) {
387 status
= NT_STATUS_FILE_LOCK_CONFLICT
;
390 last_failed_start
= start
;
392 SAFE_FREE(dbuf
.dptr
);
393 tdb_chainunlock(tdb
, kbuf
);
397 /****************************************************************************
398 Check if an unlock overlaps a pending lock.
399 ****************************************************************************/
401 static BOOL
brl_pending_overlap(struct lock_struct
*lock
, struct lock_struct
*pend_lock
)
403 if ((lock
->start
<= pend_lock
->start
) && (lock
->start
+ lock
->size
> pend_lock
->start
))
405 if ((lock
->start
>= pend_lock
->start
) && (lock
->start
<= pend_lock
->start
+ pend_lock
->size
))
410 /****************************************************************************
411 Unlock a range of bytes.
412 ****************************************************************************/
414 BOOL
brl_unlock(SMB_DEV_T dev
, SMB_INO_T ino
, int fnum
,
415 uint16 smbpid
, pid_t pid
, uint16 tid
,
416 br_off start
, br_off size
,
417 BOOL remove_pending_locks_only
,
418 void (*pre_unlock_fn
)(void *),
419 void *pre_unlock_data
)
423 struct lock_struct
*locks
;
424 struct lock_context context
;
426 kbuf
= locking_key(dev
,ino
);
430 tdb_chainlock(tdb
, kbuf
);
431 dbuf
= tdb_fetch(tdb
, kbuf
);
434 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
438 context
.smbpid
= smbpid
;
442 /* there are existing locks - find a match */
443 locks
= (struct lock_struct
*)dbuf
.dptr
;
444 count
= dbuf
.dsize
/ sizeof(*locks
);
447 for (i
=0; i
<count
; i
++) {
448 struct lock_struct
*lock
= &locks
[i
];
450 if (lock
->lock_type
== WRITE_LOCK
&&
451 brl_same_context(&lock
->context
, &context
) &&
452 lock
->fnum
== fnum
&&
453 lock
->start
== start
&&
454 lock
->size
== size
) {
457 (*pre_unlock_fn
)(pre_unlock_data
);
459 /* found it - delete it */
461 tdb_delete(tdb
, kbuf
);
464 memmove(&locks
[i
], &locks
[i
+1],
465 sizeof(*locks
)*((count
-1) - i
));
467 dbuf
.dsize
-= sizeof(*locks
);
468 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
471 SAFE_FREE(dbuf
.dptr
);
472 tdb_chainunlock(tdb
, kbuf
);
478 locks
= (struct lock_struct
*)dbuf
.dptr
;
479 count
= dbuf
.dsize
/ sizeof(*locks
);
480 for (i
=0; i
<count
; i
++) {
481 struct lock_struct
*lock
= &locks
[i
];
483 if (brl_same_context(&lock
->context
, &context
) &&
484 lock
->fnum
== fnum
&&
485 lock
->start
== start
&&
486 lock
->size
== size
) {
488 if (remove_pending_locks_only
&& lock
->lock_type
!= PENDING_LOCK
)
491 if (lock
->lock_type
!= PENDING_LOCK
) {
493 /* Do any POSIX unlocks needed. */
495 (*pre_unlock_fn
)(pre_unlock_data
);
497 /* Send unlock messages to any pending waiters that overlap. */
498 for (j
=0; j
<count
; j
++) {
499 struct lock_struct
*pend_lock
= &locks
[j
];
501 /* Ignore non-pending locks. */
502 if (pend_lock
->lock_type
!= PENDING_LOCK
)
505 /* We could send specific lock info here... */
506 if (brl_pending_overlap(lock
, pend_lock
)) {
507 DEBUG(10,("brl_unlock: sending unlock message to pid %u\n",
508 (unsigned int)pend_lock
->context
.pid
));
510 message_send_pid(pend_lock
->context
.pid
,
517 /* found it - delete it */
519 tdb_delete(tdb
, kbuf
);
522 memmove(&locks
[i
], &locks
[i
+1],
523 sizeof(*locks
)*((count
-1) - i
));
525 dbuf
.dsize
-= sizeof(*locks
);
526 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
529 SAFE_FREE(dbuf
.dptr
);
530 tdb_chainunlock(tdb
, kbuf
);
535 /* we didn't find it */
538 SAFE_FREE(dbuf
.dptr
);
539 tdb_chainunlock(tdb
, kbuf
);
544 /****************************************************************************
545 Test if we could add a lock if we wanted to.
546 ****************************************************************************/
548 BOOL
brl_locktest(SMB_DEV_T dev
, SMB_INO_T ino
, int fnum
,
549 uint16 smbpid
, pid_t pid
, uint16 tid
,
550 br_off start
, br_off size
,
551 enum brl_type lock_type
, int check_self
)
555 struct lock_struct lock
, *locks
;
557 kbuf
= locking_key(dev
,ino
);
561 tdb_chainlock(tdb
, kbuf
);
562 dbuf
= tdb_fetch(tdb
, kbuf
);
564 lock
.context
.smbpid
= smbpid
;
565 lock
.context
.pid
= pid
;
566 lock
.context
.tid
= tid
;
570 lock
.lock_type
= lock_type
;
573 /* there are existing locks - make sure they don't conflict */
574 locks
= (struct lock_struct
*)dbuf
.dptr
;
575 count
= dbuf
.dsize
/ sizeof(*locks
);
576 for (i
=0; i
<count
; i
++) {
578 if (brl_conflict(&locks
[i
], &lock
))
582 * Our own locks don't conflict.
584 if (brl_conflict_other(&locks
[i
], &lock
))
590 /* no conflicts - we could have added it */
591 SAFE_FREE(dbuf
.dptr
);
592 tdb_chainunlock(tdb
, kbuf
);
596 SAFE_FREE(dbuf
.dptr
);
597 tdb_chainunlock(tdb
, kbuf
);
601 /****************************************************************************
602 Remove any locks associated with a open file.
603 ****************************************************************************/
605 void brl_close(SMB_DEV_T dev
, SMB_INO_T ino
, pid_t pid
, int tid
, int fnum
)
608 int count
, i
, j
, dcount
=0;
609 struct lock_struct
*locks
;
611 kbuf
= locking_key(dev
,ino
);
615 tdb_chainlock(tdb
, kbuf
);
616 dbuf
= tdb_fetch(tdb
, kbuf
);
618 if (!dbuf
.dptr
) goto fail
;
620 /* there are existing locks - remove any for this fnum */
621 locks
= (struct lock_struct
*)dbuf
.dptr
;
622 count
= dbuf
.dsize
/ sizeof(*locks
);
624 for (i
=0; i
<count
; i
++) {
625 struct lock_struct
*lock
= &locks
[i
];
627 if (lock
->context
.tid
== tid
&&
628 lock
->context
.pid
== pid
&&
629 lock
->fnum
== fnum
) {
631 /* Send unlock messages to any pending waiters that overlap. */
632 for (j
=0; j
<count
; j
++) {
633 struct lock_struct
*pend_lock
= &locks
[j
];
635 /* Ignore our own or non-pending locks. */
636 if (pend_lock
->lock_type
!= PENDING_LOCK
)
639 if (pend_lock
->context
.tid
== tid
&&
640 pend_lock
->context
.pid
== pid
&&
641 pend_lock
->fnum
== fnum
)
644 /* We could send specific lock info here... */
645 if (brl_pending_overlap(lock
, pend_lock
))
646 message_send_pid(pend_lock
->context
.pid
,
651 /* found it - delete it */
652 if (count
> 1 && i
< count
-1) {
653 memmove(&locks
[i
], &locks
[i
+1],
654 sizeof(*locks
)*((count
-1) - i
));
663 tdb_delete(tdb
, kbuf
);
664 } else if (count
< (dbuf
.dsize
/ sizeof(*locks
))) {
665 dbuf
.dsize
-= dcount
* sizeof(*locks
);
666 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
669 /* we didn't find it */
671 SAFE_FREE(dbuf
.dptr
);
672 tdb_chainunlock(tdb
, kbuf
);
675 /****************************************************************************
676 Traverse the whole database with this function, calling traverse_callback
678 ****************************************************************************/
680 static int traverse_fn(TDB_CONTEXT
*ttdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
682 struct lock_struct
*locks
;
683 struct lock_key
*key
;
686 BRLOCK_FN(traverse_callback
) = (BRLOCK_FN_CAST())state
;
688 locks
= (struct lock_struct
*)dbuf
.dptr
;
689 key
= (struct lock_key
*)kbuf
.dptr
;
691 for (i
=0;i
<dbuf
.dsize
/sizeof(*locks
);i
++) {
692 traverse_callback(key
->device
, key
->inode
,
693 locks
[i
].context
.pid
,
701 /*******************************************************************
702 Call the specified function on each lock in the database.
703 ********************************************************************/
705 int brl_forall(BRLOCK_FN(fn
))
708 return tdb_traverse(tdb
, traverse_fn
, (void *)fn
);