2 Unix SMB/Netbios implementation.
4 byte range locking code
5 Updated to handle range splits/merges.
7 Copyright (C) Andrew Tridgell 1992-2000
8 Copyright (C) Jeremy Allison 1992-2000
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /* This module implements a tdb based byte range locking service,
26 replacing the fcntl() based byte range locking previously
27 used. This allows us to provide the same semantics as NT */
33 /* This contains elements that differentiate locks. The smbpid is a
34 client supplied pid, and is essentially the locking context for
43 /* The data in brlock records is an unsorted linear array of these
44 records. It is unnecessary to store the count as tdb provides the
48 struct lock_context context;
52 enum brl_type lock_type;
55 /* The key used in the brlock database. */
62 /* The open brlock.tdb database. */
64 static TDB_CONTEXT *tdb;
66 /****************************************************************************
67 Create a locking key - ensuring zero filled for pad purposes.
68 ****************************************************************************/
70 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
72 static struct lock_key key;
75 memset(&key, '\0', sizeof(key));
78 kbuf.dptr = (char *)&key;
79 kbuf.dsize = sizeof(key);
83 /****************************************************************************
84 See if two locking contexts are equal.
85 ****************************************************************************/
87 static BOOL brl_same_context(struct lock_context *ctx1,
88 struct lock_context *ctx2)
90 return (ctx1->pid == ctx2->pid) &&
91 (ctx1->smbpid == ctx2->smbpid) &&
92 (ctx1->tid == ctx2->tid);
95 /****************************************************************************
96 See if lock2 can be added when lock1 is in place.
97 ****************************************************************************/
99 static BOOL brl_conflict(struct lock_struct *lck1,
100 struct lock_struct *lck2)
102 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
106 if (brl_same_context(&lck1->context, &lck2->context) &&
107 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
111 if (lck1->start >= (lck2->start + lck2->size) ||
112 lck2->start >= (lck1->start + lck1->size)) {
120 static BOOL brl_conflict1(struct lock_struct *lck1,
121 struct lock_struct *lck2)
123 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
127 if (brl_same_context(&lck1->context, &lck2->context) &&
128 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
132 if (lck2->start == 0 && lck2->size == 0 && lck1->size != 0) {
136 if (lck1->start >= (lck2->start + lck2->size) ||
137 lck2->start >= (lck1->start + lck1->size)) {
145 /****************************************************************************
146 Check to see if this lock conflicts, but ignore our own locks on the
148 ****************************************************************************/
150 static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
152 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
155 if (brl_same_context(&lck1->context, &lck2->context) &&
156 lck1->fnum == lck2->fnum)
159 if (lck1->start >= (lck2->start + lck2->size) ||
160 lck2->start >= (lck1->start + lck1->size)) return False;
166 /****************************************************************************
167 Delete a record if it is for a dead process, if check_self is true, then
168 delete any records belonging to this pid also (there shouldn't be any).
169 ****************************************************************************/
171 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
173 struct lock_struct *locks;
175 BOOL check_self = *(BOOL *)state;
176 pid_t mypid = sys_getpid();
178 tdb_chainlock(tdb, kbuf);
180 locks = (struct lock_struct *)dbuf.dptr;
182 count = dbuf.dsize / sizeof(*locks);
183 for (i=0; i<count; i++) {
184 struct lock_struct *lock = &locks[i];
186 /* If check_self is true we want to remove our own records. */
187 if (check_self && (mypid == lock->context.pid)) {
189 DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
190 (unsigned int)lock->context.pid ));
192 } else if (process_exists(lock->context.pid)) {
194 DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid ));
198 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
199 (unsigned int)lock->context.pid ));
201 if (count > 1 && i < count-1) {
202 memmove(&locks[i], &locks[i+1],
203 sizeof(*locks)*((count-1) - i));
210 tdb_delete(tdb, kbuf);
211 } else if (count < (dbuf.dsize / sizeof(*locks))) {
212 dbuf.dsize = count * sizeof(*locks);
213 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
216 tdb_chainunlock(tdb, kbuf);
220 /****************************************************************************
221 Open up the brlock.tdb database.
222 ****************************************************************************/
224 void brl_init(int read_only)
226 BOOL check_self = False;
230 tdb = tdb_open_log(lock_path("brlock.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
231 read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
233 DEBUG(0,("Failed to open byte range locking database\n"));
237 /* delete any dead locks */
239 tdb_traverse(tdb, delete_fn, &check_self);
242 /****************************************************************************
243 Close down the brlock.tdb database.
244 ****************************************************************************/
246 void brl_shutdown(int read_only)
248 BOOL check_self = True;
253 /* delete any dead locks */
255 tdb_traverse(tdb, delete_fn, &check_self);
261 /****************************************************************************
262 compare two locks for sorting
263 ****************************************************************************/
264 static int lock_compare(struct lock_struct *lck1,
265 struct lock_struct *lck2)
267 if (lck1->start != lck2->start) return (lck1->start - lck2->start);
268 if (lck2->size != lck1->size) {
269 return ((int)lck1->size - (int)lck2->size);
275 /****************************************************************************
276 Lock a range of bytes.
277 ****************************************************************************/
279 NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
280 uint16 smbpid, pid_t pid, uint16 tid,
281 br_off start, br_off size,
282 enum brl_type lock_type)
286 struct lock_struct lock, *locks;
288 NTSTATUS status = NT_STATUS_OK;
290 kbuf = locking_key(dev,ino);
295 if (start == 0 && size == 0) {
296 DEBUG(0,("client sent 0/0 lock - please report this\n"));
297 return NT_STATUS_INVALID_PARAMETER;
301 tdb_chainlock(tdb, kbuf);
302 dbuf = tdb_fetch(tdb, kbuf);
304 lock.context.smbpid = smbpid;
305 lock.context.pid = pid;
306 lock.context.tid = tid;
310 lock.lock_type = lock_type;
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;
322 if (lock.start == 0 && lock.size == 0 &&
323 locks[i].size == 0) {
330 /* no conflicts - add it to the list of locks */
331 tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
333 status = NT_STATUS_NO_MEMORY;
338 memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
339 dbuf.dsize += sizeof(lock);
342 /* sort the lock list */
343 qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare);
346 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
348 SAFE_FREE(dbuf.dptr);
349 tdb_chainunlock(tdb, kbuf);
353 SAFE_FREE(dbuf.dptr);
354 tdb_chainunlock(tdb, kbuf);
358 /****************************************************************************
359 Unlock a range of bytes.
360 ****************************************************************************/
362 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
363 uint16 smbpid, pid_t pid, uint16 tid,
364 br_off start, br_off size)
368 struct lock_struct *locks;
369 struct lock_context context;
371 kbuf = locking_key(dev,ino);
375 tdb_chainlock(tdb, kbuf);
376 dbuf = tdb_fetch(tdb, kbuf);
379 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
383 context.smbpid = smbpid;
387 /* there are existing locks - find a match */
388 locks = (struct lock_struct *)dbuf.dptr;
389 count = dbuf.dsize / sizeof(*locks);
392 for (i=0; i<count; i++) {
393 struct lock_struct *lock = &locks[i];
395 if (lock->lock_type == WRITE_LOCK &&
396 brl_same_context(&lock->context, &context) &&
397 lock->fnum == fnum &&
398 lock->start == start &&
399 lock->size == size) {
400 /* found it - delete it */
402 tdb_delete(tdb, kbuf);
405 memmove(&locks[i], &locks[i+1],
406 sizeof(*locks)*((count-1) - i));
408 dbuf.dsize -= sizeof(*locks);
409 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
412 SAFE_FREE(dbuf.dptr);
413 tdb_chainunlock(tdb, kbuf);
419 locks = (struct lock_struct *)dbuf.dptr;
420 count = dbuf.dsize / sizeof(*locks);
421 for (i=0; i<count; i++) {
422 struct lock_struct *lock = &locks[i];
424 if (brl_same_context(&lock->context, &context) &&
425 lock->fnum == fnum &&
426 lock->start == start &&
427 lock->size == size) {
428 /* found it - delete it */
430 tdb_delete(tdb, kbuf);
433 memmove(&locks[i], &locks[i+1],
434 sizeof(*locks)*((count-1) - i));
436 dbuf.dsize -= sizeof(*locks);
437 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
440 SAFE_FREE(dbuf.dptr);
441 tdb_chainunlock(tdb, kbuf);
446 /* we didn't find it */
449 SAFE_FREE(dbuf.dptr);
450 tdb_chainunlock(tdb, kbuf);
455 /****************************************************************************
456 Test if we could add a lock if we wanted to.
457 ****************************************************************************/
459 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
460 uint16 smbpid, pid_t pid, uint16 tid,
461 br_off start, br_off size,
462 enum brl_type lock_type, int check_self)
466 struct lock_struct lock, *locks;
468 kbuf = locking_key(dev,ino);
472 tdb_chainlock(tdb, kbuf);
473 dbuf = tdb_fetch(tdb, kbuf);
475 lock.context.smbpid = smbpid;
476 lock.context.pid = pid;
477 lock.context.tid = tid;
481 lock.lock_type = lock_type;
484 /* there are existing locks - make sure they don't conflict */
485 locks = (struct lock_struct *)dbuf.dptr;
486 count = dbuf.dsize / sizeof(*locks);
487 for (i=0; i<count; i++) {
489 if (brl_conflict(&locks[i], &lock))
493 * Our own locks don't conflict.
495 if (brl_conflict_other(&locks[i], &lock))
501 /* no conflicts - we could have added it */
502 SAFE_FREE(dbuf.dptr);
503 tdb_chainunlock(tdb, kbuf);
507 SAFE_FREE(dbuf.dptr);
508 tdb_chainunlock(tdb, kbuf);
512 /****************************************************************************
513 Remove any locks associated with a open file.
514 ****************************************************************************/
516 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
519 int count, i, dcount=0;
520 struct lock_struct *locks;
522 kbuf = locking_key(dev,ino);
526 tdb_chainlock(tdb, kbuf);
527 dbuf = tdb_fetch(tdb, kbuf);
529 if (!dbuf.dptr) goto fail;
531 /* there are existing locks - remove any for this fnum */
532 locks = (struct lock_struct *)dbuf.dptr;
533 count = dbuf.dsize / sizeof(*locks);
534 for (i=0; i<count; i++) {
535 struct lock_struct *lock = &locks[i];
537 if (lock->context.tid == tid &&
538 lock->context.pid == pid &&
539 lock->fnum == fnum) {
540 /* found it - delete it */
541 if (count > 1 && i < count-1) {
542 memmove(&locks[i], &locks[i+1],
543 sizeof(*locks)*((count-1) - i));
552 tdb_delete(tdb, kbuf);
553 } else if (count < (dbuf.dsize / sizeof(*locks))) {
554 dbuf.dsize -= dcount * sizeof(*locks);
555 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
558 /* we didn't find it */
560 SAFE_FREE(dbuf.dptr);
561 tdb_chainunlock(tdb, kbuf);
564 /****************************************************************************
565 Traverse the whole database with this function, calling traverse_callback
567 ****************************************************************************/
569 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
571 struct lock_struct *locks;
572 struct lock_key *key;
575 BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
577 locks = (struct lock_struct *)dbuf.dptr;
578 key = (struct lock_key *)kbuf.dptr;
580 for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
581 traverse_callback(key->device, key->inode,
582 locks[i].context.pid,
590 /*******************************************************************
591 Call the specified function on each lock in the database.
592 ********************************************************************/
594 int brl_forall(BRLOCK_FN(fn))
597 return tdb_traverse(tdb, traverse_fn, (void *)fn);