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