2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1992-2000
6 Copyright (C) Jeremy Allison 1992-2000
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.
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.
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.
24 12 aug 96: Erik.Devriendt@te6.siemens.be
25 added support for shared memory implementation of share mode locking
27 May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
28 locking to deal with multiple share modes per open file.
30 September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
33 rewrtten completely to use new tdb code. Tridge, Dec '99
35 Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
39 extern int DEBUGLEVEL;
42 /* the locking database handle */
43 static TDB_CONTEXT *tdb;
45 /****************************************************************************
47 ****************************************************************************/
49 static const char *lock_type_name(enum brl_type lock_type)
51 return (lock_type == READ_LOCK) ? "READ" : "WRITE";
54 /****************************************************************************
55 Utility function called to see if a file region is locked.
56 ****************************************************************************/
58 BOOL is_locked(files_struct *fsp,connection_struct *conn,
59 SMB_BIG_UINT count,SMB_BIG_UINT offset,
60 enum brl_type lock_type)
62 int snum = SNUM(conn);
68 if (!lp_locking(snum) || !lp_strict_locking(snum))
71 ret = !brl_locktest(fsp->dev, fsp->inode, fsp->fnum,
72 global_smbpid, sys_getpid(), conn->cnum,
73 offset, count, lock_type);
76 * There is no lock held by an SMB daemon, check to
77 * see if there is a POSIX lock from a UNIX or NFS process.
80 if(!ret && lp_posix_locking(snum))
81 ret = is_posix_locked(fsp, offset, count, lock_type);
86 /****************************************************************************
87 Utility function called by locking requests.
88 ****************************************************************************/
90 BOOL do_lock(files_struct *fsp,connection_struct *conn,
91 SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type,
92 int *eclass,uint32 *ecode)
96 if (!lp_locking(SNUM(conn)))
101 *ecode = ERRnoaccess;
105 DEBUG(10,("do_lock: lock type %s start=%.0f len=%.0f requested for file %s\n",
106 lock_type_name(lock_type), (double)offset, (double)count, fsp->fsp_name ));
108 if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn)) {
109 ok = brl_lock(fsp->dev, fsp->inode, fsp->fnum,
110 global_smbpid, sys_getpid(), conn->cnum,
114 if (ok && lp_posix_locking(SNUM(conn))) {
117 * Try and get a POSIX lock on this range.
118 * Note that this is ok if it is a read lock
119 * overlapping on a different fd. JRA.
122 ok = set_posix_lock(fsp, offset, count, lock_type);
126 * We failed to map - we must now remove the brl
129 (void)brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
130 global_smbpid, sys_getpid(), conn->cnum,
141 return True; /* Got lock */
144 /****************************************************************************
145 Utility function called by unlocking requests.
146 ****************************************************************************/
148 BOOL do_unlock(files_struct *fsp,connection_struct *conn,
149 SMB_BIG_UINT count,SMB_BIG_UINT offset,
150 int *eclass,uint32 *ecode)
154 if (!lp_locking(SNUM(conn)))
157 if (!OPEN_FSP(fsp) || !fsp->can_lock || (fsp->conn != conn)) {
163 DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
164 (double)offset, (double)count, fsp->fsp_name ));
167 * Remove the existing lock record from the tdb lockdb
168 * before looking at POSIX locks. If this record doesn't
169 * match then don't bother looking to remove POSIX locks.
172 ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum,
173 global_smbpid, sys_getpid(), conn->cnum, offset, count);
176 DEBUG(10,("do_unlock: returning ERRlock.\n" ));
182 if (!lp_posix_locking(SNUM(conn)))
185 (void)release_posix_lock(fsp, offset, count);
187 return True; /* Did unlock */
190 /****************************************************************************
191 Remove any locks on this fd. Called from file_close().
192 ****************************************************************************/
194 void locking_close_file(files_struct *fsp)
196 pid_t pid = sys_getpid();
198 if (!lp_locking(SNUM(fsp->conn)))
202 * Just release all the brl locks, no need to release individually.
205 brl_close(fsp->dev, fsp->inode, pid, fsp->conn->cnum, fsp->fnum);
207 if(lp_posix_locking(SNUM(fsp->conn))) {
210 * Release all the POSIX locks.
212 posix_locking_close_file(fsp);
217 /****************************************************************************
218 Initialise the locking functions.
219 ****************************************************************************/
220 BOOL locking_init(int read_only)
224 if (tdb) return True;
226 tdb = tdb_open(lock_path("locking.tdb"),
227 0, TDB_CLEAR_IF_FIRST,
228 read_only?O_RDONLY:O_RDWR|O_CREAT,
232 DEBUG(0,("ERROR: Failed to initialise share modes\n"));
236 if (!posix_locking_init())
242 /*******************************************************************
243 Deinitialize the share_mode management.
244 ******************************************************************/
245 BOOL locking_end(void)
247 if (tdb && tdb_close(tdb) != 0) return False;
251 /*******************************************************************
252 form a static locking key for a dev/inode pair
253 ******************************************************************/
254 static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
256 static struct locking_key key;
259 memset(&key, '\0', sizeof(key));
262 kbuf.dptr = (char *)&key;
263 kbuf.dsize = sizeof(key);
266 static TDB_DATA locking_key_fsp(files_struct *fsp)
268 return locking_key(fsp->dev, fsp->inode);
271 /*******************************************************************
272 Lock a hash bucket entry.
273 ******************************************************************/
274 BOOL lock_share_entry(connection_struct *conn,
275 SMB_DEV_T dev, SMB_INO_T inode)
277 return tdb_lockchain(tdb, locking_key(dev, inode)) == 0;
280 /*******************************************************************
281 Unlock a hash bucket entry.
282 ******************************************************************/
283 BOOL unlock_share_entry(connection_struct *conn,
284 SMB_DEV_T dev, SMB_INO_T inode)
286 return tdb_unlockchain(tdb, locking_key(dev, inode)) == 0;
290 /*******************************************************************
291 Lock a hash bucket entry. use a fsp for convenience
292 ******************************************************************/
293 BOOL lock_share_entry_fsp(files_struct *fsp)
295 return tdb_lockchain(tdb, locking_key(fsp->dev, fsp->inode)) == 0;
298 /*******************************************************************
299 Unlock a hash bucket entry.
300 ******************************************************************/
301 BOOL unlock_share_entry_fsp(files_struct *fsp)
303 return tdb_unlockchain(tdb, locking_key(fsp->dev, fsp->inode)) == 0;
306 /*******************************************************************
307 Get all share mode entries for a dev/inode pair.
308 ********************************************************************/
309 int get_share_modes(connection_struct *conn,
310 SMB_DEV_T dev, SMB_INO_T inode,
311 share_mode_entry **shares)
314 struct locking_data *data;
319 dbuf = tdb_fetch(tdb, locking_key(dev, inode));
320 if (!dbuf.dptr) return 0;
322 data = (struct locking_data *)dbuf.dptr;
323 ret = data->num_share_mode_entries;
325 *shares = (share_mode_entry *)memdup(dbuf.dptr + sizeof(*data), ret * sizeof(**shares));
328 if (! *shares) return 0;
333 /*******************************************************************
334 Del the share mode of a file for this process
335 ********************************************************************/
336 void del_share_mode(files_struct *fsp)
339 struct locking_data *data;
341 share_mode_entry *shares;
342 pid_t pid = sys_getpid();
344 /* read in the existing share modes */
345 dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
346 if (!dbuf.dptr) return;
348 data = (struct locking_data *)dbuf.dptr;
349 shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
351 /* find any with our pid and delete it by overwriting with the rest of the data
353 for (i=0;i<data->num_share_mode_entries;) {
354 if (shares[i].pid == pid &&
355 memcmp(&shares[i].time,
356 &fsp->open_time,sizeof(struct timeval)) == 0) {
357 data->num_share_mode_entries--;
358 memmove(&shares[i], &shares[i+1],
359 dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
366 /* the record has shrunk a bit */
367 dbuf.dsize -= del_count * sizeof(*shares);
369 /* store it back in the database */
370 if (data->num_share_mode_entries == 0) {
371 tdb_delete(tdb, locking_key_fsp(fsp));
373 tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
379 /*******************************************************************
380 fill a share mode entry
381 ********************************************************************/
382 static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_type)
384 share_mode_entry *e = (share_mode_entry *)p;
385 e->pid = sys_getpid();
386 e->share_mode = fsp->share_mode;
388 e->op_type = op_type;
389 memcpy((char *)&e->time, (char *)&fsp->open_time, sizeof(struct timeval));
392 /*******************************************************************
393 Set the share mode of a file. Return False on fail, True on success.
394 ********************************************************************/
395 BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type)
398 struct locking_data *data;
399 share_mode_entry *shares;
403 /* read in the existing share modes if any */
404 dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
406 /* we'll need to create a new record */
409 pstrcpy(fname, fsp->conn->connectpath);
411 pstrcat(fname, fsp->fsp_name);
413 size = sizeof(*data) + sizeof(*shares) + strlen(fname) + 1;
414 p = (char *)malloc(size);
415 data = (struct locking_data *)p;
416 shares = (share_mode_entry *)(p + sizeof(*data));
417 data->num_share_mode_entries = 1;
418 pstrcpy(p + sizeof(*data) + sizeof(*shares), fname);
419 fill_share_mode(p + sizeof(*data), fsp, port, op_type);
422 tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
427 /* we're adding to an existing entry - this is a bit fiddly */
428 data = (struct locking_data *)dbuf.dptr;
429 shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
431 data->num_share_mode_entries++;
432 size = dbuf.dsize + sizeof(*shares);
434 memcpy(p, dbuf.dptr, sizeof(*data));
435 fill_share_mode(p + sizeof(*data), fsp, port, op_type);
436 memcpy(p + sizeof(*data) + sizeof(*shares), dbuf.dptr + sizeof(*data),
437 dbuf.dsize - sizeof(*data));
441 tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
447 /*******************************************************************
448 a generic in-place modification call for share mode entries
449 ********************************************************************/
450 static BOOL mod_share_mode(files_struct *fsp,
451 void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
455 struct locking_data *data;
457 share_mode_entry *shares;
458 pid_t pid = sys_getpid();
461 /* read in the existing share modes */
462 dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
463 if (!dbuf.dptr) return False;
465 data = (struct locking_data *)dbuf.dptr;
466 shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
468 /* find any with our pid and call the supplied function */
469 for (i=0;i<data->num_share_mode_entries;i++) {
470 if (pid == shares[i].pid &&
471 shares[i].share_mode == fsp->share_mode &&
472 memcmp(&shares[i].time,
473 &fsp->open_time,sizeof(struct timeval)) == 0) {
474 mod_fn(&shares[i], fsp->dev, fsp->inode, param);
479 /* if the mod fn was called then store it back */
481 if (data->num_share_mode_entries == 0) {
482 tdb_delete(tdb, locking_key_fsp(fsp));
484 tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
493 /*******************************************************************
494 Static function that actually does the work for the generic function
496 ********************************************************************/
497 static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
500 DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n",
501 (unsigned int)dev, (double)inode ));
502 /* Delete the oplock info. */
504 entry->op_type = NO_OPLOCK;
507 /*******************************************************************
508 Remove an oplock port and mode entry from a share mode.
509 ********************************************************************/
510 BOOL remove_share_oplock(files_struct *fsp)
512 return mod_share_mode(fsp, remove_share_oplock_fn, NULL);
515 /*******************************************************************
516 Static function that actually does the work for the generic function
518 ********************************************************************/
519 static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
522 DEBUG(10,("downgrade_share_oplock_fn: downgrading oplock info for entry dev=%x ino=%.0f\n",
523 (unsigned int)dev, (double)inode ));
524 entry->op_type = LEVEL_II_OPLOCK;
527 /*******************************************************************
528 Downgrade a oplock type from exclusive to level II.
529 ********************************************************************/
530 BOOL downgrade_share_oplock(files_struct *fsp)
532 return mod_share_mode(fsp, downgrade_share_oplock_fn, NULL);
536 /*******************************************************************
537 Static function that actually does the work for the generic function
539 ********************************************************************/
545 static void modify_share_mode_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
548 struct mod_val *mvp = (struct mod_val *)param;
550 DEBUG(10,("modify_share_mode_fn: changing share mode info from %x to %x for entry dev=%x ino=%.0f\n",
551 entry->share_mode, mvp->new_share_mode, (unsigned int)dev, (double)inode ));
552 DEBUG(10,("modify_share_mode_fn: changing oplock state from %x to %x for entry dev=%x ino=%.0f\n",
553 entry->op_type, (int)mvp->new_oplock, (unsigned int)dev, (double)inode ));
554 /* Change the share mode info. */
555 entry->share_mode = mvp->new_share_mode;
556 entry->op_type = mvp->new_oplock;
559 /*******************************************************************
560 Modify a share mode on a file. Used by the delete open file code.
561 Return False on fail, True on success.
562 ********************************************************************/
563 BOOL modify_share_mode(files_struct *fsp, int new_mode, uint16 new_oplock)
567 mv.new_share_mode = new_mode;
568 mv.new_oplock = new_oplock;
570 return mod_share_mode(fsp, modify_share_mode_fn, (void *)&mv);
574 /****************************************************************************
575 traverse the whole database with this function, calling traverse_callback
577 ****************************************************************************/
578 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
581 struct locking_data *data;
582 share_mode_entry *shares;
586 SHAREMODE_FN(traverse_callback) = (SHAREMODE_FN_CAST())state;
588 data = (struct locking_data *)dbuf.dptr;
589 shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
590 name = dbuf.dptr + sizeof(*data) + data->num_share_mode_entries*sizeof(*shares);
592 for (i=0;i<data->num_share_mode_entries;i++) {
593 traverse_callback(&shares[i], name);
598 /*******************************************************************
599 Call the specified function on each entry under management by the
601 ********************************************************************/
602 int share_mode_forall(SHAREMODE_FN(fn))
605 return tdb_traverse(tdb, traverse_fn, (void*)fn);