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