home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Wtestowe / Clico / UNIX / SAMBA / SOURCE / SAMBA.TAR / samba-1.9.17 / source / shmem.c < prev    next >
C/C++ Source or Header  |  1997-07-24  |  25KB  |  845 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    Shared memory functions
  5.    Copyright (C) Erik Devriendt 1996-1997
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21. */
  22.  
  23. #include "includes.h"
  24.  
  25.  
  26. #ifdef FAST_SHARE_MODES
  27.  
  28.  
  29. extern int DEBUGLEVEL;
  30.  
  31.  
  32. #define SMB_SHM_MAGIC 0x53484100
  33. /* = "SHM" in hex */
  34.  
  35. #define SMB_SHM_VERSION 2
  36.  
  37. /* WARNING : offsets are used because mmap() does not guarantee that all processes have the 
  38.    shared memory mapped to the same address */
  39.  
  40. struct SmbShmHeader
  41. {
  42.    int smb_shm_magic;
  43.    int smb_shm_version;
  44.    int total_size;    /* in bytes */
  45.    BOOL consistent;
  46.    smb_shm_offset_t first_free_off;
  47.    smb_shm_offset_t userdef_off;    /* a userdefined offset. can be used to store root of tree or list */
  48.    struct {        /* a cell is a range of bytes of sizeof(struct SmbShmBlockDesc) size */
  49.       int cells_free;
  50.       int cells_used;
  51.       int cells_system; /* number of cells used as allocated block descriptors */
  52.    } statistics;
  53. };
  54.  
  55. #define SMB_SHM_NOT_FREE_OFF (-1)
  56. struct SmbShmBlockDesc
  57. {
  58.    smb_shm_offset_t next;    /* offset of next block in the free list or SMB_SHM_NOT_FREE_OFF when block in use  */
  59.    int          size;   /* user size in BlockDescSize units */
  60. };
  61.  
  62. #define    EOList_Addr    (struct SmbShmBlockDesc *)( 0 )
  63. #define EOList_Off      (NULL_OFFSET)
  64.  
  65. #define    CellSize    sizeof(struct SmbShmBlockDesc)
  66.  
  67. /* HeaderSize aligned on 8 byte boundary */
  68. #define    AlignedHeaderSize      ((sizeof(struct SmbShmHeader)+7) & ~7)
  69.  
  70. static int  smb_shm_fd = -1;
  71. static pstring smb_shm_processreg_name = "";
  72.  
  73. static struct SmbShmHeader *smb_shm_header_p = (struct SmbShmHeader *)0;
  74. static int smb_shm_times_locked = 0;
  75.  
  76. static BOOL smb_shm_initialize_called = False;
  77.  
  78. static BOOL smb_shm_global_lock(void)
  79. {
  80.    if (smb_shm_fd < 0)
  81.    {
  82.       DEBUG(0,("ERROR smb_shm_global_lock : bad smb_shm_fd (%d)\n",smb_shm_fd));
  83.       return False;
  84.    }
  85.    
  86.    smb_shm_times_locked++;
  87.    
  88.    if(smb_shm_times_locked > 1)
  89.    {
  90.       DEBUG(5,("smb_shm_global_lock : locked %d times\n",smb_shm_times_locked));
  91.       return True;
  92.    }
  93.    
  94.    /* Do an exclusive wait lock on the first byte of the file */
  95.    if (fcntl_lock(smb_shm_fd, F_SETLKW, 0, 1, F_WRLCK) == False)
  96.    {
  97.       DEBUG(0,("ERROR smb_shm_global_lock : fcntl_lock failed with code %d\n",errno));
  98.       smb_shm_times_locked--;
  99.       return False;
  100.    }
  101.    
  102.    return True;
  103.    
  104. }
  105.  
  106. static BOOL smb_shm_global_unlock(void)
  107. {
  108.    if (smb_shm_fd < 0)
  109.    {
  110.       DEBUG(0,("ERROR smb_shm_global_unlock : bad smb_shm_fd (%d)\n",smb_shm_fd));
  111.       return False;
  112.    }
  113.    
  114.    if(smb_shm_times_locked == 0)
  115.    {
  116.       DEBUG(0,("ERROR smb_shm_global_unlock : shmem not locked\n",smb_shm_fd));
  117.       return False;
  118.    }
  119.    
  120.    smb_shm_times_locked--;
  121.    
  122.    if(smb_shm_times_locked > 0)
  123.    {
  124.       DEBUG(5,("smb_shm_global_unlock : still locked %d times\n",smb_shm_times_locked));
  125.       return True;
  126.    }
  127.    
  128.    /* Do a wait unlock on the first byte of the file */
  129.    if (fcntl_lock(smb_shm_fd, F_SETLKW, 0, 1, F_UNLCK) == False)
  130.    {
  131.       DEBUG(0,("ERROR smb_shm_global_unlock : fcntl_lock failed with code %d\n",errno));
  132.       smb_shm_times_locked++;
  133.       return False;
  134.    }
  135.    
  136.    return True;
  137.    
  138. }
  139.  
  140. /* 
  141.  * Function to create the hash table for the share mode entries. Called
  142.  * when smb shared memory is global locked.
  143.  */
  144.  
  145. BOOL smb_shm_create_hash_table( unsigned int size )
  146. {
  147.   size *= sizeof(smb_shm_offset_t);
  148.  
  149.   smb_shm_global_lock();
  150.   smb_shm_header_p->userdef_off = smb_shm_alloc( size );
  151.  
  152.   if(smb_shm_header_p->userdef_off == NULL_OFFSET)
  153.     {
  154.       DEBUG(0,("smb_shm_create_hash_table: Failed to create hash table of size %d\n",size));
  155.       smb_shm_global_unlock();
  156.       return False;
  157.     }
  158.  
  159.   /* Clear hash buckets. */
  160.   memset( smb_shm_offset2addr(smb_shm_header_p->userdef_off), '\0', size);
  161.   smb_shm_global_unlock();
  162.   return True;
  163. }
  164.  
  165. static BOOL smb_shm_register_process(char *processreg_file, pid_t pid, BOOL *other_processes)
  166. {
  167.    int smb_shm_processes_fd = -1;
  168.    int nb_read;
  169.    pid_t other_pid;
  170.    int seek_back = -((int)sizeof(other_pid));
  171.    int free_slot = -1;
  172.    int erased_slot;   
  173.    
  174. #ifndef SECURE_SHARE_MODES
  175.    smb_shm_processes_fd = open(processreg_file, O_RDWR | O_CREAT, 0666);
  176. #else /* SECURE_SHARE_MODES */
  177.    smb_shm_processes_fd = open(processreg_file, O_RDWR | O_CREAT, 0600);
  178. #endif /* SECURE_SHARE_MODES */
  179.    if ( smb_shm_processes_fd < 0 )
  180.    {
  181.       DEBUG(0,("ERROR smb_shm_register_process : processreg_file open failed with code %d\n",errno));
  182.       return False;
  183.    }
  184.    
  185.    *other_processes = False;
  186.    
  187.    while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
  188.    {
  189.       if(other_pid)
  190.       {
  191.      if(process_exists(other_pid))
  192.         *other_processes = True;
  193.      else
  194.      {
  195.         /* erase old pid */
  196.             DEBUG(5,("smb_shm_register_process : erasing stale record for pid %d (seek_back = %d)\n",
  197.                       other_pid, seek_back));
  198.         other_pid = (pid_t)0;
  199.         erased_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
  200.         write(smb_shm_processes_fd, &other_pid, sizeof(other_pid));
  201.         if(free_slot < 0)
  202.            free_slot = erased_slot;
  203.      }
  204.       }
  205.       else 
  206.      if(free_slot < 0)
  207.         free_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
  208.    }
  209.    if (nb_read < 0)
  210.    {
  211.       DEBUG(0,("ERROR smb_shm_register_process : processreg_file read failed with code %d\n",errno));
  212.       close(smb_shm_processes_fd);
  213.       return False;
  214.    }
  215.    
  216.    if(free_slot < 0)
  217.       free_slot = lseek(smb_shm_processes_fd, 0, SEEK_END);
  218.  
  219.    DEBUG(5,("smb_shm_register_process : writing record for pid %d at offset %d\n",pid,free_slot));
  220.    lseek(smb_shm_processes_fd, free_slot, SEEK_SET);
  221.    if(write(smb_shm_processes_fd, &pid, sizeof(pid)) < 0)
  222.    {
  223.       DEBUG(0,("ERROR smb_shm_register_process : processreg_file write failed with code %d\n",errno));
  224.       close(smb_shm_processes_fd);
  225.       return False;
  226.    }
  227.  
  228.    close(smb_shm_processes_fd);
  229.  
  230.    return True;
  231. }
  232.  
  233. static BOOL smb_shm_unregister_process(char *processreg_file, pid_t pid)
  234. {
  235.    int old_umask;
  236.    int smb_shm_processes_fd = -1;
  237.    int nb_read;
  238.    pid_t other_pid;
  239.    int seek_back = -((int)sizeof(other_pid));
  240.    int erased_slot;
  241.    BOOL found = False;
  242.    
  243.    
  244.    old_umask = umask(0);
  245.    smb_shm_processes_fd = open(processreg_file, O_RDWR);
  246.    umask(old_umask);
  247.    if ( smb_shm_processes_fd < 0 )
  248.    {
  249.       DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file open failed with code %d\n",errno));
  250.       return False;
  251.    }
  252.    
  253.    while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
  254.    {
  255.       DEBUG(5,("smb_shm_unregister_process : read record for pid %d\n",other_pid));
  256.       if(other_pid == pid)
  257.       {
  258.      /* erase pid */
  259.          DEBUG(5,("smb_shm_unregister_process : erasing record for pid %d (seek_val = %d)\n",
  260.                      other_pid, seek_back));
  261.      other_pid = (pid_t)0;
  262.      erased_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
  263.      if(write(smb_shm_processes_fd, &other_pid, sizeof(other_pid)) < 0)
  264.      {
  265.         DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file write failed with code %d\n",errno));
  266.         close(smb_shm_processes_fd);
  267.         return False;
  268.      }
  269.      
  270.      found = True;
  271.      break;
  272.       }
  273.    }
  274.    if (nb_read < 0)
  275.    {
  276.       DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file read failed with code %d\n",errno));
  277.       close(smb_shm_processes_fd);
  278.       return False;
  279.    }
  280.    
  281.    if(!found)
  282.    {
  283.       DEBUG(0,("ERROR smb_shm_unregister_process : couldn't find pid %d in file %s\n",pid,processreg_file));
  284.       close(smb_shm_processes_fd);
  285.       return False;
  286.    }
  287.       
  288.    
  289.    close(smb_shm_processes_fd);
  290.  
  291.    return True;
  292. }
  293.  
  294.  
  295. static BOOL smb_shm_validate_header(int size)
  296. {
  297.    if( !smb_shm_header_p )
  298.    {
  299.       /* not mapped yet */
  300.       DEBUG(0,("ERROR smb_shm_validate_header : shmem not mapped\n"));
  301.       return False;
  302.    }
  303.    
  304.    if(smb_shm_header_p->smb_shm_magic != SMB_SHM_MAGIC)
  305.    {
  306.       DEBUG(0,("ERROR smb_shm_validate_header : bad magic\n"));
  307.       return False;
  308.    }
  309.    if(smb_shm_header_p->smb_shm_version != SMB_SHM_VERSION)
  310.    {
  311.       DEBUG(0,("ERROR smb_shm_validate_header : bad version %X\n",smb_shm_header_p->smb_shm_version));
  312.       return False;
  313.    }
  314.    
  315.    if(smb_shm_header_p->total_size != size)
  316.    {
  317.       DEBUG(0,("ERROR smb_shm_validate_header : shmem size mismatch (old = %d, new = %d)\n",smb_shm_header_p->total_size,size));
  318.       return False;
  319.    }
  320.  
  321.    if(!smb_shm_header_p->consistent)
  322.    {
  323.       DEBUG(0,("ERROR smb_shm_validate_header : shmem not consistent\n"));
  324.       return False;
  325.    }
  326.    return True;
  327. }
  328.  
  329. static BOOL smb_shm_initialize(int size)
  330. {
  331.    struct SmbShmBlockDesc * first_free_block_p;
  332.    
  333.    DEBUG(5,("smb_shm_initialize : initializing shmem file of size %d\n",size));
  334.    
  335.    if( !smb_shm_header_p )
  336.    {
  337.       /* not mapped yet */
  338.       DEBUG(0,("ERROR smb_shm_initialize : shmem not mapped\n"));
  339.       return False;
  340.    }
  341.    
  342.    smb_shm_header_p->smb_shm_magic = SMB_SHM_MAGIC;
  343.    smb_shm_header_p->smb_shm_version = SMB_SHM_VERSION;
  344.    smb_shm_header_p->total_size = size;
  345.    smb_shm_header_p->first_free_off = AlignedHeaderSize;
  346.    smb_shm_header_p->userdef_off = NULL_OFFSET;
  347.    
  348.    first_free_block_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
  349.    first_free_block_p->next = EOList_Off;
  350.    first_free_block_p->size = ( size - AlignedHeaderSize - CellSize ) / CellSize ;
  351.    
  352.    smb_shm_header_p->statistics.cells_free = first_free_block_p->size;
  353.    smb_shm_header_p->statistics.cells_used = 0;
  354.    smb_shm_header_p->statistics.cells_system = 1;
  355.    
  356.    smb_shm_header_p->consistent = True;
  357.    
  358.    smb_shm_initialize_called = True;
  359.  
  360.    return True;
  361. }
  362.    
  363. static void smb_shm_solve_neighbors(struct SmbShmBlockDesc *head_p )
  364. {
  365.    struct SmbShmBlockDesc *next_p;
  366.    
  367.    /* Check if head_p and head_p->next are neighbors and if so join them */
  368.    if ( head_p == EOList_Addr ) return ;
  369.    if ( head_p->next == EOList_Off ) return ;
  370.    
  371.    next_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(head_p->next);
  372.    if ( ( head_p + head_p->size + 1 ) == next_p)
  373.    {
  374.       head_p->size += next_p->size +1 ;    /* adapt size */
  375.       head_p->next = next_p->next      ; /* link out */
  376.       
  377.       smb_shm_header_p->statistics.cells_free += 1;
  378.       smb_shm_header_p->statistics.cells_system -= 1;
  379.    }
  380. }
  381.  
  382.  
  383.  
  384. BOOL smb_shm_open( char *file_name, int size)
  385. {
  386.    int filesize;
  387.    BOOL created_new = False;
  388.    BOOL other_processes = True;
  389.    int old_umask;
  390.    
  391.    DEBUG(5,("smb_shm_open : using shmem file %s to be of size %d\n",file_name,size));
  392.  
  393.    old_umask = umask(0);
  394. #ifndef SECURE_SHARE_MODES
  395.    smb_shm_fd = open(file_name, O_RDWR | O_CREAT, 0666);
  396. #else /* SECURE_SHARE_MODES */
  397.    smb_shm_fd = open(file_name, O_RDWR | O_CREAT, 0600);
  398. #endif /* SECURE_SHARE_MODE */
  399.    umask(old_umask);
  400.    if ( smb_shm_fd < 0 )
  401.    {
  402.       DEBUG(0,("ERROR smb_shm_open : open failed with code %d\n",errno));
  403.       return False;
  404.    }
  405.    
  406.    if (!smb_shm_global_lock())
  407.    {
  408.       DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_global_lock\n"));
  409.       return False;
  410.    }
  411.    
  412.    if( (filesize = lseek(smb_shm_fd, 0, SEEK_END)) < 0)
  413.    {
  414.       DEBUG(0,("ERROR smb_shm_open : lseek failed with code %d\n",errno));
  415.       smb_shm_global_unlock();
  416.       close(smb_shm_fd);
  417.       return False;
  418.    }
  419.  
  420.    /* return the file offset to 0 to save on later seeks */
  421.    lseek(smb_shm_fd,0,SEEK_SET);
  422.  
  423.    if (filesize == 0)
  424.    {
  425.       /* we just created a new one */
  426.       created_new = True;
  427.    }
  428.    
  429.    /* to find out if some other process is already mapping the file,
  430.       we use a registration file containing the processids of the file mapping processes
  431.       */
  432.  
  433.    /* construct processreg file name */
  434.    strcpy(smb_shm_processreg_name, file_name);
  435.    strcat(smb_shm_processreg_name, ".processes");
  436.  
  437.    if (! smb_shm_register_process(smb_shm_processreg_name, getpid(), &other_processes))
  438.    {
  439.       smb_shm_global_unlock();
  440.       close(smb_shm_fd);
  441.       return False;
  442.    }
  443.  
  444.    if (created_new || !other_processes)
  445.    {
  446.       /* we just created a new one, or are the first opener, lets set it size */
  447.       if( ftruncate(smb_shm_fd, size) <0)
  448.       {
  449.          DEBUG(0,("ERROR smb_shm_open : ftruncate failed with code %d\n",errno));
  450.      smb_shm_unregister_process(smb_shm_processreg_name, getpid());
  451.      smb_shm_global_unlock();
  452.      close(smb_shm_fd);
  453.      return False;
  454.       }
  455.  
  456.       /* paranoia */
  457.       lseek(smb_shm_fd,0,SEEK_SET);
  458.  
  459.       filesize = size;
  460.    }
  461.    
  462.    if (size != filesize )
  463.    {
  464.       /* the existing file has a different size and we are not the first opener.
  465.      Since another process is still using it, we will use the file size */
  466.       DEBUG(0,("WARNING smb_shm_open : filesize (%d) != expected size (%d), using filesize\n",filesize,size));
  467.       size = filesize;
  468.    }
  469.    
  470.    smb_shm_header_p = (struct SmbShmHeader *)mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, smb_shm_fd, 0);
  471.    /* WARNING, smb_shm_header_p can be different for different processes mapping the same file ! */
  472.    if (smb_shm_header_p  == (struct SmbShmHeader *)(-1))
  473.    {
  474.       DEBUG(0,("ERROR smb_shm_open : mmap failed with code %d\n",errno));
  475.       smb_shm_unregister_process(smb_shm_processreg_name, getpid());
  476.       smb_shm_global_unlock();
  477.       close(smb_shm_fd);
  478.       return False;
  479.    }      
  480.    
  481.       
  482.    if (created_new || !other_processes)
  483.    {
  484.       smb_shm_initialize(size);
  485.       /* Create the hash buckets for the share file entries. */
  486.       smb_shm_create_hash_table( lp_shmem_hash_size() );
  487.    }
  488.    else if (!smb_shm_validate_header(size) )
  489.    {
  490.       /* existing file is corrupt, samba admin should remove it by hand */
  491.       DEBUG(0,("ERROR smb_shm_open : corrupt shared mem file, remove it manually\n"));
  492.       munmap((caddr_t)smb_shm_header_p, size);
  493.       smb_shm_unregister_process(smb_shm_processreg_name, getpid());
  494.       smb_shm_global_unlock();
  495.       close(smb_shm_fd);
  496.       return False;
  497.    }
  498.    
  499.    smb_shm_global_unlock();
  500.    return True;
  501.       
  502. }
  503.  
  504.  
  505. BOOL smb_shm_close( void )
  506. {
  507.    
  508.    if(smb_shm_initialize_called == False)
  509.      return True;
  510.  
  511.    DEBUG(5,("smb_shm_close\n"));
  512.    if(smb_shm_times_locked > 0)
  513.       DEBUG(0,("WARNING smb_shm_close : shmem was still locked %d times\n",smb_shm_times_locked));;
  514.    if ((smb_shm_header_p != NULL) && 
  515.               (munmap((caddr_t)smb_shm_header_p, smb_shm_header_p->total_size) < 0))
  516.    {
  517.       DEBUG(0,("ERROR smb_shm_close : munmap failed with code %d\n",errno));
  518.    }
  519.  
  520.    smb_shm_global_lock();
  521.    DEBUG(5,("calling smb_shm_unregister_process(%s, %d)\n", smb_shm_processreg_name, getpid()));
  522.    smb_shm_unregister_process(smb_shm_processreg_name, getpid());
  523.    smb_shm_global_unlock();
  524.    
  525.    close(smb_shm_fd);
  526.    
  527.    smb_shm_fd = -1;
  528.    smb_shm_processreg_name[0] = '\0';
  529.  
  530.    smb_shm_header_p = (struct SmbShmHeader *)0;
  531.    smb_shm_times_locked = 0;
  532.    
  533.    return True;
  534. }
  535.  
  536. smb_shm_offset_t smb_shm_alloc(int size)
  537. {
  538.    unsigned num_cells ;
  539.    struct SmbShmBlockDesc *scanner_p;
  540.    struct SmbShmBlockDesc *prev_p;
  541.    struct SmbShmBlockDesc *new_p;
  542.    smb_shm_offset_t result_offset;
  543.    
  544.    
  545.    if( !smb_shm_header_p )
  546.    {
  547.       /* not mapped yet */
  548.       DEBUG(0,("ERROR smb_shm_alloc : shmem not mapped\n"));
  549.       return NULL_OFFSET;
  550.    }
  551.    
  552.    smb_shm_global_lock();
  553.  
  554.    if( !smb_shm_header_p->consistent)
  555.    {
  556.       DEBUG(0,("ERROR smb_shm_alloc : shmem not consistent\n"));
  557.       smb_shm_global_unlock();
  558.       return NULL_OFFSET;
  559.    }
  560.    
  561.    
  562.    /* calculate    the number of cells */
  563.    num_cells = (size + CellSize -1) / CellSize;
  564.  
  565.    /* set start    of scan */
  566.    prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
  567.    scanner_p =    prev_p ;
  568.    
  569.    /* scan the free list to find a matching free space */
  570.    while ( ( scanner_p != EOList_Addr ) && ( scanner_p->size < num_cells ) )
  571.    {
  572.       prev_p = scanner_p;
  573.       scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next);
  574.    }
  575.    
  576.    /* at this point scanner point to a block header or to the end of the list */
  577.    if ( scanner_p == EOList_Addr )    
  578.    {
  579.       DEBUG(0,("ERROR smb_shm_alloc : alloc of %d bytes failed, no free space found\n",size));
  580.       smb_shm_global_unlock();
  581.       return (NULL_OFFSET);
  582.    }
  583.    
  584.    /* going to modify shared mem */
  585.    smb_shm_header_p->consistent = False;
  586.    
  587.    /* if we found a good one : scanner == the good one */
  588.    if ( scanner_p->size <= num_cells + 2 )
  589.    {
  590.       /* there is no use in making a new one, it will be too small anyway 
  591.       *     we will link out scanner
  592.       */
  593.       if ( prev_p == scanner_p )
  594.       {
  595.      smb_shm_header_p->first_free_off = scanner_p->next ;
  596.       }
  597.       else
  598.       {
  599.      prev_p->next = scanner_p->next ;
  600.       }
  601.       smb_shm_header_p->statistics.cells_free -= scanner_p->size;
  602.       smb_shm_header_p->statistics.cells_used += scanner_p->size;
  603.    }
  604.    else
  605.    {
  606.       /* Make a new one */
  607.       new_p = scanner_p + 1 + num_cells;
  608.       new_p->size = scanner_p->size - num_cells - 1;
  609.       new_p->next = scanner_p->next;
  610.       scanner_p->size = num_cells;
  611.       scanner_p->next = smb_shm_addr2offset(new_p);
  612.       
  613.       if ( prev_p    != scanner_p )
  614.       {
  615.      prev_p->next       = smb_shm_addr2offset(new_p)  ;
  616.       }
  617.       else
  618.       {
  619.      smb_shm_header_p->first_free_off = smb_shm_addr2offset(new_p)  ;
  620.       }
  621.       smb_shm_header_p->statistics.cells_free -= num_cells+1;
  622.       smb_shm_header_p->statistics.cells_used += num_cells;
  623.       smb_shm_header_p->statistics.cells_system += 1;
  624.    }
  625.  
  626.    result_offset = smb_shm_addr2offset( &(scanner_p[1]) );
  627.    scanner_p->next =    SMB_SHM_NOT_FREE_OFF ;
  628.  
  629.    /* end modification of shared mem */
  630.    smb_shm_header_p->consistent = True;
  631.  
  632.    DEBUG(6,("smb_shm_alloc : request for %d bytes, allocated %d bytes at offset %d\n",size,scanner_p->size*CellSize,result_offset ));
  633.  
  634.    smb_shm_global_unlock();
  635.    return ( result_offset );
  636. }   
  637.  
  638.  
  639.  
  640. BOOL smb_shm_free(smb_shm_offset_t offset)
  641. {
  642.    struct SmbShmBlockDesc *header_p  ; /*    pointer    to header of block to free */
  643.    struct SmbShmBlockDesc *scanner_p ; /*    used to    scan the list               */
  644.    struct SmbShmBlockDesc *prev_p       ; /*    holds previous in the list           */
  645.    
  646.    if( !smb_shm_header_p )
  647.    {
  648.       /* not mapped yet */
  649.       DEBUG(0,("ERROR smb_shm_free : shmem not mapped\n"));
  650.       return False;
  651.    }
  652.    
  653.    smb_shm_global_lock();
  654.  
  655.    if( !smb_shm_header_p->consistent)
  656.    {
  657.       DEBUG(0,("ERROR smb_shm_free : shmem not consistent\n"));
  658.       smb_shm_global_unlock();
  659.       return False;
  660.    }
  661.    
  662.    header_p = (    (struct SmbShmBlockDesc *)smb_shm_offset2addr(offset) - 1); /* make pointer to header of block */
  663.  
  664.    if (header_p->next != SMB_SHM_NOT_FREE_OFF)
  665.    {
  666.       DEBUG(0,("ERROR smb_shm_free : bad offset (%d)\n",offset));
  667.       smb_shm_global_unlock();
  668.       return False;
  669.    }
  670.    
  671.    /* find a place in the free_list to put the header in */
  672.    
  673.    /* set scanner and previous pointer to start of list */
  674.    prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
  675.    scanner_p = prev_p ;
  676.    
  677.    while ( ( scanner_p != EOList_Addr) && (scanner_p < header_p) ) /* while we didn't scan past its position */
  678.    {
  679.       prev_p = scanner_p ;
  680.       scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next);
  681.    }
  682.    
  683.    smb_shm_header_p->consistent = False;
  684.    
  685.    DEBUG(6,("smb_shm_free : freeing %d bytes at offset %d\n",header_p->size*CellSize,offset));
  686.  
  687.    if ( scanner_p == prev_p )
  688.    {
  689.       smb_shm_header_p->statistics.cells_free += header_p->size;
  690.       smb_shm_header_p->statistics.cells_used -= header_p->size;
  691.  
  692.       /* we must free it at the beginning of the list */
  693.       smb_shm_header_p->first_free_off = smb_shm_addr2offset(header_p);                         /*    set    the free_list_pointer to this block_header */
  694.  
  695.       /* scanner is the one that was first in the list */
  696.       header_p->next = smb_shm_addr2offset(scanner_p);
  697.       smb_shm_solve_neighbors( header_p ); /* if neighbors then link them */
  698.       
  699.       smb_shm_header_p->consistent = True;
  700.       smb_shm_global_unlock();
  701.       return True;
  702.    } 
  703.    else
  704.    {
  705.       smb_shm_header_p->statistics.cells_free += header_p->size;
  706.       smb_shm_header_p->statistics.cells_used -= header_p->size;
  707.  
  708.       prev_p->next = smb_shm_addr2offset(header_p);
  709.       header_p->next = smb_shm_addr2offset(scanner_p);
  710.       smb_shm_solve_neighbors(header_p) ;
  711.       smb_shm_solve_neighbors(prev_p) ;
  712.  
  713.       smb_shm_header_p->consistent = True;
  714.       smb_shm_global_unlock();
  715.       return True;
  716.    }
  717. }
  718.  
  719. smb_shm_offset_t smb_shm_get_userdef_off(void)
  720. {
  721.    if (!smb_shm_header_p)
  722.       return NULL_OFFSET;
  723.    else
  724.       return smb_shm_header_p->userdef_off;
  725. }
  726.  
  727. BOOL smb_shm_set_userdef_off(smb_shm_offset_t userdef_off)
  728. {
  729.    if (!smb_shm_header_p)
  730.       return False;
  731.    else
  732.       smb_shm_header_p->userdef_off = userdef_off;
  733.    return True;
  734. }
  735.  
  736. void * smb_shm_offset2addr(smb_shm_offset_t offset)
  737. {
  738.    if (offset == NULL_OFFSET )
  739.       return (void *)(0);
  740.    
  741.    if (!smb_shm_header_p)
  742.       return (void *)(0);
  743.    
  744.    return (void *)((char *)smb_shm_header_p + offset );
  745. }
  746.  
  747. smb_shm_offset_t smb_shm_addr2offset(void *addr)
  748. {
  749.    if (!addr)
  750.       return NULL_OFFSET;
  751.    
  752.    if (!smb_shm_header_p)
  753.       return NULL_OFFSET;
  754.    
  755.    return (smb_shm_offset_t)((char *)addr - (char *)smb_shm_header_p);
  756. }
  757.  
  758. /*******************************************************************
  759.   Lock a particular hash bucket entry.
  760.   ******************************************************************/
  761.  
  762. BOOL smb_shm_lock_hash_entry( unsigned int entry)
  763. {
  764.   int start = (smb_shm_header_p->userdef_off + (entry * sizeof(smb_shm_offset_t)));
  765.  
  766.   if (smb_shm_fd < 0)
  767.     {
  768.       DEBUG(0,("ERROR smb_shm_lock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
  769.       return False;
  770.     }
  771.  
  772.   if(entry >= lp_shmem_hash_size())
  773.     {
  774.       DEBUG(0,("ERROR smb_shm_lock_hash_entry : hash entry size too big (%d)\n", entry));
  775.       return False;
  776.     }
  777.   
  778.   /* Do an exclusive wait lock on the 4 byte region mapping into this entry  */
  779.   if (fcntl_lock(smb_shm_fd, F_SETLKW, start, sizeof(smb_shm_offset_t), F_WRLCK) == False)
  780.     {
  781.       DEBUG(0,("ERROR smb_shm_lock_hash_entry : fcntl_lock failed with code %d\n",errno));
  782.       return False;
  783.     }
  784.   
  785.   DEBUG(9,("smb_shm_lock_hash_entry: locked hash bucket %d\n", entry)); 
  786.   return True;
  787. }
  788.  
  789. /*******************************************************************
  790.   Unlock a particular hash bucket entry.
  791.   ******************************************************************/
  792.  
  793. BOOL smb_shm_unlock_hash_entry( unsigned int entry )
  794. {
  795.   int start = (smb_shm_header_p->userdef_off + (entry * sizeof(smb_shm_offset_t)));
  796.  
  797.   if (smb_shm_fd < 0)
  798.     {
  799.       DEBUG(0,("ERROR smb_shm_unlock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
  800.       return False;
  801.     }
  802.    
  803.   if(entry >= lp_shmem_hash_size())
  804.     {
  805.       DEBUG(0,("ERROR smb_shm_unlock_hash_entry : hash entry size too big (%d)\n", entry));
  806.       return False;
  807.     }
  808.  
  809.   /* Do a wait lock on the 4 byte region mapping into this entry  */
  810.   if (fcntl_lock(smb_shm_fd, F_SETLKW, start, sizeof(smb_shm_offset_t), F_UNLCK) == False)
  811.     {
  812.       DEBUG(0,("ERROR smb_shm_unlock_hash_entry : fcntl_lock failed with code %d\n",errno));
  813.       return False;
  814.     }
  815.   
  816.   DEBUG(9,("smb_shm_unlock_hash_entry: unlocked hash bucket %d\n", entry)); 
  817.   return True;
  818. }
  819.  
  820. /*******************************************************************
  821.   Gather statistics on shared memory usage.
  822.   ******************************************************************/
  823.  
  824. BOOL smb_shm_get_usage(int *bytes_free,
  825.            int *bytes_used,
  826.            int *bytes_overhead)
  827. {
  828.    if( !smb_shm_header_p )
  829.    {
  830.       /* not mapped yet */
  831.       DEBUG(0,("ERROR smb_shm_free : shmem not mapped\n"));
  832.       return False;
  833.    }
  834.    *bytes_free = smb_shm_header_p->statistics.cells_free * CellSize;
  835.    *bytes_used = smb_shm_header_p->statistics.cells_used * CellSize;
  836.    *bytes_overhead = smb_shm_header_p->statistics.cells_system * CellSize + AlignedHeaderSize;
  837.    
  838.    return True;
  839. }
  840.  
  841. #else /* FAST_SHARE_MODES */
  842.  int shmem_dummy_procedure(void)
  843. {return 0;}
  844. #endif /* FAST_SHARE_MODES */
  845.