this is a big global fix for the ptr = Realloc(ptr, size) bug.
[Samba.git] / source3 / locking / brlock.c
blobd22297a948817f09a1d03698893c4198528291a5
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
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 */
29 #include "includes.h"
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
35 this client */
37 struct lock_context {
38 uint16 smbpid;
39 uint16 tid;
40 pid_t pid;
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
45 size of the record */
47 struct lock_struct {
48 struct lock_context context;
49 br_off start;
50 br_off size;
51 int fnum;
52 enum brl_type lock_type;
55 /* The key used in the brlock database. */
57 struct lock_key {
58 SMB_DEV_T device;
59 SMB_INO_T inode;
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;
73 TDB_DATA kbuf;
75 memset(&key, '\0', sizeof(key));
76 key.device = dev;
77 key.inode = inode;
78 kbuf.dptr = (char *)&key;
79 kbuf.dsize = sizeof(key);
80 return kbuf;
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)
103 return False;
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;
111 return True;
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;
123 int count, i;
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 ));
144 continue;
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));
154 count--;
155 i--;
158 if (count == 0) {
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);
166 return 0;
169 /****************************************************************************
170 Open up the brlock.tdb database.
171 ****************************************************************************/
173 void brl_init(int read_only)
175 BOOL check_self = False;
177 if (tdb)
178 return;
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);
181 if (!tdb) {
182 DEBUG(0,("Failed to open byte range locking database\n"));
183 return;
186 /* delete any dead locks */
187 if (!read_only)
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;
199 if (!tdb)
200 return;
202 /* delete any dead locks */
203 if (!read_only)
204 tdb_traverse(tdb, delete_fn, &check_self);
206 tdb_close(tdb);
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)
218 TDB_DATA kbuf, dbuf;
219 int count, i;
220 struct lock_struct lock, *locks;
221 char *tp;
223 kbuf = locking_key(dev,ino);
225 dbuf.dptr = NULL;
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;
233 lock.start = start;
234 lock.size = size;
235 lock.fnum = fnum;
236 lock.lock_type = lock_type;
238 if (dbuf.dptr) {
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)) {
244 goto fail;
249 /* no conflicts - add it to the list of locks */
250 tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
251 if (!tp) goto fail;
252 else dbuf.dptr = tp;
253 memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
254 dbuf.dsize += sizeof(lock);
255 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
257 free(dbuf.dptr);
258 tdb_chainunlock(tdb, kbuf);
259 return True;
261 fail:
262 if (dbuf.dptr) free(dbuf.dptr);
263 tdb_chainunlock(tdb, kbuf);
264 return False;
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)
275 TDB_DATA kbuf, dbuf;
276 int count, i;
277 struct lock_struct *locks;
278 struct lock_context context;
280 kbuf = locking_key(dev,ino);
282 dbuf.dptr = NULL;
284 tdb_chainlock(tdb, kbuf);
285 dbuf = tdb_fetch(tdb, kbuf);
287 if (!dbuf.dptr) {
288 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
289 goto fail;
292 context.smbpid = smbpid;
293 context.pid = pid;
294 context.tid = tid;
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];
303 #if 0
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 ));
312 /* JRATEST */
313 #endif
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 */
320 if (count == 1) {
321 tdb_delete(tdb, kbuf);
322 } else {
323 if (i < count-1) {
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);
331 free(dbuf.dptr);
332 tdb_chainunlock(tdb, kbuf);
333 return True;
337 /* we didn't find it */
339 fail:
340 if (dbuf.dptr) free(dbuf.dptr);
341 tdb_chainunlock(tdb, kbuf);
342 return False;
345 /****************************************************************************
346 Check to see if this lock conflicts, but ignore our own locks on the
347 same fnum only.
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)
353 return False;
355 if (brl_same_context(&lck1->context, &lck2->context) &&
356 lck1->fnum == lck2->fnum)
357 return False;
359 if (lck1->start >= (lck2->start + lck2->size) ||
360 lck2->start >= (lck1->start + lck1->size)) return False;
362 return True;
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)
374 TDB_DATA kbuf, dbuf;
375 int count, i;
376 struct lock_struct lock, *locks;
378 kbuf = locking_key(dev,ino);
380 dbuf.dptr = NULL;
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;
388 lock.start = start;
389 lock.size = size;
390 lock.fnum = fnum;
391 lock.lock_type = lock_type;
393 if (dbuf.dptr) {
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++) {
398 if (check_self) {
399 if (brl_conflict(&locks[i], &lock))
400 goto fail;
401 } else {
403 * Our own locks don't conflict.
405 if (brl_conflict_other(&locks[i], &lock))
406 goto fail;
411 /* no conflicts - we could have added it */
412 free(dbuf.dptr);
413 tdb_chainunlock(tdb, kbuf);
414 return True;
416 fail:
417 if (dbuf.dptr) free(dbuf.dptr);
418 tdb_chainunlock(tdb, kbuf);
419 return False;
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)
428 TDB_DATA kbuf, dbuf;
429 int count, i, dcount=0;
430 struct lock_struct *locks;
432 kbuf = locking_key(dev,ino);
434 dbuf.dptr = NULL;
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));
455 count--;
456 i--;
457 dcount++;
461 if (count == 0) {
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 */
469 fail:
470 if (dbuf.dptr) free(dbuf.dptr);
471 tdb_chainunlock(tdb, kbuf);
474 /****************************************************************************
475 Traverse the whole database with this function, calling traverse_callback
476 on each lock.
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;
483 int i;
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,
493 locks[i].lock_type,
494 locks[i].start,
495 locks[i].size);
497 return 0;
500 /*******************************************************************
501 Call the specified function on each lock in the database.
502 ********************************************************************/
504 int brl_forall(BRLOCK_FN(fn))
506 if (!tdb) return 0;
507 return tdb_traverse(tdb, traverse_fn, (void *)fn);