add another registry rpc (opnum 0x14). Have no idea what it's real name
[Samba.git] / source / locking / brlock.c
blob8c22f7d7ab2dc4f3508f3732c9981fa72b589bb4
1 /*
2 Unix SMB/CIFS implementation.
3 byte range locking code
4 Updated to handle range splits/merges.
6 Copyright (C) Andrew Tridgell 1992-2000
7 Copyright (C) Jeremy Allison 1992-2000
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* This module implements a tdb based byte range locking service,
25 replacing the fcntl() based byte range locking previously
26 used. This allows us to provide the same semantics as NT */
28 #include "includes.h"
30 #define ZERO_ZERO 0
32 /* This contains elements that differentiate locks. The smbpid is a
33 client supplied pid, and is essentially the locking context for
34 this client */
36 struct lock_context {
37 uint16 smbpid;
38 uint16 tid;
39 pid_t pid;
42 /* The data in brlock records is an unsorted linear array of these
43 records. It is unnecessary to store the count as tdb provides the
44 size of the record */
46 struct lock_struct {
47 struct lock_context context;
48 br_off start;
49 br_off size;
50 int fnum;
51 enum brl_type lock_type;
54 /* The key used in the brlock database. */
56 struct lock_key {
57 SMB_DEV_T device;
58 SMB_INO_T inode;
61 /* The open brlock.tdb database. */
63 static TDB_CONTEXT *tdb;
65 /****************************************************************************
66 Create a locking key - ensuring zero filled for pad purposes.
67 ****************************************************************************/
69 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
71 static struct lock_key key;
72 TDB_DATA kbuf;
74 memset(&key, '\0', sizeof(key));
75 key.device = dev;
76 key.inode = inode;
77 kbuf.dptr = (char *)&key;
78 kbuf.dsize = sizeof(key);
79 return kbuf;
82 /****************************************************************************
83 See if two locking contexts are equal.
84 ****************************************************************************/
86 static BOOL brl_same_context(struct lock_context *ctx1,
87 struct lock_context *ctx2)
89 return (ctx1->pid == ctx2->pid) &&
90 (ctx1->smbpid == ctx2->smbpid) &&
91 (ctx1->tid == ctx2->tid);
94 /****************************************************************************
95 See if lock2 can be added when lock1 is in place.
96 ****************************************************************************/
98 static BOOL brl_conflict(struct lock_struct *lck1,
99 struct lock_struct *lck2)
101 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
102 return False;
105 if (brl_same_context(&lck1->context, &lck2->context) &&
106 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
107 return False;
110 if (lck1->start >= (lck2->start + lck2->size) ||
111 lck2->start >= (lck1->start + lck1->size)) {
112 return False;
115 return True;
118 #if ZERO_ZERO
119 static BOOL brl_conflict1(struct lock_struct *lck1,
120 struct lock_struct *lck2)
122 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
123 return False;
126 if (brl_same_context(&lck1->context, &lck2->context) &&
127 lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
128 return False;
131 if (lck2->start == 0 && lck2->size == 0 && lck1->size != 0) {
132 return True;
135 if (lck1->start >= (lck2->start + lck2->size) ||
136 lck2->start >= (lck1->start + lck1->size)) {
137 return False;
140 return True;
142 #endif
144 /****************************************************************************
145 Check to see if this lock conflicts, but ignore our own locks on the
146 same fnum only.
147 ****************************************************************************/
149 static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
151 if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK)
152 return False;
154 if (brl_same_context(&lck1->context, &lck2->context) &&
155 lck1->fnum == lck2->fnum)
156 return False;
158 if (lck1->start >= (lck2->start + lck2->size) ||
159 lck2->start >= (lck1->start + lck1->size)) return False;
161 return True;
165 #if DONT_DO_THIS
166 /* doing this traversal could kill solaris machines under high load (tridge) */
167 /* delete any dead locks */
169 /****************************************************************************
170 Delete a record if it is for a dead process, if check_self is true, then
171 delete any records belonging to this pid also (there shouldn't be any).
172 ****************************************************************************/
174 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
176 struct lock_struct *locks;
177 int count, i;
178 BOOL check_self = *(BOOL *)state;
179 pid_t mypid = sys_getpid();
181 tdb_chainlock(tdb, kbuf);
183 locks = (struct lock_struct *)dbuf.dptr;
185 count = dbuf.dsize / sizeof(*locks);
186 for (i=0; i<count; i++) {
187 struct lock_struct *lock = &locks[i];
189 /* If check_self is true we want to remove our own records. */
190 if (check_self && (mypid == lock->context.pid)) {
192 DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
193 (unsigned int)lock->context.pid ));
195 } else if (process_exists(lock->context.pid)) {
197 DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid ));
198 continue;
201 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
202 (unsigned int)lock->context.pid ));
204 if (count > 1 && i < count-1) {
205 memmove(&locks[i], &locks[i+1],
206 sizeof(*locks)*((count-1) - i));
208 count--;
209 i--;
212 if (count == 0) {
213 tdb_delete(tdb, kbuf);
214 } else if (count < (dbuf.dsize / sizeof(*locks))) {
215 dbuf.dsize = count * sizeof(*locks);
216 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
219 tdb_chainunlock(tdb, kbuf);
220 return 0;
222 #endif
224 /****************************************************************************
225 Open up the brlock.tdb database.
226 ****************************************************************************/
228 void brl_init(int read_only)
230 if (tdb)
231 return;
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);
234 if (!tdb) {
235 DEBUG(0,("Failed to open byte range locking database\n"));
236 return;
239 #if DONT_DO_THIS
240 /* doing this traversal could kill solaris machines under high load (tridge) */
241 /* delete any dead locks */
242 if (!read_only) {
243 BOOL check_self = False;
244 tdb_traverse(tdb, delete_fn, &check_self);
246 #endif
249 /****************************************************************************
250 Close down the brlock.tdb database.
251 ****************************************************************************/
253 void brl_shutdown(int read_only)
255 if (!tdb)
256 return;
258 #if DONT_DO_THIS
259 /* doing this traversal could kill solaris machines under high load (tridge) */
260 /* delete any dead locks */
261 if (!read_only) {
262 BOOL check_self = True;
263 tdb_traverse(tdb, delete_fn, &check_self);
265 #endif
267 tdb_close(tdb);
270 #if ZERO_ZERO
271 /****************************************************************************
272 compare two locks for sorting
273 ****************************************************************************/
274 static int lock_compare(struct lock_struct *lck1,
275 struct lock_struct *lck2)
277 if (lck1->start != lck2->start) return (lck1->start - lck2->start);
278 if (lck2->size != lck1->size) {
279 return ((int)lck1->size - (int)lck2->size);
281 return 0;
283 #endif
285 /****************************************************************************
286 Lock a range of bytes.
287 ****************************************************************************/
289 NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
290 uint16 smbpid, pid_t pid, uint16 tid,
291 br_off start, br_off size,
292 enum brl_type lock_type)
294 TDB_DATA kbuf, dbuf;
295 int count, i;
296 struct lock_struct lock, *locks;
297 char *tp;
298 NTSTATUS status = NT_STATUS_OK;
299 static int last_failed = -1;
300 static br_off last_failed_start;
302 kbuf = locking_key(dev,ino);
304 dbuf.dptr = NULL;
306 #if !ZERO_ZERO
307 if (start == 0 && size == 0) {
308 DEBUG(0,("client sent 0/0 lock - please report this\n"));
310 #endif
312 tdb_chainlock(tdb, kbuf);
313 dbuf = tdb_fetch(tdb, kbuf);
315 lock.context.smbpid = smbpid;
316 lock.context.pid = pid;
317 lock.context.tid = tid;
318 lock.start = start;
319 lock.size = size;
320 lock.fnum = fnum;
321 lock.lock_type = lock_type;
323 if (dbuf.dptr) {
324 /* there are existing locks - make sure they don't conflict */
325 locks = (struct lock_struct *)dbuf.dptr;
326 count = dbuf.dsize / sizeof(*locks);
327 for (i=0; i<count; i++) {
328 if (brl_conflict(&locks[i], &lock)) {
329 status = NT_STATUS_LOCK_NOT_GRANTED;
330 goto fail;
332 #if ZERO_ZERO
333 if (lock.start == 0 && lock.size == 0 &&
334 locks[i].size == 0) {
335 break;
337 #endif
341 /* no conflicts - add it to the list of locks */
342 tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
343 if (!tp) {
344 status = NT_STATUS_NO_MEMORY;
345 goto fail;
346 } else {
347 dbuf.dptr = tp;
349 memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
350 dbuf.dsize += sizeof(lock);
352 #if ZERO_ZERO
353 /* sort the lock list */
354 qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare);
355 #endif
357 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
359 SAFE_FREE(dbuf.dptr);
360 tdb_chainunlock(tdb, kbuf);
361 return NT_STATUS_OK;
363 fail:
364 /* this is a nasty hack to try to simulate the lock result cache code in w2k.
365 It isn't completely accurate as I haven't yet worked out the correct
366 semantics (tridge)
368 if (last_failed == fnum &&
369 last_failed_start == start &&
370 NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
371 status = NT_STATUS_FILE_LOCK_CONFLICT;
373 last_failed = fnum;
374 last_failed_start = start;
376 SAFE_FREE(dbuf.dptr);
377 tdb_chainunlock(tdb, kbuf);
378 return status;
381 /****************************************************************************
382 Unlock a range of bytes.
383 ****************************************************************************/
385 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
386 uint16 smbpid, pid_t pid, uint16 tid,
387 br_off start, br_off size)
389 TDB_DATA kbuf, dbuf;
390 int count, i;
391 struct lock_struct *locks;
392 struct lock_context context;
394 kbuf = locking_key(dev,ino);
396 dbuf.dptr = NULL;
398 tdb_chainlock(tdb, kbuf);
399 dbuf = tdb_fetch(tdb, kbuf);
401 if (!dbuf.dptr) {
402 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
403 goto fail;
406 context.smbpid = smbpid;
407 context.pid = pid;
408 context.tid = tid;
410 /* there are existing locks - find a match */
411 locks = (struct lock_struct *)dbuf.dptr;
412 count = dbuf.dsize / sizeof(*locks);
414 #if ZERO_ZERO
415 for (i=0; i<count; i++) {
416 struct lock_struct *lock = &locks[i];
418 if (lock->lock_type == WRITE_LOCK &&
419 brl_same_context(&lock->context, &context) &&
420 lock->fnum == fnum &&
421 lock->start == start &&
422 lock->size == size) {
423 /* found it - delete it */
424 if (count == 1) {
425 tdb_delete(tdb, kbuf);
426 } else {
427 if (i < count-1) {
428 memmove(&locks[i], &locks[i+1],
429 sizeof(*locks)*((count-1) - i));
431 dbuf.dsize -= sizeof(*locks);
432 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
435 SAFE_FREE(dbuf.dptr);
436 tdb_chainunlock(tdb, kbuf);
437 return True;
440 #endif
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 (brl_same_context(&lock->context, &context) &&
448 lock->fnum == fnum &&
449 lock->start == start &&
450 lock->size == size) {
451 /* found it - delete it */
452 if (count == 1) {
453 tdb_delete(tdb, kbuf);
454 } else {
455 if (i < count-1) {
456 memmove(&locks[i], &locks[i+1],
457 sizeof(*locks)*((count-1) - i));
459 dbuf.dsize -= sizeof(*locks);
460 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
463 SAFE_FREE(dbuf.dptr);
464 tdb_chainunlock(tdb, kbuf);
465 return True;
469 /* we didn't find it */
471 fail:
472 SAFE_FREE(dbuf.dptr);
473 tdb_chainunlock(tdb, kbuf);
474 return False;
478 /****************************************************************************
479 Test if we could add a lock if we wanted to.
480 ****************************************************************************/
482 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
483 uint16 smbpid, pid_t pid, uint16 tid,
484 br_off start, br_off size,
485 enum brl_type lock_type, int check_self)
487 TDB_DATA kbuf, dbuf;
488 int count, i;
489 struct lock_struct lock, *locks;
491 kbuf = locking_key(dev,ino);
493 dbuf.dptr = NULL;
495 tdb_chainlock(tdb, kbuf);
496 dbuf = tdb_fetch(tdb, kbuf);
498 lock.context.smbpid = smbpid;
499 lock.context.pid = pid;
500 lock.context.tid = tid;
501 lock.start = start;
502 lock.size = size;
503 lock.fnum = fnum;
504 lock.lock_type = lock_type;
506 if (dbuf.dptr) {
507 /* there are existing locks - make sure they don't conflict */
508 locks = (struct lock_struct *)dbuf.dptr;
509 count = dbuf.dsize / sizeof(*locks);
510 for (i=0; i<count; i++) {
511 if (check_self) {
512 if (brl_conflict(&locks[i], &lock))
513 goto fail;
514 } else {
516 * Our own locks don't conflict.
518 if (brl_conflict_other(&locks[i], &lock))
519 goto fail;
524 /* no conflicts - we could have added it */
525 SAFE_FREE(dbuf.dptr);
526 tdb_chainunlock(tdb, kbuf);
527 return True;
529 fail:
530 SAFE_FREE(dbuf.dptr);
531 tdb_chainunlock(tdb, kbuf);
532 return False;
535 /****************************************************************************
536 Remove any locks associated with a open file.
537 ****************************************************************************/
539 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
541 TDB_DATA kbuf, dbuf;
542 int count, i, dcount=0;
543 struct lock_struct *locks;
545 kbuf = locking_key(dev,ino);
547 dbuf.dptr = NULL;
549 tdb_chainlock(tdb, kbuf);
550 dbuf = tdb_fetch(tdb, kbuf);
552 if (!dbuf.dptr) goto fail;
554 /* there are existing locks - remove any for this fnum */
555 locks = (struct lock_struct *)dbuf.dptr;
556 count = dbuf.dsize / sizeof(*locks);
557 for (i=0; i<count; i++) {
558 struct lock_struct *lock = &locks[i];
560 if (lock->context.tid == tid &&
561 lock->context.pid == pid &&
562 lock->fnum == fnum) {
563 /* found it - delete it */
564 if (count > 1 && i < count-1) {
565 memmove(&locks[i], &locks[i+1],
566 sizeof(*locks)*((count-1) - i));
568 count--;
569 i--;
570 dcount++;
574 if (count == 0) {
575 tdb_delete(tdb, kbuf);
576 } else if (count < (dbuf.dsize / sizeof(*locks))) {
577 dbuf.dsize -= dcount * sizeof(*locks);
578 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
581 /* we didn't find it */
582 fail:
583 SAFE_FREE(dbuf.dptr);
584 tdb_chainunlock(tdb, kbuf);
587 /****************************************************************************
588 Traverse the whole database with this function, calling traverse_callback
589 on each lock.
590 ****************************************************************************/
592 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
594 struct lock_struct *locks;
595 struct lock_key *key;
596 int i;
598 BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
600 locks = (struct lock_struct *)dbuf.dptr;
601 key = (struct lock_key *)kbuf.dptr;
603 for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
604 traverse_callback(key->device, key->inode,
605 locks[i].context.pid,
606 locks[i].lock_type,
607 locks[i].start,
608 locks[i].size);
610 return 0;
613 /*******************************************************************
614 Call the specified function on each lock in the database.
615 ********************************************************************/
617 int brl_forall(BRLOCK_FN(fn))
619 if (!tdb) return 0;
620 return tdb_traverse(tdb, traverse_fn, (void *)fn);