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 == READ_LOCK && lck2->lock_type == READ_LOCK) {
105 if (brl_same_context(&lck1->context, &lck2->context) &&
106 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
110 if (lck1->start >= (lck2->start + lck2->size) ||
111 lck2->start >= (lck1->start + lck1->size)) {
119 static BOOL brl_conflict1(struct lock_struct *lck1,
120 struct lock_struct *lck2)
122 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
126 if (brl_same_context(&lck1->context, &lck2->context) &&
127 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
131 if (lck2->start == 0 && lck2->size == 0 && lck1->size != 0) {
135 if (lck1->start >= (lck2->start + lck2->size) ||
136 lck2->start >= (lck1->start + lck1->size)) {
144 /****************************************************************************
145 Check to see if this lock conflicts, but ignore our own locks on the
147 ****************************************************************************/
149 static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
151 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
155 * Incoming WRITE locks conflict with existing READ locks even
156 * if the context is the same. JRA. See LOCKTEST7 in smbtorture.
159 if (!(lck2->lock_type == WRITE_LOCK && lck1->lock_type == READ_LOCK)) {
160 if (brl_same_context(&lck1->context, &lck2->context) &&
161 lck1->fnum == lck2->fnum)
165 if (lck1->start >= (lck2->start + lck2->size) ||
166 lck2->start >= (lck1->start + lck1->size)) return False;
173 /* doing this traversal could kill solaris machines under high load (tridge) */
174 /* delete any dead locks */
176 /****************************************************************************
177 Delete a record if it is for a dead process, if check_self is true, then
178 delete any records belonging to this pid also (there shouldn't be any).
179 ****************************************************************************/
181 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
183 struct lock_struct *locks;
185 BOOL check_self = *(BOOL *)state;
186 pid_t mypid = sys_getpid();
188 tdb_chainlock(tdb, kbuf);
190 locks = (struct lock_struct *)dbuf.dptr;
192 count = dbuf.dsize / sizeof(*locks);
193 for (i=0; i<count; i++) {
194 struct lock_struct *lock = &locks[i];
196 /* If check_self is true we want to remove our own records. */
197 if (check_self && (mypid == lock->context.pid)) {
199 DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
200 (unsigned int)lock->context.pid ));
202 } else if (process_exists(lock->context.pid)) {
204 DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid ));
208 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
209 (unsigned int)lock->context.pid ));
211 if (count > 1 && i < count-1) {
212 memmove(&locks[i], &locks[i+1],
213 sizeof(*locks)*((count-1) - i));
220 tdb_delete(tdb, kbuf);
221 } else if (count < (dbuf.dsize / sizeof(*locks))) {
222 dbuf.dsize = count * sizeof(*locks);
223 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
226 tdb_chainunlock(tdb, kbuf);
231 /****************************************************************************
232 Open up the brlock.tdb database.
233 ****************************************************************************/
235 void brl_init(int read_only)
239 tdb = tdb_open_log(lock_path("brlock.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
240 read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
242 DEBUG(0,("Failed to open byte range locking database\n"));
247 /* doing this traversal could kill solaris machines under high load (tridge) */
248 /* delete any dead locks */
250 BOOL check_self = False;
251 tdb_traverse(tdb, delete_fn, &check_self);
256 /****************************************************************************
257 Close down the brlock.tdb database.
258 ****************************************************************************/
260 void brl_shutdown(int read_only)
266 /* doing this traversal could kill solaris machines under high load (tridge) */
267 /* delete any dead locks */
269 BOOL check_self = True;
270 tdb_traverse(tdb, delete_fn, &check_self);
278 /****************************************************************************
279 compare two locks for sorting
280 ****************************************************************************/
281 static int lock_compare(struct lock_struct *lck1,
282 struct lock_struct *lck2)
284 if (lck1->start != lck2->start) return (lck1->start - lck2->start);
285 if (lck2->size != lck1->size) {
286 return ((int)lck1->size - (int)lck2->size);
292 /****************************************************************************
293 Lock a range of bytes.
294 ****************************************************************************/
296 NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
297 uint16 smbpid, pid_t pid, uint16 tid,
298 br_off start, br_off size,
299 enum brl_type lock_type)
303 struct lock_struct lock, *locks;
305 NTSTATUS status = NT_STATUS_OK;
306 static int last_failed = -1;
307 static br_off last_failed_start;
309 kbuf = locking_key(dev,ino);
314 if (start == 0 && size == 0) {
315 DEBUG(0,("client sent 0/0 lock - please report this\n"));
319 tdb_chainlock(tdb, kbuf);
320 dbuf = tdb_fetch(tdb, kbuf);
322 lock.context.smbpid = smbpid;
323 lock.context.pid = pid;
324 lock.context.tid = tid;
328 lock.lock_type = lock_type;
331 /* there are existing locks - make sure they don't conflict */
332 locks = (struct lock_struct *)dbuf.dptr;
333 count = dbuf.dsize / sizeof(*locks);
334 for (i=0; i<count; i++) {
335 if (brl_conflict(&locks[i], &lock)) {
336 status = NT_STATUS_LOCK_NOT_GRANTED;
340 if (lock.start == 0 && lock.size == 0 &&
341 locks[i].size == 0) {
348 /* no conflicts - add it to the list of locks */
349 tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
351 status = NT_STATUS_NO_MEMORY;
356 memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
357 dbuf.dsize += sizeof(lock);
360 /* sort the lock list */
361 qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare);
364 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
366 SAFE_FREE(dbuf.dptr);
367 tdb_chainunlock(tdb, kbuf);
371 /* this is a nasty hack to try to simulate the lock result cache code in w2k.
372 It isn't completely accurate as I haven't yet worked out the correct
375 if (last_failed == fnum &&
376 last_failed_start == start &&
377 NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
378 status = NT_STATUS_FILE_LOCK_CONFLICT;
381 last_failed_start = start;
383 SAFE_FREE(dbuf.dptr);
384 tdb_chainunlock(tdb, kbuf);
388 /****************************************************************************
389 Unlock a range of bytes.
390 ****************************************************************************/
392 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
393 uint16 smbpid, pid_t pid, uint16 tid,
394 br_off start, br_off size)
398 struct lock_struct *locks;
399 struct lock_context context;
401 kbuf = locking_key(dev,ino);
405 tdb_chainlock(tdb, kbuf);
406 dbuf = tdb_fetch(tdb, kbuf);
409 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
413 context.smbpid = smbpid;
417 /* there are existing locks - find a match */
418 locks = (struct lock_struct *)dbuf.dptr;
419 count = dbuf.dsize / sizeof(*locks);
422 for (i=0; i<count; i++) {
423 struct lock_struct *lock = &locks[i];
425 if (lock->lock_type == WRITE_LOCK &&
426 brl_same_context(&lock->context, &context) &&
427 lock->fnum == fnum &&
428 lock->start == start &&
429 lock->size == size) {
430 /* found it - delete it */
432 tdb_delete(tdb, kbuf);
435 memmove(&locks[i], &locks[i+1],
436 sizeof(*locks)*((count-1) - i));
438 dbuf.dsize -= sizeof(*locks);
439 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
442 SAFE_FREE(dbuf.dptr);
443 tdb_chainunlock(tdb, kbuf);
449 locks = (struct lock_struct *)dbuf.dptr;
450 count = dbuf.dsize / sizeof(*locks);
451 for (i=0; i<count; i++) {
452 struct lock_struct *lock = &locks[i];
454 if (brl_same_context(&lock->context, &context) &&
455 lock->fnum == fnum &&
456 lock->start == start &&
457 lock->size == size) {
458 /* found it - delete it */
460 tdb_delete(tdb, kbuf);
463 memmove(&locks[i], &locks[i+1],
464 sizeof(*locks)*((count-1) - i));
466 dbuf.dsize -= sizeof(*locks);
467 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
470 SAFE_FREE(dbuf.dptr);
471 tdb_chainunlock(tdb, kbuf);
476 /* we didn't find it */
479 SAFE_FREE(dbuf.dptr);
480 tdb_chainunlock(tdb, kbuf);
485 /****************************************************************************
486 Test if we could add a lock if we wanted to.
487 ****************************************************************************/
489 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
490 uint16 smbpid, pid_t pid, uint16 tid,
491 br_off start, br_off size,
492 enum brl_type lock_type, int check_self)
496 struct lock_struct lock, *locks;
498 kbuf = locking_key(dev,ino);
502 tdb_chainlock(tdb, kbuf);
503 dbuf = tdb_fetch(tdb, kbuf);
505 lock.context.smbpid = smbpid;
506 lock.context.pid = pid;
507 lock.context.tid = tid;
511 lock.lock_type = lock_type;
514 /* there are existing locks - make sure they don't conflict */
515 locks = (struct lock_struct *)dbuf.dptr;
516 count = dbuf.dsize / sizeof(*locks);
517 for (i=0; i<count; i++) {
519 if (brl_conflict(&locks[i], &lock))
523 * Our own locks don't conflict.
525 if (brl_conflict_other(&locks[i], &lock))
531 /* no conflicts - we could have added it */
532 SAFE_FREE(dbuf.dptr);
533 tdb_chainunlock(tdb, kbuf);
537 SAFE_FREE(dbuf.dptr);
538 tdb_chainunlock(tdb, kbuf);
542 /****************************************************************************
543 Remove any locks associated with a open file.
544 ****************************************************************************/
546 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
549 int count, i, dcount=0;
550 struct lock_struct *locks;
552 kbuf = locking_key(dev,ino);
556 tdb_chainlock(tdb, kbuf);
557 dbuf = tdb_fetch(tdb, kbuf);
559 if (!dbuf.dptr) goto fail;
561 /* there are existing locks - remove any for this fnum */
562 locks = (struct lock_struct *)dbuf.dptr;
563 count = dbuf.dsize / sizeof(*locks);
564 for (i=0; i<count; i++) {
565 struct lock_struct *lock = &locks[i];
567 if (lock->context.tid == tid &&
568 lock->context.pid == pid &&
569 lock->fnum == fnum) {
570 /* found it - delete it */
571 if (count > 1 && i < count-1) {
572 memmove(&locks[i], &locks[i+1],
573 sizeof(*locks)*((count-1) - i));
582 tdb_delete(tdb, kbuf);
583 } else if (count < (dbuf.dsize / sizeof(*locks))) {
584 dbuf.dsize -= dcount * sizeof(*locks);
585 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
588 /* we didn't find it */
590 SAFE_FREE(dbuf.dptr);
591 tdb_chainunlock(tdb, kbuf);
594 /****************************************************************************
595 Traverse the whole database with this function, calling traverse_callback
597 ****************************************************************************/
599 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
601 struct lock_struct *locks;
602 struct lock_key *key;
605 BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
607 locks = (struct lock_struct *)dbuf.dptr;
608 key = (struct lock_key *)kbuf.dptr;
610 for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
611 traverse_callback(key->device, key->inode,
612 locks[i].context.pid,
620 /*******************************************************************
621 Call the specified function on each lock in the database.
622 ********************************************************************/
624 int brl_forall(BRLOCK_FN(fn))
627 return tdb_traverse(tdb, traverse_fn, (void *)fn);