📄 ufs_namei.c
字号:
/* * We want ourselves (".") * dp = pdp, and the gnode is * locked and refed twice, because * the bottom of the loop expects * dp to be locked, and pdp to just * be refed. */ gref(dp); } else if (isdotdot) { /* * Parsing "..", pdp should be refed, * and dp should be locked and refed. */ ufs_gunlock(pdp); dp = (struct gnode *)ggrab(dp, cacheid); if (dp == NULL) { /* * Couldn't initialize gp. * Goto findslot, with * dp being the parent of the * the entry that wasn't * initialized. Also dp * should be locked and refed. */ ufs_glock(pdp); dp = pdp; ncp = NULL; nchstats.ncs_nullgp++; goto findslot; } } else { /* * Traversing down the tree. pdp * should be refed, and dp should be * locked and refed. */ dp = (struct gnode *)ggrab(dp, cacheid); if (dp == NULL) { /* * See above comment starting * with "Couldn't initialize". */ dp = pdp; ncp = NULL; nchstats.ncs_nullgp++; goto findslot; } else ufs_gunlock(pdp); } /* * We expect dp to be locked and refed. * If pdp = dp, then an extra refed was * performed above. If the two do not equal * pdp is just refed. * Now revalidate cache and gp. */ smp_lock(&lk_namecache, LK_RETRY); /* * If nchinval() was invoked or the cache * entry was expunged, ncp is * completely bogus. It could be on the * free list, or reused by the time we get * here. Search directory for entry... */ if (ncp->nc_id != cacheid) { smp_unlock(&lk_namecache); if (pdp == dp) grele(dp); else { unggrab(dp); ufs_glock(pdp); dp = pdp; } ncp = NULL; nchstats.ncs_nchinval++; goto findslot; } /* * Verify that the gnode that we got * was not reclaimed while we were waiting * for it to be locked. */ if (ncp->nc_id != dp->g_id) { expunge_cache(ncp); smp_unlock(&lk_namecache); unggrab(dp); ufs_glock(pdp); dp = pdp; ncp = NULL; nchstats.ncs_gp_reused++; goto findslot; } if (dp->g_nlink == 0) panic("ufs_namei: dp had 0 nlink\n"); /* * Cache entry is valid */ if (dp->g_mp->m_fstype != GT_ULTRIX) { /* * I don't think this can happen... */ ndp->ni_cp = cp; ndp->ni_pdir = dp; smp_unlock(&lk_namecache); grele(pdp); dp->g_flag |= GINCOMPLETE; nchstats.ncs_not_ufs++; return(dp); } /* * If we are an NFS server lookup, traversing * downwards, make sure we don't give * out the root gp of another file system. * Equivilent of gget with nomount argument. */ if (nomount && (pdp != dp) && (!isdotdot) && (dp->g_number == ROOTINO)) { sdp = dp->g_mp->m_gnodp ? dp->g_mp->m_gnodp : rootdir; ndp->ni_cp = cp; ndp->ni_pdir = sdp; smp_unlock(&lk_namecache); unggrab(dp); grele(pdp); dp = (struct gnode *)ggrab(sdp, sdp->g_id); if (dp == NULL) panic("ufs_namei: Null root mp"); dp->g_flag &= ~GINCOMPLETE; nchstats.ncs_nomount++; return(dp); } /* * dp is valid ! */ ndp->ni_dent.d_ino = dp->g_number; smp_unlock(&lk_namecache); /* ni_dent.d_reclen is garbage ... */ nchstats.ncs_goodhits++; goto haveino; }/* expunge_cache: */ /* * Last component and we are renaming or deleting, * the cache entry is invalid, or otherwise don't * want cache entry to exist. NOTE: the entry could * have been reused while we were doing other stuff, * but this is still safe since every namecache struct * is always linked into both chains. The worst that * can happen is that we disturb the normal LRU * pattern, which isn't worth the trouble to avoid. */ expunge_cache(ncp); ncp = NULL; } smp_unlock(&lk_namecache); }findslot: /* * Suppress search for slots unless creating * file and at end of pathname, in which case * we watch for a place to put the new file in * case it doesn't already exist. */ slotstatus = FOUND; if (flag == CREATE && *cp == 0) { slotstatus = NONE; slotfreespace = 0; slotneeded = DIRSIZ(&ndp->ni_dent); } /* * If this is the same directory that this process * previously searched, pick up where we last left off. * We cache only lookups as these are the most common * and have the greatest payoff. Caching CREATE has little * benefit as it usually must search the entire directory * to determine that the entry does not exist. Caching the * location of the last DELETE has not reduced profiling time * and hence has been removed in the interest of simplicity. */ if (flag != LOOKUP || dp->g_number != u.u_ncache.nc_inumber || dp->g_dev != u.u_ncache.nc_dev) { ndp->ni_offset = 0; numdirpasses = 1; } else { if (u.u_ncache.nc_prevoffset > dp->g_size) u.u_ncache.nc_prevoffset = 0; else u.u_ncache.nc_prevoffset &= ~(DIRBLKSIZ - 1); ndp->ni_offset = u.u_ncache.nc_prevoffset; entryoffsetinblock = blkoff(FS(dp), ndp->ni_offset); if (entryoffsetinblock != 0) { bp = blkatoff(dp, ndp->ni_offset, (char **)0); if (bp == 0) goto bad; } numdirpasses = 2; nchstats.ncs_2passes++; } endsearch = roundup(dp->g_size, DIRBLKSIZ); enduseful = 0;searchloop: while (ndp->ni_offset < endsearch) { /* * If offset is on a block boundary, * read the next directory block. * Release previous if it exists. */ if (blkoff(FS(dp), ndp->ni_offset) == 0) { if (bp != NULL) brelse(bp); bp = blkatoff(dp, ndp->ni_offset, (char **)0); if (bp == 0) goto bad; entryoffsetinblock = 0; } /* * If still looking for a slot, and at a DIRBLKSIZE * boundary, have to start looking for free space again. */ if (slotstatus == NONE && (entryoffsetinblock&(DIRBLKSIZ-1)) == 0) { slotoffset = -1; slotfreespace = 0; } /* * Get pointer to next entry. * Full validation checks are slow, so we only check * enough to insure forward progress through the * directory. Complete checks can be run by patching * "dirchk" to be true. */ ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); if (ep->d_reclen <= 0 || dirchk && dirbadentry(ep, entryoffsetinblock)) { dirbad(dp, ndp->ni_offset, "mangled entry"); i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); ndp->ni_offset += i; entryoffsetinblock += i; continue; } /* * If an appropriate sized slot has not yet been found, * check to see if one is available. Also accumulate space * in the current block so that we can determine if * compaction is viable. */ if (slotstatus != FOUND) { int size = ep->d_reclen; if (ep->d_ino != 0) size -= DIRSIZ(ep); if (size > 0) { if (size >= slotneeded) { slotstatus = FOUND; slotoffset = ndp->ni_offset; slotsize = ep->d_reclen; } else if (slotstatus == NONE) { slotfreespace += size; if (slotoffset == -1) slotoffset = ndp->ni_offset; if (slotfreespace >= slotneeded) { slotstatus = COMPACT; slotsize = ndp->ni_offset + ep->d_reclen - slotoffset; } } } } /* * Check for a name match. */ if (ep->d_ino) { if (ep->d_namlen == ndp->ni_dent.d_namlen && !bcmp(ndp->ni_dent.d_name, ep->d_name, ep->d_namlen)) { goto found; } } prevoff = ndp->ni_offset; ndp->ni_offset += ep->d_reclen; entryoffsetinblock += ep->d_reclen; if (ep->d_ino) enduseful = ndp->ni_offset; }/* notfound: */ /* * If we started in the middle of the directory and failed * to find our target, we must check the beginning as well. */ if (numdirpasses == 2) { numdirpasses--; ndp->ni_offset = 0; endsearch = u.u_ncache.nc_prevoffset; goto searchloop; } /* * If creating, and at end of pathname and current * directory has not been removed, then can consider * allowing file to be created. */ if (flag == CREATE && *cp == 0 && dp->g_nlink != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. */ if (access(dp, GWRITE)) goto bad; /* * Return an indication of where the new directory * entry should be put. If we didn't find a slot, * then set ndp->ni_count to 0 indicating that the new * slot belongs at the end of the directory. If we found * a slot, then the new entry can be put in the range * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count) */ if (slotstatus == NONE) { ndp->ni_offset = roundup(dp->g_size, DIRBLKSIZ); ndp->ni_count = 0; enduseful = ndp->ni_offset; } else { ndp->ni_offset = slotoffset; ndp->ni_count = slotsize; if (enduseful < slotoffset + slotsize) enduseful = slotoffset + slotsize; } ndp->ni_endoff = roundup(enduseful, DIRBLKSIZ); dp->g_flag |= GUPD|GCHG; if (bp) brelse(bp); /* * We return with the directory locked, so that * the parameters we set up above will still be * valid if we actually decide to do a direnter(). * We return NULL to indicate that the entry doesn't * currently exist, leaving a pointer to the (locked) * directory inode in ndp->ni_pdir. */ dp->g_flag &= ~GINCOMPLETE; ndp->ni_pdir = dp; ndp->ni_cp = cp; return (NULL); } u.u_error = ENOENT; goto bad;found: if (numdirpasses == 2) nchstats.ncs_pass2++; /* * Check that directory length properly reflects presence * of this entry. */ if (entryoffsetinblock + DIRSIZ(ep) > dp->g_size) { dirbad(dp, ndp->ni_offset, "i_size too small"); dp->g_size = entryoffsetinblock + DIRSIZ(ep); dp->g_flag |= GUPD|GCHG; } /* * Found component in pathname. * If the final component of path name, save information * in the cache as to where the entry was found. */ if (*cp == '\0' && flag == LOOKUP) { u.u_ncache.nc_prevoffset = ndp->ni_offset; u.u_ncache.nc_inumber = dp->g_number; u.u_ncache.nc_dev = dp->g_dev; u.u_ncache.nc_time = timepick->tv_sec; } /* * Save directory entry's inode number and reclen in ndp->ni_dent, * and release directory buffer. */ ndp->ni_dent.d_ino = ep->d_ino; ndp->ni_dent.d_reclen = ep->d_reclen; brelse(bp); bp = NULL; /* * If deleting, and at end of pathname, return * parameters which can be used to remove file. * If the lockparent flag isn't set, we return only * the directory (in ndp->ni_pdir), otherwise we go * on and lock the inode, being careful with ".". */ if (flag == DELETE && *cp == 0) { /* * Write access to directory required to delete files. */ if (access(dp, GWRITE)) goto bad; ndp->ni_pdir = dp; /* for dirremove() */ /* * Return pointer to current entry in ndp->ni_offset, * and distance past previous entry (if there * is a previous entry in this block) in ndp->ni_count. * Save directory inode pointer in ndp->ni_pdir for dirremove(). */ if ((ndp->ni_offset&(DIRBLKSIZ-1)) == 0) ndp->ni_count = 0; else ndp->ni_count = ndp->ni_offset - prevoff; if (lockparent) { if (dp->g_number == ndp->ni_dent.d_ino) gref(dp); else { /* * XXX - This is real ugly, but we have * to uphold the locking protocol. The * observent reader will note that ni_pdir * will be a descendant of dp. This is ok, * because this operation will eventually fail * when the sfs does a dirempty(). */ if (isdotdot) gfs_unlock(ndp->ni_pdir); dp = gget(dp->g_mp, ndp->ni_dent.d_ino, nomount, NULL); if (isdotdot) gfs_lock(ndp->ni_pdir); if (dp == NULL) { gput(ndp->ni_pdir); goto bad; } if(dp->g_mp->m_fstype != GT_ULTRIX) { ndp->ni_cp = cp; gput(ndp->ni_pdir); ndp->ni_pdir = dp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -