2 Unix SMB/Netbios implementation.
4 shared memory locking implementation
5 Copyright (C) Andrew Tridgell 1992-1997
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 12 aug 96: Erik.Devriendt@te6.siemens.be
24 added support for shared memory implementation of share mode locking
26 May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
27 locking to deal with multiple share modes per open file.
29 September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
32 October 1997 - split into separate file (tridge)
35 #ifdef FAST_SHARE_MODES
38 extern int DEBUGLEVEL;
39 extern connection_struct Connections[];
40 extern files_struct Files[];
42 /* share mode record pointed to in shared memory hash bucket */
45 int next_offset; /* offset of next record in chain from hash bucket */
49 int num_share_mode_entries;
50 int share_mode_entries; /* Chain of share mode entries for this file */
54 /* share mode entry pointed to by share_mode_record struct */
57 int next_share_mode_entry;
59 } shm_share_mode_entry;
63 /*******************************************************************
64 deinitialize the shared memory for share_mode management
65 ******************************************************************/
66 static BOOL shm_stop_share_mode_mgmt(void)
68 return smb_shm_close();
71 /*******************************************************************
72 lock a hash bucket entry in shared memory for share_mode management
73 ******************************************************************/
74 static BOOL shm_lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok)
76 return smb_shm_lock_hash_entry(HASH_ENTRY(dev, inode));
79 /*******************************************************************
80 unlock a hash bucket entry in shared memory for share_mode management
81 ******************************************************************/
82 static BOOL shm_unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token)
84 return smb_shm_unlock_hash_entry(HASH_ENTRY(dev, inode));
87 /*******************************************************************
88 get all share mode entries in shared memory for a dev/inode pair.
89 ********************************************************************/
90 static int shm_get_share_modes(int cnum, int token, uint32 dev, uint32 inode,
91 share_mode_entry **old_shares)
94 unsigned int hash_entry = HASH_ENTRY(dev, inode);
95 share_mode_record *file_scanner_p;
96 share_mode_record *file_prev_p;
97 shm_share_mode_entry *entry_scanner_p;
98 shm_share_mode_entry *entry_prev_p;
100 int num_entries_copied;
102 share_mode_entry *share_array = (share_mode_entry *)0;
106 if(hash_entry > lp_shmem_hash_size() )
109 ("PANIC ERROR : get_share_modes (FAST_SHARE_MODES): hash_entry %d too large \
111 hash_entry, lp_shmem_hash_size() ));
115 mode_array = (int *)smb_shm_offset2addr(smb_shm_get_userdef_off());
117 if(mode_array[hash_entry] == NULL_OFFSET)
119 DEBUG(5,("get_share_modes (FAST_SHARE_MODES): hash bucket %d empty\n", hash_entry));
123 file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
124 file_prev_p = file_scanner_p;
125 while(file_scanner_p)
127 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
134 file_prev_p = file_scanner_p ;
135 file_scanner_p = (share_mode_record *)smb_shm_offset2addr(
136 file_scanner_p->next_offset);
142 DEBUG(5,("get_share_modes (FAST_SHARE_MODES): no entry for \
143 file dev = %d, ino = %d in hash_bucket %d\n", dev, inode, hash_entry));
147 if(file_scanner_p->locking_version != LOCKING_VERSION)
149 DEBUG(0,("ERROR:get_share_modes (FAST_SHARE_MODES): Deleting old share mode \
150 record due to old locking version %d for file dev = %d, inode = %d in hash \
151 bucket %d\n", file_scanner_p->locking_version, dev, inode, hash_entry));
152 if(file_prev_p == file_scanner_p)
153 mode_array[hash_entry] = file_scanner_p->next_offset;
155 file_prev_p->next_offset = file_scanner_p->next_offset;
156 smb_shm_free(smb_shm_addr2offset(file_scanner_p));
160 /* Allocate the old_shares array */
161 num_entries = file_scanner_p->num_share_mode_entries;
164 *old_shares = share_array = (share_mode_entry *)
165 malloc(num_entries * sizeof(share_mode_entry));
168 DEBUG(0,("get_share_modes (FAST_SHARE_MODES): malloc fail !\n"));
173 num_entries_copied = 0;
175 entry_scanner_p = (shm_share_mode_entry*)smb_shm_offset2addr(
176 file_scanner_p->share_mode_entries);
177 entry_prev_p = entry_scanner_p;
178 while(entry_scanner_p)
180 int pid = entry_scanner_p->e.pid;
182 if (pid && !process_exists(pid))
184 /* Delete this share mode entry */
185 shm_share_mode_entry *delete_entry_p = entry_scanner_p;
186 int share_mode = entry_scanner_p->e.share_mode;
188 if(entry_prev_p == entry_scanner_p)
190 /* We are at start of list */
191 file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
192 entry_scanner_p = (shm_share_mode_entry*)smb_shm_offset2addr(
193 file_scanner_p->share_mode_entries);
194 entry_prev_p = entry_scanner_p;
198 entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
199 entry_scanner_p = (shm_share_mode_entry*)
200 smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
202 /* Decrement the number of share mode entries on this share mode record */
203 file_scanner_p->num_share_mode_entries -= 1;
206 if(file_scanner_p->num_share_mode_entries < 0)
208 DEBUG(0,("PANIC ERROR:get_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
209 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
210 dev, inode, hash_entry));
214 DEBUG(0,("get_share_modes (FAST_SHARE_MODES): process %d no longer exists and \
215 it left a share mode entry with mode 0x%X for file dev = %d, ino = %d in hash \
216 bucket %d (number of entries now = %d)\n",
217 pid, share_mode, dev, inode, hash_entry,
218 file_scanner_p->num_share_mode_entries));
220 smb_shm_free(smb_shm_addr2offset(delete_entry_p));
224 /* This is a valid share mode entry and the process that
225 created it still exists. Copy it into the output array.
227 share_array[num_entries_copied].pid = entry_scanner_p->e.pid;
228 share_array[num_entries_copied].share_mode = entry_scanner_p->e.share_mode;
229 share_array[num_entries_copied].op_port = entry_scanner_p->e.op_port;
230 share_array[num_entries_copied].op_type = entry_scanner_p->e.op_type;
231 memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->e.time,
232 sizeof(struct timeval));
233 num_entries_copied++;
234 DEBUG(5,("get_share_modes (FAST_SHARE_MODES): Read share mode \
235 record mode 0x%X pid=%d\n", entry_scanner_p->e.share_mode, entry_scanner_p->e.pid));
236 entry_prev_p = entry_scanner_p;
237 entry_scanner_p = (shm_share_mode_entry *)
238 smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
242 /* If no valid share mode entries were found then this record shouldn't exist ! */
243 if(num_entries_copied == 0)
245 DEBUG(0,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
246 hash bucket %d has a share mode record but no entries - deleting\n",
247 dev, inode, hash_entry));
249 free((char *)*old_shares);
252 if(file_prev_p == file_scanner_p)
253 mode_array[hash_entry] = file_scanner_p->next_offset;
255 file_prev_p->next_offset = file_scanner_p->next_offset;
256 smb_shm_free(smb_shm_addr2offset(file_scanner_p));
259 DEBUG(5,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
260 hash bucket %d returning %d entries\n", dev, inode, hash_entry, num_entries_copied));
262 return(num_entries_copied);
265 /*******************************************************************
266 del the share mode of a file.
267 ********************************************************************/
268 static void shm_del_share_mode(int token, int fnum)
272 unsigned int hash_entry;
273 share_mode_record *file_scanner_p;
274 share_mode_record *file_prev_p;
275 shm_share_mode_entry *entry_scanner_p;
276 shm_share_mode_entry *entry_prev_p;
280 dev = Files[fnum].fd_ptr->dev;
281 inode = Files[fnum].fd_ptr->inode;
283 hash_entry = HASH_ENTRY(dev, inode);
285 if(hash_entry > lp_shmem_hash_size() )
288 ("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
290 hash_entry, lp_shmem_hash_size() ));
294 mode_array = (int *)smb_shm_offset2addr(smb_shm_get_userdef_off());
296 if(mode_array[hash_entry] == NULL_OFFSET)
298 DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash bucket %d empty\n",
303 file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
304 file_prev_p = file_scanner_p;
306 while(file_scanner_p)
308 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
315 file_prev_p = file_scanner_p ;
316 file_scanner_p = (share_mode_record *)
317 smb_shm_offset2addr(file_scanner_p->next_offset);
323 DEBUG(0,("ERROR:del_share_mode (FAST_SHARE_MODES): no entry found for dev %d, \
324 inode %d in hash bucket %d\n", dev, inode, hash_entry));
328 if(file_scanner_p->locking_version != LOCKING_VERSION)
330 DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): Deleting old share mode \
331 record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
332 file_scanner_p->locking_version, dev, inode, hash_entry ));
333 if(file_prev_p == file_scanner_p)
334 mode_array[hash_entry] = file_scanner_p->next_offset;
336 file_prev_p->next_offset = file_scanner_p->next_offset;
337 smb_shm_free(smb_shm_addr2offset(file_scanner_p));
342 entry_scanner_p = (shm_share_mode_entry*)smb_shm_offset2addr(
343 file_scanner_p->share_mode_entries);
344 entry_prev_p = entry_scanner_p;
345 while(entry_scanner_p)
347 if( (pid == entry_scanner_p->e.pid) &&
348 (memcmp(&entry_scanner_p->e.time,
349 &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
356 entry_prev_p = entry_scanner_p;
357 entry_scanner_p = (shm_share_mode_entry *)
358 smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
364 /* Decrement the number of entries in the record. */
365 file_scanner_p->num_share_mode_entries -= 1;
367 DEBUG(2,("del_share_modes (FAST_SHARE_MODES): \
368 Deleting share mode entry dev = %d, inode = %d in hash bucket %d (num entries now = %d)\n",
369 dev, inode, hash_entry, file_scanner_p->num_share_mode_entries));
370 if(entry_prev_p == entry_scanner_p)
371 /* We are at start of list */
372 file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
374 entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
375 smb_shm_free(smb_shm_addr2offset(entry_scanner_p));
378 if(file_scanner_p->num_share_mode_entries < 0)
380 DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
381 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
382 dev, inode, hash_entry));
386 /* If we deleted the last share mode entry then remove the share mode record. */
387 if(file_scanner_p->num_share_mode_entries == 0)
389 DEBUG(2,("del_share_modes (FAST_SHARE_MODES): num entries = 0, deleting share_mode \
390 record dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
391 if(file_prev_p == file_scanner_p)
392 mode_array[hash_entry] = file_scanner_p->next_offset;
394 file_prev_p->next_offset = file_scanner_p->next_offset;
395 smb_shm_free(smb_shm_addr2offset(file_scanner_p));
400 DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): No share mode record found \
401 dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
405 /*******************************************************************
406 set the share mode of a file. Return False on fail, True on success.
407 ********************************************************************/
408 static BOOL shm_set_share_mode(int token, int fnum, uint16 port, uint16 op_type)
410 files_struct *fs_p = &Files[fnum];
413 unsigned int hash_entry;
414 share_mode_record *file_scanner_p;
415 share_mode_record *file_prev_p;
416 shm_share_mode_entry *new_entry_p;
417 int new_entry_offset;
420 dev = fs_p->fd_ptr->dev;
421 inode = fs_p->fd_ptr->inode;
423 hash_entry = HASH_ENTRY(dev, inode);
424 if(hash_entry > lp_shmem_hash_size() )
427 ("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
429 hash_entry, lp_shmem_hash_size() ));
433 mode_array = (int *)smb_shm_offset2addr(smb_shm_get_userdef_off());
435 file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
436 file_prev_p = file_scanner_p;
438 while(file_scanner_p)
440 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
447 file_prev_p = file_scanner_p ;
448 file_scanner_p = (share_mode_record *)
449 smb_shm_offset2addr(file_scanner_p->next_offset);
455 /* We must create a share_mode_record */
456 share_mode_record *new_mode_p = NULL;
457 int new_offset = smb_shm_alloc( sizeof(share_mode_record) +
458 strlen(fs_p->name) + 1);
459 if(new_offset == NULL_OFFSET)
461 DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail !\n"));
464 new_mode_p = smb_shm_offset2addr(new_offset);
465 new_mode_p->locking_version = LOCKING_VERSION;
466 new_mode_p->st_dev = dev;
467 new_mode_p->st_ino = inode;
468 new_mode_p->num_share_mode_entries = 0;
469 new_mode_p->share_mode_entries = NULL_OFFSET;
470 strcpy(new_mode_p->file_name, fs_p->name);
472 /* Chain onto the start of the hash chain (in the hope we will be used first). */
473 new_mode_p->next_offset = mode_array[hash_entry];
474 mode_array[hash_entry] = new_offset;
476 file_scanner_p = new_mode_p;
478 DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share record for %s (dev %d \
479 inode %d in hash bucket %d\n", fs_p->name, dev, inode, hash_entry));
482 /* Now create the share mode entry */
483 new_entry_offset = smb_shm_alloc( sizeof(shm_share_mode_entry));
484 if(new_entry_offset == NULL_OFFSET)
486 int delete_offset = mode_array[hash_entry];
487 DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail 1!\n"));
488 /* Unlink the damaged record */
489 mode_array[hash_entry] = file_scanner_p->next_offset;
491 smb_shm_free( delete_offset );
495 new_entry_p = smb_shm_offset2addr(new_entry_offset);
497 new_entry_p->e.pid = getpid();
498 new_entry_p->e.share_mode = fs_p->share_mode;
499 new_entry_p->e.op_port = port;
500 new_entry_p->e.op_type = op_type;
501 memcpy( (char *)&new_entry_p->e.time, (char *)&fs_p->open_time, sizeof(struct timeval));
503 /* Chain onto the share_mode_record */
504 new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
505 file_scanner_p->share_mode_entries = new_entry_offset;
508 if(file_scanner_p->num_share_mode_entries < 0)
510 DEBUG(0,("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
511 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
512 dev, inode, hash_entry));
516 /* Increment the share_mode_entries counter */
517 file_scanner_p->num_share_mode_entries += 1;
519 DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share entry for %s with mode \
520 0x%X pid=%d (num_entries now = %d)\n",fs_p->name, fs_p->share_mode, new_entry_p->e.pid,
521 file_scanner_p->num_share_mode_entries));
526 /*******************************************************************
527 Remove an oplock port and mode entry from a share mode.
528 ********************************************************************/
529 static BOOL shm_remove_share_oplock(int fnum, int token)
533 unsigned int hash_entry;
534 share_mode_record *file_scanner_p;
535 share_mode_record *file_prev_p;
536 shm_share_mode_entry *entry_scanner_p;
537 shm_share_mode_entry *entry_prev_p;
541 dev = Files[fnum].fd_ptr->dev;
542 inode = Files[fnum].fd_ptr->inode;
544 hash_entry = HASH_ENTRY(dev, inode);
546 if(hash_entry > lp_shmem_hash_size() )
549 ("PANIC ERROR:remove_share_oplock (FAST_SHARE_MODES): hash_entry %d too large \
551 hash_entry, lp_shmem_hash_size() ));
555 mode_array = (int *)smb_shm_offset2addr(smb_shm_get_userdef_off());
557 if(mode_array[hash_entry] == NULL_OFFSET)
559 DEBUG(0,("PANIC ERROR:remove_share_oplock (FAST_SHARE_MODES): hash bucket %d empty\n",
564 file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
565 file_prev_p = file_scanner_p;
567 while(file_scanner_p)
569 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
576 file_prev_p = file_scanner_p ;
577 file_scanner_p = (share_mode_record *)
578 smb_shm_offset2addr(file_scanner_p->next_offset);
584 DEBUG(0,("ERROR:remove_share_oplock (FAST_SHARE_MODES): no entry found for dev %d, \
585 inode %d in hash bucket %d\n", dev, inode, hash_entry));
589 if(file_scanner_p->locking_version != LOCKING_VERSION)
591 DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): Deleting old share mode \
592 record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
593 file_scanner_p->locking_version, dev, inode, hash_entry ));
594 if(file_prev_p == file_scanner_p)
595 mode_array[hash_entry] = file_scanner_p->next_offset;
597 file_prev_p->next_offset = file_scanner_p->next_offset;
598 smb_shm_free(smb_shm_addr2offset(file_scanner_p));
603 entry_scanner_p = (shm_share_mode_entry*)smb_shm_offset2addr(
604 file_scanner_p->share_mode_entries);
605 entry_prev_p = entry_scanner_p;
606 while(entry_scanner_p)
608 if( (pid == entry_scanner_p->e.pid) &&
609 (entry_scanner_p->e.share_mode == Files[fnum].share_mode) &&
610 (memcmp(&entry_scanner_p->e.time,
611 &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
613 /* Delete the oplock info. */
614 entry_scanner_p->e.op_port = 0;
615 entry_scanner_p->e.op_type = 0;
621 entry_prev_p = entry_scanner_p;
622 entry_scanner_p = (shm_share_mode_entry *)
623 smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
629 DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): No oplock granted share \
630 mode record found dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
638 /*******************************************************************
639 call the specified function on each entry under management by the
641 ********************************************************************/
642 static int shm_share_forall(void (*fn)(share_mode_entry *, char *))
646 share_mode_record *file_scanner_p;
648 mode_array = (int *)smb_shm_offset2addr(smb_shm_get_userdef_off());
650 for( i = 0; i < lp_shmem_hash_size(); i++) {
651 smb_shm_lock_hash_entry(i);
652 if(mode_array[i] == NULL_OFFSET) {
653 smb_shm_unlock_hash_entry(i);
657 file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[i]);
658 while((file_scanner_p != 0) &&
659 (file_scanner_p->num_share_mode_entries != 0)) {
660 shm_share_mode_entry *entry_scanner_p =
661 (shm_share_mode_entry *)
662 smb_shm_offset2addr(file_scanner_p->share_mode_entries);
664 while(entry_scanner_p != 0) {
666 fn(&entry_scanner_p->e,
667 file_scanner_p->file_name);
670 (shm_share_mode_entry *)
672 entry_scanner_p->next_share_mode_entry);
674 } /* end while entry_scanner_p */
675 file_scanner_p = (share_mode_record *)
676 smb_shm_offset2addr(file_scanner_p->next_offset);
677 } /* end while file_scanner_p */
678 smb_shm_unlock_hash_entry(i);
685 /*******************************************************************
686 dump the state of the system
687 ********************************************************************/
688 static void shm_share_status(FILE *f)
690 int bytes_free, bytes_used, bytes_overhead, bytes_total;
692 smb_shm_get_usage(&bytes_free, &bytes_used, &bytes_overhead);
693 bytes_total = bytes_free + bytes_used + bytes_overhead;
695 fprintf(f, "Share mode memory usage (bytes):\n");
696 fprintf(f, " %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n",
697 bytes_free, (bytes_free * 100)/bytes_total,
698 bytes_used, (bytes_used * 100)/bytes_total,
699 bytes_overhead, (bytes_overhead * 100)/bytes_total,
704 static struct share_ops share_ops = {
705 shm_stop_share_mode_mgmt,
706 shm_lock_share_entry,
707 shm_unlock_share_entry,
711 shm_remove_share_oplock,
716 /*******************************************************************
717 initialize the shared memory for share_mode management
718 ******************************************************************/
719 struct share_ops *locking_shm_init(int ronly)
721 pstring shmem_file_name;
725 pstrcpy(shmem_file_name,lp_lockdir());
726 if (!directory_exist(shmem_file_name,NULL)) {
727 if (read_only) return NULL;
728 mkdir(shmem_file_name,0755);
730 trim_string(shmem_file_name,"","/");
731 if (!*shmem_file_name) return(False);
732 strcat(shmem_file_name, "/SHARE_MEM_FILE");
733 if (smb_shm_open(shmem_file_name, lp_shmem_size(), read_only))
739 int locking_shm_dummy_procedure(void)