diff options
author | Andrew Tridgell <tridge@samba.org> | 1997-10-28 14:19:54 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 1997-10-28 14:19:54 +0000 |
commit | c9fa24b7a8809a7963f0970cf2dd21f6804e31a4 (patch) | |
tree | 4bd06b65991e13b8aac3771f5d27a54b1fdb6505 | |
parent | 7c20ee083f6820a4c8776cefae3e0477f79ea934 (diff) | |
download | samba-c9fa24b7a8809a7963f0970cf2dd21f6804e31a4.tar.gz samba-c9fa24b7a8809a7963f0970cf2dd21f6804e31a4.tar.bz2 samba-c9fa24b7a8809a7963f0970cf2dd21f6804e31a4.zip |
SYSV IPC implementation of fast share modes.
It will try sysv IPC first, then if that fails it will try mmap(),
then after that it will try share files.
I have defined USE_SYSV_IPC for Linux, Solaris and HPUX at the
moment. Probably a lot more could have it defined. In fact, the vast
majority of systems support it. Need autoconf again :-)
It should actually be faster than the mmap() version, and doesn't need
any lock files. This means the problem of the share mem file being on
a NFS drive will be gone.
(This used to be commit cc8fe0f0629eea9acc39e30d8d76d5890a5b6978)
-rw-r--r-- | source3/include/includes.h | 12 | ||||
-rw-r--r-- | source3/include/proto.h | 17 | ||||
-rw-r--r-- | source3/include/smb.h | 5 | ||||
-rw-r--r-- | source3/locking/locking_shm.c | 106 | ||||
-rw-r--r-- | source3/locking/shmem.c | 531 | ||||
-rw-r--r-- | source3/locking/shmem_sysv.c | 621 |
6 files changed, 973 insertions, 319 deletions
diff --git a/source3/include/includes.h b/source3/include/includes.h index 09c687aed5..91a2ec5c67 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -214,6 +214,9 @@ Here come some platform specific sections #include <dirent.h> #include <string.h> #include <sys/vfs.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <sys/shm.h> #include <netinet/in.h> #ifndef NO_ASMSIGNALH #include <asm/signal.h> @@ -233,6 +236,7 @@ Here come some platform specific sections #define HAVE_MEMMOVE #define USE_SIGPROCMASK #define USE_WAITPID +#define USE_SYSV_IPC #if 0 /* SETFS disabled until we can check on some bug reports */ #if _LINUX_C_LIB_VERSION_MAJOR >= 5 @@ -293,6 +297,9 @@ typedef unsigned short mode_t; #include <sys/statvfs.h> #include <sys/filio.h> #include <sys/sockio.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <sys/shm.h> #include <netinet/in_systm.h> #include <netinet/tcp.h> #include <netinet/ip.h> @@ -317,6 +324,7 @@ extern int innetgr (const char *, const char *, const char *, const char *); #define USE_STATVFS #define USE_GETCWD #define USE_SETSID +#define USE_SYSV_IPC #ifndef REPLACE_GETPASS #define REPLACE_GETPASS #endif /* REPLACE_GETPASS */ @@ -548,6 +556,9 @@ char *mktemp(char *); /* No standard include */ #include <sys/types.h> #include <sys/termios.h> #include <netinet/tcp.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <sys/shm.h> #ifdef HPUX_10_TRUSTED #include <hpsecurity.h> #include <prot.h> @@ -563,6 +574,7 @@ char *mktemp(char *); /* No standard include */ #define USE_GETCWD #define USE_SETSID #define USE_SETRES +#define USE_SYSV_IPC #define DEFAULT_PRINTING PRINT_HPUX /* Ken Weiss <krweiss@ucdavis.edu> tells us that SIGCLD_IGNORE is not good for HPUX */ diff --git a/source3/include/proto.h b/source3/include/proto.h index 669ed5fd8d..13368c873d 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -878,18 +878,11 @@ int construct_reply(char *inbuf,char *outbuf,int size,int bufsize); /*The following definitions come from shmem.c */ -BOOL smb_shm_open(char *file_name, int size, int ronly); -BOOL smb_shm_close( void ); -int smb_shm_alloc(int size); -BOOL smb_shm_free(int offset); -int smb_shm_get_userdef_off(void); -void *smb_shm_offset2addr(int offset); -int smb_shm_addr2offset(void *addr); -BOOL smb_shm_lock_hash_entry( unsigned int entry); -BOOL smb_shm_unlock_hash_entry( unsigned int entry ); -BOOL smb_shm_get_usage(int *bytes_free, - int *bytes_used, - int *bytes_overhead); +struct shmem_ops *smb_shm_open(char *file_name, int size, int ronly); + +/*The following definitions come from shmem_sysv.c */ + +struct shmem_ops *sysv_shm_open(int size, int ronly); /*The following definitions come from smbdes.c */ diff --git a/source3/include/smb.h b/source3/include/smb.h index 057a0b7550..d7a576de85 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -46,8 +46,12 @@ /* Default number of hash buckets used in shared memory share mode */ #ifndef SHMEM_HASH_SIZE +#ifdef SEMMSL +#define SHMEM_HASH_SIZE (SEMMSL-1) +#else #define SHMEM_HASH_SIZE 113 #endif +#endif #define NMB_PORT 137 #define DGRAM_PORT 138 @@ -1328,7 +1332,6 @@ struct share_ops { /* each implementation of the shared memory code needs to support the following operations */ struct shmem_ops { - BOOL (*open)(char *, int ); BOOL (*close)( void ); int (*alloc)(int ); BOOL (*free)(int ); diff --git a/source3/locking/locking_shm.c b/source3/locking/locking_shm.c index 410fcb9760..f2ae641808 100644 --- a/source3/locking/locking_shm.c +++ b/source3/locking/locking_shm.c @@ -39,6 +39,8 @@ extern int DEBUGLEVEL; extern connection_struct Connections[]; extern files_struct Files[]; +static struct shmem_ops *shmops; + /* share mode record pointed to in shared memory hash bucket */ typedef struct { @@ -65,7 +67,7 @@ static int read_only; ******************************************************************/ static BOOL shm_stop_share_mode_mgmt(void) { - return smb_shm_close(); + return shmops->close(); } /******************************************************************* @@ -73,7 +75,7 @@ static BOOL shm_stop_share_mode_mgmt(void) ******************************************************************/ static BOOL shm_lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok) { - return smb_shm_lock_hash_entry(HASH_ENTRY(dev, inode)); + return shmops->lock_hash_entry(HASH_ENTRY(dev, inode)); } /******************************************************************* @@ -81,7 +83,7 @@ static BOOL shm_lock_share_entry(int cnum, uint32 dev, uint32 inode, int *ptok) ******************************************************************/ static BOOL shm_unlock_share_entry(int cnum, uint32 dev, uint32 inode, int token) { - return smb_shm_unlock_hash_entry(HASH_ENTRY(dev, inode)); + return shmops->unlock_hash_entry(HASH_ENTRY(dev, inode)); } /******************************************************************* @@ -112,7 +114,7 @@ static int shm_get_share_modes(int cnum, int token, uint32 dev, uint32 inode, return 0; } - mode_array = (int *)smb_shm_offset2addr(smb_shm_get_userdef_off()); + mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off()); if(mode_array[hash_entry] == NULL_OFFSET) { @@ -120,7 +122,7 @@ static int shm_get_share_modes(int cnum, int token, uint32 dev, uint32 inode, return 0; } - file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]); + file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]); file_prev_p = file_scanner_p; while(file_scanner_p) { @@ -132,7 +134,7 @@ static int shm_get_share_modes(int cnum, int token, uint32 dev, uint32 inode, else { file_prev_p = file_scanner_p ; - file_scanner_p = (share_mode_record *)smb_shm_offset2addr( + file_scanner_p = (share_mode_record *)shmops->offset2addr( file_scanner_p->next_offset); } } @@ -153,7 +155,7 @@ bucket %d\n", file_scanner_p->locking_version, dev, inode, hash_entry)); mode_array[hash_entry] = file_scanner_p->next_offset; else file_prev_p->next_offset = file_scanner_p->next_offset; - smb_shm_free(smb_shm_addr2offset(file_scanner_p)); + shmops->free(shmops->addr2offset(file_scanner_p)); return (0); } @@ -172,7 +174,7 @@ bucket %d\n", file_scanner_p->locking_version, dev, inode, hash_entry)); num_entries_copied = 0; - entry_scanner_p = (shm_share_mode_entry*)smb_shm_offset2addr( + entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr( file_scanner_p->share_mode_entries); entry_prev_p = entry_scanner_p; while(entry_scanner_p) @@ -189,7 +191,7 @@ bucket %d\n", file_scanner_p->locking_version, dev, inode, hash_entry)); { /* We are at start of list */ file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry; - entry_scanner_p = (shm_share_mode_entry*)smb_shm_offset2addr( + entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr( file_scanner_p->share_mode_entries); entry_prev_p = entry_scanner_p; } @@ -197,7 +199,7 @@ bucket %d\n", file_scanner_p->locking_version, dev, inode, hash_entry)); { entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry; entry_scanner_p = (shm_share_mode_entry*) - smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry); + shmops->offset2addr(entry_scanner_p->next_share_mode_entry); } /* Decrement the number of share mode entries on this share mode record */ file_scanner_p->num_share_mode_entries -= 1; @@ -217,7 +219,7 @@ bucket %d (number of entries now = %d)\n", pid, share_mode, dev, inode, hash_entry, file_scanner_p->num_share_mode_entries)); - smb_shm_free(smb_shm_addr2offset(delete_entry_p)); + shmops->free(shmops->addr2offset(delete_entry_p)); } else { @@ -235,7 +237,7 @@ bucket %d (number of entries now = %d)\n", record mode 0x%X pid=%d\n", entry_scanner_p->e.share_mode, entry_scanner_p->e.pid)); entry_prev_p = entry_scanner_p; entry_scanner_p = (shm_share_mode_entry *) - smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry); + shmops->offset2addr(entry_scanner_p->next_share_mode_entry); } } @@ -253,7 +255,7 @@ hash bucket %d has a share mode record but no entries - deleting\n", mode_array[hash_entry] = file_scanner_p->next_offset; else file_prev_p->next_offset = file_scanner_p->next_offset; - smb_shm_free(smb_shm_addr2offset(file_scanner_p)); + shmops->free(shmops->addr2offset(file_scanner_p)); } DEBUG(5,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \ @@ -291,7 +293,7 @@ static void shm_del_share_mode(int token, int fnum) return; } - mode_array = (int *)smb_shm_offset2addr(smb_shm_get_userdef_off()); + mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off()); if(mode_array[hash_entry] == NULL_OFFSET) { @@ -300,7 +302,7 @@ static void shm_del_share_mode(int token, int fnum) return; } - file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]); + file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]); file_prev_p = file_scanner_p; while(file_scanner_p) @@ -314,7 +316,7 @@ static void shm_del_share_mode(int token, int fnum) { file_prev_p = file_scanner_p ; file_scanner_p = (share_mode_record *) - smb_shm_offset2addr(file_scanner_p->next_offset); + shmops->offset2addr(file_scanner_p->next_offset); } } @@ -334,12 +336,12 @@ record due to old locking version %d for file dev %d, inode %d hash bucket %d\n" mode_array[hash_entry] = file_scanner_p->next_offset; else file_prev_p->next_offset = file_scanner_p->next_offset; - smb_shm_free(smb_shm_addr2offset(file_scanner_p)); + shmops->free(shmops->addr2offset(file_scanner_p)); return; } found = False; - entry_scanner_p = (shm_share_mode_entry*)smb_shm_offset2addr( + entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr( file_scanner_p->share_mode_entries); entry_prev_p = entry_scanner_p; while(entry_scanner_p) @@ -355,7 +357,7 @@ record due to old locking version %d for file dev %d, inode %d hash bucket %d\n" { entry_prev_p = entry_scanner_p; entry_scanner_p = (shm_share_mode_entry *) - smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry); + shmops->offset2addr(entry_scanner_p->next_share_mode_entry); } } @@ -372,7 +374,7 @@ Deleting share mode entry dev = %d, inode = %d in hash bucket %d (num entries no file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry; else entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry; - smb_shm_free(smb_shm_addr2offset(entry_scanner_p)); + shmops->free(shmops->addr2offset(entry_scanner_p)); /* PARANOIA TEST */ if(file_scanner_p->num_share_mode_entries < 0) @@ -392,7 +394,7 @@ record dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry)); mode_array[hash_entry] = file_scanner_p->next_offset; else file_prev_p->next_offset = file_scanner_p->next_offset; - smb_shm_free(smb_shm_addr2offset(file_scanner_p)); + shmops->free(shmops->addr2offset(file_scanner_p)); } } else @@ -430,9 +432,9 @@ static BOOL shm_set_share_mode(int token, int fnum, uint16 port, uint16 op_type) return False; } - mode_array = (int *)smb_shm_offset2addr(smb_shm_get_userdef_off()); + mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off()); - file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]); + file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]); file_prev_p = file_scanner_p; while(file_scanner_p) @@ -446,7 +448,7 @@ static BOOL shm_set_share_mode(int token, int fnum, uint16 port, uint16 op_type) { file_prev_p = file_scanner_p ; file_scanner_p = (share_mode_record *) - smb_shm_offset2addr(file_scanner_p->next_offset); + shmops->offset2addr(file_scanner_p->next_offset); } } @@ -454,14 +456,14 @@ static BOOL shm_set_share_mode(int token, int fnum, uint16 port, uint16 op_type) { /* We must create a share_mode_record */ share_mode_record *new_mode_p = NULL; - int new_offset = smb_shm_alloc( sizeof(share_mode_record) + + int new_offset = shmops->alloc( sizeof(share_mode_record) + strlen(fs_p->name) + 1); if(new_offset == NULL_OFFSET) { - DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail !\n")); + DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): shmops->alloc fail !\n")); return False; } - new_mode_p = smb_shm_offset2addr(new_offset); + new_mode_p = shmops->offset2addr(new_offset); new_mode_p->locking_version = LOCKING_VERSION; new_mode_p->st_dev = dev; new_mode_p->st_ino = inode; @@ -480,19 +482,19 @@ inode %d in hash bucket %d\n", fs_p->name, dev, inode, hash_entry)); } /* Now create the share mode entry */ - new_entry_offset = smb_shm_alloc( sizeof(shm_share_mode_entry)); + new_entry_offset = shmops->alloc( sizeof(shm_share_mode_entry)); if(new_entry_offset == NULL_OFFSET) { int delete_offset = mode_array[hash_entry]; - DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail 1!\n")); + DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): shmops->alloc fail 1!\n")); /* Unlink the damaged record */ mode_array[hash_entry] = file_scanner_p->next_offset; /* And delete it */ - smb_shm_free( delete_offset ); + shmops->free( delete_offset ); return False; } - new_entry_p = smb_shm_offset2addr(new_entry_offset); + new_entry_p = shmops->offset2addr(new_entry_offset); new_entry_p->e.pid = getpid(); new_entry_p->e.share_mode = fs_p->share_mode; @@ -552,7 +554,7 @@ static BOOL shm_remove_share_oplock(int fnum, int token) return False; } - mode_array = (int *)smb_shm_offset2addr(smb_shm_get_userdef_off()); + mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off()); if(mode_array[hash_entry] == NULL_OFFSET) { @@ -561,7 +563,7 @@ static BOOL shm_remove_share_oplock(int fnum, int token) return False; } - file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]); + file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]); file_prev_p = file_scanner_p; while(file_scanner_p) @@ -575,7 +577,7 @@ static BOOL shm_remove_share_oplock(int fnum, int token) { file_prev_p = file_scanner_p ; file_scanner_p = (share_mode_record *) - smb_shm_offset2addr(file_scanner_p->next_offset); + shmops->offset2addr(file_scanner_p->next_offset); } } @@ -595,12 +597,12 @@ record due to old locking version %d for file dev %d, inode %d hash bucket %d\n" mode_array[hash_entry] = file_scanner_p->next_offset; else file_prev_p->next_offset = file_scanner_p->next_offset; - smb_shm_free(smb_shm_addr2offset(file_scanner_p)); + shmops->free(shmops->addr2offset(file_scanner_p)); return False; } found = False; - entry_scanner_p = (shm_share_mode_entry*)smb_shm_offset2addr( + entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr( file_scanner_p->share_mode_entries); entry_prev_p = entry_scanner_p; while(entry_scanner_p) @@ -620,7 +622,7 @@ record due to old locking version %d for file dev %d, inode %d hash bucket %d\n" { entry_prev_p = entry_scanner_p; entry_scanner_p = (shm_share_mode_entry *) - smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry); + shmops->offset2addr(entry_scanner_p->next_share_mode_entry); } } @@ -645,21 +647,21 @@ static int shm_share_forall(void (*fn)(share_mode_entry *, char *)) int *mode_array; share_mode_record *file_scanner_p; - mode_array = (int *)smb_shm_offset2addr(smb_shm_get_userdef_off()); + mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off()); for( i = 0; i < lp_shmem_hash_size(); i++) { - smb_shm_lock_hash_entry(i); + shmops->lock_hash_entry(i); if(mode_array[i] == NULL_OFFSET) { - smb_shm_unlock_hash_entry(i); + shmops->unlock_hash_entry(i); continue; } - file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[i]); + file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[i]); while((file_scanner_p != 0) && (file_scanner_p->num_share_mode_entries != 0)) { shm_share_mode_entry *entry_scanner_p = (shm_share_mode_entry *) - smb_shm_offset2addr(file_scanner_p->share_mode_entries); + shmops->offset2addr(file_scanner_p->share_mode_entries); while(entry_scanner_p != 0) { @@ -668,14 +670,14 @@ static int shm_share_forall(void (*fn)(share_mode_entry *, char *)) entry_scanner_p = (shm_share_mode_entry *) - smb_shm_offset2addr( + shmops->offset2addr( entry_scanner_p->next_share_mode_entry); count++; } /* end while entry_scanner_p */ file_scanner_p = (share_mode_record *) - smb_shm_offset2addr(file_scanner_p->next_offset); + shmops->offset2addr(file_scanner_p->next_offset); } /* end while file_scanner_p */ - smb_shm_unlock_hash_entry(i); + shmops->unlock_hash_entry(i); } /* end for */ return count; @@ -689,7 +691,7 @@ static void shm_share_status(FILE *f) { int bytes_free, bytes_used, bytes_overhead, bytes_total; - smb_shm_get_usage(&bytes_free, &bytes_used, &bytes_overhead); + shmops->get_usage(&bytes_free, &bytes_used, &bytes_overhead); bytes_total = bytes_free + bytes_used + bytes_overhead; fprintf(f, "Share mode memory usage (bytes):\n"); @@ -721,7 +723,12 @@ struct share_ops *locking_shm_init(int ronly) pstring shmem_file_name; read_only = ronly; - + +#ifdef USE_SYSV_IPC + shmops = sysv_shm_open(lp_shmem_size(), read_only); + if (shmops) return &share_ops; +#endif + pstrcpy(shmem_file_name,lp_lockdir()); if (!directory_exist(shmem_file_name,NULL)) { if (read_only) return NULL; @@ -730,8 +737,9 @@ struct share_ops *locking_shm_init(int ronly) trim_string(shmem_file_name,"","/"); if (!*shmem_file_name) return(False); strcat(shmem_file_name, "/SHARE_MEM_FILE"); - if (smb_shm_open(shmem_file_name, lp_shmem_size(), read_only)) - return &share_ops; + shmops = smb_shm_open(shmem_file_name, lp_shmem_size(), read_only); + if (shmops) return &share_ops; + return NULL; } diff --git a/source3/locking/shmem.c b/source3/locking/shmem.c index 1f9cb8b732..72d7c07751 100644 --- a/source3/locking/shmem.c +++ b/source3/locking/shmem.c @@ -152,6 +152,136 @@ static BOOL smb_shm_global_unlock(void) } + +static void *smb_shm_offset2addr(int offset) +{ + if (offset == NULL_OFFSET ) + return (void *)(0); + + if (!smb_shm_header_p) + return (void *)(0); + + return (void *)((char *)smb_shm_header_p + offset ); +} + +static int smb_shm_addr2offset(void *addr) +{ + if (!addr) + return NULL_OFFSET; + + if (!smb_shm_header_p) + return NULL_OFFSET; + + return (int)((char *)addr - (char *)smb_shm_header_p); +} + + + +static int smb_shm_alloc(int size) +{ + unsigned num_cells ; + struct SmbShmBlockDesc *scanner_p; + struct SmbShmBlockDesc *prev_p; + struct SmbShmBlockDesc *new_p; + int result_offset; + + + if( !smb_shm_header_p ) + { + /* not mapped yet */ + DEBUG(0,("ERROR smb_shm_alloc : shmem not mapped\n")); + return NULL_OFFSET; + } + + smb_shm_global_lock(); + + if( !smb_shm_header_p->consistent) + { + DEBUG(0,("ERROR smb_shm_alloc : shmem not consistent\n")); + smb_shm_global_unlock(); + return NULL_OFFSET; + } + + + /* calculate the number of cells */ + num_cells = (size + CellSize -1) / CellSize; + + /* set start of scan */ + prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off); + scanner_p = prev_p ; + + /* scan the free list to find a matching free space */ + while ( ( scanner_p != EOList_Addr ) && ( scanner_p->size < num_cells ) ) + { + prev_p = scanner_p; + scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next); + } + + /* at this point scanner point to a block header or to the end of the list */ + if ( scanner_p == EOList_Addr ) + { + DEBUG(0,("ERROR smb_shm_alloc : alloc of %d bytes failed, no free space found\n",size)); + smb_shm_global_unlock(); + return (NULL_OFFSET); + } + + /* going to modify shared mem */ + smb_shm_header_p->consistent = False; + + /* if we found a good one : scanner == the good one */ + if ( scanner_p->size <= num_cells + 2 ) + { + /* there is no use in making a new one, it will be too small anyway + * we will link out scanner + */ + if ( prev_p == scanner_p ) + { + smb_shm_header_p->first_free_off = scanner_p->next ; + } + else + { + prev_p->next = scanner_p->next ; + } + smb_shm_header_p->statistics.cells_free -= scanner_p->size; + smb_shm_header_p->statistics.cells_used += scanner_p->size; + } + else + { + /* Make a new one */ + new_p = scanner_p + 1 + num_cells; + new_p->size = scanner_p->size - num_cells - 1; + new_p->next = scanner_p->next; + scanner_p->size = num_cells; + scanner_p->next = smb_shm_addr2offset(new_p); + + if ( prev_p != scanner_p ) + { + prev_p->next = smb_shm_addr2offset(new_p) ; + } + else + { + smb_shm_header_p->first_free_off = smb_shm_addr2offset(new_p) ; + } + smb_shm_header_p->statistics.cells_free -= num_cells+1; + smb_shm_header_p->statistics.cells_used += num_cells; + smb_shm_header_p->statistics.cells_system += 1; + } + + result_offset = smb_shm_addr2offset( &(scanner_p[1]) ); + scanner_p->next = SMB_SHM_NOT_FREE_OFF ; + + /* end modification of shared mem */ + smb_shm_header_p->consistent = True; + + DEBUG(6,("smb_shm_alloc : request for %d bytes, allocated %d bytes at offset %d\n",size,scanner_p->size*CellSize,result_offset )); + + smb_shm_global_unlock(); + return ( result_offset ); +} + + + + /* * Function to create the hash table for the share mode entries. Called * when smb shared memory is global locked. @@ -391,130 +521,7 @@ static void smb_shm_solve_neighbors(struct SmbShmBlockDesc *head_p ) -BOOL smb_shm_open(char *file_name, int size, int ronly) -{ - int filesize; - BOOL created_new = False; - BOOL other_processes = True; - - read_only = ronly; - - DEBUG(5,("smb_shm_open : using shmem file %s to be of size %d\n",file_name,size)); - - smb_shm_fd = open(file_name, read_only?O_RDONLY:(O_RDWR|O_CREAT), - SHM_FILE_MODE); - - if ( smb_shm_fd < 0 ) - { - DEBUG(0,("ERROR smb_shm_open : open failed with code %s\n",strerror(errno))); - return False; - } - - if (!smb_shm_global_lock()) - { - DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_global_lock\n")); - return False; - } - - if( (filesize = lseek(smb_shm_fd, 0, SEEK_END)) < 0) - { - DEBUG(0,("ERROR smb_shm_open : lseek failed with code %s\n",strerror(errno))); - smb_shm_global_unlock(); - close(smb_shm_fd); - return False; - } - - /* return the file offset to 0 to save on later seeks */ - lseek(smb_shm_fd,0,SEEK_SET); - - if (filesize == 0) - { - /* we just created a new one */ - created_new = True; - } - - /* to find out if some other process is already mapping the file, - we use a registration file containing the processids of the file mapping processes - */ - - /* construct processreg file name */ - strcpy(smb_shm_processreg_name, file_name); - strcat(smb_shm_processreg_name, ".processes"); - - if (!read_only && - !smb_shm_register_process(smb_shm_processreg_name, getpid(), &other_processes)) - { - smb_shm_global_unlock(); - close(smb_shm_fd); - return False; - } - - if (!read_only && (created_new || !other_processes)) - { - /* we just created a new one, or are the first opener, lets set it size */ - if( ftruncate(smb_shm_fd, size) <0) - { - DEBUG(0,("ERROR smb_shm_open : ftruncate failed with code %s\n",strerror(errno))); - smb_shm_unregister_process(smb_shm_processreg_name, getpid()); - smb_shm_global_unlock(); - close(smb_shm_fd); - return False; - } - - /* paranoia */ - lseek(smb_shm_fd,0,SEEK_SET); - - filesize = size; - } - - if (size != filesize ) - { - /* the existing file has a different size and we are not the first opener. - Since another process is still using it, we will use the file size */ - DEBUG(0,("WARNING smb_shm_open : filesize (%d) != expected size (%d), using filesize\n",filesize,size)); - size = filesize; - } - - smb_shm_header_p = (struct SmbShmHeader *)mmap(NULL, size, - read_only?PROT_READ: - (PROT_READ | PROT_WRITE), - MAP_FILE | MAP_SHARED, - smb_shm_fd, 0); - /* WARNING, smb_shm_header_p can be different for different processes mapping the same file ! */ - if (smb_shm_header_p == (struct SmbShmHeader *)(-1)) - { - DEBUG(0,("ERROR smb_shm_open : mmap failed with code %s\n",strerror(errno))); - smb_shm_unregister_process(smb_shm_processreg_name, getpid()); - smb_shm_global_unlock(); - close(smb_shm_fd); - return False; - } - - - if (!read_only && (created_new || !other_processes)) - { - smb_shm_initialize(size); - /* Create the hash buckets for the share file entries. */ - smb_shm_create_hash_table( lp_shmem_hash_size() ); - } - else if (!smb_shm_validate_header(size) ) - { - /* existing file is corrupt, samba admin should remove it by hand */ - DEBUG(0,("ERROR smb_shm_open : corrupt shared mem file, remove it manually\n")); - munmap((caddr_t)smb_shm_header_p, size); - smb_shm_unregister_process(smb_shm_processreg_name, getpid()); - smb_shm_global_unlock(); - close(smb_shm_fd); - return False; - } - - smb_shm_global_unlock(); - return True; - -} - - -BOOL smb_shm_close( void ) +static BOOL smb_shm_close( void ) { if(smb_shm_initialize_called == False) @@ -545,111 +552,8 @@ BOOL smb_shm_close( void ) return True; } -int smb_shm_alloc(int size) -{ - unsigned num_cells ; - struct SmbShmBlockDesc *scanner_p; - struct SmbShmBlockDesc *prev_p; - struct SmbShmBlockDesc *new_p; - int result_offset; - - - if( !smb_shm_header_p ) - { - /* not mapped yet */ - DEBUG(0,("ERROR smb_shm_alloc : shmem not mapped\n")); - return NULL_OFFSET; - } - - smb_shm_global_lock(); - if( !smb_shm_header_p->consistent) - { - DEBUG(0,("ERROR smb_shm_alloc : shmem not consistent\n")); - smb_shm_global_unlock(); - return NULL_OFFSET; - } - - - /* calculate the number of cells */ - num_cells = (size + CellSize -1) / CellSize; - - /* set start of scan */ - prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off); - scanner_p = prev_p ; - - /* scan the free list to find a matching free space */ - while ( ( scanner_p != EOList_Addr ) && ( scanner_p->size < num_cells ) ) - { - prev_p = scanner_p; - scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next); - } - - /* at this point scanner point to a block header or to the end of the list */ - if ( scanner_p == EOList_Addr ) - { - DEBUG(0,("ERROR smb_shm_alloc : alloc of %d bytes failed, no free space found\n",size)); - smb_shm_global_unlock(); - return (NULL_OFFSET); - } - - /* going to modify shared mem */ - smb_shm_header_p->consistent = False; - - /* if we found a good one : scanner == the good one */ - if ( scanner_p->size <= num_cells + 2 ) - { - /* there is no use in making a new one, it will be too small anyway - * we will link out scanner - */ - if ( prev_p == scanner_p ) - { - smb_shm_header_p->first_free_off = scanner_p->next ; - } - else - { - prev_p->next = scanner_p->next ; - } - smb_shm_header_p->statistics.cells_free -= scanner_p->size; - smb_shm_header_p->statistics.cells_used += scanner_p->size; - } - else - { - /* Make a new one */ - new_p = scanner_p + 1 + num_cells; - new_p->size = scanner_p->size - num_cells - 1; - new_p->next = scanner_p->next; - scanner_p->size = num_cells; - scanner_p->next = smb_shm_addr2offset(new_p); - - if ( prev_p != scanner_p ) - { - prev_p->next = smb_shm_addr2offset(new_p) ; - } - else - { - smb_shm_header_p->first_free_off = smb_shm_addr2offset(new_p) ; - } - smb_shm_header_p->statistics.cells_free -= num_cells+1; - smb_shm_header_p->statistics.cells_used += num_cells; - smb_shm_header_p->statistics.cells_system += 1; - } - - result_offset = smb_shm_addr2offset( &(scanner_p[1]) ); - scanner_p->next = SMB_SHM_NOT_FREE_OFF ; - - /* end modification of shared mem */ - smb_shm_header_p->consistent = True; - - DEBUG(6,("smb_shm_alloc : request for %d bytes, allocated %d bytes at offset %d\n",size,scanner_p->size*CellSize,result_offset )); - - smb_shm_global_unlock(); - return ( result_offset ); -} - - - -BOOL smb_shm_free(int offset) +static BOOL smb_shm_free(int offset) { struct SmbShmBlockDesc *header_p ; /* pointer to header of block to free */ struct SmbShmBlockDesc *scanner_p ; /* used to scan the list */ @@ -728,7 +632,7 @@ BOOL smb_shm_free(int offset) } } -int smb_shm_get_userdef_off(void) +static int smb_shm_get_userdef_off(void) { if (!smb_shm_header_p) return NULL_OFFSET; @@ -736,33 +640,10 @@ int smb_shm_get_userdef_off(void) return smb_shm_header_p->userdef_off; } -void *smb_shm_offset2addr(int offset) -{ - if (offset == NULL_OFFSET ) - return (void *)(0); - - if (!smb_shm_header_p) - return (void *)(0); - - return (void *)((char *)smb_shm_header_p + offset ); -} - -int smb_shm_addr2offset(void *addr) -{ - if (!addr) - return NULL_OFFSET; - - if (!smb_shm_header_p) - return NULL_OFFSET; - - return (int)((char *)addr - (char *)smb_shm_header_p); -} - /******************************************************************* Lock a particular hash bucket entry. ******************************************************************/ - -BOOL smb_shm_lock_hash_entry( unsigned int entry) +static BOOL smb_shm_lock_hash_entry( unsigned int entry) { int start = (smb_shm_header_p->userdef_off + (entry * sizeof(int))); @@ -792,8 +673,7 @@ BOOL smb_shm_lock_hash_entry( unsigned int entry) /******************************************************************* Unlock a particular hash bucket entry. ******************************************************************/ - -BOOL smb_shm_unlock_hash_entry( unsigned int entry ) +static BOOL smb_shm_unlock_hash_entry( unsigned int entry ) { int start = (smb_shm_header_p->userdef_off + (entry * sizeof(int))); @@ -823,8 +703,7 @@ BOOL smb_shm_unlock_hash_entry( unsigned int entry ) /******************************************************************* Gather statistics on shared memory usage. ******************************************************************/ - -BOOL smb_shm_get_usage(int *bytes_free, +static BOOL smb_shm_get_usage(int *bytes_free, int *bytes_used, int *bytes_overhead) { @@ -841,6 +720,144 @@ BOOL smb_shm_get_usage(int *bytes_free, return True; } + +static struct shmem_ops shmops = { + smb_shm_close, + smb_shm_alloc, + smb_shm_free, + smb_shm_get_userdef_off, + smb_shm_offset2addr, + smb_shm_addr2offset, + smb_shm_lock_hash_entry, + smb_shm_unlock_hash_entry, + smb_shm_get_usage, +}; + +/******************************************************************* + open the shared memory + ******************************************************************/ +struct shmem_ops *smb_shm_open(char *file_name, int size, int ronly) +{ + int filesize; + BOOL created_new = False; + BOOL other_processes = True; + + read_only = ronly; + + DEBUG(5,("smb_shm_open : using shmem file %s to be of size %d\n",file_name,size)); + + smb_shm_fd = open(file_name, read_only?O_RDONLY:(O_RDWR|O_CREAT), + SHM_FILE_MODE); + + if ( smb_shm_fd < 0 ) + { + DEBUG(0,("ERROR smb_shm_open : open failed with code %s\n",strerror(errno))); + return NULL; + } + + if (!smb_shm_global_lock()) + { + DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_global_lock\n")); + return NULL; + } + + if( (filesize = lseek(smb_shm_fd, 0, SEEK_END)) < 0) + { + DEBUG(0,("ERROR smb_shm_open : lseek failed with code %s\n",strerror(errno))); + smb_shm_global_unlock(); + close(smb_shm_fd); + return NULL; + } + + /* return the file offset to 0 to save on later seeks */ + lseek(smb_shm_fd,0,SEEK_SET); + + if (filesize == 0) + { + /* we just created a new one */ + created_new = True; + } + + /* to find out if some other process is already mapping the file, + we use a registration file containing the processids of the file mapping processes + */ + + /* construct processreg file name */ + strcpy(smb_shm_processreg_name, file_name); + strcat(smb_shm_processreg_name, ".processes"); + + if (!read_only && + !smb_shm_register_process(smb_shm_processreg_name, getpid(), &other_processes)) + { + smb_shm_global_unlock(); + close(smb_shm_fd); + return NULL; + } + + if (!read_only && (created_new || !other_processes)) + { + /* we just created a new one, or are the first opener, lets set it size */ + if( ftruncate(smb_shm_fd, size) <0) + { + DEBUG(0,("ERROR smb_shm_open : ftruncate failed with code %s\n",strerror(errno))); + smb_shm_unregister_process(smb_shm_processreg_name, getpid()); + smb_shm_global_unlock(); + close(smb_shm_fd); + return NULL; + } + + /* paranoia */ + lseek(smb_shm_fd,0,SEEK_SET); + + filesize = size; + } + + if (size != filesize ) + { + /* the existing file has a different size and we are not the first opener. + Since another process is still using it, we will use the file size */ + DEBUG(0,("WARNING smb_shm_open : filesize (%d) != expected size (%d), using filesize\n",filesize,size)); + size = filesize; + } + + smb_shm_header_p = (struct SmbShmHeader *)mmap(NULL, size, + read_only?PROT_READ: + (PROT_READ | PROT_WRITE), + MAP_FILE | MAP_SHARED, + smb_shm_fd, 0); + /* WARNING, smb_shm_header_p can be different for different processes mapping the same file ! */ + if (smb_shm_header_p == (struct SmbShmHeader *)(-1)) + { + DEBUG(0,("ERROR smb_shm_open : mmap failed with code %s\n",strerror(errno))); + smb_shm_unregister_process(smb_shm_processreg_name, getpid()); + smb_shm_global_unlock(); + close(smb_shm_fd); + return NULL; + } + + + if (!read_only && (created_new || !other_processes)) + { + smb_shm_initialize(size); + /* Create the hash buckets for the share file entries. */ + smb_shm_create_hash_table( lp_shmem_hash_size() ); + } + else if (!smb_shm_validate_header(size) ) + { + /* existing file is corrupt, samba admin should remove it by hand */ + DEBUG(0,("ERROR smb_shm_open : corrupt shared mem file, remove it manually\n")); + munmap((caddr_t)smb_shm_header_p, size); + smb_shm_unregister_process(smb_shm_processreg_name, getpid()); + smb_shm_global_unlock(); + close(smb_shm_fd); + return NULL; + } + + smb_shm_global_unlock(); + return &shmops; +} + + #else /* FAST_SHARE_MODES */ int shmem_dummy_procedure(void) {return 0;} diff --git a/source3/locking/shmem_sysv.c b/source3/locking/shmem_sysv.c new file mode 100644 index 0000000000..793e508c71 --- /dev/null +++ b/source3/locking/shmem_sysv.c @@ -0,0 +1,621 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Shared memory functions - SYSV IPC implementation + Copyright (C) Erik Devriendt 1996-1997 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "includes.h" + + +#ifdef USE_SYSV_IPC + +extern int DEBUGLEVEL; + +#define SHMEM_KEY ((key_t)0x280267) +#define SEMAPHORE_KEY (SHMEM_KEY+2) + +#define SHM_MAGIC 0x53484100 +#define SHM_VERSION 2 + +#define IPC_PERMS ((SHM_R | SHM_W) | (SHM_R>>3) | (SHM_R>>6)) + +static int shm_id; +static int sem_id; +static int shm_size; +static int hash_size; +static int global_lock_count; + +struct ShmHeader { + int shm_magic; + int shm_version; + int total_size; /* in bytes */ + BOOL consistent; + int first_free_off; + int userdef_off; /* a userdefined offset. can be used to store + root of tree or list */ + struct { /* a cell is a range of bytes of sizeof(struct + ShmBlockDesc) size */ + int cells_free; + int cells_used; + int cells_system; /* number of cells used as allocated + block descriptors */ + } statistics; +}; + +#define SHM_NOT_FREE_OFF (-1) +struct ShmBlockDesc +{ + int next; /* offset of next block in the free list or + SHM_NOT_FREE_OFF when block in use */ + int size; /* user size in BlockDescSize units */ +}; + +#define EOList_Addr (struct ShmBlockDesc *)( 0 ) +#define EOList_Off (NULL_OFFSET) + +#define CellSize sizeof(struct ShmBlockDesc) + +/* HeaderSize aligned on 8 byte boundary */ +#define AlignedHeaderSize ((sizeof(struct ShmHeader)+7) & ~7) + +static struct ShmHeader *shm_header_p = (struct ShmHeader *)0; + +static BOOL shm_initialize_called = False; + +static int read_only; + +static BOOL sem_lock(int i) +{ + struct sembuf sb; + if (read_only) return True; + + sb.sem_num = i; + sb.sem_op = -1; + sb.sem_flg = SEM_UNDO; + + if (semop(sem_id, &sb, 1) != 0) { + DEBUG(0,("ERROR: IPC lock failed on semaphore %d\n", i)); + return False; + } + + return True; +} + +static BOOL sem_unlock(int i) +{ + struct sembuf sb; + if (read_only) return True; + + sb.sem_num = i; + sb.sem_op = 1; + sb.sem_flg = SEM_UNDO; + + if (semop(sem_id, &sb, 1) != 0) { + DEBUG(0,("ERROR: IPC unlock failed on semaphore %d\n", i)); + return False; + } + + return True; +} + +static BOOL global_lock(void) +{ + global_lock_count++; + if (global_lock_count == 1) + return sem_lock(0); + return True; +} + +static BOOL global_unlock(void) +{ + global_lock_count--; + if (global_lock_count == 0) + return sem_unlock(0); + return True; +} + +static void *shm_offset2addr(int offset) +{ + if (offset == NULL_OFFSET ) + return (void *)(0); + + if (!shm_header_p) + return (void *)(0); + + return (void *)((char *)shm_header_p + offset ); +} + +static int shm_addr2offset(void *addr) +{ + if (!addr) + return NULL_OFFSET; + + if (!shm_header_p) + return NULL_OFFSET; + + return (int)((char *)addr - (char *)shm_header_p); +} + + +static int shm_alloc(int size) +{ + unsigned num_cells ; + struct ShmBlockDesc *scanner_p; + struct ShmBlockDesc *prev_p; + struct ShmBlockDesc *new_p; + int result_offset; + + + if (!shm_header_p) { + /* not mapped yet */ + DEBUG(0,("ERROR shm_alloc : shmem not mapped\n")); + return NULL_OFFSET; + } + + global_lock(); + + if (!shm_header_p->consistent) { + DEBUG(0,("ERROR shm_alloc : shmem not consistent\n")); + global_unlock(); + return NULL_OFFSET; + } + + /* calculate the number of cells */ + num_cells = (size + CellSize -1) / CellSize; + + /* set start of scan */ + prev_p = (struct ShmBlockDesc *)shm_offset2addr(shm_header_p->first_free_off); + scanner_p = prev_p ; + + /* scan the free list to find a matching free space */ + while ((scanner_p != EOList_Addr) && (scanner_p->size < num_cells)) { + prev_p = scanner_p; + scanner_p = (struct ShmBlockDesc *)shm_offset2addr(scanner_p->next); + } + + /* at this point scanner point to a block header or to the end of + the list */ + if (scanner_p == EOList_Addr) { + DEBUG(0,("ERROR shm_alloc : alloc of %d bytes failed, no free space found\n",size)); + global_unlock(); + return (NULL_OFFSET); + } + + /* going to modify shared mem */ + shm_header_p->consistent = False; + + /* if we found a good one : scanner == the good one */ + if (scanner_p->size <= num_cells + 2) { + /* there is no use in making a new one, it will be too small anyway + * we will link out scanner + */ + if ( prev_p == scanner_p ) { + shm_header_p->first_free_off = scanner_p->next ; + } else { + prev_p->next = scanner_p->next ; + } + shm_header_p->statistics.cells_free -= scanner_p->size; + shm_header_p->statistics.cells_used += scanner_p->size; + } else { + /* Make a new one */ + new_p = scanner_p + 1 + num_cells; + new_p->size = scanner_p->size - num_cells - 1; + new_p->next = scanner_p->next; + scanner_p->size = num_cells; + scanner_p->next = shm_addr2offset(new_p); + + if (prev_p != scanner_p) { + prev_p->next = shm_addr2offset(new_p) ; + } else { + shm_header_p->first_free_off = shm_addr2offset(new_p); + } + shm_header_p->statistics.cells_free -= num_cells+1; + shm_header_p->statistics.cells_used += num_cells; + shm_header_p->statistics.cells_system += 1; + } + + result_offset = shm_addr2offset( &(scanner_p[1]) ); + scanner_p->next = SHM_NOT_FREE_OFF ; + + /* end modification of shared mem */ + shm_header_p->consistent = True; + + DEBUG(6,("shm_alloc : request for %d bytes, allocated %d bytes at offset %d\n",size,scanner_p->size*CellSize,result_offset )); + + global_unlock(); + return result_offset; +} + + + +/* + * Function to create the hash table for the share mode entries. Called + * when smb shared memory is global locked. + */ +static BOOL shm_create_hash_table( unsigned int size ) +{ + size *= sizeof(int); + + global_lock(); + shm_header_p->userdef_off = shm_alloc( size ); + + if(shm_header_p->userdef_off == NULL_OFFSET) { + DEBUG(0,("shm_create_hash_table: Failed to create hash table of size %d\n",size)); + global_unlock(); + return False; + } + + /* Clear hash buckets. */ + memset( shm_offset2addr(shm_header_p->userdef_off), '\0', size); + global_unlock(); + return True; +} + +static BOOL shm_validate_header(int size) +{ + if( !shm_header_p ) { + /* not mapped yet */ + DEBUG(0,("ERROR shm_validate_header : shmem not mapped\n")); + return False; + } + + if(shm_header_p->shm_magic != SHM_MAGIC) { + DEBUG(0,("ERROR shm_validate_header : bad magic\n")); + return False; + } + + if(shm_header_p->shm_version != SHM_VERSION) { + DEBUG(0,("ERROR shm_validate_header : bad version %X\n",shm_header_p->shm_version)); + return False; + } + + if(shm_header_p->total_size != size) { + DEBUG(0,("ERROR shm_validate_header : shmem size mismatch (old = %d, new = %d)\n",shm_header_p->total_size,size)); + return False; + } + + if(!shm_header_p->consistent) { + DEBUG(0,("ERROR shm_validate_header : shmem not consistent\n")); + return False; + } + return True; +} + +static BOOL shm_initialize(int size) +{ + struct ShmBlockDesc * first_free_block_p; + + DEBUG(5,("shm_initialize : initializing shmem file of size %d\n",size)); + + if( !shm_header_p ) { + /* not mapped yet */ + DEBUG(0,("ERROR shm_initialize : shmem not mapped\n")); + return False; + } + + shm_header_p->shm_magic = SHM_MAGIC; + shm_header_p->shm_version = SHM_VERSION; + shm_header_p->total_size = size; + shm_header_p->first_free_off = AlignedHeaderSize; + shm_header_p->userdef_off = NULL_OFFSET; + + first_free_block_p = (struct ShmBlockDesc *)shm_offset2addr(shm_header_p->first_free_off); + first_free_block_p->next = EOList_Off; + first_free_block_p->size = ( size - AlignedHeaderSize - CellSize ) / CellSize ; + + shm_header_p->statistics.cells_free = first_free_block_p->size; + shm_header_p->statistics.cells_used = 0; + shm_header_p->statistics.cells_system = 1; + + shm_header_p->consistent = True; + + shm_initialize_called = True; + + return True; +} + +static void shm_solve_neighbors(struct ShmBlockDesc *head_p ) +{ + struct ShmBlockDesc *next_p; + + /* Check if head_p and head_p->next are neighbors and if so + join them */ + if ( head_p == EOList_Addr ) return ; + if ( head_p->next == EOList_Off ) return ; + + next_p = (struct ShmBlockDesc *)shm_offset2addr(head_p->next); + if ( ( head_p + head_p->size + 1 ) == next_p) { + head_p->size += next_p->size +1 ; /* adapt size */ + head_p->next = next_p->next ; /* link out */ + + shm_header_p->statistics.cells_free += 1; + shm_header_p->statistics.cells_system -= 1; + } +} + + + + +static BOOL shm_close( void ) +{ + return True; +} + + +static BOOL shm_free(int offset) +{ + struct ShmBlockDesc *header_p; /* pointer to header of + block to free */ + struct ShmBlockDesc *scanner_p; /* used to scan the list */ + struct ShmBlockDesc *prev_p; /* holds previous in the + list */ + + if (!shm_header_p) { + /* not mapped yet */ + DEBUG(0,("ERROR shm_free : shmem not mapped\n")); + return False; + } + + global_lock(); + + if (!shm_header_p->consistent) { + DEBUG(0,("ERROR shm_free : shmem not consistent\n")); + global_unlock(); + return False; + } + + /* make pointer to header of block */ + header_p = ((struct ShmBlockDesc *)shm_offset2addr(offset) - 1); + + if (header_p->next != SHM_NOT_FREE_OFF) { + DEBUG(0,("ERROR shm_free : bad offset (%d)\n",offset)); + global_unlock(); + return False; + } + + /* find a place in the free_list to put the header in */ + + /* set scanner and previous pointer to start of list */ + prev_p = (struct ShmBlockDesc *)shm_offset2addr(shm_header_p->first_free_off); + scanner_p = prev_p ; + + while ((scanner_p != EOList_Addr) && + (scanner_p < header_p)) { + /* while we didn't scan past its position */ + prev_p = scanner_p ; + scanner_p = (struct ShmBlockDesc *)shm_offset2addr(scanner_p->next); + } + + shm_header_p->consistent = False; + + DEBUG(6,("shm_free : freeing %d bytes at offset %d\n", + header_p->size*CellSize,offset)); + + if (scanner_p == prev_p) { + shm_header_p->statistics.cells_free += header_p->size; + shm_header_p->statistics.cells_used -= header_p->size; + + /* we must free it at the beginning of the list */ + shm_header_p->first_free_off = shm_addr2offset(header_p); /* set the free_list_pointer to this block_header */ + + /* scanner is the one that was first in the list */ + header_p->next = shm_addr2offset(scanner_p); + shm_solve_neighbors( header_p ); /* if neighbors then link them */ + + shm_header_p->consistent = True; + } else { + shm_header_p->statistics.cells_free += header_p->size; + shm_header_p->statistics.cells_used -= header_p->size; + + prev_p->next = shm_addr2offset(header_p); + header_p->next = shm_addr2offset(scanner_p); + shm_solve_neighbors(header_p) ; + shm_solve_neighbors(prev_p) ; + + shm_header_p->consistent = True; + } + + global_unlock(); + return True; +} + + +static int shm_get_userdef_off(void) +{ + if (!shm_header_p) + return NULL_OFFSET; + else + return shm_header_p->userdef_off; +} + +/******************************************************************* + Lock a particular hash bucket entry. + ******************************************************************/ +static BOOL shm_lock_hash_entry(unsigned int entry) +{ + DEBUG(0,("hash lock %d\n", entry)); + return sem_lock(entry+1); +} + +/******************************************************************* + Unlock a particular hash bucket entry. + ******************************************************************/ +static BOOL shm_unlock_hash_entry(unsigned int entry) +{ + DEBUG(0,("hash unlock %d\n", entry)); + return sem_unlock(entry+1); +} + + +/******************************************************************* + Gather statistics on shared memory usage. + ******************************************************************/ +static BOOL shm_get_usage(int *bytes_free, + int *bytes_used, + int *bytes_overhead) +{ + if(!shm_header_p) { + /* not mapped yet */ + DEBUG(0,("ERROR shm_free : shmem not mapped\n")); + return False; + } + + *bytes_free = shm_header_p->statistics.cells_free * CellSize; + *bytes_used = shm_header_p->statistics.cells_used * CellSize; + *bytes_overhead = shm_header_p->statistics.cells_system * CellSize + AlignedHeaderSize; + + return True; +} + +static struct shmem_ops shmops = { + shm_close, + shm_alloc, + shm_free, + shm_get_userdef_off, + shm_offset2addr, + shm_addr2offset, + shm_lock_hash_entry, + shm_unlock_hash_entry, + shm_get_usage, +}; + +/******************************************************************* + open the shared memory + ******************************************************************/ +struct shmem_ops *sysv_shm_open(int size, int ronly) +{ + BOOL created_new = False; + BOOL other_processes; + struct shmid_ds shm_ds; + struct semid_ds sem_ds; + union semun su; + int i; + + read_only = ronly; + + shm_size = size; + + DEBUG(4,("Trying sysv shmem open of size %d\n", size)); + + /* first the semaphore */ + sem_id = semget(SEMAPHORE_KEY, 0, 0); + if (sem_id == -1) { + if (read_only) return NULL; + + sem_id = semget(SEMAPHORE_KEY, lp_shmem_hash_size()+1, + IPC_CREAT | IPC_EXCL | IPC_PERMS); + + if (sem_id == -1) { + DEBUG(0,("Can't create or use semaphore %s\n", + strerror(errno))); + } + + if (sem_id != -1) { + su.val = 1; + for (i=0;i<lp_shmem_hash_size()+1;i++) { + if (semctl(sem_id, i, SETVAL, su) != 0) { + DEBUG(1,("Failed to init semaphore %d\n", i)); + } + } + } + } + if (shm_id == -1) { + sem_id = semget(SEMAPHORE_KEY, 0, 0); + } + if (sem_id == -1) { + DEBUG(0,("Can't create or use semaphore %s\n", + strerror(errno))); + return NULL; + } + + su.buf = &sem_ds; + if (semctl(sem_id, 0, IPC_STAT, su) != 0) { + DEBUG(0,("ERROR shm_open : can't IPC_STAT\n")); + } + hash_size = sem_ds.sem_nsems; + if (hash_size != lp_shmem_hash_size()+1) { + DEBUG(0,("WARNING: nsems=%d\n", hash_size)); + } + + if (!global_lock()) + return NULL; + + /* try to use an existing key */ + shm_id = shmget(SHMEM_KEY, shm_size, 0); + + /* if that failed then create one */ + if (shm_id == -1) { + if (read_only) return NULL; + shm_id = shmget(SHMEM_KEY, shm_size, IPC_CREAT | IPC_EXCL); + created_new = (shm_id != -1); + } + + if (shm_id == -1) { + DEBUG(0,("Can't create or use IPC area\n")); + global_unlock(); + return NULL; + } + + + shm_header_p = (struct ShmHeader *)shmat(shm_id, 0, + read_only?SHM_RDONLY:0); + if ((int)shm_header_p == -1) { + DEBUG(0,("Can't attach to IPC area\n")); + global_unlock(); + return NULL; + } + + /* to find out if some other process is already mapping the file, + we use a registration file containing the processids of the file + mapping processes */ + if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) { + DEBUG(0,("ERROR shm_open : can't IPC_STAT\n")); + } + + /* set the permissions */ + if (!read_only) { + shm_ds.shm_perm.mode = IPC_PERMS; + shmctl(shm_id, IPC_SET, &shm_ds); + } + + other_processes = (shm_ds.shm_nattch > 1); + + if (!read_only && !other_processes) { + memset((char *)shm_header_p, 0, shm_size); + shm_initialize(shm_size); + shm_create_hash_table(lp_shmem_hash_size()); + DEBUG(1,("Initialised IPC area of size %d\n", shm_size)); + } else if (!shm_validate_header(shm_size)) { + /* existing file is corrupt, samba admin should remove + it by hand */ + DEBUG(0,("ERROR shm_open : corrupt IPC area - remove it!\n")); + global_unlock(); + return NULL; + } + + global_unlock(); + return &shmops; +} + + + +#else + int ipc_dummy_procedure(void) +{return 0;} +#endif |