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