Added "use mmap" for HPUX.
[ira/wip.git] / source3 / locking / locking.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    Locking functions
5    Copyright (C) Andrew Tridgell 1992-2000
6    Copyright (C) Jeremy Allison 1992-2000
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22    Revision History:
23
24    12 aug 96: Erik.Devriendt@te6.siemens.be
25    added support for shared memory implementation of share mode locking
26
27    May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
28    locking to deal with multiple share modes per open file.
29
30    September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
31    support.
32
33    rewrtten completely to use new tdb code. Tridge, Dec '99
34
35    Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
36 */
37
38 #include "includes.h"
39 extern int DEBUGLEVEL;
40 uint16 global_smbpid;
41
42 /* the locking database handle */
43 static TDB_CONTEXT *tdb;
44
45 /****************************************************************************
46  Debugging aid :-).
47 ****************************************************************************/
48
49 static const char *lock_type_name(enum brl_type lock_type)
50 {
51         return (lock_type == READ_LOCK) ? "READ" : "WRITE";
52 }
53
54 /****************************************************************************
55  Utility function called to see if a file region is locked.
56  If check_self is True, then checks on our own fd with the same locking context
57  are still made. If check_self is False, then checks are not made on our own fd
58  with the same locking context are not made.
59 ****************************************************************************/
60
61 BOOL is_locked(files_struct *fsp,connection_struct *conn,
62                SMB_BIG_UINT count,SMB_BIG_UINT offset, 
63                enum brl_type lock_type, BOOL check_self)
64 {
65         int snum = SNUM(conn);
66         BOOL ret;
67         
68         if (count == 0)
69                 return(False);
70
71         if (!lp_locking(snum) || !lp_strict_locking(snum))
72                 return(False);
73
74         ret = !brl_locktest(fsp->dev, fsp->inode, fsp->fnum,
75                              global_smbpid, sys_getpid(), conn->cnum, 
76                              offset, count, lock_type, check_self);
77
78         DEBUG(10,("is_locked: brl start=%.0f len=%.0f %s for file %s\n",
79                         (double)offset, (double)count, ret ? "locked" : "unlocked",
80                         fsp->fsp_name ));
81
82         /*
83          * There is no lock held by an SMB daemon, check to
84          * see if there is a POSIX lock from a UNIX or NFS process.
85          */
86
87         if(!ret && lp_posix_locking(snum)) {
88                 ret = is_posix_locked(fsp, offset, count, lock_type);
89
90                 DEBUG(10,("is_locked: posix start=%.0f len=%.0f %s for file %s\n",
91                                 (double)offset, (double)count, ret ? "locked" : "unlocked",
92                                 fsp->fsp_name ));
93         }
94
95         return ret;
96 }
97
98 /****************************************************************************
99  Utility function called by locking requests.
100 ****************************************************************************/
101
102 BOOL do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
103              SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type,
104              int *eclass,uint32 *ecode)
105 {
106         BOOL ok = False;
107
108         if (!lp_locking(SNUM(conn)))
109                 return(True);
110
111         if (count == 0) {
112                 *eclass = ERRDOS;
113                 *ecode = ERRnoaccess;
114                 return False;
115         }
116         
117         DEBUG(10,("do_lock: lock type %s start=%.0f len=%.0f requested for file %s\n",
118                   lock_type_name(lock_type), (double)offset, (double)count, fsp->fsp_name ));
119
120         if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn)) {
121                 ok = brl_lock(fsp->dev, fsp->inode, fsp->fnum,
122                               lock_pid, sys_getpid(), conn->cnum, 
123                               offset, count, 
124                               lock_type);
125
126                 if (ok && lp_posix_locking(SNUM(conn))) {
127
128                         /*
129                          * Try and get a POSIX lock on this range.
130                          * Note that this is ok if it is a read lock
131                          * overlapping on a different fd. JRA.
132                          */
133
134                         ok = set_posix_lock(fsp, offset, count, lock_type);
135
136                         if (!ok) {
137                                 /*
138                                  * We failed to map - we must now remove the brl
139                                  * lock entry.
140                                  */
141                                 (void)brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
142                                                                 lock_pid, sys_getpid(), conn->cnum, 
143                                                                 offset, count);
144                         }
145                 }
146         }
147
148         if (!ok) {
149                 *eclass = ERRDOS;
150                 *ecode = ERRlock;
151                 return False;
152         }
153         return True; /* Got lock */
154 }
155
156 /****************************************************************************
157  Utility function called by unlocking requests.
158 ****************************************************************************/
159
160 BOOL do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid,
161                SMB_BIG_UINT count,SMB_BIG_UINT offset, 
162                int *eclass,uint32 *ecode)
163 {
164         BOOL ok = False;
165         
166         if (!lp_locking(SNUM(conn)))
167                 return(True);
168         
169         if (!OPEN_FSP(fsp) || !fsp->can_lock || (fsp->conn != conn)) {
170                 *eclass = ERRDOS;
171                 *ecode = ERRbadfid;
172                 return False;
173         }
174         
175         DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
176                   (double)offset, (double)count, fsp->fsp_name ));
177
178         /*
179          * Remove the existing lock record from the tdb lockdb
180          * before looking at POSIX locks. If this record doesn't
181          * match then don't bother looking to remove POSIX locks.
182          */
183
184         ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
185                         lock_pid, sys_getpid(), conn->cnum, offset, count);
186    
187         if (!ok) {
188                 DEBUG(10,("do_unlock: returning ERRlock.\n" ));
189                 *eclass = ERRDOS;
190                 *ecode = ERRnotlocked;
191                 return False;
192         }
193
194         if (!lp_posix_locking(SNUM(conn)))
195                 return True;
196
197         (void)release_posix_lock(fsp, offset, count);
198
199         return True; /* Did unlock */
200 }
201
202 /****************************************************************************
203  Remove any locks on this fd. Called from file_close().
204 ****************************************************************************/
205
206 void locking_close_file(files_struct *fsp)
207 {
208         pid_t pid = sys_getpid();
209
210         if (!lp_locking(SNUM(fsp->conn)))
211                 return;
212
213         /*
214          * Just release all the brl locks, no need to release individually.
215          */
216
217         brl_close(fsp->dev, fsp->inode, pid, fsp->conn->cnum, fsp->fnum);
218
219         if(lp_posix_locking(SNUM(fsp->conn))) {
220
221                 /* 
222                  * Release all the POSIX locks.
223                  */
224                 posix_locking_close_file(fsp);
225
226         }
227 }
228
229 /****************************************************************************
230  Delete a record if it is for a dead process, if check_self is true, then
231  delete any records belonging to this pid also (there shouldn't be any).
232  This function is only called on locking startup and shutdown.
233 ****************************************************************************/
234
235 static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
236 {
237         struct locking_data *data;
238         share_mode_entry *shares;
239         int i, del_count=0;
240         pid_t mypid = sys_getpid();
241         BOOL check_self = *(BOOL *)state;
242
243         tdb_chainlock(tdb, kbuf);
244
245         data = (struct locking_data *)dbuf.dptr;
246         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
247
248         for (i=0;i<data->num_share_mode_entries;) {
249
250                 if (check_self && (shares[i].pid == mypid)) {
251                         DEBUG(0,("locking : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n",
252                                         (unsigned int)shares[i].pid ));
253                 } else if (!process_exists(shares[i].pid)) {
254                         DEBUG(0,("locking : delete_fn. LOGIC ERROR ! Entry for pid %u and it no longer exists !\n",
255                                         (unsigned int)shares[i].pid ));
256                 } else {
257                         /* Process exists, leave this record alone. */
258                         i++;
259                         continue;
260                 }
261
262                 data->num_share_mode_entries--;
263                 memmove(&shares[i], &shares[i+1],
264                 dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
265                 del_count++;
266
267         }
268
269         /* the record has shrunk a bit */
270         dbuf.dsize -= del_count * sizeof(*shares);
271
272         /* store it back in the database */
273         if (data->num_share_mode_entries == 0)
274                 tdb_delete(ttdb, kbuf);
275         else
276                 tdb_store(ttdb, kbuf, dbuf, TDB_REPLACE);
277
278         tdb_chainunlock(tdb, kbuf);
279         return 0;
280 }
281
282 /****************************************************************************
283  Initialise the locking functions.
284 ****************************************************************************/
285
286 static int open_read_only;
287
288 BOOL locking_init(int read_only)
289 {
290         BOOL check_self = False;
291
292         brl_init(read_only);
293
294         if (tdb)
295                 return True;
296
297         tdb = tdb_open_log(lock_path("locking.tdb"), 
298                        0, TDB_CLEAR_IF_FIRST|USE_TDB_MMAP_FLAG, 
299                        read_only?O_RDONLY:O_RDWR|O_CREAT,
300                        0644);
301
302         if (!tdb) {
303                 DEBUG(0,("ERROR: Failed to initialise locking database\n"));
304                 return False;
305         }
306         
307         if (!posix_locking_init(read_only))
308                 return False;
309
310         /* delete any dead locks */
311         if (!read_only)
312                 tdb_traverse(tdb, delete_fn, &check_self);
313
314         open_read_only = read_only;
315
316         return True;
317 }
318
319 /*******************************************************************
320  Deinitialize the share_mode management.
321 ******************************************************************/
322
323 BOOL locking_end(void)
324 {
325         BOOL check_self = True;
326
327         brl_shutdown(open_read_only);
328         if (tdb) {
329
330                 /* delete any dead locks */
331
332                 if (!open_read_only)
333                         tdb_traverse(tdb, delete_fn, &check_self);
334
335                 if (tdb_close(tdb) != 0)
336                         return False;
337         }
338
339         return True;
340 }
341
342 /*******************************************************************
343  form a static locking key for a dev/inode pair 
344 ******************************************************************/
345 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
346 {
347         static struct locking_key key;
348         TDB_DATA kbuf;
349
350         memset(&key, '\0', sizeof(key));
351         key.dev = dev;
352         key.inode = inode;
353         kbuf.dptr = (char *)&key;
354         kbuf.dsize = sizeof(key);
355         return kbuf;
356 }
357 static TDB_DATA locking_key_fsp(files_struct *fsp)
358 {
359         return locking_key(fsp->dev, fsp->inode);
360 }
361
362 /*******************************************************************
363  Lock a hash bucket entry.
364 ******************************************************************/
365 BOOL lock_share_entry(connection_struct *conn,
366                       SMB_DEV_T dev, SMB_INO_T inode)
367 {
368         return tdb_chainlock(tdb, locking_key(dev, inode)) == 0;
369 }
370
371 /*******************************************************************
372  Unlock a hash bucket entry.
373 ******************************************************************/
374 void unlock_share_entry(connection_struct *conn,
375                         SMB_DEV_T dev, SMB_INO_T inode)
376 {
377         tdb_chainunlock(tdb, locking_key(dev, inode));
378 }
379
380
381 /*******************************************************************
382  Lock a hash bucket entry. use a fsp for convenience
383 ******************************************************************/
384 BOOL lock_share_entry_fsp(files_struct *fsp)
385 {
386         return tdb_chainlock(tdb, locking_key(fsp->dev, fsp->inode)) == 0;
387 }
388
389 /*******************************************************************
390  Unlock a hash bucket entry.
391 ******************************************************************/
392 void unlock_share_entry_fsp(files_struct *fsp)
393 {
394         tdb_chainunlock(tdb, locking_key(fsp->dev, fsp->inode));
395 }
396
397 /*******************************************************************
398  Get all share mode entries for a dev/inode pair.
399 ********************************************************************/
400 int get_share_modes(connection_struct *conn, 
401                     SMB_DEV_T dev, SMB_INO_T inode, 
402                     share_mode_entry **shares)
403 {
404         TDB_DATA dbuf;
405         struct locking_data *data;
406         int ret;
407
408         *shares = NULL;
409
410         dbuf = tdb_fetch(tdb, locking_key(dev, inode));
411         if (!dbuf.dptr) return 0;
412
413         data = (struct locking_data *)dbuf.dptr;
414         ret = data->num_share_mode_entries;
415         if(ret)
416                 *shares = (share_mode_entry *)memdup(dbuf.dptr + sizeof(*data), ret * sizeof(**shares));
417         free(dbuf.dptr);
418
419         if (! *shares) return 0;
420
421         return ret;
422 }
423
424 /*******************************************************************
425  Del the share mode of a file for this process. Return the number
426  of entries left, and a memdup'ed copy of the entry deleted.
427 ********************************************************************/
428
429 size_t del_share_mode(files_struct *fsp, share_mode_entry **ppse)
430 {
431         TDB_DATA dbuf;
432         struct locking_data *data;
433         int i, del_count=0;
434         share_mode_entry *shares;
435         pid_t pid = sys_getpid();
436         size_t count;
437
438         *ppse = NULL;
439
440         /* read in the existing share modes */
441         dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
442         if (!dbuf.dptr) return 0;
443
444         data = (struct locking_data *)dbuf.dptr;
445         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
446
447         /* find any with our pid and delete it by overwriting with the rest of the data 
448            from the record */
449         for (i=0;i<data->num_share_mode_entries;) {
450                 if (shares[i].pid == pid &&
451                     memcmp(&shares[i].time, 
452                            &fsp->open_time,sizeof(struct timeval)) == 0) {
453                         *ppse = memdup(&shares[i], sizeof(*shares));
454                         data->num_share_mode_entries--;
455                         memmove(&shares[i], &shares[i+1], 
456                                 dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
457                         del_count++;
458                 } else {
459                         i++;
460                 }
461         }
462
463         /* the record has shrunk a bit */
464         dbuf.dsize -= del_count * sizeof(*shares);
465
466         count = data->num_share_mode_entries;
467
468         /* store it back in the database */
469         if (data->num_share_mode_entries == 0) {
470                 tdb_delete(tdb, locking_key_fsp(fsp));
471         } else {
472                 tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
473         }
474
475         free(dbuf.dptr);
476         return count;
477 }
478
479 /*******************************************************************
480 fill a share mode entry
481 ********************************************************************/
482 static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_type)
483 {
484         share_mode_entry *e = (share_mode_entry *)p;
485         e->pid = sys_getpid();
486         e->share_mode = fsp->share_mode;
487         e->op_port = port;
488         e->op_type = op_type;
489         memcpy((char *)&e->time, (char *)&fsp->open_time, sizeof(struct timeval));
490 }
491
492 /*******************************************************************
493  Set the share mode of a file. Return False on fail, True on success.
494 ********************************************************************/
495 BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type)
496 {
497         TDB_DATA dbuf;
498         struct locking_data *data;
499         char *p=NULL;
500         int size;
501                 
502         /* read in the existing share modes if any */
503         dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
504         if (!dbuf.dptr) {
505                 /* we'll need to create a new record */
506                 pstring fname;
507
508                 pstrcpy(fname, fsp->conn->connectpath);
509                 pstrcat(fname, "/");
510                 pstrcat(fname, fsp->fsp_name);
511
512                 size = sizeof(*data) + sizeof(share_mode_entry) + strlen(fname) + 1;
513                 p = (char *)malloc(size);
514                 data = (struct locking_data *)p;
515                 data->num_share_mode_entries = 1;
516                 pstrcpy(p + sizeof(*data) + sizeof(share_mode_entry), fname);
517                 fill_share_mode(p + sizeof(*data), fsp, port, op_type);
518                 dbuf.dptr = p;
519                 dbuf.dsize = size;
520                 tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
521                 free(p);
522                 return True;
523         }
524
525         /* we're adding to an existing entry - this is a bit fiddly */
526         data = (struct locking_data *)dbuf.dptr;
527
528         data->num_share_mode_entries++;
529         size = dbuf.dsize + sizeof(share_mode_entry);
530         p = malloc(size);
531         memcpy(p, dbuf.dptr, sizeof(*data));
532         fill_share_mode(p + sizeof(*data), fsp, port, op_type);
533         memcpy(p + sizeof(*data) + sizeof(share_mode_entry), dbuf.dptr + sizeof(*data),
534                dbuf.dsize - sizeof(*data));
535         free(dbuf.dptr);
536         dbuf.dptr = p;
537         dbuf.dsize = size;
538         tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
539         free(p);
540         return True;
541 }
542
543
544 /*******************************************************************
545 a generic in-place modification call for share mode entries
546 ********************************************************************/
547 static BOOL mod_share_mode(files_struct *fsp,
548                            void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
549                            void *param)
550 {
551         TDB_DATA dbuf;
552         struct locking_data *data;
553         int i;
554         share_mode_entry *shares;
555         pid_t pid = sys_getpid();
556         int need_store=0;
557
558         /* read in the existing share modes */
559         dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
560         if (!dbuf.dptr) return False;
561
562         data = (struct locking_data *)dbuf.dptr;
563         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
564
565         /* find any with our pid and call the supplied function */
566         for (i=0;i<data->num_share_mode_entries;i++) {
567                 if (pid == shares[i].pid && 
568                     shares[i].share_mode == fsp->share_mode &&
569                     memcmp(&shares[i].time, 
570                            &fsp->open_time,sizeof(struct timeval)) == 0) {
571                         mod_fn(&shares[i], fsp->dev, fsp->inode, param);
572                         need_store=1;
573                 }
574         }
575
576         /* if the mod fn was called then store it back */
577         if (need_store) {
578                 if (data->num_share_mode_entries == 0) {
579                         tdb_delete(tdb, locking_key_fsp(fsp));
580                 } else {
581                         tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
582                 }
583         }
584
585         free(dbuf.dptr);
586         return need_store;
587 }
588
589
590 /*******************************************************************
591  Static function that actually does the work for the generic function
592  below.
593 ********************************************************************/
594 static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
595                                    void *param)
596 {
597         DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n",
598                   (unsigned int)dev, (double)inode ));
599         /* Delete the oplock info. */
600         entry->op_port = 0;
601         entry->op_type = NO_OPLOCK;
602 }
603
604 /*******************************************************************
605  Remove an oplock port and mode entry from a share mode.
606 ********************************************************************/
607 BOOL remove_share_oplock(files_struct *fsp)
608 {
609         return mod_share_mode(fsp, remove_share_oplock_fn, NULL);
610 }
611
612 /*******************************************************************
613  Static function that actually does the work for the generic function
614  below.
615 ********************************************************************/
616 static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, 
617                                    void *param)
618 {
619         DEBUG(10,("downgrade_share_oplock_fn: downgrading oplock info for entry dev=%x ino=%.0f\n",
620                   (unsigned int)dev, (double)inode ));
621         entry->op_type = LEVEL_II_OPLOCK;
622 }
623
624 /*******************************************************************
625  Downgrade a oplock type from exclusive to level II.
626 ********************************************************************/
627 BOOL downgrade_share_oplock(files_struct *fsp)
628 {
629         return mod_share_mode(fsp, downgrade_share_oplock_fn, NULL);
630 }
631
632 /*******************************************************************
633  Get/Set the delete on close flag in a set of share modes.
634  Return False on fail, True on success.
635 ********************************************************************/
636
637 BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close)
638 {
639         TDB_DATA dbuf;
640         struct locking_data *data;
641         int i;
642         share_mode_entry *shares;
643
644         /* read in the existing share modes */
645         dbuf = tdb_fetch(tdb, locking_key(dev, inode));
646         if (!dbuf.dptr) return False;
647
648         data = (struct locking_data *)dbuf.dptr;
649         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
650
651         /* Set/Unset the delete on close element. */
652         for (i=0;i<data->num_share_mode_entries;i++,shares++) {
653                 shares->share_mode = (delete_on_close ?
654                             (shares->share_mode | DELETE_ON_CLOSE_FLAG) :
655                             (shares->share_mode & ~DELETE_ON_CLOSE_FLAG) );
656         }
657
658         /* store it back */
659         if (data->num_share_mode_entries) {
660                 if (tdb_store(tdb, locking_key(dev,inode), dbuf, TDB_REPLACE)==-1)
661                         return False;
662         }
663
664         free(dbuf.dptr);
665         return True;
666 }
667
668
669 /****************************************************************************
670 traverse the whole database with this function, calling traverse_callback
671 on each share mode
672 ****************************************************************************/
673 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
674                        void* state)
675 {
676         struct locking_data *data;
677         share_mode_entry *shares;
678         char *name;
679         int i;
680
681         SHAREMODE_FN(traverse_callback) = (SHAREMODE_FN_CAST())state;
682
683         data = (struct locking_data *)dbuf.dptr;
684         shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
685         name = dbuf.dptr + sizeof(*data) + data->num_share_mode_entries*sizeof(*shares);
686
687         for (i=0;i<data->num_share_mode_entries;i++) {
688                 traverse_callback(&shares[i], name);
689         }
690         return 0;
691 }
692
693 /*******************************************************************
694  Call the specified function on each entry under management by the
695  share mode system.
696 ********************************************************************/
697 int share_mode_forall(SHAREMODE_FN(fn))
698 {
699         if (!tdb) return 0;
700         return tdb_traverse(tdb, traverse_fn, (void*)fn);
701 }