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
117 ****************************************************************************/
118 static int delete_fn(TDB_CONTEXT
*ttdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
120 struct lock_struct
*locks
;
121 struct lock_key
*key
;
124 tdb_chainlock(tdb
, kbuf
);
126 locks
= (struct lock_struct
*)dbuf
.dptr
;
127 key
= (struct lock_key
*)kbuf
.dptr
;
129 count
= dbuf
.dsize
/ sizeof(*locks
);
130 for (i
=0; i
<count
; i
++) {
131 struct lock_struct
*lock
= &locks
[i
];
133 if (process_exists(lock
->context
.pid
)) continue;
135 if (count
> 1 && i
< count
-1) {
136 memmove(&locks
[i
], &locks
[i
+1],
137 sizeof(*locks
)*((count
-1) - i
));
144 tdb_delete(tdb
, kbuf
);
145 } else if (count
< (dbuf
.dsize
/ sizeof(*locks
))) {
146 dbuf
.dsize
= count
* sizeof(*locks
);
147 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
150 tdb_chainunlock(tdb
, kbuf
);
154 /****************************************************************************
155 Open up the brlock.tdb database.
156 ****************************************************************************/
157 void brl_init(int read_only
)
160 tdb
= tdb_open(lock_path("brlock.tdb"), 0, TDB_CLEAR_IF_FIRST
,
161 read_only
?O_RDONLY
:(O_RDWR
|O_CREAT
), 0644);
163 DEBUG(0,("Failed to open byte range locking database\n"));
167 /* delete any dead locks */
169 tdb_traverse(tdb
, delete_fn
, NULL
);
174 /****************************************************************************
175 Lock a range of bytes.
176 ****************************************************************************/
178 BOOL
brl_lock(SMB_DEV_T dev
, SMB_INO_T ino
, int fnum
,
179 uint16 smbpid
, pid_t pid
, uint16 tid
,
180 br_off start
, br_off size
,
181 enum brl_type lock_type
)
185 struct lock_struct lock
, *locks
;
187 kbuf
= locking_key(dev
,ino
);
191 tdb_chainlock(tdb
, kbuf
);
192 dbuf
= tdb_fetch(tdb
, kbuf
);
194 lock
.context
.smbpid
= smbpid
;
195 lock
.context
.pid
= pid
;
196 lock
.context
.tid
= tid
;
200 lock
.lock_type
= lock_type
;
203 /* there are existing locks - make sure they don't conflict */
204 locks
= (struct lock_struct
*)dbuf
.dptr
;
205 count
= dbuf
.dsize
/ sizeof(*locks
);
206 for (i
=0; i
<count
; i
++) {
207 if (brl_conflict(&locks
[i
], &lock
)) {
213 /* no conflicts - add it to the list of locks */
214 dbuf
.dptr
= Realloc(dbuf
.dptr
, dbuf
.dsize
+ sizeof(*locks
));
215 if (!dbuf
.dptr
) goto fail
;
216 memcpy(dbuf
.dptr
+ dbuf
.dsize
, &lock
, sizeof(lock
));
217 dbuf
.dsize
+= sizeof(lock
);
218 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
221 tdb_chainunlock(tdb
, kbuf
);
225 if (dbuf
.dptr
) free(dbuf
.dptr
);
226 tdb_chainunlock(tdb
, kbuf
);
230 /****************************************************************************
231 Unlock a range of bytes.
232 ****************************************************************************/
234 BOOL
brl_unlock(SMB_DEV_T dev
, SMB_INO_T ino
, int fnum
,
235 uint16 smbpid
, pid_t pid
, uint16 tid
,
236 br_off start
, br_off size
)
240 struct lock_struct
*locks
;
241 struct lock_context context
;
243 kbuf
= locking_key(dev
,ino
);
247 tdb_chainlock(tdb
, kbuf
);
248 dbuf
= tdb_fetch(tdb
, kbuf
);
251 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
255 context
.smbpid
= smbpid
;
259 /* there are existing locks - find a match */
260 locks
= (struct lock_struct
*)dbuf
.dptr
;
261 count
= dbuf
.dsize
/ sizeof(*locks
);
262 for (i
=0; i
<count
; i
++) {
264 struct lock_struct
*lock
= &locks
[i
];
267 /* JRATEST - DEBUGGING INFO */
268 if(!brl_same_context(&lock
->context
, &context
)) {
269 DEBUG(10,("brl_unlock: Not same context. l_smbpid = %u, l_pid = %u, l_tid = %u: \
270 smbpid = %u, pid = %u, tid = %u\n",
271 lock
->context
.smbpid
, lock
->context
.pid
, lock
->context
.tid
,
272 context
.smbpid
, context
.pid
, context
.tid
));
278 if (brl_same_context(&lock
->context
, &context
) &&
279 lock
->fnum
== fnum
&&
280 lock
->start
== start
&&
281 lock
->size
== size
) {
282 /* found it - delete it */
284 tdb_delete(tdb
, kbuf
);
287 memmove(&locks
[i
], &locks
[i
+1],
288 sizeof(*locks
)*((count
-1) - i
));
290 dbuf
.dsize
-= sizeof(*locks
);
291 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
295 tdb_chainunlock(tdb
, kbuf
);
300 /* we didn't find it */
303 if (dbuf
.dptr
) free(dbuf
.dptr
);
304 tdb_chainunlock(tdb
, kbuf
);
308 /****************************************************************************
309 Test if we could add a lock if we wanted to.
310 ****************************************************************************/
312 BOOL
brl_locktest(SMB_DEV_T dev
, SMB_INO_T ino
, int fnum
,
313 uint16 smbpid
, pid_t pid
, uint16 tid
,
314 br_off start
, br_off size
,
315 enum brl_type lock_type
)
319 struct lock_struct lock
, *locks
;
321 kbuf
= locking_key(dev
,ino
);
325 tdb_chainlock(tdb
, kbuf
);
326 dbuf
= tdb_fetch(tdb
, kbuf
);
328 lock
.context
.smbpid
= smbpid
;
329 lock
.context
.pid
= pid
;
330 lock
.context
.tid
= tid
;
334 lock
.lock_type
= lock_type
;
337 /* there are existing locks - make sure they don't conflict */
338 locks
= (struct lock_struct
*)dbuf
.dptr
;
339 count
= dbuf
.dsize
/ sizeof(*locks
);
340 for (i
=0; i
<count
; i
++) {
341 if (brl_conflict(&locks
[i
], &lock
)) {
347 /* no conflicts - we could have added it */
349 tdb_chainunlock(tdb
, kbuf
);
353 if (dbuf
.dptr
) free(dbuf
.dptr
);
354 tdb_chainunlock(tdb
, kbuf
);
358 /****************************************************************************
359 Remove any locks associated with a open file.
360 ****************************************************************************/
362 void brl_close(SMB_DEV_T dev
, SMB_INO_T ino
, pid_t pid
, int tid
, int fnum
)
365 int count
, i
, dcount
=0;
366 struct lock_struct
*locks
;
368 kbuf
= locking_key(dev
,ino
);
372 tdb_chainlock(tdb
, kbuf
);
373 dbuf
= tdb_fetch(tdb
, kbuf
);
375 if (!dbuf
.dptr
) goto fail
;
377 /* there are existing locks - remove any for this fnum */
378 locks
= (struct lock_struct
*)dbuf
.dptr
;
379 count
= dbuf
.dsize
/ sizeof(*locks
);
380 for (i
=0; i
<count
; i
++) {
381 struct lock_struct
*lock
= &locks
[i
];
383 if (lock
->context
.tid
== tid
&&
384 lock
->context
.pid
== pid
&&
385 lock
->fnum
== fnum
) {
386 /* found it - delete it */
387 if (count
> 1 && i
< count
-1) {
388 memmove(&locks
[i
], &locks
[i
+1],
389 sizeof(*locks
)*((count
-1) - i
));
398 tdb_delete(tdb
, kbuf
);
399 } else if (count
< (dbuf
.dsize
/ sizeof(*locks
))) {
400 dbuf
.dsize
-= dcount
* sizeof(*locks
);
401 tdb_store(tdb
, kbuf
, dbuf
, TDB_REPLACE
);
404 /* we didn't find it */
406 if (dbuf
.dptr
) free(dbuf
.dptr
);
407 tdb_chainunlock(tdb
, kbuf
);
410 /****************************************************************************
411 Traverse the whole database with this function, calling traverse_callback
413 ****************************************************************************/
415 static int traverse_fn(TDB_CONTEXT
*ttdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
417 struct lock_struct
*locks
;
418 struct lock_key
*key
;
421 BRLOCK_FN(traverse_callback
) = (BRLOCK_FN_CAST())state
;
423 locks
= (struct lock_struct
*)dbuf
.dptr
;
424 key
= (struct lock_key
*)kbuf
.dptr
;
426 for (i
=0;i
<dbuf
.dsize
/sizeof(*locks
);i
++) {
427 traverse_callback(key
->device
, key
->inode
,
428 locks
[i
].context
.pid
,
436 /*******************************************************************
437 Call the specified function on each lock in the database.
438 ********************************************************************/
440 int brl_forall(BRLOCK_FN(fn
))
443 return tdb_traverse(tdb
, traverse_fn
, (void *)fn
);