clean up the hash entry code a bit. Got rid of lp_shmem_hash_size()
[kai/samba.git] / source3 / locking / locking_shm.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    shared memory locking implementation
5    Copyright (C) Andrew Tridgell 1992-1997
6    
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.
11    
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.
16    
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.
20
21    Revision History:
22
23    12 aug 96: Erik.Devriendt@te6.siemens.be
24    added support for shared memory implementation of share mode locking
25
26    May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
27    locking to deal with multiple share modes per open file.
28
29    September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
30    support.
31
32    October 1997 - split into separate file (tridge)
33 */
34
35 #ifdef FAST_SHARE_MODES
36
37 #include "includes.h"
38 extern int DEBUGLEVEL;
39 extern connection_struct Connections[];
40 extern files_struct Files[];
41
42 static struct shmem_ops *shmops;
43
44 /* share mode record pointed to in shared memory hash bucket */
45 typedef struct
46 {
47   int next_offset; /* offset of next record in chain from hash bucket */
48   int locking_version;
49   int32 st_dev;
50   int32 st_ino;
51   int num_share_mode_entries;
52   int share_mode_entries; /* Chain of share mode entries for this file */
53   char file_name[1];
54 } share_mode_record;
55
56 /* share mode entry pointed to by share_mode_record struct */
57 typedef struct
58 {
59         int next_share_mode_entry;
60         share_mode_entry e;
61 } shm_share_mode_entry;
62
63 static int read_only;
64
65
66 /* Conversion to hash entry index from device and inode numbers. */
67 #define HASH_ENTRY(dev,ino) ((((uint32)(dev)) * ((uint32)(ino))) % shmops->hash_size())
68
69
70 /*******************************************************************
71   deinitialize the shared memory for share_mode management 
72   ******************************************************************/
73 static BOOL shm_stop_share_mode_mgmt(void)
74 {
75    return shmops->close();
76 }
77
78 /*******************************************************************
79   lock a hash bucket entry in shared memory for share_mode management 
80   ******************************************************************/
81 static BOOL shm_lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok)
82 {
83   return shmops->lock_hash_entry(HASH_ENTRY(dev, inode));
84 }
85
86 /*******************************************************************
87   unlock a hash bucket entry in shared memory for share_mode management 
88   ******************************************************************/
89 static BOOL shm_unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token)
90 {
91   return shmops->unlock_hash_entry(HASH_ENTRY(dev, inode));
92 }
93
94 /*******************************************************************
95 get all share mode entries in shared memory for a dev/inode pair.
96 ********************************************************************/
97 static int shm_get_share_modes(int cnum, int token, uint32 dev, uint32 inode, 
98                                share_mode_entry **old_shares)
99 {
100   int *mode_array;
101   unsigned int hash_entry = HASH_ENTRY(dev, inode); 
102   share_mode_record *file_scanner_p;
103   share_mode_record *file_prev_p;
104   shm_share_mode_entry *entry_scanner_p;
105   shm_share_mode_entry *entry_prev_p;
106   int num_entries;
107   int num_entries_copied;
108   BOOL found = False;
109   share_mode_entry *share_array = (share_mode_entry *)0;
110
111   *old_shares = 0;
112
113   mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
114   
115   if(mode_array[hash_entry] == NULL_OFFSET)
116   {
117     DEBUG(5,("get_share_modes (FAST_SHARE_MODES): hash bucket %d empty\n", hash_entry));
118     return 0;
119   }
120
121   file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
122   file_prev_p = file_scanner_p;
123   while(file_scanner_p)
124   {
125     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
126     {
127       found = True;
128       break;
129     }
130     else
131     {
132       file_prev_p = file_scanner_p ;
133       file_scanner_p = (share_mode_record *)shmops->offset2addr(
134                                     file_scanner_p->next_offset);
135     }
136   }
137   
138   if(!found)
139   {
140     DEBUG(5,("get_share_modes (FAST_SHARE_MODES): no entry for \
141 file dev = %d, ino = %d in hash_bucket %d\n", dev, inode, hash_entry));
142     return (0);
143   }
144   
145   if(file_scanner_p->locking_version != LOCKING_VERSION)
146   {
147     DEBUG(0,("ERROR:get_share_modes (FAST_SHARE_MODES): Deleting old share mode \
148 record due to old locking version %d for file dev = %d, inode = %d in hash \
149 bucket %d\n", file_scanner_p->locking_version, dev, inode, hash_entry));
150     if(file_prev_p == file_scanner_p)
151       mode_array[hash_entry] = file_scanner_p->next_offset;
152     else
153       file_prev_p->next_offset = file_scanner_p->next_offset;
154     shmops->free(shmops->addr2offset(file_scanner_p));
155     return (0);
156   }
157
158   /* Allocate the old_shares array */
159   num_entries = file_scanner_p->num_share_mode_entries;
160   if(num_entries)
161   {
162     *old_shares = share_array = (share_mode_entry *)
163                  malloc(num_entries * sizeof(share_mode_entry));
164     if(*old_shares == 0)
165     {
166       DEBUG(0,("get_share_modes (FAST_SHARE_MODES): malloc fail !\n"));
167       return 0;
168     }
169   }
170
171   num_entries_copied = 0;
172   
173   entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
174                                            file_scanner_p->share_mode_entries);
175   entry_prev_p = entry_scanner_p;
176   while(entry_scanner_p)
177   {
178     int pid = entry_scanner_p->e.pid;
179
180     if (pid && !process_exists(pid))
181     {
182       /* Delete this share mode entry */
183       shm_share_mode_entry *delete_entry_p = entry_scanner_p;
184       int share_mode = entry_scanner_p->e.share_mode;
185
186       if(entry_prev_p == entry_scanner_p)
187       {
188         /* We are at start of list */
189         file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
190         entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
191                                            file_scanner_p->share_mode_entries);
192         entry_prev_p = entry_scanner_p;
193       }
194       else
195       {
196         entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
197         entry_scanner_p = (shm_share_mode_entry*)
198                            shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
199       }
200       /* Decrement the number of share mode entries on this share mode record */
201       file_scanner_p->num_share_mode_entries -= 1;
202
203       /* PARANOIA TEST */
204       if(file_scanner_p->num_share_mode_entries < 0)
205       {
206         DEBUG(0,("PANIC ERROR:get_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
207 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
208              dev, inode, hash_entry));
209         return 0;
210       }
211
212       DEBUG(0,("get_share_modes (FAST_SHARE_MODES): process %d no longer exists and \
213 it left a share mode entry with mode 0x%X for file dev = %d, ino = %d in hash \
214 bucket %d (number of entries now = %d)\n", 
215             pid, share_mode, dev, inode, hash_entry,
216             file_scanner_p->num_share_mode_entries));
217
218       shmops->free(shmops->addr2offset(delete_entry_p));
219     } 
220     else
221     {
222        /* This is a valid share mode entry and the process that
223            created it still exists. Copy it into the output array.
224        */
225        share_array[num_entries_copied].pid = entry_scanner_p->e.pid;
226        share_array[num_entries_copied].share_mode = entry_scanner_p->e.share_mode;
227        share_array[num_entries_copied].op_port = entry_scanner_p->e.op_port;
228        share_array[num_entries_copied].op_type = entry_scanner_p->e.op_type;
229        memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->e.time,
230               sizeof(struct timeval));
231        num_entries_copied++;
232        DEBUG(5,("get_share_modes (FAST_SHARE_MODES): Read share mode \
233 record mode 0x%X pid=%d\n", entry_scanner_p->e.share_mode, entry_scanner_p->e.pid));
234        entry_prev_p = entry_scanner_p;
235        entry_scanner_p = (shm_share_mode_entry *)
236                            shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
237     }
238   }
239   
240   /* If no valid share mode entries were found then this record shouldn't exist ! */
241   if(num_entries_copied == 0)
242   {
243     DEBUG(0,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
244 hash bucket %d has a share mode record but no entries - deleting\n", 
245                  dev, inode, hash_entry));
246     if(*old_shares)
247       free((char *)*old_shares);
248     *old_shares = 0;
249
250     if(file_prev_p == file_scanner_p)
251       mode_array[hash_entry] = file_scanner_p->next_offset;
252     else
253       file_prev_p->next_offset = file_scanner_p->next_offset;
254     shmops->free(shmops->addr2offset(file_scanner_p));
255   }
256
257   DEBUG(5,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
258 hash bucket %d returning %d entries\n", dev, inode, hash_entry, num_entries_copied));
259
260   return(num_entries_copied);
261 }  
262
263 /*******************************************************************
264 del the share mode of a file.
265 ********************************************************************/
266 static void shm_del_share_mode(int token, int fnum)
267 {
268   uint32 dev, inode;
269   int *mode_array;
270   unsigned int hash_entry;
271   share_mode_record *file_scanner_p;
272   share_mode_record *file_prev_p;
273   shm_share_mode_entry *entry_scanner_p;
274   shm_share_mode_entry *entry_prev_p;
275   BOOL found = False;
276   int pid = getpid();
277
278   dev = Files[fnum].fd_ptr->dev;
279   inode = Files[fnum].fd_ptr->inode;
280
281   hash_entry = HASH_ENTRY(dev, inode);
282
283   mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
284  
285   if(mode_array[hash_entry] == NULL_OFFSET)
286   {  
287     DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash bucket %d empty\n", 
288                   hash_entry));
289     return;
290   }  
291   
292   file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
293   file_prev_p = file_scanner_p;
294
295   while(file_scanner_p)
296   {
297     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
298     {
299       found = True;
300       break;
301     }
302     else
303     {
304       file_prev_p = file_scanner_p ;
305       file_scanner_p = (share_mode_record *)
306                         shmops->offset2addr(file_scanner_p->next_offset);
307     }
308   }
309     
310   if(!found)
311   {
312      DEBUG(0,("ERROR:del_share_mode (FAST_SHARE_MODES): no entry found for dev %d, \
313 inode %d in hash bucket %d\n", dev, inode, hash_entry));
314      return;
315   }
316   
317   if(file_scanner_p->locking_version != LOCKING_VERSION)
318   {
319     DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): Deleting old share mode \
320 record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
321        file_scanner_p->locking_version, dev, inode, hash_entry ));
322     if(file_prev_p == file_scanner_p)
323       mode_array[hash_entry] = file_scanner_p->next_offset;
324     else
325       file_prev_p->next_offset = file_scanner_p->next_offset;
326     shmops->free(shmops->addr2offset(file_scanner_p));
327     return;
328   }
329
330   found = False;
331   entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
332                                          file_scanner_p->share_mode_entries);
333   entry_prev_p = entry_scanner_p;
334   while(entry_scanner_p)
335   {
336     if( (pid == entry_scanner_p->e.pid) && 
337           (memcmp(&entry_scanner_p->e.time, 
338                  &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
339     {
340       found = True;
341       break;
342     }
343     else
344     {
345       entry_prev_p = entry_scanner_p;
346       entry_scanner_p = (shm_share_mode_entry *)
347                           shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
348     }
349   } 
350
351   if (found)
352   {
353     /* Decrement the number of entries in the record. */
354     file_scanner_p->num_share_mode_entries -= 1;
355
356     DEBUG(2,("del_share_modes (FAST_SHARE_MODES): \
357 Deleting share mode entry dev = %d, inode = %d in hash bucket %d (num entries now = %d)\n",
358               dev, inode, hash_entry, file_scanner_p->num_share_mode_entries));
359     if(entry_prev_p == entry_scanner_p)
360       /* We are at start of list */
361       file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
362     else
363       entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
364     shmops->free(shmops->addr2offset(entry_scanner_p));
365
366     /* PARANOIA TEST */
367     if(file_scanner_p->num_share_mode_entries < 0)
368     {
369       DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
370 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
371            dev, inode, hash_entry));
372       return;
373     }
374
375     /* If we deleted the last share mode entry then remove the share mode record. */
376     if(file_scanner_p->num_share_mode_entries == 0)
377     {
378       DEBUG(2,("del_share_modes (FAST_SHARE_MODES): num entries = 0, deleting share_mode \
379 record dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
380       if(file_prev_p == file_scanner_p)
381         mode_array[hash_entry] = file_scanner_p->next_offset;
382       else
383         file_prev_p->next_offset = file_scanner_p->next_offset;
384       shmops->free(shmops->addr2offset(file_scanner_p));
385     }
386   }
387   else
388   {
389     DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): No share mode record found \
390 dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
391   }
392 }
393
394 /*******************************************************************
395 set the share mode of a file. Return False on fail, True on success.
396 ********************************************************************/
397 static BOOL shm_set_share_mode(int token, int fnum, uint16 port, uint16 op_type)
398 {
399   files_struct *fs_p = &Files[fnum];
400   int32 dev, inode;
401   int *mode_array;
402   unsigned int hash_entry;
403   share_mode_record *file_scanner_p;
404   share_mode_record *file_prev_p;
405   shm_share_mode_entry *new_entry_p;
406   int new_entry_offset;
407   BOOL found = False;
408
409   dev = fs_p->fd_ptr->dev;
410   inode = fs_p->fd_ptr->inode;
411
412   hash_entry = HASH_ENTRY(dev, inode);
413
414   mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
415
416   file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
417   file_prev_p = file_scanner_p;
418   
419   while(file_scanner_p)
420   {
421     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
422     {
423       found = True;
424       break;
425     }
426     else
427     {
428       file_prev_p = file_scanner_p ;
429       file_scanner_p = (share_mode_record *)
430                          shmops->offset2addr(file_scanner_p->next_offset);
431     }
432   }
433   
434   if(!found)
435   {
436     /* We must create a share_mode_record */
437     share_mode_record *new_mode_p = NULL;
438     int new_offset = shmops->alloc( sizeof(share_mode_record) +
439                                         strlen(fs_p->name) + 1);
440     if(new_offset == NULL_OFFSET)
441     {
442       DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): shmops->alloc fail !\n"));
443       return False;
444     }
445     new_mode_p = shmops->offset2addr(new_offset);
446     new_mode_p->locking_version = LOCKING_VERSION;
447     new_mode_p->st_dev = dev;
448     new_mode_p->st_ino = inode;
449     new_mode_p->num_share_mode_entries = 0;
450     new_mode_p->share_mode_entries = NULL_OFFSET;
451     strcpy(new_mode_p->file_name, fs_p->name);
452
453     /* Chain onto the start of the hash chain (in the hope we will be used first). */
454     new_mode_p->next_offset = mode_array[hash_entry];
455     mode_array[hash_entry] = new_offset;
456
457     file_scanner_p = new_mode_p;
458
459     DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share record for %s (dev %d \
460 inode %d in hash bucket %d\n", fs_p->name, dev, inode, hash_entry));
461   }
462  
463   /* Now create the share mode entry */ 
464   new_entry_offset = shmops->alloc( sizeof(shm_share_mode_entry));
465   if(new_entry_offset == NULL_OFFSET)
466   {
467     int delete_offset = mode_array[hash_entry];
468     DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): shmops->alloc fail 1!\n"));
469     /* Unlink the damaged record */
470     mode_array[hash_entry] = file_scanner_p->next_offset;
471     /* And delete it */
472     shmops->free( delete_offset );
473     return False;
474   }
475
476   new_entry_p = shmops->offset2addr(new_entry_offset);
477
478   new_entry_p->e.pid = getpid();
479   new_entry_p->e.share_mode = fs_p->share_mode;
480   new_entry_p->e.op_port = port;
481   new_entry_p->e.op_type = op_type;
482   memcpy( (char *)&new_entry_p->e.time, (char *)&fs_p->open_time, sizeof(struct timeval));
483
484   /* Chain onto the share_mode_record */
485   new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
486   file_scanner_p->share_mode_entries = new_entry_offset;
487
488   /* PARANOIA TEST */
489   if(file_scanner_p->num_share_mode_entries < 0)
490   {
491     DEBUG(0,("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
492 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
493          dev, inode, hash_entry));
494     return False;
495   }
496
497   /* Increment the share_mode_entries counter */
498   file_scanner_p->num_share_mode_entries += 1;
499
500   DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share entry for %s with mode \
501 0x%X pid=%d (num_entries now = %d)\n",fs_p->name, fs_p->share_mode, new_entry_p->e.pid,
502                              file_scanner_p->num_share_mode_entries));
503
504   return(True);
505 }
506
507 /*******************************************************************
508 Remove an oplock port and mode entry from a share mode.
509 ********************************************************************/
510 static BOOL shm_remove_share_oplock(int fnum, int token)
511 {
512   uint32 dev, inode;
513   int *mode_array;
514   unsigned int hash_entry;
515   share_mode_record *file_scanner_p;
516   share_mode_record *file_prev_p;
517   shm_share_mode_entry *entry_scanner_p;
518   shm_share_mode_entry *entry_prev_p;
519   BOOL found = False;
520   int pid = getpid();
521
522   dev = Files[fnum].fd_ptr->dev;
523   inode = Files[fnum].fd_ptr->inode;
524
525   hash_entry = HASH_ENTRY(dev, inode);
526
527   mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
528
529   if(mode_array[hash_entry] == NULL_OFFSET)
530   {
531     DEBUG(0,("PANIC ERROR:remove_share_oplock (FAST_SHARE_MODES): hash bucket %d empty\n",
532                   hash_entry));
533     return False;
534   } 
535     
536   file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
537   file_prev_p = file_scanner_p;
538     
539   while(file_scanner_p)
540   { 
541     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
542     {
543       found = True;
544       break;
545     }
546     else
547     {
548       file_prev_p = file_scanner_p ;
549       file_scanner_p = (share_mode_record *)
550                         shmops->offset2addr(file_scanner_p->next_offset);
551     }
552   } 
553    
554   if(!found)
555   { 
556      DEBUG(0,("ERROR:remove_share_oplock (FAST_SHARE_MODES): no entry found for dev %d, \
557 inode %d in hash bucket %d\n", dev, inode, hash_entry));
558      return False;
559   } 
560
561   if(file_scanner_p->locking_version != LOCKING_VERSION)
562   {
563     DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): Deleting old share mode \
564 record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
565        file_scanner_p->locking_version, dev, inode, hash_entry ));
566     if(file_prev_p == file_scanner_p)
567       mode_array[hash_entry] = file_scanner_p->next_offset;
568     else
569       file_prev_p->next_offset = file_scanner_p->next_offset;
570     shmops->free(shmops->addr2offset(file_scanner_p));
571     return False;
572   }
573
574   found = False;
575   entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
576                                          file_scanner_p->share_mode_entries);
577   entry_prev_p = entry_scanner_p;
578   while(entry_scanner_p)
579   {
580     if( (pid == entry_scanner_p->e.pid) && 
581         (entry_scanner_p->e.share_mode == Files[fnum].share_mode) &&
582         (memcmp(&entry_scanner_p->e.time, 
583                 &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
584     {
585       /* Delete the oplock info. */
586       entry_scanner_p->e.op_port = 0;
587       entry_scanner_p->e.op_type = 0;
588       found = True;
589       break;
590     }
591     else
592     {
593       entry_prev_p = entry_scanner_p;
594       entry_scanner_p = (shm_share_mode_entry *)
595                           shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
596     }
597   } 
598
599   if(!found)
600   {
601     DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): No oplock granted share \
602 mode record found dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
603     return False;
604   }
605
606   return True;
607 }
608
609
610 /*******************************************************************
611 call the specified function on each entry under management by the
612 share mode system
613 ********************************************************************/
614 static int shm_share_forall(void (*fn)(share_mode_entry *, char *))
615 {
616         int i, count=0;
617         int *mode_array;
618         share_mode_record *file_scanner_p;
619
620         mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
621
622         for( i = 0; i < shmops->hash_size(); i++) {
623                 shmops->lock_hash_entry(i);
624                 if(mode_array[i] == NULL_OFFSET)  {
625                         shmops->unlock_hash_entry(i);
626                         continue;
627                 }
628
629                 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[i]);
630                 while((file_scanner_p != 0) && 
631                       (file_scanner_p->num_share_mode_entries != 0)) {
632                         shm_share_mode_entry *entry_scanner_p = 
633                                 (shm_share_mode_entry *)
634                                 shmops->offset2addr(file_scanner_p->share_mode_entries);
635
636                         while(entry_scanner_p != 0) {
637                                 
638                                 fn(&entry_scanner_p->e, 
639                                    file_scanner_p->file_name);
640
641                                 entry_scanner_p = 
642                                         (shm_share_mode_entry *)
643                                         shmops->offset2addr(
644                                                             entry_scanner_p->next_share_mode_entry);
645                                 count++;
646                         } /* end while entry_scanner_p */
647                         file_scanner_p = (share_mode_record *)
648                                 shmops->offset2addr(file_scanner_p->next_offset);
649                 } /* end while file_scanner_p */
650                 shmops->unlock_hash_entry(i);
651         } /* end for */
652
653         return count;
654 }
655
656
657 /*******************************************************************
658 dump the state of the system
659 ********************************************************************/
660 static void shm_share_status(FILE *f)
661 {
662         int bytes_free, bytes_used, bytes_overhead, bytes_total;
663
664         shmops->get_usage(&bytes_free, &bytes_used, &bytes_overhead);
665         bytes_total = bytes_free + bytes_used + bytes_overhead;
666
667         fprintf(f, "Share mode memory usage (bytes):\n");
668         fprintf(f, "   %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n",
669                 bytes_free, (bytes_free * 100)/bytes_total,
670                 bytes_used, (bytes_used * 100)/bytes_total,
671                 bytes_overhead, (bytes_overhead * 100)/bytes_total,
672                 bytes_total);
673 }
674
675
676 static struct share_ops share_ops = {
677         shm_stop_share_mode_mgmt,
678         shm_lock_share_entry,
679         shm_unlock_share_entry,
680         shm_get_share_modes,
681         shm_del_share_mode,
682         shm_set_share_mode,
683         shm_remove_share_oplock,
684         shm_share_forall,
685         shm_share_status,
686 };
687
688 /*******************************************************************
689   initialize the shared memory for share_mode management 
690   ******************************************************************/
691 struct share_ops *locking_shm_init(int ronly)
692 {
693         pstring shmem_file_name;
694
695         read_only = ronly;
696
697 #ifdef USE_SYSV_IPC
698         shmops = sysv_shm_open(read_only);
699         if (shmops) return &share_ops;
700 #endif
701
702         shmops = smb_shm_open(read_only);
703         if (shmops) return &share_ops;
704
705         return NULL;
706 }
707
708 #else
709  int locking_shm_dummy_procedure(void)
710 {return 0;}
711 #endif
712
713
714