⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ufs_namei.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 4 页
字号:
					/*					 * 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 + -