2 Unix SMB/Netbios implementation.
4 shared memory locking implementation
5 Copyright (C) Andrew Tridgell 1992-1998
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)
37 #ifdef FAST_SHARE_MODES
39 extern int DEBUGLEVEL;
41 static struct shmem_ops *shmops;
43 /* share mode record pointed to in shared memory hash bucket */
46 int next_offset; /* offset of next record in chain from hash bucket */
50 int num_share_mode_entries;
51 int share_mode_entries; /* Chain of share mode entries for this file */
55 /* share mode entry pointed to by share_mode_record struct */
58 int next_share_mode_entry;
60 } shm_share_mode_entry;
65 /* Conversion to hash entry index from device and inode numbers. */
66 #define HASH_ENTRY(dev,ino) ((unsigned int)(((dev) ^ (ino)) % shmops->hash_size()))
69 /*******************************************************************
70 deinitialize the shared memory for share_mode management
71 ******************************************************************/
72 static BOOL shm_stop_share_mode_mgmt(void)
74 return shmops->shm_close();
77 /*******************************************************************
78 lock a hash bucket entry in shared memory for share_mode management
79 ******************************************************************/
80 static BOOL shm_lock_share_entry(connection_struct *conn,
81 SMB_DEV_T dev, SMB_INO_T inode, int *ptok)
83 return shmops->lock_hash_entry(HASH_ENTRY(dev, inode));
86 /*******************************************************************
87 unlock a hash bucket entry in shared memory for share_mode management
88 ******************************************************************/
89 static BOOL shm_unlock_share_entry(connection_struct *conn,
90 SMB_DEV_T dev, SMB_INO_T inode, int token)
92 return shmops->unlock_hash_entry(HASH_ENTRY(dev, inode));
95 /*******************************************************************
96 get all share mode entries in shared memory for a dev/inode pair.
97 ********************************************************************/
98 static int shm_get_share_modes(connection_struct *conn,
99 int token, SMB_DEV_T dev, SMB_INO_T inode,
100 share_mode_entry **old_shares)
103 unsigned int hash_entry = HASH_ENTRY(dev, inode);
104 share_mode_record *file_scanner_p;
105 share_mode_record *file_prev_p;
106 shm_share_mode_entry *entry_scanner_p;
107 shm_share_mode_entry *entry_prev_p;
109 int num_entries_copied;
111 share_mode_entry *share_array = (share_mode_entry *)0;
115 mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
117 if(mode_array[hash_entry] == 0)
119 DEBUG(5,("get_share_modes hash bucket %d empty\n", hash_entry));
123 file_scanner_p = (share_mode_record *)shmops->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 *)shmops->offset2addr(
136 file_scanner_p->next_offset);
142 DEBUG(5,("get_share_modes no entry for file dev = %x ino = %.0f\n",
143 (unsigned int)dev, (double)inode));
147 if(file_scanner_p->locking_version != LOCKING_VERSION)
149 DEBUG(0,("ERROR: get_share_modes Deleting old share mode v1 %d dev=%x ino=%.0f\n",
150 file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
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 shmops->shm_free(shmops->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: malloc fail!\n"));
173 num_entries_copied = 0;
175 entry_scanner_p = (shm_share_mode_entry*)shmops->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;
187 if(entry_prev_p == entry_scanner_p)
189 /* We are at start of list */
190 file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
191 entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
192 file_scanner_p->share_mode_entries);
193 entry_prev_p = entry_scanner_p;
197 entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
198 entry_scanner_p = (shm_share_mode_entry*)
199 shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
201 /* Decrement the number of share mode entries on this share mode record */
202 file_scanner_p->num_share_mode_entries -= 1;
205 if(file_scanner_p->num_share_mode_entries < 0)
207 DEBUG(0,("PANIC ERROR: get_share_mode: entries=%d dev=%x ino=%.0f\n",
208 file_scanner_p->num_share_mode_entries, (unsigned int)dev, (double)inode));
212 DEBUG(0,("get_share_modes: process %d no longer exists\n", pid));
214 shmops->shm_free(shmops->addr2offset(delete_entry_p));
218 /* This is a valid share mode entry and the process that
219 created it still exists. Copy it into the output array.
221 share_array[num_entries_copied].pid = entry_scanner_p->e.pid;
222 share_array[num_entries_copied].share_mode = entry_scanner_p->e.share_mode;
223 share_array[num_entries_copied].op_port = entry_scanner_p->e.op_port;
224 share_array[num_entries_copied].op_type = entry_scanner_p->e.op_type;
225 memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->e.time,
226 sizeof(struct timeval));
227 num_entries_copied++;
228 DEBUG(5,("get_share_modes Read share mode 0x%X pid=%d\n",
229 entry_scanner_p->e.share_mode, entry_scanner_p->e.pid));
230 entry_prev_p = entry_scanner_p;
231 entry_scanner_p = (shm_share_mode_entry *)
232 shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
236 /* If no valid share mode entries were found then this record shouldn't exist ! */
237 if(num_entries_copied == 0)
239 DEBUG(0,("get_share_modes: file with dev %x inode %.0f empty\n",
240 (unsigned int)dev, (double)inode));
243 free((char *)*old_shares);
246 if(file_prev_p == file_scanner_p)
247 mode_array[hash_entry] = file_scanner_p->next_offset;
249 file_prev_p->next_offset = file_scanner_p->next_offset;
250 shmops->shm_free(shmops->addr2offset(file_scanner_p));
253 DEBUG(5,("get_share_modes: file with dev %x inode %.0f -> %d entries\n",
254 (unsigned int)dev, (double)inode, num_entries_copied));
256 return(num_entries_copied);
259 /*******************************************************************
260 del the share mode of a file.
261 ********************************************************************/
262 static void shm_del_share_mode(int token, files_struct *fsp)
267 unsigned int hash_entry;
268 share_mode_record *file_scanner_p;
269 share_mode_record *file_prev_p;
270 shm_share_mode_entry *entry_scanner_p;
271 shm_share_mode_entry *entry_prev_p;
275 dev = fsp->fd_ptr->dev;
276 inode = fsp->fd_ptr->inode;
278 hash_entry = HASH_ENTRY(dev, inode);
280 mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
282 if(mode_array[hash_entry] == 0)
284 DEBUG(0,("PANIC ERROR:del_share_mode hash bucket %d empty\n",
289 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
290 file_prev_p = file_scanner_p;
292 while(file_scanner_p)
294 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
301 file_prev_p = file_scanner_p ;
302 file_scanner_p = (share_mode_record *)
303 shmops->offset2addr(file_scanner_p->next_offset);
309 DEBUG(0,("ERROR: del_share_mode no entry for dev %x inode %.0f\n",
310 (unsigned int)dev, (double)inode));
314 if(file_scanner_p->locking_version != LOCKING_VERSION)
316 DEBUG(0,("ERROR: del_share_modes Deleting old share mode v1 %d dev=%x ino=%.0f\n",
317 file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
319 if(file_prev_p == file_scanner_p)
320 mode_array[hash_entry] = file_scanner_p->next_offset;
322 file_prev_p->next_offset = file_scanner_p->next_offset;
323 shmops->shm_free(shmops->addr2offset(file_scanner_p));
328 entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
329 file_scanner_p->share_mode_entries);
330 entry_prev_p = entry_scanner_p;
331 while(entry_scanner_p)
333 if( (pid == entry_scanner_p->e.pid) &&
334 (memcmp(&entry_scanner_p->e.time,
335 &fsp->open_time,sizeof(struct timeval)) == 0) )
342 entry_prev_p = entry_scanner_p;
343 entry_scanner_p = (shm_share_mode_entry *)
344 shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
350 /* Decrement the number of entries in the record. */
351 file_scanner_p->num_share_mode_entries -= 1;
353 DEBUG(2,("del_share_modes Deleting share mode entry dev=%x ino=%.0f\n",
354 (unsigned int)dev, (double)inode));
356 if(entry_prev_p == entry_scanner_p)
357 /* We are at start of list */
358 file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
360 entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
361 shmops->shm_free(shmops->addr2offset(entry_scanner_p));
364 if(file_scanner_p->num_share_mode_entries < 0)
366 DEBUG(0,("PANIC ERROR:del_share_mode num_share_mode_entries=%d\n",
367 file_scanner_p->num_share_mode_entries));
371 /* If we deleted the last share mode entry then remove the share mode record. */
372 if(file_scanner_p->num_share_mode_entries == 0)
374 DEBUG(2,("del_share_modes num entries = 0, deleting share_mode dev=%x ino=%.0f\n",
375 (unsigned int)dev, (double)inode));
377 if(file_prev_p == file_scanner_p)
378 mode_array[hash_entry] = file_scanner_p->next_offset;
380 file_prev_p->next_offset = file_scanner_p->next_offset;
381 shmops->shm_free(shmops->addr2offset(file_scanner_p));
386 DEBUG(0,("ERROR: del_share_modes No share mode dev=%x ino=%.0f\n",
387 (unsigned int)dev, (double)inode));
391 /*******************************************************************
392 set the share mode of a file. Return False on fail, True on success.
393 ********************************************************************/
394 static BOOL shm_set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type)
399 unsigned int hash_entry;
400 share_mode_record *file_scanner_p;
401 shm_share_mode_entry *new_entry_p;
402 int new_entry_offset;
405 dev = fsp->fd_ptr->dev;
406 inode = fsp->fd_ptr->inode;
408 hash_entry = HASH_ENTRY(dev, inode);
410 mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
412 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
414 while(file_scanner_p)
416 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
423 file_scanner_p = (share_mode_record *)
424 shmops->offset2addr(file_scanner_p->next_offset);
430 /* We must create a share_mode_record */
431 share_mode_record *new_mode_p = NULL;
432 int new_offset = shmops->shm_alloc(sizeof(share_mode_record) +
433 strlen(fsp->fsp_name) + 1);
434 if(new_offset == 0) {
435 DEBUG(0,("ERROR:set_share_mode shmops->shm_alloc fail!\n"));
438 new_mode_p = shmops->offset2addr(new_offset);
439 new_mode_p->locking_version = LOCKING_VERSION;
440 new_mode_p->st_dev = dev;
441 new_mode_p->st_ino = inode;
442 new_mode_p->num_share_mode_entries = 0;
443 new_mode_p->share_mode_entries = 0;
444 pstrcpy(new_mode_p->file_name, fsp->fsp_name);
446 /* Chain onto the start of the hash chain (in the hope we will be used first). */
447 new_mode_p->next_offset = mode_array[hash_entry];
448 mode_array[hash_entry] = new_offset;
450 file_scanner_p = new_mode_p;
452 DEBUG(3,("set_share_mode: Created share record for %s (dev %x inode %.0f)\n",
453 fsp->fsp_name, (unsigned int)dev, (double)inode));
456 /* Now create the share mode entry */
457 new_entry_offset = shmops->shm_alloc(sizeof(shm_share_mode_entry));
458 if(new_entry_offset == 0) {
459 int delete_offset = mode_array[hash_entry];
460 DEBUG(0,("ERROR:set_share_mode: shmops->shm_alloc fail 1!\n"));
461 /* Unlink the damaged record */
462 mode_array[hash_entry] = file_scanner_p->next_offset;
464 shmops->shm_free( delete_offset );
468 new_entry_p = shmops->offset2addr(new_entry_offset);
470 new_entry_p->e.pid = getpid();
471 new_entry_p->e.share_mode = fsp->share_mode;
472 new_entry_p->e.op_port = port;
473 new_entry_p->e.op_type = op_type;
474 memcpy( (char *)&new_entry_p->e.time, (char *)&fsp->open_time, sizeof(struct timeval));
476 /* Chain onto the share_mode_record */
477 new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
478 file_scanner_p->share_mode_entries = new_entry_offset;
481 if(file_scanner_p->num_share_mode_entries < 0)
483 DEBUG(0,("PANIC ERROR:set_share_mode num_share_mode_entries=%d\n",
484 file_scanner_p->num_share_mode_entries));
488 /* Increment the share_mode_entries counter */
489 file_scanner_p->num_share_mode_entries += 1;
491 DEBUG(3,("set_share_mode: Created share entry for %s with mode 0x%X pid=%d\n",
492 fsp->fsp_name, fsp->share_mode, new_entry_p->e.pid));
497 /*******************************************************************
498 Call a generic modify function for a share mode entry.
499 ********************************************************************/
501 static BOOL shm_mod_share_entry(int token, files_struct *fsp,
502 void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
508 unsigned int hash_entry;
509 share_mode_record *file_scanner_p;
510 share_mode_record *file_prev_p;
511 shm_share_mode_entry *entry_scanner_p;
515 dev = fsp->fd_ptr->dev;
516 inode = fsp->fd_ptr->inode;
518 hash_entry = HASH_ENTRY(dev, inode);
520 mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
522 if(mode_array[hash_entry] == 0)
524 DEBUG(0,("PANIC ERROR:modify_share_entry: hash bucket %d empty\n",
529 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
530 file_prev_p = file_scanner_p;
532 while(file_scanner_p)
534 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
541 file_prev_p = file_scanner_p ;
542 file_scanner_p = (share_mode_record *)
543 shmops->offset2addr(file_scanner_p->next_offset);
549 DEBUG(0,("ERROR:modify_share_entry: no entry found for dev=%x ino=%.0f\n",
550 (unsigned int)dev, (double)inode));
554 if(file_scanner_p->locking_version != LOCKING_VERSION)
556 DEBUG(0,("ERROR: modify_share_entry: Deleting old share mode v1=%d dev=%x ino=%.0f\n",
557 file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
559 if(file_prev_p == file_scanner_p)
560 mode_array[hash_entry] = file_scanner_p->next_offset;
562 file_prev_p->next_offset = file_scanner_p->next_offset;
563 shmops->shm_free(shmops->addr2offset(file_scanner_p));
568 entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
569 file_scanner_p->share_mode_entries);
570 while(entry_scanner_p)
572 if( (pid == entry_scanner_p->e.pid) &&
573 (entry_scanner_p->e.share_mode == fsp->share_mode) &&
574 (memcmp(&entry_scanner_p->e.time,
575 &fsp->open_time,sizeof(struct timeval)) == 0) )
578 * Call the generic function with the given parameter.
581 DEBUG(5,("modify_share_entry: Calling generic function to modify entry for dev=%x ino=%.0f\n",
582 (unsigned int)dev, (double)inode));
584 (*mod_fn)( &entry_scanner_p->e, dev, inode, param);
590 entry_scanner_p = (shm_share_mode_entry *)
591 shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
597 DEBUG(0,("ERROR: modify_share_entry: No entry found for dev=%x ino=%.0f\n",
598 (unsigned int)dev, (double)inode));
605 /*******************************************************************
606 call the specified function on each entry under management by the
608 ********************************************************************/
609 static int shm_share_forall(void (*fn)(share_mode_entry *, char *))
613 share_mode_record *file_scanner_p;
615 mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
617 for( i = 0; i < shmops->hash_size(); i++) {
618 shmops->lock_hash_entry(i);
619 if(mode_array[i] == 0) {
620 shmops->unlock_hash_entry(i);
624 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[i]);
625 while((file_scanner_p != 0) &&
626 (file_scanner_p->num_share_mode_entries != 0)) {
627 shm_share_mode_entry *entry_scanner_p =
628 (shm_share_mode_entry *)
629 shmops->offset2addr(file_scanner_p->share_mode_entries);
631 while(entry_scanner_p != 0) {
633 if (process_exists(entry_scanner_p->e.pid)) {
634 fn(&entry_scanner_p->e,
635 file_scanner_p->file_name);
640 (shm_share_mode_entry *)
642 entry_scanner_p->next_share_mode_entry);
643 } /* end while entry_scanner_p */
644 file_scanner_p = (share_mode_record *)
645 shmops->offset2addr(file_scanner_p->next_offset);
646 } /* end while file_scanner_p */
647 shmops->unlock_hash_entry(i);
654 /*******************************************************************
655 dump the state of the system
656 ********************************************************************/
657 static void shm_share_status(FILE *f)
659 int bytes_free, bytes_used, bytes_overhead, bytes_total;
661 shmops->get_usage(&bytes_free, &bytes_used, &bytes_overhead);
662 bytes_total = bytes_free + bytes_used + bytes_overhead;
664 fprintf(f, "Share mode memory usage (bytes):\n");
665 fprintf(f, " %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n",
666 bytes_free, (bytes_free * 100)/bytes_total,
667 bytes_used, (bytes_used * 100)/bytes_total,
668 bytes_overhead, (bytes_overhead * 100)/bytes_total,
673 static struct share_ops share_ops = {
674 shm_stop_share_mode_mgmt,
675 shm_lock_share_entry,
676 shm_unlock_share_entry,
685 /*******************************************************************
686 initialize the shared memory for share_mode management
687 ******************************************************************/
688 struct share_ops *locking_shm_init(int ronly)
693 shmops = sysv_shm_open(read_only);
694 if (shmops) return &share_ops;
697 #ifdef HAVE_SHARED_MMAP
698 shmops = smb_shm_open(read_only);
699 if (shmops) return &share_ops;
706 int locking_shm_dummy_procedure(void)
708 #endif /* FAST_SHARE_MODES */