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 */
31 extern int DEBUGLEVEL;
35 /* This contains elements that differentiate locks. The smbpid is a
36 client supplied pid, and is essentially the locking context for
45 /* The data in brlock records is an unsorted linear array of these
46 records. It is unnecessary to store the count as tdb provides the
50 struct lock_context context;
54 enum brl_type lock_type;
57 /* The key used in the brlock database. */
64 /* The open brlock.tdb database. */
66 static TDB_CONTEXT *tdb;
68 /****************************************************************************
69 Create a locking key - ensuring zero filled for pad purposes.
70 ****************************************************************************/
72 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
74 static struct lock_key key;
77 memset(&key, '\0', sizeof(key));
80 kbuf.dptr = (char *)&key;
81 kbuf.dsize = sizeof(key);
85 /****************************************************************************
86 See if two locking contexts are equal.
87 ****************************************************************************/
89 static BOOL brl_same_context(struct lock_context *ctx1,
90 struct lock_context *ctx2)
92 return (ctx1->pid == ctx2->pid) &&
93 (ctx1->smbpid == ctx2->smbpid) &&
94 (ctx1->tid == ctx2->tid);
97 /****************************************************************************
98 See if lock2 can be added when lock1 is in place.
99 ****************************************************************************/
101 static BOOL brl_conflict(struct lock_struct *lck1,
102 struct lock_struct *lck2)
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 == READ_LOCK && lck2->lock_type == READ_LOCK) {
129 if (brl_same_context(&lck1->context, &lck2->context) &&
130 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
134 if (lck2->start == 0 && lck2->size == 0 && lck1->size != 0) {
138 if (lck1->start >= (lck2->start + lck2->size) ||
139 lck2->start >= (lck1->start + lck1->size)) {
147 /****************************************************************************
148 Check to see if this lock conflicts, but ignore our own locks on the
150 ****************************************************************************/
152 static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
154 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
157 if (brl_same_context(&lck1->context, &lck2->context) &&
158 lck1->fnum == lck2->fnum)
161 if (lck1->start >= (lck2->start + lck2->size) ||
162 lck2->start >= (lck1->start + lck1->size)) return False;
168 /****************************************************************************
169 Delete a record if it is for a dead process, if check_self is true, then
170 delete any records belonging to this pid also (there shouldn't be any).
171 ****************************************************************************/
173 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
175 struct lock_struct *locks;
177 BOOL check_self = *(BOOL *)state;
178 pid_t mypid = sys_getpid();
180 tdb_chainlock(tdb, kbuf);
182 locks = (struct lock_struct *)dbuf.dptr;
184 count = dbuf.dsize / sizeof(*locks);
185 for (i=0; i<count; i++) {
186 struct lock_struct *lock = &locks[i];
188 /* If check_self is true we want to remove our own records. */
189 if (check_self && (mypid == lock->context.pid)) {
191 DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
192 (unsigned int)lock->context.pid ));
194 } else if (process_exists(lock->context.pid)) {
196 DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid ));
200 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
201 (unsigned int)lock->context.pid ));
203 if (count > 1 && i < count-1) {
204 memmove(&locks[i], &locks[i+1],
205 sizeof(*locks)*((count-1) - i));
212 tdb_delete(tdb, kbuf);
213 } else if (count < (dbuf.dsize / sizeof(*locks))) {
214 dbuf.dsize = count * sizeof(*locks);
215 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
218 tdb_chainunlock(tdb, kbuf);
222 /****************************************************************************
223 Open up the brlock.tdb database.
224 ****************************************************************************/
226 void brl_init(int read_only)
228 BOOL check_self = False;
232 tdb = tdb_open_log(lock_path("brlock.tdb"), 0, TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
233 read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
235 DEBUG(0,("Failed to open byte range locking database\n"));
239 /* delete any dead locks */
241 tdb_traverse(tdb, delete_fn, &check_self);
244 /****************************************************************************
245 Close down the brlock.tdb database.
246 ****************************************************************************/
248 void brl_shutdown(int read_only)
250 BOOL check_self = True;
255 /* delete any dead locks */
257 tdb_traverse(tdb, delete_fn, &check_self);
263 /****************************************************************************
264 compare two locks for sorting
265 ****************************************************************************/
266 static int lock_compare(struct lock_struct *lck1,
267 struct lock_struct *lck2)
269 if (lck1->start != lck2->start) return (lck1->start - lck2->start);
270 if (lck2->size != lck1->size) {
271 return ((int)lck1->size - (int)lck2->size);
277 /****************************************************************************
278 Lock a range of bytes.
279 ****************************************************************************/
281 NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
282 uint16 smbpid, pid_t pid, uint16 tid,
283 br_off start, br_off size,
284 enum brl_type lock_type)
288 struct lock_struct lock, *locks;
290 NTSTATUS status = NT_STATUS_OK;
292 kbuf = locking_key(dev,ino);
297 if (start == 0 && size == 0) {
298 DEBUG(0,("client sent 0/0 lock - please report this\n"));
299 return NT_STATUS_INVALID_PARAMETER;
303 tdb_chainlock(tdb, kbuf);
304 dbuf = tdb_fetch(tdb, kbuf);
306 lock.context.smbpid = smbpid;
307 lock.context.pid = pid;
308 lock.context.tid = tid;
312 lock.lock_type = lock_type;
315 /* there are existing locks - make sure they don't conflict */
316 locks = (struct lock_struct *)dbuf.dptr;
317 count = dbuf.dsize / sizeof(*locks);
318 for (i=0; i<count; i++) {
319 if (brl_conflict(&locks[i], &lock)) {
320 status = NT_STATUS_LOCK_NOT_GRANTED;
324 if (lock.start == 0 && lock.size == 0 &&
325 locks[i].size == 0) {
332 /* no conflicts - add it to the list of locks */
333 tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
335 status = NT_STATUS_NO_MEMORY;
340 memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
341 dbuf.dsize += sizeof(lock);
344 /* sort the lock list */
345 qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare);
348 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
351 tdb_chainunlock(tdb, kbuf);
355 if (dbuf.dptr) free(dbuf.dptr);
356 tdb_chainunlock(tdb, kbuf);
360 /****************************************************************************
361 Unlock a range of bytes.
362 ****************************************************************************/
364 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
365 uint16 smbpid, pid_t pid, uint16 tid,
366 br_off start, br_off size)
370 struct lock_struct *locks;
371 struct lock_context context;
373 kbuf = locking_key(dev,ino);
377 tdb_chainlock(tdb, kbuf);
378 dbuf = tdb_fetch(tdb, kbuf);
381 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
385 context.smbpid = smbpid;
389 /* there are existing locks - find a match */
390 locks = (struct lock_struct *)dbuf.dptr;
391 count = dbuf.dsize / sizeof(*locks);
394 for (i=0; i<count; i++) {
395 struct lock_struct *lock = &locks[i];
397 if (lock->lock_type == WRITE_LOCK &&
398 brl_same_context(&lock->context, &context) &&
399 lock->fnum == fnum &&
400 lock->start == start &&
401 lock->size == size) {
402 /* found it - delete it */
404 tdb_delete(tdb, kbuf);
407 memmove(&locks[i], &locks[i+1],
408 sizeof(*locks)*((count-1) - i));
410 dbuf.dsize -= sizeof(*locks);
411 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
415 tdb_chainunlock(tdb, kbuf);
421 locks = (struct lock_struct *)dbuf.dptr;
422 count = dbuf.dsize / sizeof(*locks);
423 for (i=0; i<count; i++) {
424 struct lock_struct *lock = &locks[i];
426 if (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);
443 tdb_chainunlock(tdb, kbuf);
448 /* we didn't find it */
451 if (dbuf.dptr) free(dbuf.dptr);
452 tdb_chainunlock(tdb, kbuf);
457 /****************************************************************************
458 Test if we could add a lock if we wanted to.
459 ****************************************************************************/
461 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
462 uint16 smbpid, pid_t pid, uint16 tid,
463 br_off start, br_off size,
464 enum brl_type lock_type, int check_self)
468 struct lock_struct lock, *locks;
470 kbuf = locking_key(dev,ino);
474 tdb_chainlock(tdb, kbuf);
475 dbuf = tdb_fetch(tdb, kbuf);
477 lock.context.smbpid = smbpid;
478 lock.context.pid = pid;
479 lock.context.tid = tid;
483 lock.lock_type = lock_type;
486 /* there are existing locks - make sure they don't conflict */
487 locks = (struct lock_struct *)dbuf.dptr;
488 count = dbuf.dsize / sizeof(*locks);
489 for (i=0; i<count; i++) {
491 if (brl_conflict(&locks[i], &lock))
495 * Our own locks don't conflict.
497 if (brl_conflict_other(&locks[i], &lock))
503 /* no conflicts - we could have added it */
505 tdb_chainunlock(tdb, kbuf);
509 if (dbuf.dptr) free(dbuf.dptr);
510 tdb_chainunlock(tdb, kbuf);
514 /****************************************************************************
515 Remove any locks associated with a open file.
516 ****************************************************************************/
518 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
521 int count, i, dcount=0;
522 struct lock_struct *locks;
524 kbuf = locking_key(dev,ino);
528 tdb_chainlock(tdb, kbuf);
529 dbuf = tdb_fetch(tdb, kbuf);
531 if (!dbuf.dptr) goto fail;
533 /* there are existing locks - remove any for this fnum */
534 locks = (struct lock_struct *)dbuf.dptr;
535 count = dbuf.dsize / sizeof(*locks);
536 for (i=0; i<count; i++) {
537 struct lock_struct *lock = &locks[i];
539 if (lock->context.tid == tid &&
540 lock->context.pid == pid &&
541 lock->fnum == fnum) {
542 /* found it - delete it */
543 if (count > 1 && i < count-1) {
544 memmove(&locks[i], &locks[i+1],
545 sizeof(*locks)*((count-1) - i));
554 tdb_delete(tdb, kbuf);
555 } else if (count < (dbuf.dsize / sizeof(*locks))) {
556 dbuf.dsize -= dcount * sizeof(*locks);
557 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
560 /* we didn't find it */
562 if (dbuf.dptr) free(dbuf.dptr);
563 tdb_chainunlock(tdb, kbuf);
566 /****************************************************************************
567 Traverse the whole database with this function, calling traverse_callback
569 ****************************************************************************/
571 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
573 struct lock_struct *locks;
574 struct lock_key *key;
577 BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
579 locks = (struct lock_struct *)dbuf.dptr;
580 key = (struct lock_key *)kbuf.dptr;
582 for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
583 traverse_callback(key->device, key->inode,
584 locks[i].context.pid,
592 /*******************************************************************
593 Call the specified function on each lock in the database.
594 ********************************************************************/
596 int brl_forall(BRLOCK_FN(fn))
599 return tdb_traverse(tdb, traverse_fn, (void *)fn);