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