3abd6b25a70c967f86dc44aff2f5bbc5f9e12ceb
[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) )) % lp_shmem_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   if(hash_entry > lp_shmem_hash_size() )
114   {
115     DEBUG(0, 
116       ("PANIC ERROR : get_share_modes (FAST_SHARE_MODES): hash_entry %d too large \
117 (max = %d)\n",
118       hash_entry, lp_shmem_hash_size() ));
119     return 0;
120   }
121
122   mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
123   
124   if(mode_array[hash_entry] == NULL_OFFSET)
125   {
126     DEBUG(5,("get_share_modes (FAST_SHARE_MODES): hash bucket %d empty\n", hash_entry));
127     return 0;
128   }
129
130   file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
131   file_prev_p = file_scanner_p;
132   while(file_scanner_p)
133   {
134     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
135     {
136       found = True;
137       break;
138     }
139     else
140     {
141       file_prev_p = file_scanner_p ;
142       file_scanner_p = (share_mode_record *)shmops->offset2addr(
143                                     file_scanner_p->next_offset);
144     }
145   }
146   
147   if(!found)
148   {
149     DEBUG(5,("get_share_modes (FAST_SHARE_MODES): no entry for \
150 file dev = %d, ino = %d in hash_bucket %d\n", dev, inode, hash_entry));
151     return (0);
152   }
153   
154   if(file_scanner_p->locking_version != LOCKING_VERSION)
155   {
156     DEBUG(0,("ERROR:get_share_modes (FAST_SHARE_MODES): Deleting old share mode \
157 record due to old locking version %d for file dev = %d, inode = %d in hash \
158 bucket %d\n", file_scanner_p->locking_version, dev, inode, hash_entry));
159     if(file_prev_p == file_scanner_p)
160       mode_array[hash_entry] = file_scanner_p->next_offset;
161     else
162       file_prev_p->next_offset = file_scanner_p->next_offset;
163     shmops->free(shmops->addr2offset(file_scanner_p));
164     return (0);
165   }
166
167   /* Allocate the old_shares array */
168   num_entries = file_scanner_p->num_share_mode_entries;
169   if(num_entries)
170   {
171     *old_shares = share_array = (share_mode_entry *)
172                  malloc(num_entries * sizeof(share_mode_entry));
173     if(*old_shares == 0)
174     {
175       DEBUG(0,("get_share_modes (FAST_SHARE_MODES): malloc fail !\n"));
176       return 0;
177     }
178   }
179
180   num_entries_copied = 0;
181   
182   entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
183                                            file_scanner_p->share_mode_entries);
184   entry_prev_p = entry_scanner_p;
185   while(entry_scanner_p)
186   {
187     int pid = entry_scanner_p->e.pid;
188
189     if (pid && !process_exists(pid))
190     {
191       /* Delete this share mode entry */
192       shm_share_mode_entry *delete_entry_p = entry_scanner_p;
193       int share_mode = entry_scanner_p->e.share_mode;
194
195       if(entry_prev_p == entry_scanner_p)
196       {
197         /* We are at start of list */
198         file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
199         entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
200                                            file_scanner_p->share_mode_entries);
201         entry_prev_p = entry_scanner_p;
202       }
203       else
204       {
205         entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
206         entry_scanner_p = (shm_share_mode_entry*)
207                            shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
208       }
209       /* Decrement the number of share mode entries on this share mode record */
210       file_scanner_p->num_share_mode_entries -= 1;
211
212       /* PARANOIA TEST */
213       if(file_scanner_p->num_share_mode_entries < 0)
214       {
215         DEBUG(0,("PANIC ERROR:get_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
216 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
217              dev, inode, hash_entry));
218         return 0;
219       }
220
221       DEBUG(0,("get_share_modes (FAST_SHARE_MODES): process %d no longer exists and \
222 it left a share mode entry with mode 0x%X for file dev = %d, ino = %d in hash \
223 bucket %d (number of entries now = %d)\n", 
224             pid, share_mode, dev, inode, hash_entry,
225             file_scanner_p->num_share_mode_entries));
226
227       shmops->free(shmops->addr2offset(delete_entry_p));
228     } 
229     else
230     {
231        /* This is a valid share mode entry and the process that
232            created it still exists. Copy it into the output array.
233        */
234        share_array[num_entries_copied].pid = entry_scanner_p->e.pid;
235        share_array[num_entries_copied].share_mode = entry_scanner_p->e.share_mode;
236        share_array[num_entries_copied].op_port = entry_scanner_p->e.op_port;
237        share_array[num_entries_copied].op_type = entry_scanner_p->e.op_type;
238        memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->e.time,
239               sizeof(struct timeval));
240        num_entries_copied++;
241        DEBUG(5,("get_share_modes (FAST_SHARE_MODES): Read share mode \
242 record mode 0x%X pid=%d\n", entry_scanner_p->e.share_mode, entry_scanner_p->e.pid));
243        entry_prev_p = entry_scanner_p;
244        entry_scanner_p = (shm_share_mode_entry *)
245                            shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
246     }
247   }
248   
249   /* If no valid share mode entries were found then this record shouldn't exist ! */
250   if(num_entries_copied == 0)
251   {
252     DEBUG(0,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
253 hash bucket %d has a share mode record but no entries - deleting\n", 
254                  dev, inode, hash_entry));
255     if(*old_shares)
256       free((char *)*old_shares);
257     *old_shares = 0;
258
259     if(file_prev_p == file_scanner_p)
260       mode_array[hash_entry] = file_scanner_p->next_offset;
261     else
262       file_prev_p->next_offset = file_scanner_p->next_offset;
263     shmops->free(shmops->addr2offset(file_scanner_p));
264   }
265
266   DEBUG(5,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
267 hash bucket %d returning %d entries\n", dev, inode, hash_entry, num_entries_copied));
268
269   return(num_entries_copied);
270 }  
271
272 /*******************************************************************
273 del the share mode of a file.
274 ********************************************************************/
275 static void shm_del_share_mode(int token, int fnum)
276 {
277   uint32 dev, inode;
278   int *mode_array;
279   unsigned int hash_entry;
280   share_mode_record *file_scanner_p;
281   share_mode_record *file_prev_p;
282   shm_share_mode_entry *entry_scanner_p;
283   shm_share_mode_entry *entry_prev_p;
284   BOOL found = False;
285   int pid = getpid();
286
287   dev = Files[fnum].fd_ptr->dev;
288   inode = Files[fnum].fd_ptr->inode;
289
290   hash_entry = HASH_ENTRY(dev, inode);
291
292   if(hash_entry > lp_shmem_hash_size() )
293   {
294     DEBUG(0,
295       ("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
296 (max = %d)\n",
297       hash_entry, lp_shmem_hash_size() ));
298     return;
299   }
300
301   mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
302  
303   if(mode_array[hash_entry] == NULL_OFFSET)
304   {  
305     DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash bucket %d empty\n", 
306                   hash_entry));
307     return;
308   }  
309   
310   file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
311   file_prev_p = file_scanner_p;
312
313   while(file_scanner_p)
314   {
315     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
316     {
317       found = True;
318       break;
319     }
320     else
321     {
322       file_prev_p = file_scanner_p ;
323       file_scanner_p = (share_mode_record *)
324                         shmops->offset2addr(file_scanner_p->next_offset);
325     }
326   }
327     
328   if(!found)
329   {
330      DEBUG(0,("ERROR:del_share_mode (FAST_SHARE_MODES): no entry found for dev %d, \
331 inode %d in hash bucket %d\n", dev, inode, hash_entry));
332      return;
333   }
334   
335   if(file_scanner_p->locking_version != LOCKING_VERSION)
336   {
337     DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): Deleting old share mode \
338 record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
339        file_scanner_p->locking_version, dev, inode, hash_entry ));
340     if(file_prev_p == file_scanner_p)
341       mode_array[hash_entry] = file_scanner_p->next_offset;
342     else
343       file_prev_p->next_offset = file_scanner_p->next_offset;
344     shmops->free(shmops->addr2offset(file_scanner_p));
345     return;
346   }
347
348   found = False;
349   entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
350                                          file_scanner_p->share_mode_entries);
351   entry_prev_p = entry_scanner_p;
352   while(entry_scanner_p)
353   {
354     if( (pid == entry_scanner_p->e.pid) && 
355           (memcmp(&entry_scanner_p->e.time, 
356                  &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
357     {
358       found = True;
359       break;
360     }
361     else
362     {
363       entry_prev_p = entry_scanner_p;
364       entry_scanner_p = (shm_share_mode_entry *)
365                           shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
366     }
367   } 
368
369   if (found)
370   {
371     /* Decrement the number of entries in the record. */
372     file_scanner_p->num_share_mode_entries -= 1;
373
374     DEBUG(2,("del_share_modes (FAST_SHARE_MODES): \
375 Deleting share mode entry dev = %d, inode = %d in hash bucket %d (num entries now = %d)\n",
376               dev, inode, hash_entry, file_scanner_p->num_share_mode_entries));
377     if(entry_prev_p == entry_scanner_p)
378       /* We are at start of list */
379       file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
380     else
381       entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
382     shmops->free(shmops->addr2offset(entry_scanner_p));
383
384     /* PARANOIA TEST */
385     if(file_scanner_p->num_share_mode_entries < 0)
386     {
387       DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
388 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
389            dev, inode, hash_entry));
390       return;
391     }
392
393     /* If we deleted the last share mode entry then remove the share mode record. */
394     if(file_scanner_p->num_share_mode_entries == 0)
395     {
396       DEBUG(2,("del_share_modes (FAST_SHARE_MODES): num entries = 0, deleting share_mode \
397 record dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
398       if(file_prev_p == file_scanner_p)
399         mode_array[hash_entry] = file_scanner_p->next_offset;
400       else
401         file_prev_p->next_offset = file_scanner_p->next_offset;
402       shmops->free(shmops->addr2offset(file_scanner_p));
403     }
404   }
405   else
406   {
407     DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): No share mode record found \
408 dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
409   }
410 }
411
412 /*******************************************************************
413 set the share mode of a file. Return False on fail, True on success.
414 ********************************************************************/
415 static BOOL shm_set_share_mode(int token, int fnum, uint16 port, uint16 op_type)
416 {
417   files_struct *fs_p = &Files[fnum];
418   int32 dev, inode;
419   int *mode_array;
420   unsigned int hash_entry;
421   share_mode_record *file_scanner_p;
422   share_mode_record *file_prev_p;
423   shm_share_mode_entry *new_entry_p;
424   int new_entry_offset;
425   BOOL found = False;
426
427   dev = fs_p->fd_ptr->dev;
428   inode = fs_p->fd_ptr->inode;
429
430   hash_entry = HASH_ENTRY(dev, inode);
431   if(hash_entry > lp_shmem_hash_size() )
432   {
433     DEBUG(0,
434       ("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
435 (max = %d)\n",
436       hash_entry, lp_shmem_hash_size() ));
437     return False;
438   }
439
440   mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
441
442   file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
443   file_prev_p = file_scanner_p;
444   
445   while(file_scanner_p)
446   {
447     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
448     {
449       found = True;
450       break;
451     }
452     else
453     {
454       file_prev_p = file_scanner_p ;
455       file_scanner_p = (share_mode_record *)
456                          shmops->offset2addr(file_scanner_p->next_offset);
457     }
458   }
459   
460   if(!found)
461   {
462     /* We must create a share_mode_record */
463     share_mode_record *new_mode_p = NULL;
464     int new_offset = shmops->alloc( sizeof(share_mode_record) +
465                                         strlen(fs_p->name) + 1);
466     if(new_offset == NULL_OFFSET)
467     {
468       DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): shmops->alloc fail !\n"));
469       return False;
470     }
471     new_mode_p = shmops->offset2addr(new_offset);
472     new_mode_p->locking_version = LOCKING_VERSION;
473     new_mode_p->st_dev = dev;
474     new_mode_p->st_ino = inode;
475     new_mode_p->num_share_mode_entries = 0;
476     new_mode_p->share_mode_entries = NULL_OFFSET;
477     strcpy(new_mode_p->file_name, fs_p->name);
478
479     /* Chain onto the start of the hash chain (in the hope we will be used first). */
480     new_mode_p->next_offset = mode_array[hash_entry];
481     mode_array[hash_entry] = new_offset;
482
483     file_scanner_p = new_mode_p;
484
485     DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share record for %s (dev %d \
486 inode %d in hash bucket %d\n", fs_p->name, dev, inode, hash_entry));
487   }
488  
489   /* Now create the share mode entry */ 
490   new_entry_offset = shmops->alloc( sizeof(shm_share_mode_entry));
491   if(new_entry_offset == NULL_OFFSET)
492   {
493     int delete_offset = mode_array[hash_entry];
494     DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): shmops->alloc fail 1!\n"));
495     /* Unlink the damaged record */
496     mode_array[hash_entry] = file_scanner_p->next_offset;
497     /* And delete it */
498     shmops->free( delete_offset );
499     return False;
500   }
501
502   new_entry_p = shmops->offset2addr(new_entry_offset);
503
504   new_entry_p->e.pid = getpid();
505   new_entry_p->e.share_mode = fs_p->share_mode;
506   new_entry_p->e.op_port = port;
507   new_entry_p->e.op_type = op_type;
508   memcpy( (char *)&new_entry_p->e.time, (char *)&fs_p->open_time, sizeof(struct timeval));
509
510   /* Chain onto the share_mode_record */
511   new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
512   file_scanner_p->share_mode_entries = new_entry_offset;
513
514   /* PARANOIA TEST */
515   if(file_scanner_p->num_share_mode_entries < 0)
516   {
517     DEBUG(0,("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
518 for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
519          dev, inode, hash_entry));
520     return False;
521   }
522
523   /* Increment the share_mode_entries counter */
524   file_scanner_p->num_share_mode_entries += 1;
525
526   DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share entry for %s with mode \
527 0x%X pid=%d (num_entries now = %d)\n",fs_p->name, fs_p->share_mode, new_entry_p->e.pid,
528                              file_scanner_p->num_share_mode_entries));
529
530   return(True);
531 }
532
533 /*******************************************************************
534 Remove an oplock port and mode entry from a share mode.
535 ********************************************************************/
536 static BOOL shm_remove_share_oplock(int fnum, int token)
537 {
538   uint32 dev, inode;
539   int *mode_array;
540   unsigned int hash_entry;
541   share_mode_record *file_scanner_p;
542   share_mode_record *file_prev_p;
543   shm_share_mode_entry *entry_scanner_p;
544   shm_share_mode_entry *entry_prev_p;
545   BOOL found = False;
546   int pid = getpid();
547
548   dev = Files[fnum].fd_ptr->dev;
549   inode = Files[fnum].fd_ptr->inode;
550
551   hash_entry = HASH_ENTRY(dev, inode);
552
553   if(hash_entry > lp_shmem_hash_size() )
554   {
555     DEBUG(0,
556       ("PANIC ERROR:remove_share_oplock (FAST_SHARE_MODES): hash_entry %d too large \
557 (max = %d)\n",
558       hash_entry, lp_shmem_hash_size() ));
559     return False;
560   }
561
562   mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
563
564   if(mode_array[hash_entry] == NULL_OFFSET)
565   {
566     DEBUG(0,("PANIC ERROR:remove_share_oplock (FAST_SHARE_MODES): hash bucket %d empty\n",
567                   hash_entry));
568     return False;
569   } 
570     
571   file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
572   file_prev_p = file_scanner_p;
573     
574   while(file_scanner_p)
575   { 
576     if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
577     {
578       found = True;
579       break;
580     }
581     else
582     {
583       file_prev_p = file_scanner_p ;
584       file_scanner_p = (share_mode_record *)
585                         shmops->offset2addr(file_scanner_p->next_offset);
586     }
587   } 
588    
589   if(!found)
590   { 
591      DEBUG(0,("ERROR:remove_share_oplock (FAST_SHARE_MODES): no entry found for dev %d, \
592 inode %d in hash bucket %d\n", dev, inode, hash_entry));
593      return False;
594   } 
595
596   if(file_scanner_p->locking_version != LOCKING_VERSION)
597   {
598     DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): Deleting old share mode \
599 record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
600        file_scanner_p->locking_version, dev, inode, hash_entry ));
601     if(file_prev_p == file_scanner_p)
602       mode_array[hash_entry] = file_scanner_p->next_offset;
603     else
604       file_prev_p->next_offset = file_scanner_p->next_offset;
605     shmops->free(shmops->addr2offset(file_scanner_p));
606     return False;
607   }
608
609   found = False;
610   entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
611                                          file_scanner_p->share_mode_entries);
612   entry_prev_p = entry_scanner_p;
613   while(entry_scanner_p)
614   {
615     if( (pid == entry_scanner_p->e.pid) && 
616         (entry_scanner_p->e.share_mode == Files[fnum].share_mode) &&
617         (memcmp(&entry_scanner_p->e.time, 
618                 &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
619     {
620       /* Delete the oplock info. */
621       entry_scanner_p->e.op_port = 0;
622       entry_scanner_p->e.op_type = 0;
623       found = True;
624       break;
625     }
626     else
627     {
628       entry_prev_p = entry_scanner_p;
629       entry_scanner_p = (shm_share_mode_entry *)
630                           shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
631     }
632   } 
633
634   if(!found)
635   {
636     DEBUG(0,("ERROR: remove_share_oplock (FAST_SHARE_MODES): No oplock granted share \
637 mode record found dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
638     return False;
639   }
640
641   return True;
642 }
643
644
645 /*******************************************************************
646 call the specified function on each entry under management by the
647 share mode system
648 ********************************************************************/
649 static int shm_share_forall(void (*fn)(share_mode_entry *, char *))
650 {
651         int i, count=0;
652         int *mode_array;
653         share_mode_record *file_scanner_p;
654
655         mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
656
657         for( i = 0; i < lp_shmem_hash_size(); i++) {
658                 shmops->lock_hash_entry(i);
659                 if(mode_array[i] == NULL_OFFSET)  {
660                         shmops->unlock_hash_entry(i);
661                         continue;
662                 }
663
664                 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[i]);
665                 while((file_scanner_p != 0) && 
666                       (file_scanner_p->num_share_mode_entries != 0)) {
667                         shm_share_mode_entry *entry_scanner_p = 
668                                 (shm_share_mode_entry *)
669                                 shmops->offset2addr(file_scanner_p->share_mode_entries);
670
671                         while(entry_scanner_p != 0) {
672                                 
673                                 fn(&entry_scanner_p->e, 
674                                    file_scanner_p->file_name);
675
676                                 entry_scanner_p = 
677                                         (shm_share_mode_entry *)
678                                         shmops->offset2addr(
679                                                             entry_scanner_p->next_share_mode_entry);
680                                 count++;
681                         } /* end while entry_scanner_p */
682                         file_scanner_p = (share_mode_record *)
683                                 shmops->offset2addr(file_scanner_p->next_offset);
684                 } /* end while file_scanner_p */
685                 shmops->unlock_hash_entry(i);
686         } /* end for */
687
688         return count;
689 }
690
691
692 /*******************************************************************
693 dump the state of the system
694 ********************************************************************/
695 static void shm_share_status(FILE *f)
696 {
697         int bytes_free, bytes_used, bytes_overhead, bytes_total;
698
699         shmops->get_usage(&bytes_free, &bytes_used, &bytes_overhead);
700         bytes_total = bytes_free + bytes_used + bytes_overhead;
701
702         fprintf(f, "Share mode memory usage (bytes):\n");
703         fprintf(f, "   %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n",
704                 bytes_free, (bytes_free * 100)/bytes_total,
705                 bytes_used, (bytes_used * 100)/bytes_total,
706                 bytes_overhead, (bytes_overhead * 100)/bytes_total,
707                 bytes_total);
708 }
709
710
711 static struct share_ops share_ops = {
712         shm_stop_share_mode_mgmt,
713         shm_lock_share_entry,
714         shm_unlock_share_entry,
715         shm_get_share_modes,
716         shm_del_share_mode,
717         shm_set_share_mode,
718         shm_remove_share_oplock,
719         shm_share_forall,
720         shm_share_status,
721 };
722
723 /*******************************************************************
724   initialize the shared memory for share_mode management 
725   ******************************************************************/
726 struct share_ops *locking_shm_init(int ronly)
727 {
728         pstring shmem_file_name;
729
730         read_only = ronly;
731
732 #ifdef USE_SYSV_IPC
733         shmops = sysv_shm_open(lp_shmem_size(), read_only);
734         if (shmops) return &share_ops;
735 #endif
736
737         pstrcpy(shmem_file_name,lp_lockdir());
738         if (!directory_exist(shmem_file_name,NULL)) {
739                 if (read_only) return NULL;
740                 mkdir(shmem_file_name,0755);
741         }
742         trim_string(shmem_file_name,"","/");
743         if (!*shmem_file_name) return(False);
744         strcat(shmem_file_name, "/SHARE_MEM_FILE");
745         shmops = smb_shm_open(shmem_file_name, lp_shmem_size(), read_only);
746         if (shmops) return &share_ops;
747
748         return NULL;
749 }
750
751 #else
752  int locking_shm_dummy_procedure(void)
753 {return 0;}
754 #endif
755
756
757