nfsHash.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:24k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* nfsHash.c - file based hash table for file handle to file name and reverse */
  2. /* Copyright 1998 - 2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4.  
  5. /*
  6. modification history
  7. --------------------
  8. 01b,19oct01,rae  merge from truestack ver 01g, base o1a (SPRs 62705, 35767)
  9. 01a,15nov98,rjc  written
  10. */
  11. /*
  12. INTERNAL
  13. DESCRIPTION
  14. The nfs server is required to maintain a mapping of file names to file
  15. handles since the file handle is of limited size but nfs  requests
  16. use a file handle to id the file. This map is being implemented as a 2 
  17. way hash table so given a file name we can find out the corresponding
  18. file handle and correspondingly get the file name given the file handle.
  19. The name to handle operation would typically be done infrequently
  20. compared to the handle to name op since the former corresponds to 
  21. opening the file while the latter is needed for every nfs request. 
  22. Therefore the hash table has been implememnted with a bias towards
  23. keeping the latter operation more efficient.
  24. Conceptually the hash table is simple. Given a hash table entry we
  25. compute the hash value for each of the 2 hashing functions and then 
  26. plece the entry into two lists. While deleting we remove it from both
  27. lists. However since we must keep this data structure on disk we
  28. must avoid the typical in memory implementation as a linked list of 
  29. entries. That's because it is inefficient to implement a fragmentation/
  30. compaction memory management system as is done in the case of the
  31. standard malloc/free based implementation.
  32. Our design allocates the disk space in larger chunks (than may be needed
  33. to store a single entry) and uses a bit map to keep track of free blocks.
  34. The hash table is maintained in a dos file. The file offset is used as
  35. a pointer.
  36. Data structures
  37. File block bit map table
  38. This structure which is maintained in memory contains a bit per block
  39. of the dos file. In order to locate a free block we simply scan this bit 
  40. from the start until a free block is found. If none are found we would
  41. expand the hash file by seeking beyond the existing end of the file 
  42. and update the bit map block correspondingly. Freeing a block is done by 
  43. turning off the bit. Currently we do not reduce the size of the file
  44. as it would be extremely inefficient in general (in case free block is not
  45. at the end of the file. Free blocks at the end of the list could be 
  46. returned to the file system by truncating the file.
  47. Contents of a hash table block.
  48.  
  49. Each block contains a sequence of entries followed by a pointer to 
  50. the next block in the list keyed by file handle. In other words all entries
  51. in a block and the blocks after it, would have hashed to the same value,
  52. and we can locate a required entry given the file handle by examining the
  53. entries in a block and traversing the linked list of blocks
  54. Contents of an entry -
  55. Each entry consists of a triple comprising a next entry pointer, the
  56. file handle , and the file name. The next entry pointer points to the next
  57. entry in the hash chain, keyed by file name. Unlike the file handle based 
  58. chain these entries are not organized into blocks as doing so would require 
  59. that we maintain a duplicate entry since in general entries which hash into
  60. a block when keyed by file handle will not hash into the same block when
  61. keyed by file name. While maintaining duplicates will work around this
  62. problem we would end up doubling the storage requirements and increasing
  63. the size of this file would increase search times anyway and most likely
  64. negate most of the benefits of this organization.
  65. To use this feature, include the following component:
  66. INCLUDE_NETWRS_NFSHASH
  67. NOMANUAL
  68. */
  69. /* includes */
  70. #include "vxWorks.h"
  71. #include "unistd.h"
  72. #include "xdr_nfs.h"
  73. #include "string.h"
  74. #include "fcntl.h"
  75. #include "stdio.h"
  76. #include "stdlib.h"
  77. #include "memLib.h"
  78. #include "nfsdLib.h"
  79. #include "ctype.h"
  80. #include "sys/stat.h"
  81. #include "semLib.h"
  82. #include "memPartLib.h"
  83. /* defines */
  84. #define MAX_DEVS 10
  85. #define MAX_MNTS 20
  86. #define MAX_HASH_BLKS  10000
  87. #define HASH_BKT_SZ   (1 * 1024)
  88. #define CHAR_BIT_LEN    8
  89. #define INT_BIT_LEN     (sizeof (int) * CHAR_BIT_LEN)
  90. #define BAD_OFFSET      ((off_t)(~0x0))
  91. #define FH_HASH_TBL_LEN      512
  92. #define NAME_HASH_TBL_LEN    512
  93. #define MIN_ENTRY_SZ    (sizeof (HNDL_NAME))
  94. #define STR_INT_LEN(s)  ((strlen (s) + 1 + sizeof (int) - 1) / sizeof (int))
  95. #define STR_ALIGN_LEN(s) (((strlen (s) + 1 + sizeof (int) - 1) / sizeof (int)) 
  96.    *  sizeof (int))
  97. #define HASH_BKT_HDR_SZ    (sizeof (off_t) + sizeof (int))
  98. #define ENTRY_HDR_SZ    (sizeof (HNDL_NAME) - sizeof(int))
  99. /* forward declaration */
  100. LOCAL int blkRead (int, off_t, char *, int);
  101. LOCAL int blkWrite (int, off_t, char *, int );
  102. /* typedefs */
  103. /* descriptor for a nfs hashtable */
  104. typedef struct tblDesc  
  105.     {
  106.     int     allocBits [MAX_HASH_BLKS/INT_BIT_LEN + 1];  /* bits allocated */
  107.     int     numBlocks;                          /* number of blocks allocated */
  108.     int     fd;              /* file descriptor of file containing hash table*/
  109.     off_t   nameHash [NAME_HASH_TBL_LEN - 1];  /* hash by name table */
  110.     int     nextInode;        /* next inode number to allocate */
  111.     int     refCnt;           /* reference count */
  112.     SEM_ID  sem;              /* protection lock */
  113.     char    nmBuf [NFS_MAXPATHLEN];  /* file name for hash table */
  114.     }  TBL_DESC;
  115. /* 
  116.  * nfs handle and name pairs are stored in this structure. This structure 
  117.  * is contained within the hash buckets which are written to disk. These
  118.  * structures will have overall length a multple of sizeof (int) so
  119.  * that  the next field stays aligned on a word boundary when in
  120.  * memory 
  121.  */
  122. typedef struct hndlName
  123.     {
  124.     off_t        next;         /* next entry ptr */
  125.     off_t        prev;         /* prev entry ptr */
  126.     short        totalLen;     /* total length of entry */
  127.     short        nameLen;      /* length of name string, 0 for free netry */
  128.     int          fh;     /* file handlei/inode  */
  129.     char         name [sizeof (int)]; /* actual str length is upto max 
  130.  pathname lwngth, this is just for 
  131.  a minimum string. Entry length must 
  132.  be a multiple of sizeof (int) for
  133.  alignment */
  134.     }   HNDL_NAME;
  135. /* 
  136.  * hash bucket contains a number of HNDL_NAME pairs along with free space
  137.  */
  138. typedef struct hashBkt  
  139.     {
  140.     off_t        next;       /* next bkt ptr */
  141.     int          freeSpace;  /* free space remaining in bucket */
  142.     char         entries [HASH_BKT_SZ - sizeof (off_t) - sizeof (int)];
  143.   /* buffer for entries of type HNDL_NAME */
  144.     }  HASH_BKT;
  145. /* 
  146.  * Mapping from a file system device id to corresponding hash table descriptor.
  147.  * There is one hash table per file system device if there are nfs exported
  148.  *  directories in that file system
  149.  */
  150. typedef struct devIdPair
  151.     {
  152.     int         dev;
  153.     TBL_DESC *  pTbl;
  154.     } DEV_ID_PAIR  ;
  155. /* 
  156.  * Mapping from the nfs volume mount id to the hash table descriptor.
  157.  * The nfs volume id is generated in the nfsExport () routine and is
  158.  * maintained within the nfs file handle.
  159.  */
  160. typedef struct mntIdPair
  161.     {
  162.     int         mntId;
  163.     TBL_DESC *  pTbl;
  164.     } MNT_ID_PAIR;
  165. /* locals */
  166. /* device to hash table descriptor table */
  167. LOCAL DEV_ID_PAIR   devTbl[MAX_DEVS];
  168. /* mount volume  to hash table descriptor table */
  169. LOCAL MNT_ID_PAIR   mntTbl[MAX_MNTS];
  170. /******************************************************************************
  171. * insertMntId - insert entry into mount id based table 
  172. *
  173. * Inserts pointer <pTbl> to a hash file table descriptor in the mount id
  174. * based table for nfs mount point <mntId>
  175. *
  176. * NOMANUAL
  177. *
  178. * RETURNS: N/A.
  179. */
  180. LOCAL void insertMntId 
  181.     (
  182.     TBL_DESC *    pTbl,
  183.     int           mntId
  184.     )
  185.     {
  186.     MNT_ID_PAIR *   pMnt;
  187.     for (pMnt = mntTbl; pMnt < mntTbl + MAX_MNTS; ++pMnt)
  188. {
  189. if (pMnt->mntId == 0)
  190.     {
  191.     pMnt->mntId = mntId;
  192.     pMnt->pTbl = pTbl;
  193.     return ;
  194.     }
  195.         }
  196.     }
  197. /******************************************************************************
  198. * getTblEnt - get entry from mnt table 
  199. *
  200. * Returns ptr to table descriptor for give mount id <id>.
  201. *
  202. * RETURNS: ptr to entry or NULL
  203. */
  204. LOCAL TBL_DESC *  tblDescGet 
  205.     (
  206.     int   id   /* mount id */
  207.     )
  208.     {
  209.     int ix;
  210.     for (ix = 0; ix < MAX_MNTS; ++ix)
  211. {
  212. if (mntTbl[ix].mntId ==  id)
  213.     return (mntTbl[ix].pTbl);
  214.         }
  215.     return (NULL);
  216.     }
  217. /******************************************************************************
  218. * nfsHashTblInit - initialize a hash table 
  219. *
  220. * Initialize a hash table given the corresponding descriptor <pTbl>
  221. * creating the hash file in dir <dirName>.
  222. *
  223. * RETURNS: OK or ERROR
  224. */
  225. LOCAL STATUS nfsHashTblInit
  226.     (
  227.     TBL_DESC *   pTbl,
  228.     char *       dirName
  229.     )
  230.     {
  231.     off_t *      pOff;
  232.     HASH_BKT     initBuf;
  233.     HNDL_NAME *  pEnt;
  234.     int          ix;
  235.     memset ((char*) pTbl->allocBits, 0, sizeof (pTbl->allocBits));
  236.     for (pOff = pTbl->nameHash; pOff < (pTbl->nameHash + NAME_HASH_TBL_LEN); 
  237.  ++pOff)
  238. {
  239. *pOff = BAD_OFFSET;
  240. }
  241.      sprintf  (pTbl->nmBuf, "%s/leofs", dirName);
  242.      if ((pTbl->fd = open (pTbl->nmBuf, O_CREAT | O_RDWR | O_TRUNC, 0777)) 
  243.  == ERROR)
  244.  {
  245.  printf ("cannot create file %sn", pTbl->nmBuf);
  246.  return (ERROR);
  247.  }
  248.      /* create the fh hash blocks in the file */
  249.      pTbl->numBlocks = FH_HASH_TBL_LEN;
  250.      initBuf.next = BAD_OFFSET;
  251.      initBuf.freeSpace = sizeof (initBuf) - sizeof (initBuf.next) - 
  252.  sizeof (initBuf.freeSpace);
  253.      pEnt = (HNDL_NAME*)initBuf.entries;
  254.      pEnt->totalLen = initBuf.freeSpace;
  255.      pEnt->nameLen = 0;
  256.      for (ix = 0; ix < FH_HASH_TBL_LEN ; ++ix)
  257.  {
  258.  if (write (pTbl->fd, (char *)&initBuf, sizeof (initBuf)) 
  259.      != sizeof (initBuf))
  260.      {
  261.      return (ERROR);
  262.      }
  263.  }
  264.      pTbl->refCnt = 0;
  265.      pTbl->nextInode = 0;
  266.      pTbl->sem = semBCreate (SEM_Q_PRIORITY, SEM_FULL);
  267.      if (pTbl->sem == NULL)
  268. return (ERROR);
  269.      return (OK);
  270.      }
  271. /******************************************************************************
  272. *  
  273. * nfsHashTblSet - set up nfs hash table
  274. *
  275. * Set up an nfs hash table for exported directory <pDir> with mount voleume id
  276. * <mntId> and file system device id <devId>. If a hash fiel already exists
  277. * for <devId> then we simply need to setup a ptr to the existing hash table
  278. * descriptor alse a new hash file must be allocated adn initialized.
  279. *
  280. * RETURNS: N/A
  281. */
  282. void nfsHashTblSet
  283.     (
  284.     char *   pDir,     /* directory name */
  285.     int      mntId,    /*mount id */
  286.     u_long   devId     /* device Id */
  287.     )
  288.     {
  289.     DEV_ID_PAIR *   pDev;
  290.     for (pDev = devTbl; pDev < devTbl + MAX_DEVS; ++pDev)
  291. {
  292. if (pDev->dev != 0 && pDev->dev == devId)
  293.     break;
  294. }
  295.     if (pDev >= devTbl + MAX_DEVS)
  296. {
  297.         for (pDev = devTbl; pDev < devTbl + MAX_DEVS; ++pDev)
  298.     {
  299.     if (pDev->dev == 0)
  300. {
  301. pDev->dev = devId;
  302. pDev->pTbl = KHEAP_ALLOC (sizeof (TBL_DESC));
  303. if (nfsHashTblInit (pDev->pTbl, pDir) == ERROR)
  304.     {
  305.     printf ("cannot initialize nfs hash filen");
  306.     KHEAP_FREE((char *)pDev->pTbl);
  307.     return;
  308.     }
  309. break;
  310.                 }
  311.             }
  312.         }
  313.     pDev->pTbl->refCnt++;
  314.     insertMntId (pDev->pTbl, mntId);
  315.     }
  316. /******************************************************************************
  317. *  
  318. * nfsHashTblUnset - clean up  nfs hash table
  319. *
  320. * Clean up an nfs hash table for exported directory <pDir> with mount volume id
  321. * <mntId> and file system device id <devId>. Delete the allocated table 
  322. * descriptor if there are no other references to it. 
  323. *
  324. * RETURNS: N/A
  325. */
  326. void nfsHashTblUnset
  327.     (
  328.     char *   pDir,     /* directory name */
  329.     int      mntId    /*mount id */
  330.     )
  331.     {
  332.     DEV_ID_PAIR *   pDev;
  333.     MNT_ID_PAIR *   pMnt;
  334.     TBL_DESC *      pTbl;
  335.     for (pMnt = mntTbl; pMnt < mntTbl + MAX_MNTS; ++pMnt)
  336. {
  337. if (pMnt->mntId  == mntId)
  338.     break;
  339. }
  340.     if (pMnt >= mntTbl + MAX_MNTS)
  341. {
  342. return;
  343. }
  344.     else
  345. {
  346. pTbl = pMnt->pTbl;
  347. pMnt->mntId = 0;
  348. pMnt->pTbl -= 0;
  349. pTbl->refCnt--;
  350. if (pTbl->refCnt == 0)
  351.     {
  352.     close (pTbl->fd);
  353.     unlink (pTbl->nmBuf);
  354.     semDelete (pTbl->sem);
  355.     for (pDev = devTbl; pDev < devTbl + MAX_DEVS; ++pDev)
  356. {
  357. if (pDev->pTbl == pTbl)
  358.     {
  359.     KHEAP_FREE (pTbl);
  360.     pDev->pTbl = 0;
  361.     pDev->dev = 0;
  362.     }
  363.          }
  364.              }
  365.          }
  366.     }
  367. /******************************************************************************
  368. *  
  369. * blockAlloc - allocates block from the file to be used as a hash bucket 
  370. *
  371. * The length of the file being used is incremented by HASH_BKT_SZ
  372. * and the bit map updated to reflect that. The bit corresponding to
  373. * the allocated block is turned off marking the block as being in use,
  374. * so in case caller does not actually use the block he shuld free the block
  375. * with blockFree below
  376. *
  377. * RETURNS: file offset of allocated block else BAD_OFFSET
  378. * NOMANUAL
  379. */
  380. LOCAL off_t blockAlloc
  381.     (
  382.     TBL_DESC *     pTbl
  383.     )
  384.     {
  385.     int *  pBits = pTbl->allocBits;
  386.     int *  pMax = pTbl->allocBits + 
  387.   ((pTbl->numBlocks + INT_BIT_LEN -1) / sizeof (int));  
  388.   /* 1 beyond last word */
  389.     char *  pIx;
  390.     int     bitPos; /* bit position of allocated block */
  391.     int     ix;
  392.     if (pTbl->numBlocks >= MAX_HASH_BLKS)
  393. {
  394. return (BAD_OFFSET);
  395. }
  396.     for ( ; *pBits == 0 && pBits < pMax ; ++pBits)
  397. {}
  398.     if (pBits == pMax)
  399. {
  400.         /* allocate a new block in the file at the end */
  401. if (lseek (pTbl->fd, (pTbl->numBlocks + 1) *  HASH_BKT_SZ - 1, 
  402.     SEEK_SET) == ERROR)
  403.     {
  404.     return (BAD_OFFSET);
  405.     }
  406.         pTbl->numBlocks ++;
  407. return ((pTbl->numBlocks - 1) * HASH_BKT_SZ);
  408. }
  409.     else
  410.         {
  411. /* existing free block available */
  412. /* scan byte wise then bit wise */
  413. pIx = (char *) pBits;
  414. for (; *pIx == 0; ++pIx)
  415.     {};
  416.         for (ix = 0; ix < CHAR_BIT_LEN; ++ix)
  417.     {
  418.     if (*pIx & (0x1 << ix))
  419. {
  420. bitPos =  (pIx - (char*)pTbl->allocBits) * CHAR_BIT_LEN + 
  421.   (CHAR_BIT_LEN - ix) - 1;
  422. *pIx &= ~(0x1 << ix);  
  423. return (bitPos * HASH_BKT_SZ);
  424. }
  425.             }
  426. /* impossible to reach here */
  427.         }
  428.     return (BAD_OFFSET);
  429.     }
  430. /******************************************************************************
  431. *  
  432. * namehashFn - hash by name function
  433. *
  434. * RETURNS: index into hash table
  435. */
  436. LOCAL int  nameHashFn 
  437.     (
  438.     char *  pName
  439.     )
  440.     {
  441.     int   i = strlen (pName);
  442.     return (pName[i - 2] + pName[i - 1]) % NAME_HASH_TBL_LEN;
  443.     }
  444. /******************************************************************************
  445. *  
  446. * namehashFn - hash by file handle function
  447. *
  448. * Index into hash table, must be multiplies by the hash file bucket size
  449. * to get the actual file offset.
  450. *
  451. * RETURNS: index into hash table
  452. */
  453. LOCAL int fhHashFn 
  454.     (
  455.     int   fh 
  456.     )
  457.     {
  458.     return  fh % FH_HASH_TBL_LEN;
  459.     }
  460. /******************************************************************************
  461. *  
  462. * name2Fh - convert name to file handle 
  463. *
  464. * Given a file name <pName>, convert that to a file handle, using the hash 
  465. * table given by <ptbl>. We only do a lookup, so if the name does not exist 
  466. * in the lookup structure we do not create the file handle for it. 
  467. *
  468. * RETURNS: N/A
  469. */
  470. LOCAL int  name2Fh
  471.     (
  472.     TBL_DESC *   pTbl,
  473.     char *       pName
  474.     )
  475.     {
  476.     off_t        off_1 = 0;
  477.     char         buf [NFS_MAXPATHLEN + 1 + sizeof (HNDL_NAME)];
  478.     HNDL_NAME *  pEnt;
  479.     int          nameLen = strlen (pName);
  480.     semTake (pTbl->sem, WAIT_FOREVER);
  481.     for (off_1 = pTbl->nameHash [nameHashFn(pName)];
  482. off_1 != BAD_OFFSET;
  483. off_1 = pEnt->next
  484. )
  485. {
  486. if (blkRead (pTbl->fd, off_1, buf, sizeof buf) == ERROR)
  487.     {
  488.     semGive (pTbl->sem);
  489.     return (ERROR);
  490.     }
  491.         pEnt = (HNDL_NAME*)buf;
  492.         if (pEnt->nameLen == nameLen && (strcmp (pEnt->name, pName) == 
  493.  0)) 
  494.             {
  495.     semGive (pTbl->sem);
  496.     return (pEnt->fh);
  497.     }
  498.         }
  499.     semGive (pTbl->sem);
  500.     return (ERROR);
  501.     }
  502. /******************************************************************************
  503. *  
  504. * fh2Name - convert  file handle  to name
  505. *
  506. * Find the file name corresponding to a file handle <fh> using hahs table
  507. * <pTbl> and return name in <pName>.
  508. *
  509. * RETURNS: OK else ERROR if name not found.
  510. */
  511. LOCAL STATUS  fh2Name
  512.     (
  513.     TBL_DESC *  pTbl,            /* hash file descriptor ptr */
  514.     int         fh,             /* file handle */
  515.     char *      pName            /* name output buffer */
  516.     )
  517.     {
  518.     off_t              off_1 ;
  519.     HNDL_NAME *        pEnt;
  520.     HASH_BKT  *        pBlk;
  521.     char               buf [HASH_BKT_SZ];
  522.     struct stat        statBuf;
  523.     HNDL_NAME *        pTmpEnt;
  524.     char               entBuf [NFS_MAXPATHLEN + 1 + sizeof (HNDL_NAME)];
  525.     semTake (pTbl->sem, WAIT_FOREVER);
  526.     for (off_1 = fhHashFn(fh) *  HASH_BKT_SZ; off_1 != BAD_OFFSET;
  527.  off_1 = pBlk->next
  528. )
  529. {
  530. if (blkRead (pTbl->fd, off_1, buf, sizeof buf) == ERROR)
  531.     {
  532.     semGive (pTbl->sem);
  533.     return (ERROR);
  534.     }
  535. pBlk = (HASH_BKT *) buf;
  536.         pEnt = (HNDL_NAME*) pBlk->entries;
  537. for (pEnt = (HNDL_NAME *)pBlk->entries; 
  538.      (char*)pEnt < (buf + sizeof(buf) - MIN_ENTRY_SZ); 
  539.              pEnt = (HNDL_NAME*) ((char *)pEnt + pEnt->totalLen))
  540.     {
  541.             if (pEnt->fh == fh) 
  542.                 {
  543. strcpy (pName, pEnt->name);
  544.                 semGive (pTbl->sem);
  545. if (stat(pName, &statBuf) == ERROR)
  546.     {
  547.     /* delete from hash file since handle is not valid */
  548.                     if (blkRead (pTbl->fd, pEnt->next, entBuf, sizeof (entBuf))
  549. == ERROR)
  550. {
  551. return (ERROR);
  552. }
  553.     pTmpEnt = (HNDL_NAME*)entBuf;
  554.     pTmpEnt->prev = pEnt->prev;
  555.                     if (blkWrite (pTbl->fd, pEnt->next, entBuf, sizeof (entBuf))
  556. == ERROR)
  557. {
  558. return (ERROR);
  559. }
  560.                     if (blkRead (pTbl->fd, pEnt->prev, entBuf, sizeof (entBuf))
  561. == ERROR)
  562. {
  563. return (ERROR);
  564. }
  565.     pTmpEnt->next = pEnt->next;
  566.                     if (blkWrite (pTbl->fd, pEnt->prev, entBuf, sizeof (entBuf))
  567. == ERROR)
  568. {
  569. return (ERROR);
  570. }
  571.     pEnt->nameLen = 0;
  572.     pBlk->freeSpace += pEnt->totalLen;
  573.     /* if all entries in a block are gone then we could free
  574.      * the block however that is not done currently  since the 
  575.      * space will most likely be used up again unless
  576.      * the hash table gets unbalanced.
  577.      */
  578.     }
  579.              return (OK);
  580.              }
  581.             }
  582.         }
  583.     semGive (pTbl->sem);
  584.     return (ERROR);
  585.     }
  586. /******************************************************************************
  587. *  
  588. * fhInsert - insert a file handle and name pair into hash table
  589. * Inser the file handle <fh> and name <pName> into the hash table
  590. * <pTbl>.
  591. *
  592. * RETURNS: OK or ERROR if unable to insert entry.
  593. */
  594. LOCAL STATUS   fhInsert 
  595.     (
  596.     TBL_DESC *  pTbl,
  597.     int         fh,
  598.     char *      pName
  599.     )
  600.     {
  601.     /* first select block based on hash by fh , insert into blk
  602.        then onto list of entries by name */
  603.     off_t            offPrev  = 0;
  604.     off_t            offNow ;
  605.     HNDL_NAME *      pEnt = 0;
  606.     HNDL_NAME *      pTmpEnt;
  607.     HASH_BKT *       pBlk = (HASH_BKT *) NULL;
  608.     char             buf [HASH_BKT_SZ];
  609.     int              need;
  610.     int              ix;
  611.     int              newEntryLen;
  612.     char             entBuf [NFS_MAXPATHLEN + 1 + sizeof (HNDL_NAME)];
  613.     need = ENTRY_HDR_SZ  +  STR_ALIGN_LEN (pName) ;
  614.     semTake (pTbl->sem, WAIT_FOREVER);
  615.     for (offNow = fhHashFn (fh) * HASH_BKT_SZ ; offNow != BAD_OFFSET;
  616. offPrev = offNow,  offNow = pBlk->next
  617. )
  618. {
  619. if (blkRead (pTbl->fd, offNow, buf, sizeof buf) == ERROR)
  620.     {
  621.             semGive (pTbl->sem);
  622.     return (ERROR);
  623.     }
  624. pBlk = (HASH_BKT *)buf;
  625. if (pBlk->freeSpace < need)
  626.     {
  627.     continue;
  628.     }
  629. for (pEnt = (HNDL_NAME *)pBlk->entries; 
  630.      (char*)pEnt <= (buf + sizeof(buf) - need); 
  631.              pEnt = (HNDL_NAME*) ((char *)pEnt + pEnt->totalLen))
  632.     {
  633.     if (pEnt->nameLen == 0 && pEnt->totalLen >= need)
  634. {
  635. /* found an empty entry big enough */
  636. goto scanDone;
  637.                 }
  638.             }
  639.         }
  640.     /* At this point we may need to allocate a new blk */
  641.     /* allocate new block and link it in then set pEnt and offNow
  642.      * as in earlier case
  643.      */
  644. scanDone:
  645.     if (offNow == BAD_OFFSET)
  646. {
  647.         offNow = blockAlloc (pTbl);
  648. /* link new block into prev block */
  649. if (blkRead (pTbl->fd, offPrev, buf, sizeof buf) == ERROR)
  650.     {
  651.     semGive (pTbl->sem);
  652.     return (ERROR);
  653.     }
  654.         pBlk = (HASH_BKT*)buf;
  655. pBlk->next = offNow;
  656. if (blkWrite (pTbl->fd, offPrev, buf, sizeof buf) == ERROR)
  657.     {
  658.     semGive (pTbl->sem);
  659.     return (ERROR);
  660.     }
  661. /* Now convert buf into a new empty block. 
  662.    initially the whole block is just one full sized empty entry */
  663. pBlk->next = BAD_OFFSET;
  664. pBlk->freeSpace = HASH_BKT_SZ -  HASH_BKT_HDR_SZ;
  665. pEnt = (HNDL_NAME*) (pBlk->entries);
  666.         pEnt->totalLen = HASH_BKT_SZ -  HASH_BKT_HDR_SZ ;
  667. pEnt->nameLen = 0;
  668. }
  669.     /* At this point offNow points to the block to be updated and
  670.        pEnt points to the correct entry in the buffered bucket
  671.      */
  672.     ix = nameHashFn (pName);
  673.     pEnt->next = pTbl->nameHash [ix];
  674.     pEnt->prev = BAD_OFFSET;
  675.     pTbl->nameHash[ix] = offNow + ((char *)pEnt - buf);
  676.     /* update back ptr of next entry if there is one */
  677.     if (pEnt->next != BAD_OFFSET)
  678. {
  679.         if (blkRead (pTbl->fd, pEnt->next, entBuf, sizeof (entBuf) == ERROR))
  680.     {
  681.     return (ERROR);
  682.     };
  683.         pTmpEnt = (HNDL_NAME*)entBuf;
  684.         pTmpEnt->prev = pTbl->nameHash[ix];
  685.         if (blkWrite (pTbl->fd, pEnt->next, entBuf, sizeof (entBuf) == ERROR))
  686.     {
  687.     return (ERROR);
  688.     };
  689. }
  690.     /* if there is sufficient space in this entry to accomodate
  691.      * another entry at this end then divide this to get an empty entry
  692.      * at the end of first entry
  693.      */
  694.     newEntryLen = ENTRY_HDR_SZ + STR_ALIGN_LEN (pName);
  695.     if (pEnt->totalLen - newEntryLen >= MIN_ENTRY_SZ)
  696.        {
  697.        pTmpEnt = (HNDL_NAME*) ((char*)pEnt + newEntryLen);
  698.        pTmpEnt->totalLen = pEnt->totalLen - newEntryLen;
  699.        pTmpEnt->nameLen = 0;
  700.        pEnt->totalLen = newEntryLen;
  701.        }
  702.     pBlk->freeSpace -= pEnt->totalLen;
  703.     strcpy (pEnt->name, pName);
  704.     pEnt->fh = fh;
  705.     pEnt->nameLen = strlen (pName);
  706.     if (blkWrite (pTbl->fd, offNow, buf, sizeof buf) == ERROR)
  707.         {
  708.         return (ERROR);
  709.         }
  710.     semGive (pTbl->sem);
  711.     return (OK);
  712.     }
  713. /******************************************************************************
  714. *  
  715. * blkRead - read block from file
  716. * Read block from file with file descriptor <fd>, offset <offset>
  717. * buffer <buf> and buffer len <len>
  718. * RETURNS: num chars read or ERROR.
  719. */
  720. LOCAL   int blkRead 
  721.     (
  722.     int      fd,
  723.     off_t    offset,
  724.     char *   buf,
  725.     int      len
  726.     )
  727.     {
  728.     if (lseek (fd, offset, SEEK_SET) == ERROR)
  729.         {
  730.         return (ERROR);
  731.         }
  732.     return (read ( fd, buf, len));
  733.     }
  734. /******************************************************************************
  735. *  
  736. * blkWrite - write block to file
  737. * Write block to file with file descriptor <fd>, offset <offset>
  738. * buffer <buf> and buffer len <len>
  739. * RETURNS: num chars written or ERROR.
  740.  */
  741. LOCAL int blkWrite 
  742.     (
  743.     int      fd,
  744.     off_t    offset,
  745.     char *   buf,
  746.     int      len
  747.     )
  748.     {
  749.     if (lseek (fd, offset, SEEK_SET) == ERROR)
  750.         {
  751.         return (ERROR);
  752.         }
  753.     return (write ( fd, buf, len));
  754.     }
  755. /******************************************************************************
  756. *  
  757. * nfsFhLkup - find name corresponding to file handle 
  758. *
  759. * using file handle <fh> as the key get corresponding file name
  760. * in <pName>.
  761. *
  762. * RETURNS: OK or ERROR if name not found
  763. */
  764. STATUS nfsFhLkup
  765.     (
  766.     NFS_FILE_HANDLE *   pFh,  /* key for lookup */
  767.     char *              pName  /* output name */
  768.     )
  769.     {
  770.     TBL_DESC *    pT;
  771.     pT = tblDescGet (pFh->volumeId);
  772.     if (pT == NULL)
  773.        {
  774.        return (ERROR);
  775. }
  776.     if (fh2Name (pT, pFh->inode, pName) == ERROR)
  777. {
  778. return (ERROR);
  779. }
  780.     else
  781. {
  782. return OK;
  783. }
  784.     }
  785. /******************************************************************************
  786. *  
  787. * nfsNmLkupIns - find fh corresponding to file name
  788. *
  789. * Find the file handle  corresponding to the given file name  <Pname> with
  790. * nfs mount volume id <mntId> and create and insert an entry in the table
  791. * if not found.
  792. *
  793. * RETURNS: file handle or ERROR;
  794. * NOMANUAL
  795. */
  796. int nfsNmLkupIns 
  797.     (
  798.     int    mntId,     /* mount id no */
  799.     char * pName      /* seach key */
  800.     )
  801.     {
  802.     TBL_DESC *    pT;
  803.     int           in;
  804.     pT = tblDescGet (mntId);
  805.     if (pT == NULL)
  806.        return (ERROR);
  807.     if ((in = name2Fh (pT, pName)) == ERROR)
  808. {
  809. in = ++pT->nextInode;
  810. if (fhInsert (pT, pT->nextInode, pName)== ERROR)
  811.    return (ERROR);
  812. }
  813.     return (in);
  814.     }