Merge of new 2.2 code into HEAD (Gerald I hate you :-) :-). Allows new SAMR
[bbaumbach/samba-autobuild/.git] / source / 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         int count, i;
122
123         tdb_chainlock(tdb, kbuf);
124
125         locks = (struct lock_struct *)dbuf.dptr;
126
127         count = dbuf.dsize / sizeof(*locks);
128         for (i=0; i<count; i++) {
129                 struct lock_struct *lock = &locks[i];
130
131                 if (process_exists(lock->context.pid)) continue;
132
133                 if (count > 1 && i < count-1) {
134                         memmove(&locks[i], &locks[i+1], 
135                                 sizeof(*locks)*((count-1) - i));
136                 }
137                 count--;
138                 i--;
139         }
140
141         if (count == 0) {
142                 tdb_delete(tdb, kbuf);
143         } else if (count < (dbuf.dsize / sizeof(*locks))) {
144                 dbuf.dsize = count * sizeof(*locks);
145                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
146         }
147
148         tdb_chainunlock(tdb, kbuf);
149         return 0;
150 }
151
152 /****************************************************************************
153  Open up the brlock.tdb database.
154 ****************************************************************************/
155 void brl_init(int read_only)
156 {
157         if (tdb) return;
158         tdb = tdb_open(lock_path("brlock.tdb"), 0, TDB_CLEAR_IF_FIRST, 
159                        read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
160         if (!tdb) {
161                 DEBUG(0,("Failed to open byte range locking database\n"));
162                 return;
163         }
164
165         /* delete any dead locks */
166         if (!read_only) {
167                 tdb_traverse(tdb, delete_fn, NULL);
168         }
169 }
170
171
172 /****************************************************************************
173  Lock a range of bytes.
174 ****************************************************************************/
175
176 BOOL brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
177               uint16 smbpid, pid_t pid, uint16 tid,
178               br_off start, br_off size, 
179               enum brl_type lock_type)
180 {
181         TDB_DATA kbuf, dbuf;
182         int count, i;
183         struct lock_struct lock, *locks;
184
185         kbuf = locking_key(dev,ino);
186
187         dbuf.dptr = NULL;
188
189         tdb_chainlock(tdb, kbuf);
190         dbuf = tdb_fetch(tdb, kbuf);
191
192         lock.context.smbpid = smbpid;
193         lock.context.pid = pid;
194         lock.context.tid = tid;
195         lock.start = start;
196         lock.size = size;
197         lock.fnum = fnum;
198         lock.lock_type = lock_type;
199
200         if (dbuf.dptr) {
201                 /* there are existing locks - make sure they don't conflict */
202                 locks = (struct lock_struct *)dbuf.dptr;
203                 count = dbuf.dsize / sizeof(*locks);
204                 for (i=0; i<count; i++) {
205                         if (brl_conflict(&locks[i], &lock)) {
206                                 goto fail;
207                         }
208                 }
209         }
210
211         /* no conflicts - add it to the list of locks */
212         dbuf.dptr = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
213         if (!dbuf.dptr) goto fail;
214         memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
215         dbuf.dsize += sizeof(lock);
216         tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
217
218         free(dbuf.dptr);
219         tdb_chainunlock(tdb, kbuf);
220         return True;
221
222  fail:
223         if (dbuf.dptr) free(dbuf.dptr);
224         tdb_chainunlock(tdb, kbuf);
225         return False;
226 }
227
228 /****************************************************************************
229  Unlock a range of bytes.
230 ****************************************************************************/
231
232 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
233                 uint16 smbpid, pid_t pid, uint16 tid,
234                 br_off start, br_off size)
235 {
236         TDB_DATA kbuf, dbuf;
237         int count, i;
238         struct lock_struct *locks;
239         struct lock_context context;
240
241         kbuf = locking_key(dev,ino);
242
243         dbuf.dptr = NULL;
244
245         tdb_chainlock(tdb, kbuf);
246         dbuf = tdb_fetch(tdb, kbuf);
247
248         if (!dbuf.dptr) {
249                 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
250                 goto fail;
251         }
252
253         context.smbpid = smbpid;
254         context.pid = pid;
255         context.tid = tid;
256
257         /* there are existing locks - find a match */
258         locks = (struct lock_struct *)dbuf.dptr;
259         count = dbuf.dsize / sizeof(*locks);
260         for (i=0; i<count; i++) {
261
262                 struct lock_struct *lock = &locks[i];
263
264 #if 0
265                 /* JRATEST - DEBUGGING INFO */
266                 if(!brl_same_context(&lock->context, &context)) {
267                         DEBUG(10,("brl_unlock: Not same context. l_smbpid = %u, l_pid = %u, l_tid = %u: \
268 smbpid = %u, pid = %u, tid = %u\n",
269                                 lock->context.smbpid, lock->context.pid, lock->context.tid,
270                                 context.smbpid, context.pid, context.tid ));
271
272                 }
273                 /* JRATEST */
274 #endif
275
276                 if (brl_same_context(&lock->context, &context) &&
277                     lock->fnum == fnum &&
278                     lock->start == start &&
279                     lock->size == size) {
280                         /* found it - delete it */
281                         if (count == 1) {
282                                 tdb_delete(tdb, kbuf);
283                         } else {
284                                 if (i < count-1) {
285                                         memmove(&locks[i], &locks[i+1], 
286                                                 sizeof(*locks)*((count-1) - i));
287                                 }
288                                 dbuf.dsize -= sizeof(*locks);
289                                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
290                         }
291
292                         free(dbuf.dptr);
293                         tdb_chainunlock(tdb, kbuf);
294                         return True;
295                 }
296         }
297
298         /* we didn't find it */
299
300  fail:
301         if (dbuf.dptr) free(dbuf.dptr);
302         tdb_chainunlock(tdb, kbuf);
303         return False;
304 }
305
306 /****************************************************************************
307  Test if we could add a lock if we wanted to.
308 ****************************************************************************/
309
310 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
311                   uint16 smbpid, pid_t pid, uint16 tid,
312                   br_off start, br_off size, 
313                   enum brl_type lock_type)
314 {
315         TDB_DATA kbuf, dbuf;
316         int count, i;
317         struct lock_struct lock, *locks;
318
319         kbuf = locking_key(dev,ino);
320
321         dbuf.dptr = NULL;
322
323         tdb_chainlock(tdb, kbuf);
324         dbuf = tdb_fetch(tdb, kbuf);
325
326         lock.context.smbpid = smbpid;
327         lock.context.pid = pid;
328         lock.context.tid = tid;
329         lock.start = start;
330         lock.size = size;
331         lock.fnum = fnum;
332         lock.lock_type = lock_type;
333
334         if (dbuf.dptr) {
335                 /* there are existing locks - make sure they don't conflict */
336                 locks = (struct lock_struct *)dbuf.dptr;
337                 count = dbuf.dsize / sizeof(*locks);
338                 for (i=0; i<count; i++) {
339                         if (brl_conflict(&locks[i], &lock)) {
340                                 goto fail;
341                         }
342                 }
343         }
344
345         /* no conflicts - we could have added it */
346         free(dbuf.dptr);
347         tdb_chainunlock(tdb, kbuf);
348         return True;
349
350  fail:
351         if (dbuf.dptr) free(dbuf.dptr);
352         tdb_chainunlock(tdb, kbuf);
353         return False;
354 }
355
356 /****************************************************************************
357  Remove any locks associated with a open file.
358 ****************************************************************************/
359
360 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
361 {
362         TDB_DATA kbuf, dbuf;
363         int count, i, dcount=0;
364         struct lock_struct *locks;
365
366         kbuf = locking_key(dev,ino);
367
368         dbuf.dptr = NULL;
369
370         tdb_chainlock(tdb, kbuf);
371         dbuf = tdb_fetch(tdb, kbuf);
372
373         if (!dbuf.dptr) goto fail;
374
375         /* there are existing locks - remove any for this fnum */
376         locks = (struct lock_struct *)dbuf.dptr;
377         count = dbuf.dsize / sizeof(*locks);
378         for (i=0; i<count; i++) {
379                 struct lock_struct *lock = &locks[i];
380
381                 if (lock->context.tid == tid &&
382                     lock->context.pid == pid &&
383                     lock->fnum == fnum) {
384                         /* found it - delete it */
385                         if (count > 1 && i < count-1) {
386                                 memmove(&locks[i], &locks[i+1], 
387                                         sizeof(*locks)*((count-1) - i));
388                         }
389                         count--;
390                         i--;
391                         dcount++;
392                 }
393         }
394
395         if (count == 0) {
396                 tdb_delete(tdb, kbuf);
397         } else if (count < (dbuf.dsize / sizeof(*locks))) {
398                 dbuf.dsize -= dcount * sizeof(*locks);
399                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
400         }
401
402         /* we didn't find it */
403  fail:
404         if (dbuf.dptr) free(dbuf.dptr);
405         tdb_chainunlock(tdb, kbuf);
406 }
407
408 /****************************************************************************
409  Traverse the whole database with this function, calling traverse_callback
410  on each lock.
411 ****************************************************************************/
412
413 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
414 {
415         struct lock_struct *locks;
416         struct lock_key *key;
417         int i;
418
419         BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
420
421         locks = (struct lock_struct *)dbuf.dptr;
422         key = (struct lock_key *)kbuf.dptr;
423
424         for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
425                 traverse_callback(key->device, key->inode,
426                                   locks[i].context.pid,
427                                   locks[i].lock_type,
428                                   locks[i].start,
429                                   locks[i].size);
430         }
431         return 0;
432 }
433
434 /*******************************************************************
435  Call the specified function on each lock in the database.
436 ********************************************************************/
437
438 int brl_forall(BRLOCK_FN(fn))
439 {
440         if (!tdb) return 0;
441         return tdb_traverse(tdb, traverse_fn, (void *)fn);
442 }