add some brackets
[samba.git] / source3 / locking / brlock.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    byte range locking code
5    Updated to handle range splits/merges.
6
7    Copyright (C) Andrew Tridgell 1992-2000
8    Copyright (C) Jeremy Allison 1992-2000
9    
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.
14    
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.
19    
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.
23 */
24
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 */
28
29 #include "includes.h"
30
31 extern int DEBUGLEVEL;
32
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 */
36
37 struct lock_context {
38         uint16 smbpid;
39         uint16 tid;
40         pid_t pid;
41 };
42
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 */
46
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;
53 };
54
55 /* The key used in the brlock database. */
56
57 struct lock_key {
58         SMB_DEV_T device;
59         SMB_INO_T inode;
60 };
61
62 /* The open brlock.tdb database. */
63
64 static TDB_CONTEXT *tdb;
65
66 /****************************************************************************
67  Create a locking key - ensuring zero filled for pad purposes.
68 ****************************************************************************/
69
70 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
71 {
72         static struct lock_key key;
73         TDB_DATA kbuf;
74
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;
81 }
82
83 /****************************************************************************
84  See if two locking contexts are equal.
85 ****************************************************************************/
86
87 static BOOL brl_same_context(struct lock_context *ctx1, 
88                              struct lock_context *ctx2)
89 {
90         return (ctx1->pid == ctx2->pid) &&
91                 (ctx1->smbpid == ctx2->smbpid) &&
92                 (ctx1->tid == ctx2->tid);
93 }
94
95 /****************************************************************************
96  See if lock2 can be added when lock1 is in place.
97 ****************************************************************************/
98
99 static BOOL brl_conflict(struct lock_struct *lck1, 
100                          struct lock_struct *lck2)
101 {
102         if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) 
103                 return False;
104
105         if (brl_same_context(&lck1->context, &lck2->context) &&
106             lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) return False;
107
108         if (lck1->start >= (lck2->start + lck2->size) ||
109             lck2->start >= (lck1->start + lck1->size)) return False;
110             
111         return True;
112
113
114
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)
119 {
120         struct lock_struct *locks;
121         struct lock_key *key;
122         int count, i;
123
124         tdb_lockchain(tdb, kbuf);
125
126         locks = (struct lock_struct *)dbuf.dptr;
127         key = (struct lock_key *)kbuf.dptr;
128
129         count = dbuf.dsize / sizeof(*locks);
130         for (i=0; i<count; i++) {
131                 struct lock_struct *lock = &locks[i];
132
133                 if (process_exists(lock->context.pid)) continue;
134
135                 if (count > 1 && i < count-1) {
136                         memmove(&locks[i], &locks[i+1], 
137                                 sizeof(*locks)*((count-1) - i));
138                 }
139                 count--;
140                 i--;
141         }
142
143         if (count == 0) {
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);
148         }
149
150         tdb_unlockchain(tdb, kbuf);
151         return 0;
152 }
153
154 /****************************************************************************
155  Open up the brlock.tdb database.
156 ****************************************************************************/
157 void brl_init(int read_only)
158 {
159         if (tdb) return;
160         tdb = tdb_open(lock_path("brlock.tdb"), 0, TDB_CLEAR_IF_FIRST, 
161                        read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
162         if (!tdb) {
163                 DEBUG(0,("Failed to open byte range locking database\n"));
164                 return;
165         }
166
167         /* delete any dead locks */
168         if (!read_only) {
169                 tdb_traverse(tdb, delete_fn, NULL);
170         }
171 }
172
173
174 /****************************************************************************
175  Lock a range of bytes.
176 ****************************************************************************/
177
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)
182 {
183         TDB_DATA kbuf, dbuf;
184         int count, i;
185         struct lock_struct lock, *locks;
186
187         kbuf = locking_key(dev,ino);
188
189         dbuf.dptr = NULL;
190
191         tdb_lockchain(tdb, kbuf);
192         dbuf = tdb_fetch(tdb, kbuf);
193
194         lock.context.smbpid = smbpid;
195         lock.context.pid = pid;
196         lock.context.tid = tid;
197         lock.start = start;
198         lock.size = size;
199         lock.fnum = fnum;
200         lock.lock_type = lock_type;
201
202         if (dbuf.dptr) {
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)) {
208                                 goto fail;
209                         }
210                 }
211         }
212
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);
219
220         free(dbuf.dptr);
221         tdb_unlockchain(tdb, kbuf);
222         return True;
223
224  fail:
225         if (dbuf.dptr) free(dbuf.dptr);
226         tdb_unlockchain(tdb, kbuf);
227         return False;
228 }
229
230 /****************************************************************************
231  Unlock a range of bytes.
232 ****************************************************************************/
233
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)
237 {
238         TDB_DATA kbuf, dbuf;
239         int count, i;
240         struct lock_struct *locks;
241         struct lock_context context;
242
243         kbuf = locking_key(dev,ino);
244
245         dbuf.dptr = NULL;
246
247         tdb_lockchain(tdb, kbuf);
248         dbuf = tdb_fetch(tdb, kbuf);
249
250         if (!dbuf.dptr) {
251                 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
252                 goto fail;
253         }
254
255         context.smbpid = smbpid;
256         context.pid = pid;
257         context.tid = tid;
258
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++) {
263
264                 struct lock_struct *lock = &locks[i];
265
266 #if 0
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 ));
273
274                 }
275                 /* JRATEST */
276 #endif
277
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 */
283                         if (count == 1) {
284                                 tdb_delete(tdb, kbuf);
285                         } else {
286                                 if (i < count-1) {
287                                         memmove(&locks[i], &locks[i+1], 
288                                                 sizeof(*locks)*((count-1) - i));
289                                 }
290                                 dbuf.dsize -= sizeof(*locks);
291                                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
292                         }
293
294                         free(dbuf.dptr);
295                         tdb_unlockchain(tdb, kbuf);
296                         return True;
297                 }
298         }
299
300         /* we didn't find it */
301
302  fail:
303         if (dbuf.dptr) free(dbuf.dptr);
304         tdb_unlockchain(tdb, kbuf);
305         return False;
306 }
307
308 /****************************************************************************
309  Test if we could add a lock if we wanted to.
310 ****************************************************************************/
311
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)
316 {
317         TDB_DATA kbuf, dbuf;
318         int count, i;
319         struct lock_struct lock, *locks;
320
321         kbuf = locking_key(dev,ino);
322
323         dbuf.dptr = NULL;
324
325         tdb_lockchain(tdb, kbuf);
326         dbuf = tdb_fetch(tdb, kbuf);
327
328         lock.context.smbpid = smbpid;
329         lock.context.pid = pid;
330         lock.context.tid = tid;
331         lock.start = start;
332         lock.size = size;
333         lock.fnum = fnum;
334         lock.lock_type = lock_type;
335
336         if (dbuf.dptr) {
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)) {
342                                 goto fail;
343                         }
344                 }
345         }
346
347         /* no conflicts - we could have added it */
348         free(dbuf.dptr);
349         tdb_unlockchain(tdb, kbuf);
350         return True;
351
352  fail:
353         if (dbuf.dptr) free(dbuf.dptr);
354         tdb_unlockchain(tdb, kbuf);
355         return False;
356 }
357
358 /****************************************************************************
359  Remove any locks associated with a open file.
360 ****************************************************************************/
361
362 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
363 {
364         TDB_DATA kbuf, dbuf;
365         int count, i, dcount=0;
366         struct lock_struct *locks;
367
368         kbuf = locking_key(dev,ino);
369
370         dbuf.dptr = NULL;
371
372         tdb_lockchain(tdb, kbuf);
373         dbuf = tdb_fetch(tdb, kbuf);
374
375         if (!dbuf.dptr) goto fail;
376
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];
382
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));
390                         }
391                         count--;
392                         i--;
393                         dcount++;
394                 }
395         }
396
397         if (count == 0) {
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);
402         }
403
404         /* we didn't find it */
405  fail:
406         if (dbuf.dptr) free(dbuf.dptr);
407         tdb_unlockchain(tdb, kbuf);
408 }
409
410 /****************************************************************************
411  Traverse the whole database with this function, calling traverse_callback
412  on each lock.
413 ****************************************************************************/
414
415 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
416 {
417         struct lock_struct *locks;
418         struct lock_key *key;
419         int i;
420
421         BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
422
423         locks = (struct lock_struct *)dbuf.dptr;
424         key = (struct lock_key *)kbuf.dptr;
425
426         for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
427                 traverse_callback(key->device, key->inode,
428                                   locks[i].context.pid,
429                                   locks[i].lock_type,
430                                   locks[i].start,
431                                   locks[i].size);
432         }
433         return 0;
434 }
435
436 /*******************************************************************
437  Call the specified function on each lock in the database.
438 ********************************************************************/
439
440 int brl_forall(BRLOCK_FN(fn))
441 {
442         if (!tdb) return 0;
443         return tdb_traverse(tdb, traverse_fn, (BRLOCK_FN_CAST())fn);
444 }