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
;
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
)
105 if (brl_same_context(&lck1
->context
, &lck2
->context
) &&
106 lck2
->lock_type
== READ_LOCK
&& lck1
->fnum
== lck2
->fnum
) return False
;
108 if (lck1
->start
>= (lck2
->start
+ lck2
->size
) ||
109 lck2
->start
>= (lck1
->start
+ lck1
->size
)) return False
;
115 /****************************************************************************
116 Delete a record if it is for a dead process, if check_self is true, then
117 delete any records belonging to this pid also (there shouldn't be any).
118 ****************************************************************************/
120 static int delete_fn(TDB_CONTEXT
*ttdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
122 struct lock_struct
*locks
;
124 BOOL check_self
= *(BOOL
*)state
;
125 pid_t mypid
= sys_getpid();
127 tdb_chainlock(tdb
, kbuf
);
129 locks
= (struct lock_struct
*)dbuf
.dptr
;
131 count
= dbuf
.dsize
/ sizeof(*locks
);
132 for (i
=0; i
<count
; i
++) {
133 struct lock_struct
*lock
= &locks
[i
];
135 /* If check_self is true we want to remove our own records. */
136 if (check_self
&& (mypid
== lock
->context
.pid
)) {
138 DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
139 (unsigned int)lock
->context
.pid
));
141 } else if (process_exists(lock
->context
.pid
)) {
143 DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock
->context
.pid
));
147 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
148 (unsigned int)lock
->context
.pid
));
150 if (count
> 1 && i
< count
-1) {
151 memmove(&locks
[i
], &locks
[i
+1],
152 sizeof(*locks
)*((count
-1) - i
));
159 tdb_delete(tdb
, kbuf
);
160 } else if (count
< (dbuf
.dsize
/ sizeof(*locks
))) {
161 dbuf
.dsize
= count
* sizeof(*locks
);
162 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
165 tdb_chainunlock(tdb
, kbuf
);
169 /****************************************************************************
170 Open up the brlock.tdb database.
171 ****************************************************************************/
173 void brl_init(int read_only
)
175 BOOL check_self
= False
;
179 tdb
= tdb_open_log(lock_path("brlock.tdb"), 0, TDB_CLEAR_IF_FIRST
|USE_TDB_MMAP_FLAG
,
180 read_only
?O_RDONLY
:(O_RDWR
|O_CREAT
), 0644);
182 DEBUG(0,("Failed to open byte range locking database\n"));
186 /* delete any dead locks */
188 tdb_traverse(tdb
, delete_fn
, &check_self
);
191 /****************************************************************************
192 Close down the brlock.tdb database.
193 ****************************************************************************/
195 void brl_shutdown(int read_only
)
197 BOOL check_self
= True
;
202 /* delete any dead locks */
204 tdb_traverse(tdb
, delete_fn
, &check_self
);
209 /****************************************************************************
210 Lock a range of bytes.
211 ****************************************************************************/
213 BOOL
brl_lock(SMB_DEV_T dev
, SMB_INO_T ino
, int fnum
,
214 uint16 smbpid
, pid_t pid
, uint16 tid
,
215 br_off start
, br_off size
,
216 enum brl_type lock_type
)
220 struct lock_struct lock
, *locks
;
223 kbuf
= locking_key(dev
,ino
);
227 tdb_chainlock(tdb
, kbuf
);
228 dbuf
= tdb_fetch(tdb
, kbuf
);
230 lock
.context
.smbpid
= smbpid
;
231 lock
.context
.pid
= pid
;
232 lock
.context
.tid
= tid
;
236 lock
.lock_type
= lock_type
;
239 /* there are existing locks - make sure they don't conflict */
240 locks
= (struct lock_struct
*)dbuf
.dptr
;
241 count
= dbuf
.dsize
/ sizeof(*locks
);
242 for (i
=0; i
<count
; i
++) {
243 if (brl_conflict(&locks
[i
], &lock
)) {
249 /* no conflicts - add it to the list of locks */
250 tp
= Realloc(dbuf
.dptr
, dbuf
.dsize
+ sizeof(*locks
));
253 memcpy(dbuf
.dptr
+ dbuf
.dsize
, &lock
, sizeof(lock
));
254 dbuf
.dsize
+= sizeof(lock
);
255 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
258 tdb_chainunlock(tdb
, kbuf
);
262 if (dbuf
.dptr
) free(dbuf
.dptr
);
263 tdb_chainunlock(tdb
, kbuf
);
267 /****************************************************************************
268 Unlock a range of bytes.
269 ****************************************************************************/
271 BOOL
brl_unlock(SMB_DEV_T dev
, SMB_INO_T ino
, int fnum
,
272 uint16 smbpid
, pid_t pid
, uint16 tid
,
273 br_off start
, br_off size
)
277 struct lock_struct
*locks
;
278 struct lock_context context
;
280 kbuf
= locking_key(dev
,ino
);
284 tdb_chainlock(tdb
, kbuf
);
285 dbuf
= tdb_fetch(tdb
, kbuf
);
288 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
292 context
.smbpid
= smbpid
;
296 /* there are existing locks - find a match */
297 locks
= (struct lock_struct
*)dbuf
.dptr
;
298 count
= dbuf
.dsize
/ sizeof(*locks
);
299 for (i
=0; i
<count
; i
++) {
301 struct lock_struct
*lock
= &locks
[i
];
304 /* JRATEST - DEBUGGING INFO */
305 if(!brl_same_context(&lock
->context
, &context
)) {
306 DEBUG(10,("brl_unlock: Not same context. l_smbpid = %u, l_pid = %u, l_tid = %u: \
307 smbpid = %u, pid = %u, tid = %u\n",
308 lock
->context
.smbpid
, lock
->context
.pid
, lock
->context
.tid
,
309 context
.smbpid
, context
.pid
, context
.tid
));
315 if (brl_same_context(&lock
->context
, &context
) &&
316 lock
->fnum
== fnum
&&
317 lock
->start
== start
&&
318 lock
->size
== size
) {
319 /* found it - delete it */
321 tdb_delete(tdb
, kbuf
);
324 memmove(&locks
[i
], &locks
[i
+1],
325 sizeof(*locks
)*((count
-1) - i
));
327 dbuf
.dsize
-= sizeof(*locks
);
328 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
332 tdb_chainunlock(tdb
, kbuf
);
337 /* we didn't find it */
340 if (dbuf
.dptr
) free(dbuf
.dptr
);
341 tdb_chainunlock(tdb
, kbuf
);
345 /****************************************************************************
346 Check to see if this lock conflicts, but ignore our own locks on the
348 ****************************************************************************/
350 static BOOL
brl_conflict_other(struct lock_struct
*lck1
, struct lock_struct
*lck2
)
352 if (lck1
->lock_type
== READ_LOCK
&& lck2
->lock_type
== READ_LOCK
)
355 if (brl_same_context(&lck1
->context
, &lck2
->context
) &&
356 lck1
->fnum
== lck2
->fnum
)
359 if (lck1
->start
>= (lck2
->start
+ lck2
->size
) ||
360 lck2
->start
>= (lck1
->start
+ lck1
->size
)) return False
;
365 /****************************************************************************
366 Test if we could add a lock if we wanted to.
367 ****************************************************************************/
369 BOOL
brl_locktest(SMB_DEV_T dev
, SMB_INO_T ino
, int fnum
,
370 uint16 smbpid
, pid_t pid
, uint16 tid
,
371 br_off start
, br_off size
,
372 enum brl_type lock_type
, int check_self
)
376 struct lock_struct lock
, *locks
;
378 kbuf
= locking_key(dev
,ino
);
382 tdb_chainlock(tdb
, kbuf
);
383 dbuf
= tdb_fetch(tdb
, kbuf
);
385 lock
.context
.smbpid
= smbpid
;
386 lock
.context
.pid
= pid
;
387 lock
.context
.tid
= tid
;
391 lock
.lock_type
= lock_type
;
394 /* there are existing locks - make sure they don't conflict */
395 locks
= (struct lock_struct
*)dbuf
.dptr
;
396 count
= dbuf
.dsize
/ sizeof(*locks
);
397 for (i
=0; i
<count
; i
++) {
399 if (brl_conflict(&locks
[i
], &lock
))
403 * Our own locks don't conflict.
405 if (brl_conflict_other(&locks
[i
], &lock
))
411 /* no conflicts - we could have added it */
413 tdb_chainunlock(tdb
, kbuf
);
417 if (dbuf
.dptr
) free(dbuf
.dptr
);
418 tdb_chainunlock(tdb
, kbuf
);
422 /****************************************************************************
423 Remove any locks associated with a open file.
424 ****************************************************************************/
426 void brl_close(SMB_DEV_T dev
, SMB_INO_T ino
, pid_t pid
, int tid
, int fnum
)
429 int count
, i
, dcount
=0;
430 struct lock_struct
*locks
;
432 kbuf
= locking_key(dev
,ino
);
436 tdb_chainlock(tdb
, kbuf
);
437 dbuf
= tdb_fetch(tdb
, kbuf
);
439 if (!dbuf
.dptr
) goto fail
;
441 /* there are existing locks - remove any for this fnum */
442 locks
= (struct lock_struct
*)dbuf
.dptr
;
443 count
= dbuf
.dsize
/ sizeof(*locks
);
444 for (i
=0; i
<count
; i
++) {
445 struct lock_struct
*lock
= &locks
[i
];
447 if (lock
->context
.tid
== tid
&&
448 lock
->context
.pid
== pid
&&
449 lock
->fnum
== fnum
) {
450 /* found it - delete it */
451 if (count
> 1 && i
< count
-1) {
452 memmove(&locks
[i
], &locks
[i
+1],
453 sizeof(*locks
)*((count
-1) - i
));
462 tdb_delete(tdb
, kbuf
);
463 } else if (count
< (dbuf
.dsize
/ sizeof(*locks
))) {
464 dbuf
.dsize
-= dcount
* sizeof(*locks
);
465 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
468 /* we didn't find it */
470 if (dbuf
.dptr
) free(dbuf
.dptr
);
471 tdb_chainunlock(tdb
, kbuf
);
474 /****************************************************************************
475 Traverse the whole database with this function, calling traverse_callback
477 ****************************************************************************/
479 static int traverse_fn(TDB_CONTEXT
*ttdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
481 struct lock_struct
*locks
;
482 struct lock_key
*key
;
485 BRLOCK_FN(traverse_callback
) = (BRLOCK_FN_CAST())state
;
487 locks
= (struct lock_struct
*)dbuf
.dptr
;
488 key
= (struct lock_key
*)kbuf
.dptr
;
490 for (i
=0;i
<dbuf
.dsize
/sizeof(*locks
);i
++) {
491 traverse_callback(key
->device
, key
->inode
,
492 locks
[i
].context
.pid
,
500 /*******************************************************************
501 Call the specified function on each lock in the database.
502 ********************************************************************/
504 int brl_forall(BRLOCK_FN(fn
))
507 return tdb_traverse(tdb
, traverse_fn
, (void *)fn
);