📄 ufs_namei.c
字号:
#ifndef lintstatic char *sccsid = "@(#)ufs_namei.c 4.4 (ULTRIX) 2/28/91";#endif lint/************************************************************************ * * * Copyright (c) 1986,87,88,89 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* ------------------------------------------------------------------------ * Modification History: /sys/fs/ufs/ufs_namei.c * * 27 Feb 91 -- chet * Fix filesystem timestamping. * * 22-Jan-91 - prs * Added fast symbolic link support. * * 10 May 90 -- prs * Passed the expected g_id to ggrab() to avoid a deadly embrace * for stale cache entries. * * 17 Jan 90 -- prs * Fixed pathname resolution logic in POSIX mode. * * 14 Dec 89 -- prs * Removed nc_time logic, which protects namei from * panic conditions if time "goes backwards". * * 14 Nov 89 -- prs * Added logic which removed trailing slashes from a pathname * before ENOENT error condition detection. * * 20 Oct 89 -- prs * Preserved locking protocoll when DELETE and last component * of pathname is "..". * * 04 Oct 89 -- prs * Prevented the addition of mounted on gnodes to the * name cache. This change favors UFS lookups. * * 18 Aug 89 -- prs * Fixed syncronization between LOOKUP and DELETE operations. * * 02 Aug 89 -- prs * Nulled ncp if gnode was reused, and branching to * findslot. * * 24 Jul 89 -- prs * Restructured ufs_namei(). * * 6 Mar 89 -- condylis * Changed gput to grele for starting directory when ufs_namei() of * .. crosses a mount point. * * 08 Dec 88 -- prs * Changed EEXIST return code in checkpath() to EINVAL. * * 28 Jul 88 -- prs * SMP - System call turn on. * * 19 May 88 -- prs * SMP - Added namecahce locks. * * 07 Mar 88 -- prs * Removed parity bit check for I18N. * * 14 Jul 87 -- cb * Fixed lock bug, encountered when mounting ufs filesystems on * an nfs root, and referencing a symbolic link starting at "/". * * 08 May 87 -- logcher * Remove extra rdev sync since added to ufs_gget(), * and removed setting rdev to null on filesystems. * * 23 Oct 86 -- chet * Add arg to ufs_bmap() call * * 11 Sep 86 -- koehler * added support for local under remote fs * * 14 Oct 85 -- Reilly * Modified a comment * * 09 Sep 85 -- Reilly * Modified to handle the new 4.3BSD namei code. * * 26 Oct 84 -- jrs * Add code for nami cacheing * Derived from 4.2BSD, labeled: * ufs_nami.c 6.11 84/07/07 * * ----------------------------------------------------------------------- */#include "../h/param.h"#include "../h/systm.h"#include "../h/gnode_common.h"#include "../ufs/ufs_inode.h"#include "../h/gnode.h"#include "../ufs/fs.h"#include "../h/mount.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/buf.h"#include "../h/conf.h"#include "../h/uio.h"#include "../h/kernel.h"#include "../h/fs_types.h"#include "../h/proc.h"#include "../h/exec.h"/* * Convert a pathname into a pointer to a locked inode, * with side effects usable in creating and removing files. * This is a very central and rather complicated routine. * * The segflg defines whether the name is to be copied from user * space or kernel space. * * The flag argument is (LOOKUP, CREATE, DELETE) depending on whether * the name is to be (looked up, created, deleted). If flag has * LOCKPARENT or'ed into it and the target of the pathname exists, * namei returns both the target and its parent directory locked. * If the file system is not maintained in a strict tree hierarchy, * this can result in a deadlock situation. When creating and * LOCKPARENT is specified, the target may not be ".". When deleting * and LOCKPARENT is specified, the target may be ".", but the caller * must check to insure it does an grele and gput instead of two gputs. * * The FOLLOW flag is set when symbolic links are to be followed * when they occur at the end of the name translation process. * * Name caching works as follows: * * names found by directory scans are retained in a cache * for future reference. It is managed LRU, so frequently * used names will hang around. Cache is indexed by hash value * obtained from (ino,dev,name) where ino & dev refer to the * directory containing name. * * For simplicity (and economy of storage), names longer than * some (small) maximum length are not cached, they occur * infrequently in any case, and are almost never of interest. * * Upon reaching the last segment of a path, if the reference * is for DELETE, or NOCACHE is set (rewrite), and the * name is located in the cache, it will be dropped. * * We must be sure never to enter the name ".." into the cache * because of the extremely kludgey way that rename() alters * ".." in a situation like * mv a/x b/x * where x is a directory, and x/.. is the ".." in question. * * Overall outline of namei: * * copy in name * get starting directory * dirloop: * check accessibility of directory * dirloop2: * copy next component of name to ndp->ni_dent * handle degenerate case where name is null string * look for name in cache, if found, then if at end of path * and deleting or creating, drop it, else to haveino * search for name in directory, to found or notfound * notfound: * if creating, return locked directory, leaving info on avail. slots * else return error * found: * if at end of path and deleting, return information to allow delete * if at end of path and rewriting (create and LOCKPARENT), lock target * inode and return info to allow rewrite * if .. and on mounted filesys, look in mount table for parent * if not at end, if neither creating nor deleting, add name to cache * haveino: * if symbolic link, massage name in buffer and continue at dirloop * if more components of name, do next level at dirloop * return the answer as locked inode * * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode, * but unlocked. *//* * GFS expects sfs's to gput the pdir when passed and that the * returned gnode is locked and has the reference count incremented */int old_namei = 0;struct gnode *ufs_namei(ndp) register struct nameidata *ndp;{ register char *cp; /* pointer into pathname argument *//* these variables refer to things which must be freed or unlocked */ register struct gnode *dp = 0; /* the directory we are searching */ register struct nch *ncp; /* cache slot for entry */ register struct mount *mp; /* file system that directory is in */ register struct buf *bp = 0; /* a buffer of directory entries */ register struct direct *ep; /* the current directory entry */ int entryoffsetinblock; /* offset of ep in bp's buffer *//* these variables hold information about the search for a slot */ enum {NONE, COMPACT, FOUND} slotstatus; int slotoffset = -1; /* offset of area with free space */ int slotsize; /* size of area at slotoffset */ int slotfreespace; /* amount of space free in slot */ int slotneeded; /* size of the entry we're seeking *//* */ int numdirpasses; /* strategy for directory search */ int endsearch; /* offset to end directory search */ int prevoff; /* ndp->ni_offset of previous entry */ struct gnode *pdp; /* saved dp during symlink work */ struct gnode *sdp; /* saved dp if nomount and hit mp */ int i; int lockparent; int docache; int makeentry; /* != 0 if name to be added to cache */ unsigned hash; /* value of name hash for entry */ union nchash *nhp; /* cache chain head for entry */ int isdotdot; /* != 0 if current name is ".." */ int flag; /* op ie, LOOKUP, CREATE, or DELETE */ off_t enduseful; /* pointer past last used dir slot */ int nomount; int cacheid; /* save from name cache entry... */ char *tcp; /* temp cp for removal of trailing slashes */ int trailing_slashes = 0; /* Set if only trailing slashes remain in path */ lockparent = ndp->ni_nameiop & LOCKPARENT; nomount = ndp->ni_nameiop & NOMOUNT; docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; flag = ndp->ni_nameiop &~ (LOCKPARENT|NOCACHE|FOLLOW|NOMOUNT); if (old_namei) docache = docache & (nomount == 0 & flag == CREATE); if (flag == DELETE || lockparent) docache = 0; dp = ndp->ni_pdir; cp = ndp->ni_cp; while(*cp && (*cp == '/')) cp++; ndp->ni_endoff = 0; /* * We come to dirloop to search a new directory. * The directory must be locked so that it can be * gput, and fs must be already set to dp->i_fs. */dirloop: /* * Check accessiblity of directory. */ if ((dp->g_mode&GFMT) != GFDIR) { u.u_error = ENOTDIR; goto bad; } if (access(dp, GEXEC)) goto bad;dirloop2: /* * Copy next component of name to ndp->ni_dent. */ hash = 0; for (i = 0; *cp != 0 && *cp != '/'; cp++) { if (i >= MAXNAMLEN) { u.u_error = ENAMETOOLONG; goto bad; } /* * Remove parity bit check for I18N. */ /* * if (*cp & 0200) * if ((*cp&0377) == ('/'|0200) || flag != DELETE) { * u.u_error = EINVAL; * goto bad; * } */ ndp->ni_dent.d_name[i++] = *cp; hash += (unsigned char)*cp * i; } ndp->ni_dent.d_namlen = i; ndp->ni_dent.d_name[i] = '\0'; /* * Remove trailing slashes from cp. Note * This will only be performed on last * component of pathname. */ if (u.u_procp->p_progenv == A_POSIX) { tcp = cp; while ((*tcp != 0) && (*tcp == '/')) { trailing_slashes++; tcp++; } if (*tcp == 0) { if (flag == CREATE || flag == DELETE) cp = tcp; } else trailing_slashes = 0; } isdotdot = (i == 2 && ndp->ni_dent.d_name[0] == '.' && ndp->ni_dent.d_name[1] == '.'); makeentry = 1; if (*cp == '\0' && docache == 0) makeentry = 0; /* * Check for degenerate name (e.g. / or "") * which is a way of talking about a directory, * e.g. like "/." or ".". */ if (ndp->ni_dent.d_name[0] == '\0') { if (flag != LOOKUP || lockparent) { u.u_error = EISDIR; goto bad; } dp->g_flag &= ~GINCOMPLETE; ndp->ni_cp = cp; return (dp); } /* * 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_too_long++; makeentry = 0; } else { nchstats.ncs_looks++; smp_lock(&lk_namecache, LK_RETRY); nhp = &nchash[NHASH(hash, dp->g_number, dp->g_dev)]; for (ncp = nhp->nch_forw; ncp != (struct nch *)nhp; ncp = ncp->nc_forw) { if (ncp->nc_ino == dp->g_number && (!makeentry ? 1 : ncp->nc_id) && ncp->nc_dev == dp->g_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) { /* * Did not find component in cache. */ nchstats.ncs_miss++; ncp = NULL; } else { if (!makeentry) { /* * Remove this entry from cache. Per order * of the caller. */ nchstats.ncs_gp_reused++; /* goto expunge_cache; */ } else if (ncp->nc_id != ncp->nc_ip->g_id) { /* * gp stored in cache entry was reused by GFS. * Expunge from cache because gp no longer * is valid. */ nchstats.ncs_del_leaf++; /* goto expunge_cache; */ } 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; } /* * Save some stuff from the name cache entry * in case it gets reused after we unlock the * cache. */ cacheid = ncp->nc_id; /* * Get the next inode in the path. * We expect dp to be locked and refed, and * pdp to be unlocked and unrefed. */ pdp = dp; if (!isdotdot || dp != u.u_rdir) dp = ncp->nc_ip; smp_unlock(&lk_namecache); if (dp == NULL) panic("ufs_namei: null cache ino"); if (pdp == dp) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -