When checking is_locked() new WRITE locks conflict with existing READ locks even
[tprouty/samba.git] / source / locking / brlock.c
1 /* 
2    Unix SMB/CIFS implementation.
3    byte range locking code
4    Updated to handle range splits/merges.
5
6    Copyright (C) Andrew Tridgell 1992-2000
7    Copyright (C) Jeremy Allison 1992-2000
8    
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.
13    
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.
18    
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.
22 */
23
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 */
27
28 #include "includes.h"
29
30 #define ZERO_ZERO 0
31
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 */
35
36 struct lock_context {
37         uint16 smbpid;
38         uint16 tid;
39         pid_t pid;
40 };
41
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 */
45
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;
52 };
53
54 /* The key used in the brlock database. */
55
56 struct lock_key {
57         SMB_DEV_T device;
58         SMB_INO_T inode;
59 };
60
61 /* The open brlock.tdb database. */
62
63 static TDB_CONTEXT *tdb;
64
65 /****************************************************************************
66  Create a locking key - ensuring zero filled for pad purposes.
67 ****************************************************************************/
68
69 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
70 {
71         static struct lock_key key;
72         TDB_DATA kbuf;
73
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;
80 }
81
82 /****************************************************************************
83  See if two locking contexts are equal.
84 ****************************************************************************/
85
86 static BOOL brl_same_context(struct lock_context *ctx1, 
87                              struct lock_context *ctx2)
88 {
89         return (ctx1->pid == ctx2->pid) &&
90                 (ctx1->smbpid == ctx2->smbpid) &&
91                 (ctx1->tid == ctx2->tid);
92 }
93
94 /****************************************************************************
95  See if lock2 can be added when lock1 is in place.
96 ****************************************************************************/
97
98 static BOOL brl_conflict(struct lock_struct *lck1, 
99                          struct lock_struct *lck2)
100 {
101         if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
102                 return False;
103         }
104
105         if (brl_same_context(&lck1->context, &lck2->context) &&
106             lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
107                 return False;
108         }
109
110         if (lck1->start >= (lck2->start + lck2->size) ||
111             lck2->start >= (lck1->start + lck1->size)) {
112                 return False;
113         }
114             
115         return True;
116
117
118 #if ZERO_ZERO
119 static BOOL brl_conflict1(struct lock_struct *lck1, 
120                          struct lock_struct *lck2)
121 {
122         if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) {
123                 return False;
124         }
125
126         if (brl_same_context(&lck1->context, &lck2->context) &&
127             lck2->lock_type == READ_LOCK && lck1->fnum == lck2->fnum) {
128                 return False;
129         }
130
131         if (lck2->start == 0 && lck2->size == 0 && lck1->size != 0) {
132                 return True;
133         }
134
135         if (lck1->start >= (lck2->start + lck2->size) ||
136             lck2->start >= (lck1->start + lck1->size)) {
137                 return False;
138         }
139             
140         return True;
141
142 #endif
143
144 /****************************************************************************
145  Check to see if this lock conflicts, but ignore our own locks on the
146  same fnum only.
147 ****************************************************************************/
148
149 static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2)
150 {
151         if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) 
152                 return False;
153
154         /*
155          * Incoming WRITE locks conflict with existing READ locks even
156          * if the context is the same. JRA. See LOCKTEST7 in smbtorture.
157          */
158
159         if (!(lck2->lock_type == WRITE_LOCK && lck1->lock_type == READ_LOCK)) {
160                 if (brl_same_context(&lck1->context, &lck2->context) &&
161                                         lck1->fnum == lck2->fnum)
162                         return False;
163         }
164
165         if (lck1->start >= (lck2->start + lck2->size) ||
166             lck2->start >= (lck1->start + lck1->size)) return False;
167             
168         return True;
169
170
171
172 #if DONT_DO_THIS
173         /* doing this traversal could kill solaris machines under high load (tridge) */
174         /* delete any dead locks */
175
176 /****************************************************************************
177  Delete a record if it is for a dead process, if check_self is true, then
178  delete any records belonging to this pid also (there shouldn't be any).
179 ****************************************************************************/
180
181 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
182 {
183         struct lock_struct *locks;
184         int count, i;
185         BOOL check_self = *(BOOL *)state;
186         pid_t mypid = sys_getpid();
187
188         tdb_chainlock(tdb, kbuf);
189
190         locks = (struct lock_struct *)dbuf.dptr;
191
192         count = dbuf.dsize / sizeof(*locks);
193         for (i=0; i<count; i++) {
194                 struct lock_struct *lock = &locks[i];
195
196                 /* If check_self is true we want to remove our own records. */
197                 if (check_self && (mypid == lock->context.pid)) {
198
199                         DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
200                                         (unsigned int)lock->context.pid ));
201
202                 } else if (process_exists(lock->context.pid)) {
203
204                         DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid ));
205                         continue;
206                 }
207
208                 DEBUG(10,("brlock : delete_fn. Deleting record for process %u\n",
209                                 (unsigned int)lock->context.pid ));
210
211                 if (count > 1 && i < count-1) {
212                         memmove(&locks[i], &locks[i+1], 
213                                 sizeof(*locks)*((count-1) - i));
214                 }
215                 count--;
216                 i--;
217         }
218
219         if (count == 0) {
220                 tdb_delete(tdb, kbuf);
221         } else if (count < (dbuf.dsize / sizeof(*locks))) {
222                 dbuf.dsize = count * sizeof(*locks);
223                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
224         }
225
226         tdb_chainunlock(tdb, kbuf);
227         return 0;
228 }
229 #endif
230
231 /****************************************************************************
232  Open up the brlock.tdb database.
233 ****************************************************************************/
234
235 void brl_init(int read_only)
236 {
237         if (tdb)
238                 return;
239         tdb = tdb_open_log(lock_path("brlock.tdb"), 0,  TDB_DEFAULT|(read_only?0x0:TDB_CLEAR_IF_FIRST),
240                        read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
241         if (!tdb) {
242                 DEBUG(0,("Failed to open byte range locking database\n"));
243                 return;
244         }
245
246 #if DONT_DO_THIS
247         /* doing this traversal could kill solaris machines under high load (tridge) */
248         /* delete any dead locks */
249         if (!read_only) {
250                 BOOL check_self = False;
251                 tdb_traverse(tdb, delete_fn, &check_self);
252         }
253 #endif
254 }
255
256 /****************************************************************************
257  Close down the brlock.tdb database.
258 ****************************************************************************/
259
260 void brl_shutdown(int read_only)
261 {
262         if (!tdb)
263                 return;
264
265 #if DONT_DO_THIS
266         /* doing this traversal could kill solaris machines under high load (tridge) */
267         /* delete any dead locks */
268         if (!read_only) {
269                 BOOL check_self = True;
270                 tdb_traverse(tdb, delete_fn, &check_self);
271         }
272 #endif
273
274         tdb_close(tdb);
275 }
276
277 #if ZERO_ZERO
278 /****************************************************************************
279 compare two locks for sorting
280 ****************************************************************************/
281 static int lock_compare(struct lock_struct *lck1, 
282                          struct lock_struct *lck2)
283 {
284         if (lck1->start != lck2->start) return (lck1->start - lck2->start);
285         if (lck2->size != lck1->size) {
286                 return ((int)lck1->size - (int)lck2->size);
287         }
288         return 0;
289 }
290 #endif
291
292 /****************************************************************************
293  Lock a range of bytes.
294 ****************************************************************************/
295
296 NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
297                   uint16 smbpid, pid_t pid, uint16 tid,
298                   br_off start, br_off size, 
299                   enum brl_type lock_type)
300 {
301         TDB_DATA kbuf, dbuf;
302         int count, i;
303         struct lock_struct lock, *locks;
304         char *tp;
305         NTSTATUS status = NT_STATUS_OK;
306         static int last_failed = -1;
307         static br_off last_failed_start;
308
309         kbuf = locking_key(dev,ino);
310
311         dbuf.dptr = NULL;
312
313 #if !ZERO_ZERO
314         if (start == 0 && size == 0) {
315                 DEBUG(0,("client sent 0/0 lock - please report this\n"));
316         }
317 #endif
318
319         tdb_chainlock(tdb, kbuf);
320         dbuf = tdb_fetch(tdb, kbuf);
321
322         lock.context.smbpid = smbpid;
323         lock.context.pid = pid;
324         lock.context.tid = tid;
325         lock.start = start;
326         lock.size = size;
327         lock.fnum = fnum;
328         lock.lock_type = lock_type;
329
330         if (dbuf.dptr) {
331                 /* there are existing locks - make sure they don't conflict */
332                 locks = (struct lock_struct *)dbuf.dptr;
333                 count = dbuf.dsize / sizeof(*locks);
334                 for (i=0; i<count; i++) {
335                         if (brl_conflict(&locks[i], &lock)) {
336                                 status = NT_STATUS_LOCK_NOT_GRANTED;
337                                 goto fail;
338                         }
339 #if ZERO_ZERO
340                         if (lock.start == 0 && lock.size == 0 && 
341                             locks[i].size == 0) {
342                                 break;
343                         }
344 #endif
345                 }
346         }
347
348         /* no conflicts - add it to the list of locks */
349         tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks));
350         if (!tp) {
351                 status = NT_STATUS_NO_MEMORY;
352                 goto fail;
353         } else {
354                 dbuf.dptr = tp;
355         }
356         memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock));
357         dbuf.dsize += sizeof(lock);
358
359 #if ZERO_ZERO
360         /* sort the lock list */
361         qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare);
362 #endif
363
364         tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
365
366         SAFE_FREE(dbuf.dptr);
367         tdb_chainunlock(tdb, kbuf);
368         return NT_STATUS_OK;
369
370  fail:
371         /* this is a nasty hack to try to simulate the lock result cache code in w2k.
372            It isn't completely accurate as I haven't yet worked out the correct
373            semantics (tridge)
374         */
375         if (last_failed == fnum &&
376             last_failed_start == start &&
377             NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) {
378                 status = NT_STATUS_FILE_LOCK_CONFLICT;
379         }
380         last_failed = fnum;
381         last_failed_start = start;
382
383         SAFE_FREE(dbuf.dptr);
384         tdb_chainunlock(tdb, kbuf);
385         return status;
386 }
387
388 /****************************************************************************
389  Unlock a range of bytes.
390 ****************************************************************************/
391
392 BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
393                 uint16 smbpid, pid_t pid, uint16 tid,
394                 br_off start, br_off size)
395 {
396         TDB_DATA kbuf, dbuf;
397         int count, i;
398         struct lock_struct *locks;
399         struct lock_context context;
400
401         kbuf = locking_key(dev,ino);
402
403         dbuf.dptr = NULL;
404
405         tdb_chainlock(tdb, kbuf);
406         dbuf = tdb_fetch(tdb, kbuf);
407
408         if (!dbuf.dptr) {
409                 DEBUG(10,("brl_unlock: tdb_fetch failed !\n"));
410                 goto fail;
411         }
412
413         context.smbpid = smbpid;
414         context.pid = pid;
415         context.tid = tid;
416
417         /* there are existing locks - find a match */
418         locks = (struct lock_struct *)dbuf.dptr;
419         count = dbuf.dsize / sizeof(*locks);
420
421 #if ZERO_ZERO
422         for (i=0; i<count; i++) {
423                 struct lock_struct *lock = &locks[i];
424
425                 if (lock->lock_type == WRITE_LOCK &&
426                     brl_same_context(&lock->context, &context) &&
427                     lock->fnum == fnum &&
428                     lock->start == start &&
429                     lock->size == size) {
430                         /* found it - delete it */
431                         if (count == 1) {
432                                 tdb_delete(tdb, kbuf);
433                         } else {
434                                 if (i < count-1) {
435                                         memmove(&locks[i], &locks[i+1], 
436                                                 sizeof(*locks)*((count-1) - i));
437                                 }
438                                 dbuf.dsize -= sizeof(*locks);
439                                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
440                         }
441
442                         SAFE_FREE(dbuf.dptr);
443                         tdb_chainunlock(tdb, kbuf);
444                         return True;
445                 }
446         }
447 #endif
448
449         locks = (struct lock_struct *)dbuf.dptr;
450         count = dbuf.dsize / sizeof(*locks);
451         for (i=0; i<count; i++) {
452                 struct lock_struct *lock = &locks[i];
453
454                 if (brl_same_context(&lock->context, &context) &&
455                     lock->fnum == fnum &&
456                     lock->start == start &&
457                     lock->size == size) {
458                         /* found it - delete it */
459                         if (count == 1) {
460                                 tdb_delete(tdb, kbuf);
461                         } else {
462                                 if (i < count-1) {
463                                         memmove(&locks[i], &locks[i+1], 
464                                                 sizeof(*locks)*((count-1) - i));
465                                 }
466                                 dbuf.dsize -= sizeof(*locks);
467                                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
468                         }
469
470                         SAFE_FREE(dbuf.dptr);
471                         tdb_chainunlock(tdb, kbuf);
472                         return True;
473                 }
474         }
475
476         /* we didn't find it */
477
478  fail:
479         SAFE_FREE(dbuf.dptr);
480         tdb_chainunlock(tdb, kbuf);
481         return False;
482 }
483
484
485 /****************************************************************************
486  Test if we could add a lock if we wanted to.
487 ****************************************************************************/
488
489 BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum,
490                   uint16 smbpid, pid_t pid, uint16 tid,
491                   br_off start, br_off size, 
492                   enum brl_type lock_type, int check_self)
493 {
494         TDB_DATA kbuf, dbuf;
495         int count, i;
496         struct lock_struct lock, *locks;
497
498         kbuf = locking_key(dev,ino);
499
500         dbuf.dptr = NULL;
501
502         tdb_chainlock(tdb, kbuf);
503         dbuf = tdb_fetch(tdb, kbuf);
504
505         lock.context.smbpid = smbpid;
506         lock.context.pid = pid;
507         lock.context.tid = tid;
508         lock.start = start;
509         lock.size = size;
510         lock.fnum = fnum;
511         lock.lock_type = lock_type;
512
513         if (dbuf.dptr) {
514                 /* there are existing locks - make sure they don't conflict */
515                 locks = (struct lock_struct *)dbuf.dptr;
516                 count = dbuf.dsize / sizeof(*locks);
517                 for (i=0; i<count; i++) {
518                         if (check_self) {
519                                 if (brl_conflict(&locks[i], &lock))
520                                         goto fail;
521                         } else {
522                                 /*
523                                  * Our own locks don't conflict.
524                                  */
525                                 if (brl_conflict_other(&locks[i], &lock))
526                                         goto fail;
527                         }
528                 }
529         }
530
531         /* no conflicts - we could have added it */
532         SAFE_FREE(dbuf.dptr);
533         tdb_chainunlock(tdb, kbuf);
534         return True;
535
536  fail:
537         SAFE_FREE(dbuf.dptr);
538         tdb_chainunlock(tdb, kbuf);
539         return False;
540 }
541
542 /****************************************************************************
543  Remove any locks associated with a open file.
544 ****************************************************************************/
545
546 void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum)
547 {
548         TDB_DATA kbuf, dbuf;
549         int count, i, dcount=0;
550         struct lock_struct *locks;
551
552         kbuf = locking_key(dev,ino);
553
554         dbuf.dptr = NULL;
555
556         tdb_chainlock(tdb, kbuf);
557         dbuf = tdb_fetch(tdb, kbuf);
558
559         if (!dbuf.dptr) goto fail;
560
561         /* there are existing locks - remove any for this fnum */
562         locks = (struct lock_struct *)dbuf.dptr;
563         count = dbuf.dsize / sizeof(*locks);
564         for (i=0; i<count; i++) {
565                 struct lock_struct *lock = &locks[i];
566
567                 if (lock->context.tid == tid &&
568                     lock->context.pid == pid &&
569                     lock->fnum == fnum) {
570                         /* found it - delete it */
571                         if (count > 1 && i < count-1) {
572                                 memmove(&locks[i], &locks[i+1], 
573                                         sizeof(*locks)*((count-1) - i));
574                         }
575                         count--;
576                         i--;
577                         dcount++;
578                 }
579         }
580
581         if (count == 0) {
582                 tdb_delete(tdb, kbuf);
583         } else if (count < (dbuf.dsize / sizeof(*locks))) {
584                 dbuf.dsize -= dcount * sizeof(*locks);
585                 tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
586         }
587
588         /* we didn't find it */
589  fail:
590         SAFE_FREE(dbuf.dptr);
591         tdb_chainunlock(tdb, kbuf);
592 }
593
594 /****************************************************************************
595  Traverse the whole database with this function, calling traverse_callback
596  on each lock.
597 ****************************************************************************/
598
599 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
600 {
601         struct lock_struct *locks;
602         struct lock_key *key;
603         int i;
604
605         BRLOCK_FN(traverse_callback) = (BRLOCK_FN_CAST())state;
606
607         locks = (struct lock_struct *)dbuf.dptr;
608         key = (struct lock_key *)kbuf.dptr;
609
610         for (i=0;i<dbuf.dsize/sizeof(*locks);i++) {
611                 traverse_callback(key->device, key->inode,
612                                   locks[i].context.pid,
613                                   locks[i].lock_type,
614                                   locks[i].start,
615                                   locks[i].size);
616         }
617         return 0;
618 }
619
620 /*******************************************************************
621  Call the specified function on each lock in the database.
622 ********************************************************************/
623
624 int brl_forall(BRLOCK_FN(fn))
625 {
626         if (!tdb) return 0;
627         return tdb_traverse(tdb, traverse_fn, (void *)fn);
628 }