+ /*
+ * We now have a segment name to search for, and a directory to search.
+ *
+ * Before tediously performing a linear scan of the directory,
+ * check the name cache to see if the directory/name pair
+ * we are looking for is known already. We don't do this
+ * if the segment name is long, simply so the cache can avoid
+ * holding long names (which would either waste space, or
+ * add greatly to the complexity).
+ */
+ if (ndp->ni_dent.d_namlen > NCHNAMLEN) {
+ nchstats.ncs_long++;
+ makeentry = 0;
+ } else {
+ nhp = &nchash[NHASH(hash, dp->i_number, dp->i_dev)];
+ for (ncp = nhp->nch_forw; ncp != (struct nch *)nhp;
+ ncp = ncp->nc_forw) {
+ if (ncp->nc_ino == dp->i_number &&
+ ncp->nc_dev == dp->i_dev &&
+ ncp->nc_nlen == ndp->ni_dent.d_namlen &&
+ !bcmp(ncp->nc_name, ndp->ni_dent.d_name,
+ ncp->nc_nlen))
+ break;
+ }
+
+ if (ncp == (struct nch *)nhp) {
+ nchstats.ncs_miss++;
+ ncp = NULL;
+ } else {
+ if (ncp->nc_id != ncp->nc_ip->i_id) {
+ nchstats.ncs_falsehits++;
+ } else if (!makeentry) {
+ nchstats.ncs_badhits++;
+ } else {
+
+ /*
+ * move this slot to end of LRU
+ * chain, if not already there
+ */
+ if (ncp->nc_nxt) {
+ /* remove from LRU chain */
+ *ncp->nc_prev = ncp->nc_nxt;
+ ncp->nc_nxt->nc_prev = ncp->nc_prev;
+
+ /* and replace at end of it */
+ ncp->nc_nxt = NULL;
+ ncp->nc_prev = nchtail;
+ *nchtail = ncp;
+ nchtail = &ncp->nc_nxt;
+ }
+
+ /*
+ * Get the next inode in the path.
+ * See comment above other `IUNLOCK' code for
+ * an explaination of the locking protocol.
+ */
+ pdp = dp;
+ if (!isdotdot || dp != u.u_rdir)
+ dp = ncp->nc_ip;
+ if (dp == NULL)
+ panic("nami: null cache ino");
+ if (pdp == dp) {
+ dp->i_count++;
+ } else if (isdotdot) {
+ IUNLOCK(pdp);
+ igrab(dp);
+ } else {
+ igrab(dp);
+ IUNLOCK(pdp);
+ }
+
+ /*
+ * Verify that the inode that we got
+ * did not change while we were waiting
+ * for it to be locked.
+ */
+ if (ncp->nc_id != ncp->nc_ip->i_id) {
+ iput(dp);
+ ILOCK(pdp);
+ dp = pdp;
+ nchstats.ncs_falsehits++;
+ } else {
+ ndp->ni_dent.d_ino = dp->i_number;
+ /* ni_dent.d_reclen is garbage ... */
+ nchstats.ncs_goodhits++;
+ goto haveino;
+ }
+ }
+
+ /*
+ * Last component and we are renaming or deleting,
+ * the cache entry is invalid, or otherwise don't
+ * want cache entry to exist.
+ */
+
+ /* remove from LRU chain */
+ *ncp->nc_prev = ncp->nc_nxt;
+ if (ncp->nc_nxt)
+ ncp->nc_nxt->nc_prev = ncp->nc_prev;
+ else
+ nchtail = ncp->nc_prev;
+
+ /* remove from hash chain */
+ remque(ncp);
+
+ /* insert at head of LRU list (first to grab) */
+ ncp->nc_nxt = nchhead;
+ ncp->nc_prev = &nchhead;
+ nchhead->nc_prev = &ncp->nc_nxt;
+ nchhead = ncp;
+
+ /* and make a dummy hash chain */
+ ncp->nc_forw = ncp;
+ ncp->nc_back = ncp;
+
+ ncp = NULL;
+ }