Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / samba / source / locking / locking_shm.c
blob174ad73e97758d3788b1a6537a9ea53c303e0782
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 shared memory locking implementation
5 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
21 Revision History:
23 12 aug 96: Erik.Devriendt@te6.siemens.be
24 added support for shared memory implementation of share mode locking
26 May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
27 locking to deal with multiple share modes per open file.
29 September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
30 support.
32 October 1997 - split into separate file (tridge)
35 #include "includes.h"
37 #ifdef FAST_SHARE_MODES
39 extern int DEBUGLEVEL;
41 static struct shmem_ops *shmops;
43 /* share mode record pointed to in shared memory hash bucket */
44 typedef struct
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;
55 /* share mode entry pointed to by share_mode_record struct */
56 typedef struct
58 int next_share_mode_entry;
59 share_mode_entry e;
60 } shm_share_mode_entry;
62 static int read_only;
65 /* Conversion to hash entry index from device and inode numbers. */
66 #define HASH_ENTRY(dev,ino) ((unsigned int)(((dev) ^ (ino)) % shmops->hash_size()))
69 /*******************************************************************
70 deinitialize the shared memory for share_mode management
71 ******************************************************************/
72 static BOOL shm_stop_share_mode_mgmt(void)
74 return shmops->shm_close();
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)
83 *ptok = 0; /* For purify... */
84 return shmops->lock_hash_entry(HASH_ENTRY(dev, inode));
87 /*******************************************************************
88 unlock a hash bucket entry in shared memory for share_mode management
89 ******************************************************************/
90 static BOOL shm_unlock_share_entry(connection_struct *conn,
91 SMB_DEV_T dev, SMB_INO_T inode, int token)
93 return shmops->unlock_hash_entry(HASH_ENTRY(dev, inode));
96 /*******************************************************************
97 get all share mode entries in shared memory for a dev/inode pair.
98 ********************************************************************/
99 static int shm_get_share_modes(connection_struct *conn,
100 int token, SMB_DEV_T dev, SMB_INO_T inode,
101 share_mode_entry **old_shares)
103 int *mode_array;
104 unsigned int hash_entry = HASH_ENTRY(dev, inode);
105 share_mode_record *file_scanner_p;
106 share_mode_record *file_prev_p;
107 shm_share_mode_entry *entry_scanner_p;
108 shm_share_mode_entry *entry_prev_p;
109 int num_entries;
110 int num_entries_copied;
111 BOOL found = False;
112 share_mode_entry *share_array = (share_mode_entry *)0;
114 *old_shares = 0;
116 mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
118 if(mode_array[hash_entry] == 0)
120 DEBUG(5,("get_share_modes hash bucket %d empty\n", hash_entry));
121 return 0;
124 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
125 file_prev_p = file_scanner_p;
126 while(file_scanner_p)
128 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
130 found = True;
131 break;
133 else
135 file_prev_p = file_scanner_p ;
136 file_scanner_p = (share_mode_record *)shmops->offset2addr(
137 file_scanner_p->next_offset);
141 if(!found)
143 DEBUG(5,("get_share_modes no entry for file dev = %x ino = %.0f\n",
144 (unsigned int)dev, (double)inode));
145 return (0);
148 if(file_scanner_p->locking_version != LOCKING_VERSION)
150 DEBUG(0,("ERROR: get_share_modes Deleting old share mode v1 %d dev=%x ino=%.0f\n",
151 file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
153 if(file_prev_p == file_scanner_p)
154 mode_array[hash_entry] = file_scanner_p->next_offset;
155 else
156 file_prev_p->next_offset = file_scanner_p->next_offset;
157 shmops->shm_free(shmops->addr2offset(file_scanner_p));
158 return (0);
161 /* Allocate the old_shares array */
162 num_entries = file_scanner_p->num_share_mode_entries;
163 if(num_entries)
165 *old_shares = share_array = (share_mode_entry *)
166 malloc(num_entries * sizeof(share_mode_entry));
167 if(*old_shares == 0)
169 DEBUG(0,("get_share_modes: malloc fail for size 0x%x!\n", (unsigned int)(num_entries * sizeof(share_mode_entry))));
170 return 0;
174 num_entries_copied = 0;
176 entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
177 file_scanner_p->share_mode_entries);
178 entry_prev_p = entry_scanner_p;
179 while(entry_scanner_p)
181 pid_t pid = entry_scanner_p->e.pid;
183 if (pid && !process_exists(pid))
185 /* Delete this share mode entry */
186 shm_share_mode_entry *delete_entry_p = entry_scanner_p;
188 if(entry_prev_p == entry_scanner_p)
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*)shmops->offset2addr(
193 file_scanner_p->share_mode_entries);
194 entry_prev_p = entry_scanner_p;
196 else
198 entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
199 entry_scanner_p = (shm_share_mode_entry*)
200 shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
202 /* Decrement the number of share mode entries on this share mode record */
203 file_scanner_p->num_share_mode_entries -= 1;
205 /* PARANOIA TEST */
206 if(file_scanner_p->num_share_mode_entries < 0)
208 DEBUG(0,("PANIC ERROR: get_share_mode: entries=%d dev=%x ino=%.0f\n",
209 file_scanner_p->num_share_mode_entries, (unsigned int)dev, (double)inode));
210 return 0;
213 DEBUG(0,("get_share_modes: process %d no longer exists\n", (int)pid));
215 shmops->shm_free(shmops->addr2offset(delete_entry_p));
217 else
219 /* This is a valid share mode entry and the process that
220 created it still exists. Copy it into the output array.
222 share_array[num_entries_copied].pid = entry_scanner_p->e.pid;
223 share_array[num_entries_copied].share_mode = entry_scanner_p->e.share_mode;
224 share_array[num_entries_copied].op_port = entry_scanner_p->e.op_port;
225 share_array[num_entries_copied].op_type = entry_scanner_p->e.op_type;
226 memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->e.time,
227 sizeof(struct timeval));
228 num_entries_copied++;
229 DEBUG(5,("get_share_modes Read share mode 0x%X pid=%d\n",
230 entry_scanner_p->e.share_mode, (int)entry_scanner_p->e.pid));
231 entry_prev_p = entry_scanner_p;
232 entry_scanner_p = (shm_share_mode_entry *)
233 shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
237 /* If no valid share mode entries were found then this record shouldn't exist ! */
238 if(num_entries_copied == 0)
240 DEBUG(0,("get_share_modes: file with dev %x inode %.0f empty\n",
241 (unsigned int)dev, (double)inode));
243 if(*old_shares)
244 free((char *)*old_shares);
245 *old_shares = 0;
247 if(file_prev_p == file_scanner_p)
248 mode_array[hash_entry] = file_scanner_p->next_offset;
249 else
250 file_prev_p->next_offset = file_scanner_p->next_offset;
251 shmops->shm_free(shmops->addr2offset(file_scanner_p));
254 DEBUG(5,("get_share_modes: file with dev %x inode %.0f -> %d entries\n",
255 (unsigned int)dev, (double)inode, num_entries_copied));
257 return(num_entries_copied);
260 /*******************************************************************
261 del the share mode of a file.
262 ********************************************************************/
263 static void shm_del_share_mode(int token, files_struct *fsp)
265 SMB_DEV_T dev;
266 SMB_INO_T inode;
267 int *mode_array;
268 unsigned int hash_entry;
269 share_mode_record *file_scanner_p;
270 share_mode_record *file_prev_p;
271 shm_share_mode_entry *entry_scanner_p;
272 shm_share_mode_entry *entry_prev_p;
273 BOOL found = False;
274 pid_t pid = getpid();
276 dev = fsp->fd_ptr->dev;
277 inode = fsp->fd_ptr->inode;
279 hash_entry = HASH_ENTRY(dev, inode);
281 mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
283 if(mode_array[hash_entry] == 0)
285 DEBUG(0,("PANIC ERROR:del_share_mode hash bucket %d empty\n",
286 hash_entry));
287 return;
290 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
291 file_prev_p = file_scanner_p;
293 while(file_scanner_p)
295 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
297 found = True;
298 break;
300 else
302 file_prev_p = file_scanner_p ;
303 file_scanner_p = (share_mode_record *)
304 shmops->offset2addr(file_scanner_p->next_offset);
308 if(!found)
310 DEBUG(0,("ERROR: del_share_mode no entry for dev %x inode %.0f\n",
311 (unsigned int)dev, (double)inode));
312 return;
315 if(file_scanner_p->locking_version != LOCKING_VERSION)
317 DEBUG(0,("ERROR: del_share_modes Deleting old share mode v1 %d dev=%x ino=%.0f\n",
318 file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
320 if(file_prev_p == file_scanner_p)
321 mode_array[hash_entry] = file_scanner_p->next_offset;
322 else
323 file_prev_p->next_offset = file_scanner_p->next_offset;
324 shmops->shm_free(shmops->addr2offset(file_scanner_p));
325 return;
328 found = False;
329 entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
330 file_scanner_p->share_mode_entries);
331 entry_prev_p = entry_scanner_p;
332 while(entry_scanner_p)
334 if( (pid == entry_scanner_p->e.pid) &&
335 (memcmp(&entry_scanner_p->e.time,
336 &fsp->open_time,sizeof(struct timeval)) == 0) )
338 found = True;
339 break;
341 else
343 entry_prev_p = entry_scanner_p;
344 entry_scanner_p = (shm_share_mode_entry *)
345 shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
349 if (found)
351 /* Decrement the number of entries in the record. */
352 file_scanner_p->num_share_mode_entries -= 1;
354 DEBUG(2,("del_share_modes Deleting share mode entry dev=%x ino=%.0f\n",
355 (unsigned int)dev, (double)inode));
357 if(entry_prev_p == entry_scanner_p)
358 /* We are at start of list */
359 file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
360 else
361 entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
362 shmops->shm_free(shmops->addr2offset(entry_scanner_p));
364 /* PARANOIA TEST */
365 if(file_scanner_p->num_share_mode_entries < 0)
367 DEBUG(0,("PANIC ERROR:del_share_mode num_share_mode_entries=%d\n",
368 file_scanner_p->num_share_mode_entries));
369 return;
372 /* If we deleted the last share mode entry then remove the share mode record. */
373 if(file_scanner_p->num_share_mode_entries == 0)
375 DEBUG(2,("del_share_modes num entries = 0, deleting share_mode dev=%x ino=%.0f\n",
376 (unsigned int)dev, (double)inode));
378 if(file_prev_p == file_scanner_p)
379 mode_array[hash_entry] = file_scanner_p->next_offset;
380 else
381 file_prev_p->next_offset = file_scanner_p->next_offset;
382 shmops->shm_free(shmops->addr2offset(file_scanner_p));
385 else
387 DEBUG(0,("ERROR: del_share_modes No share mode dev=%x ino=%.0f\n",
388 (unsigned int)dev, (double)inode));
392 /*******************************************************************
393 set the share mode of a file. Return False on fail, True on success.
394 ********************************************************************/
395 static BOOL shm_set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type)
397 SMB_DEV_T dev;
398 SMB_INO_T inode;
399 int *mode_array;
400 unsigned int hash_entry;
401 share_mode_record *file_scanner_p;
402 shm_share_mode_entry *new_entry_p;
403 int new_entry_offset;
404 BOOL found = False;
406 dev = fsp->fd_ptr->dev;
407 inode = fsp->fd_ptr->inode;
409 hash_entry = HASH_ENTRY(dev, inode);
411 mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
413 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
415 while(file_scanner_p)
417 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
419 found = True;
420 break;
422 else
424 file_scanner_p = (share_mode_record *)
425 shmops->offset2addr(file_scanner_p->next_offset);
429 if(!found)
431 /* We must create a share_mode_record */
432 share_mode_record *new_mode_p = NULL;
433 int new_offset = shmops->shm_alloc(sizeof(share_mode_record) +
434 strlen(fsp->fsp_name) + strlen(fsp->conn->connectpath) + 2);
435 if(new_offset == 0) {
436 DEBUG(0,("ERROR:set_share_mode shmops->shm_alloc fail!\n"));
437 return False;
439 new_mode_p = shmops->offset2addr(new_offset);
440 new_mode_p->locking_version = LOCKING_VERSION;
441 new_mode_p->st_dev = dev;
442 new_mode_p->st_ino = inode;
443 new_mode_p->num_share_mode_entries = 0;
444 new_mode_p->share_mode_entries = 0;
445 pstrcpy(new_mode_p->file_name, fsp->conn->connectpath);
446 pstrcat(new_mode_p->file_name, "/");
447 pstrcat(new_mode_p->file_name, fsp->fsp_name);
449 /* Chain onto the start of the hash chain (in the hope we will be used first). */
450 new_mode_p->next_offset = mode_array[hash_entry];
451 mode_array[hash_entry] = new_offset;
453 file_scanner_p = new_mode_p;
455 DEBUG(3,("set_share_mode: Created share record for %s (dev %x inode %.0f)\n",
456 fsp->fsp_name, (unsigned int)dev, (double)inode));
459 /* Now create the share mode entry */
460 new_entry_offset = shmops->shm_alloc(sizeof(shm_share_mode_entry));
461 if(new_entry_offset == 0) {
462 int delete_offset = mode_array[hash_entry];
463 DEBUG(0,("ERROR:set_share_mode: shmops->shm_alloc fail 1!\n"));
464 /* Unlink the damaged record */
465 mode_array[hash_entry] = file_scanner_p->next_offset;
466 /* And delete it */
467 shmops->shm_free( delete_offset );
468 return False;
471 new_entry_p = shmops->offset2addr(new_entry_offset);
473 new_entry_p->e.pid = getpid();
474 new_entry_p->e.share_mode = fsp->share_mode;
475 new_entry_p->e.op_port = port;
476 new_entry_p->e.op_type = op_type;
477 memcpy( (char *)&new_entry_p->e.time, (char *)&fsp->open_time, sizeof(struct timeval));
479 /* Chain onto the share_mode_record */
480 new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
481 file_scanner_p->share_mode_entries = new_entry_offset;
483 /* PARANOIA TEST */
484 if(file_scanner_p->num_share_mode_entries < 0)
486 DEBUG(0,("PANIC ERROR:set_share_mode num_share_mode_entries=%d\n",
487 file_scanner_p->num_share_mode_entries));
488 return False;
491 /* Increment the share_mode_entries counter */
492 file_scanner_p->num_share_mode_entries += 1;
494 DEBUG(3,("set_share_mode: Created share entry for %s with mode 0x%X pid=%d\n",
495 fsp->fsp_name, fsp->share_mode, (int)new_entry_p->e.pid));
497 return(True);
500 /*******************************************************************
501 Call a generic modify function for a share mode entry.
502 ********************************************************************/
504 static BOOL shm_mod_share_entry(int token, files_struct *fsp,
505 void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
506 void *param)
508 SMB_DEV_T dev;
509 SMB_INO_T inode;
510 int *mode_array;
511 unsigned int hash_entry;
512 share_mode_record *file_scanner_p;
513 share_mode_record *file_prev_p;
514 shm_share_mode_entry *entry_scanner_p;
515 BOOL found = False;
516 pid_t pid = getpid();
518 dev = fsp->fd_ptr->dev;
519 inode = fsp->fd_ptr->inode;
521 hash_entry = HASH_ENTRY(dev, inode);
523 mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
525 if(mode_array[hash_entry] == 0)
527 DEBUG(0,("PANIC ERROR:modify_share_entry: hash bucket %d empty\n",
528 hash_entry));
529 return False;
532 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
533 file_prev_p = file_scanner_p;
535 while(file_scanner_p)
537 if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
539 found = True;
540 break;
542 else
544 file_prev_p = file_scanner_p ;
545 file_scanner_p = (share_mode_record *)
546 shmops->offset2addr(file_scanner_p->next_offset);
550 if(!found)
552 DEBUG(0,("ERROR:modify_share_entry: no entry found for dev=%x ino=%.0f\n",
553 (unsigned int)dev, (double)inode));
554 return False;
557 if(file_scanner_p->locking_version != LOCKING_VERSION)
559 DEBUG(0,("ERROR: modify_share_entry: Deleting old share mode v1=%d dev=%x ino=%.0f\n",
560 file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
562 if(file_prev_p == file_scanner_p)
563 mode_array[hash_entry] = file_scanner_p->next_offset;
564 else
565 file_prev_p->next_offset = file_scanner_p->next_offset;
566 shmops->shm_free(shmops->addr2offset(file_scanner_p));
567 return False;
570 found = False;
571 entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
572 file_scanner_p->share_mode_entries);
573 while(entry_scanner_p)
575 if( (pid == entry_scanner_p->e.pid) &&
576 (entry_scanner_p->e.share_mode == fsp->share_mode) &&
577 (memcmp(&entry_scanner_p->e.time,
578 &fsp->open_time,sizeof(struct timeval)) == 0) )
581 * Call the generic function with the given parameter.
584 DEBUG(5,("modify_share_entry: Calling generic function to modify entry for dev=%x ino=%.0f\n",
585 (unsigned int)dev, (double)inode));
587 (*mod_fn)( &entry_scanner_p->e, dev, inode, param);
588 found = True;
589 break;
591 else
593 entry_scanner_p = (shm_share_mode_entry *)
594 shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
598 if(!found)
600 DEBUG(0,("ERROR: modify_share_entry: No entry found for dev=%x ino=%.0f\n",
601 (unsigned int)dev, (double)inode));
602 return False;
605 return True;
608 /*******************************************************************
609 call the specified function on each entry under management by the
610 share mode system
611 ********************************************************************/
612 static int shm_share_forall(void (*fn)(share_mode_entry *, char *))
614 int i, count=0;
615 int *mode_array;
616 share_mode_record *file_scanner_p;
618 mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
620 for( i = 0; i < shmops->hash_size(); i++) {
621 shmops->lock_hash_entry(i);
622 if(mode_array[i] == 0) {
623 shmops->unlock_hash_entry(i);
624 continue;
627 file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[i]);
628 while((file_scanner_p != 0) &&
629 (file_scanner_p->num_share_mode_entries != 0)) {
630 shm_share_mode_entry *entry_scanner_p =
631 (shm_share_mode_entry *)
632 shmops->offset2addr(file_scanner_p->share_mode_entries);
634 while(entry_scanner_p != 0) {
636 if (process_exists(entry_scanner_p->e.pid)) {
637 fn(&entry_scanner_p->e,
638 file_scanner_p->file_name);
639 count++;
642 entry_scanner_p =
643 (shm_share_mode_entry *)
644 shmops->offset2addr(
645 entry_scanner_p->next_share_mode_entry);
646 } /* end while entry_scanner_p */
647 file_scanner_p = (share_mode_record *)
648 shmops->offset2addr(file_scanner_p->next_offset);
649 } /* end while file_scanner_p */
650 shmops->unlock_hash_entry(i);
651 } /* end for */
653 return count;
657 /*******************************************************************
658 dump the state of the system
659 ********************************************************************/
660 static void shm_share_status(FILE *f)
662 int bytes_free, bytes_used, bytes_overhead, bytes_total;
664 shmops->get_usage(&bytes_free, &bytes_used, &bytes_overhead);
665 bytes_total = bytes_free + bytes_used + bytes_overhead;
667 fprintf(f, "Share mode memory usage (bytes):\n");
668 fprintf(f, " %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n",
669 bytes_free, (bytes_free * 100)/bytes_total,
670 bytes_used, (bytes_used * 100)/bytes_total,
671 bytes_overhead, (bytes_overhead * 100)/bytes_total,
672 bytes_total);
676 static struct share_ops share_ops = {
677 shm_stop_share_mode_mgmt,
678 shm_lock_share_entry,
679 shm_unlock_share_entry,
680 shm_get_share_modes,
681 shm_del_share_mode,
682 shm_set_share_mode,
683 shm_mod_share_entry,
684 shm_share_forall,
685 shm_share_status,
688 /*******************************************************************
689 initialize the shared memory for share_mode management
690 ******************************************************************/
691 struct share_ops *locking_shm_init(int ronly)
693 read_only = ronly;
695 #ifdef USE_SYSV_IPC
696 shmops = sysv_shm_open(read_only);
697 if (shmops) return &share_ops;
698 #endif
700 #ifdef USE_SHARED_MMAP
701 shmops = smb_shm_open(read_only);
702 if (shmops) return &share_ops;
703 #endif
705 return NULL;
708 #else
709 int locking_shm_dummy_procedure(void)
710 {return 0;}
711 #endif /* FAST_SHARE_MODES */