2 Unix SMB/Netbios implementation.
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.
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
32 October 1997 - split into separate file (tridge)
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 */
46 int next_offset
; /* offset of next record in chain from hash bucket */
50 int num_share_mode_entries
;
51 int share_mode_entries
; /* Chain of share mode entries for this file */
55 /* share mode entry pointed to by share_mode_record struct */
58 int next_share_mode_entry
;
60 } shm_share_mode_entry
;
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
)
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
;
110 int num_entries_copied
;
112 share_mode_entry
*share_array
= (share_mode_entry
*)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
));
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
) )
135 file_prev_p
= file_scanner_p
;
136 file_scanner_p
= (share_mode_record
*)shmops
->offset2addr(
137 file_scanner_p
->next_offset
);
143 DEBUG(5,("get_share_modes no entry for file dev = %x ino = %.0f\n",
144 (unsigned int)dev
, (double)inode
));
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
;
156 file_prev_p
->next_offset
= file_scanner_p
->next_offset
;
157 shmops
->shm_free(shmops
->addr2offset(file_scanner_p
));
161 /* Allocate the old_shares array */
162 num_entries
= file_scanner_p
->num_share_mode_entries
;
165 *old_shares
= share_array
= (share_mode_entry
*)
166 malloc(num_entries
* sizeof(share_mode_entry
));
169 DEBUG(0,("get_share_modes: malloc fail for size 0x%x!\n", (unsigned int)(num_entries
* sizeof(share_mode_entry
))));
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
;
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;
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
));
213 DEBUG(0,("get_share_modes: process %d no longer exists\n", (int)pid
));
215 shmops
->shm_free(shmops
->addr2offset(delete_entry_p
));
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
));
244 free((char *)*old_shares
);
247 if(file_prev_p
== file_scanner_p
)
248 mode_array
[hash_entry
] = file_scanner_p
->next_offset
;
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
)
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
;
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",
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
) )
302 file_prev_p
= file_scanner_p
;
303 file_scanner_p
= (share_mode_record
*)
304 shmops
->offset2addr(file_scanner_p
->next_offset
);
310 DEBUG(0,("ERROR: del_share_mode no entry for dev %x inode %.0f\n",
311 (unsigned int)dev
, (double)inode
));
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
;
323 file_prev_p
->next_offset
= file_scanner_p
->next_offset
;
324 shmops
->shm_free(shmops
->addr2offset(file_scanner_p
));
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) )
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
);
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
;
361 entry_prev_p
->next_share_mode_entry
= entry_scanner_p
->next_share_mode_entry
;
362 shmops
->shm_free(shmops
->addr2offset(entry_scanner_p
));
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
));
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
;
381 file_prev_p
->next_offset
= file_scanner_p
->next_offset
;
382 shmops
->shm_free(shmops
->addr2offset(file_scanner_p
));
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
)
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
;
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
) )
424 file_scanner_p
= (share_mode_record
*)
425 shmops
->offset2addr(file_scanner_p
->next_offset
);
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"));
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
;
467 shmops
->shm_free( delete_offset
);
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
;
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
));
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
));
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 *),
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
;
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",
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
) )
544 file_prev_p
= file_scanner_p
;
545 file_scanner_p
= (share_mode_record
*)
546 shmops
->offset2addr(file_scanner_p
->next_offset
);
552 DEBUG(0,("ERROR:modify_share_entry: no entry found for dev=%x ino=%.0f\n",
553 (unsigned int)dev
, (double)inode
));
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
;
565 file_prev_p
->next_offset
= file_scanner_p
->next_offset
;
566 shmops
->shm_free(shmops
->addr2offset(file_scanner_p
));
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
);
593 entry_scanner_p
= (shm_share_mode_entry
*)
594 shmops
->offset2addr(entry_scanner_p
->next_share_mode_entry
);
600 DEBUG(0,("ERROR: modify_share_entry: No entry found for dev=%x ino=%.0f\n",
601 (unsigned int)dev
, (double)inode
));
608 /*******************************************************************
609 call the specified function on each entry under management by the
611 ********************************************************************/
612 static int shm_share_forall(void (*fn
)(share_mode_entry
*, char *))
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
);
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
);
643 (shm_share_mode_entry
*)
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
);
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
,
676 static struct share_ops share_ops
= {
677 shm_stop_share_mode_mgmt
,
678 shm_lock_share_entry
,
679 shm_unlock_share_entry
,
688 /*******************************************************************
689 initialize the shared memory for share_mode management
690 ******************************************************************/
691 struct share_ops
*locking_shm_init(int ronly
)
696 shmops
= sysv_shm_open(read_only
);
697 if (shmops
) return &share_ops
;
700 #ifdef USE_SHARED_MMAP
701 shmops
= smb_shm_open(read_only
);
702 if (shmops
) return &share_ops
;
709 int locking_shm_dummy_procedure(void)
711 #endif /* FAST_SHARE_MODES */