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