VOP_LOOKUP(9)

명칭
VOP_LOOKUP - 패스명의 원가요소의 조사

서식
<sys/param.h> <sys/vnode.h> <sys/namei.h> int VOP_LOOKUP(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)

해설
이 엔트리 포인트는 주어진 디렉토리내의 단일의 패스명 요소를 조사합니다.

인수는 이하대로입니다.

dvp 검색하는 디렉토리의 락 된 vnode 입니다.

vpp 결과의 락 된 vnode 가 격납되어야 할 변수의 주소입니다.

cnp 검색되기 위한 패스명 요소입니다.

cnp (은)는 이하로 정의되고 있는 componentname 구조체에의 포인터입니다.

    struct componentname {
    	/*
    	 * lookup 에의 인수입니다.
    	 */
    	u_long	cn_nameiop;	/* namei 조작 */
    	u_long	cn_flags;	/* namei 에의 플래그 */
    	struct	proc *cn_proc;	/* lookup 를 요구하고 있는 프로세스 */
    	struct	ucred *cn_cred;	/* 증명 */
    	/*
    	 * 검색 routine 및 위탁 routine로 공유됩니다.
    	 */
    	char	*cn_pnbuf;	/* 패스명 버퍼 */
    	char	*cn_nameptr;	/* 검색된 이름에의 포인터 */
    	long	cn_namelen;	/* 검색된 요소의 길이 */
    	u_long	cn_hash;	/* 검색된 이름의 해시치 */
    	long	cn_consume;	/* lookup()로 소비하는 캐릭터수 */
    };

패스명의 요소를 락 된 vnode 에의 포인터로 변환합니다. 이것이 정말로 중심이며, 보다 복잡한 routine입니다. 파일 시스템이 엄밀한 트리 계층으로 유지되지 않은 경우에는, 데드 록 상태에 빠지는 일이 있습니다.

cnp->cn_nameiop 인수는, 오브젝트의 용도 목적으로 의존해, LOOKUP, CREATE, RENAME, 또는 DELETE 입니다. CREATE, RENAME, 또는 DELETE 하지만 명시되었을 때에는, 디렉토리 엔트리의 작성, 이름 변경, 삭제에 사용하는 정보를 계산할 수 있습니다.

VOP_LOOKUP 의 전체의 개요입니다.

디렉토리의 액세스권을 체크합니다. 캐쉬안의 이름을 검색해, 만약 발견되면, 그 이름을 돌려줍니다. 디렉토리안의 이름을 검색해, found 또는 notfound 에 적절히 진행됩니다.

notfound:

작성 또는 이름 변경으로 패스명의 마지막 경우에는, EJUSTRETURN (을)를 돌려주어, 이용 가능한 위치에 정보를 남깁니다. 그렇지 않으면 ENOENT (을)를 돌려줍니다.

found:

패스명의 최후로 삭제의 경우에는, 삭제를 가능하게 하는 정보를 돌려줍니다. 패스명의 최후로 이름 변경의 경우에는, 변경처의 inode 를 잠그어 이름 변경을 가능하게 하는 정보를 돌려줍니다. 최후가 아닌 경우에는, 이름을 캐쉬에 추가합니다. 최후로 작성도 삭제도 아닌 경우에는, 이름을 캐쉬에 추가합니다.

락
디렉토리 dvp (은)는 엔트리시에 락 되고 있어야 합니다. 에러 (주: 반환값 EJUSTRETURN (은)는 에러라고는 보이지 않습니다)가 검출되었을 경우에는, 락 된 채로 돌아옵니다. 그렇지만, cnp->cn_flags 에 LOCKPARENT 및 ISLASTCN 의 양쪽 모두가 명시되어 있지 않은 경우에는, 언로크 되지 않습니다. 엔트리가 그 디렉토리 중(안)에서 발견되었을 경우에는, 락 되어 돌려주어집니다.

반환값
요소가 발견되었을 경우에는, *vpp 에 그 파일의 락 된 vnode 가 설정되어, 0 이 돌려주어집니다. 검색되고 있는 요소가 ". " 의 경우, 그 vnode 는 vref(9) (을)를 사용해 추가된 여분의 참조를 얻습니다. 이 경우는, 호출측이 적절히 락을 해방하는 것에 주의하지 않으면 안됩니다.

요소가 발견되지 않고 조작이 CREATE 또는 RENAME 인 경우에는, 플래그 ISLASTCN 하지만 명시되어 조작은 성공해, 특별한 반환값 EJUSTRETURN 하지만 돌려주어집니다. 그렇지 않은 경우에는, 적절한 에러 코드가 돌려주어집니다.

의사 코드

    int
    vop_lookup(struct vnode *dvp,
    	   struct vnode **vpp,
    	   struct componentname *cnp)
    {
        int error;
        int nameiop = cnp->cn_nameiop;
        int flags = cnp->cn_flags;
        int lockparent = flags & LOCKPARENT;
        int islastcn = flags & ISLASTCN;
        struct vnode *vp = NULL;
        /*
         * 디렉토리의 액세스권을 체크합니다.
         */
        if (dvp->v_type ! = VDIR)
    	return ENOTDIR;
        error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc);
        if (error)
    	return (error);
        if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
    	(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
    	return (EROFS);
        /*
         * 디렉토리/이름의 페어를 위한 이름 캐쉬를 체크합니다.
         * 이것은, 존재하고 있지 않는 이름의 경우에는 ENOENT 를, 이름이 발견되었다
         * 경우에는 -1 을, 그렇지 않은 경우에는 0 을 돌려줍니다.
         */
        error = cache_lookup(dvp, vpp, cnp);
        if (error) {
    	int vpid;
    	if (error = ENOENT)
    	    return error;
    	vp = *vpp;
    	if (dvp == vp) {	/* ". " 위를 찾습니다 */
    	    VREF(vp);
    	    error = 0;
    	} else if (flags & ISDOTDOT) {
                /*
    	     * 데드 록을 피하기 (위해)때문에,".." 의 락 된 vnode 를
    	     * 취득하기 전에, 그 디렉토리를 언로크 할 필요가
    	     * 있습니다.
    	     */
    	    VOP_UNLOCK(dvp);
    	    error = vget(vp, 1);
    	    if (! error) {
    		if (lockparent && islastcn)
    		    error = VOP_LOCK(dvp);
    	    }
    	} else {
    	    error = vget(vp, 1);
    	    if (error || ! (lockparent && islastcn)) {
    		VOP_UNLOCK(dvp);
    	    }
    	}
    	/*
    	 * 락을 기다리고 있는 동안에 특성의 수가 변화하고 있지 않는 것을
    	 * 체크합니다.
    	 */
    	if (! error) {
    	    if (vpid == vp->v_id) {
    		/*
    		 * lockparent && islastcn 의 경우에는 dvp 가 락
    		 * 됩니다. vp 가 락 됩니다.
    		 */
    		return (0);
    	    }
    	    vput(vp);
    	    if (dvp ! = vp && lockparent && islastcn)
    		VOP_UNLOCK(pdp);
    	}
    	/*
    	 * 이하의 디렉토리 검색을 위해서(때문에) dvp 를 재차 잠급니다.
    	 */
    	error = VOP_LOCK(dvp);
    	if (error) {
    	    return (error);
    	}
    	*vpp = NULL;
        }
        /*
         * 요소 cnp->cn_nameptr 를 위해서(때문에) dvp 를 검색합니다.
         */
        ...;
        if (! found) {
    	if ((nameiop == CREATE || nameiop == RENAME)
    	    && islastcn
    	    && directory dvp has not been removed) {
    	    /*
    	     * 디렉토리의 기록권을 체크합니다.
    	     */
    	    /*
    	     * 할 수 있는 한, 디렉토리안의 새로운 요소의 이름을 위해서(때문에)
    	     * 충분히 큰 장소의 위치를 기록합니다. 이것은 dvp 를 위한
    	     * vnode 의 사적 데이터안에 기록되는 것이 가능합니다.
    	     * VOP_CREATE 또는 VOP_RENAME 로 다음에 사용하기 위해서,
    	     * 패스명 으로 유지하기 위해서(때문에) SAVENAME 플래그를 설정합니다.
    	     */
    	    cnp->cn_flags |= SAVENAME;
    	    if (! lockparent)
    		/*
    		 * 상기로 기록된 추가의 데이터는 lockparent 가 명시
    		 * 되었을 때에게만 유용한 것으로 주의해 주세요.
    		 */
    		VOP_UNLOCK(dvp);
    	    return EJUSTRETURN;
    	}
    	/*
    	 * 캐쉬에 이름을 삽입하는 것을 고려합니다.
    	 */
    	if ((cnp->cn_flags & MAKEENTRY) && nameiop ! = CREATE)
    	    cache_enter(dvp, NULL, cnp);
    	return ENOENT;
        } else {
    	/*
    	 * 삭제로 패스명의 마지막 경우에는, 파일의 삭제에 사용할 수 있다
    	 * 파라미터를 돌려줍니다. wantparent 플래그가 설정되어 있지 않다
    	 * 경우에는 그 디렉토리만을 돌려주어, 그렇지 않은 경우에는
    	 * 계속해 그 inode 를 잠그어,". " 에 주의합니다.
    	 */
    	if (nameiop == DELETE && islastcn) {
    	    /*
    	     * 디렉토리의 기록권을 체크합니다.
    	     */
    	    error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc);
    	    if (error)
    		return (error);
    	    if (found entry is same as dvp) {
    		VREF(dvp);
    		*vpp = dvp;
    		return 0;
    	    }
    	    error = VFS_VGET(dvp->v_mount, ..., &vp);
    	    if (error)
    		return error;
    	    if (directory is sticky
    		&& cred->cr_uid ! = 0
    		&& cred->cr_uid ! = owner of dvp
    		&& owner of vp ! = cred->cr_uid) {
    		vput(vp);
    		return EPERM;
    	    }
    	    *vpp = vp;
    	    if (! lockparent)
    		VOP_UNLOCK(dvp);
    	    return 0;
    	}
    	/*
    	 * 재기록 (RENAME)의 경우에는, 그 inode 및 현재의
    	 * 디렉토리를 재기록 하기 위해서 요구되는 정보를 돌려줍니다.
    	 * 통상 파일 또는 하늘의 디렉토리인 것을 확인하기 위해서,
    	 * 디렉토리 엔트리의 inode 를 취득하지 않으면 안됩니다.
    	 */
    	if (nameiop == RENAME && wantparent && islastcn) {
    	    error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_proc);
    	    if (error)
    		return (error);
    	    /*
    	     * ". " (을)를 체크합니다.
    	     */
    	    if (found entry is same as dvp)
    		return EISDIR;
    	    error = VFS_VGET(dvp->v_mount, ..., &vp);
    	    if (error)
    		return error;
    	    *vpp = vp;
    	    /*
    	     * 다음에 VOP_RENAME 로 사용하기 위해서 이름을 보존합니다.
    	     */
    	    cnp->cn_flags |= SAVENAME;
    	    if (! lockparent)
    		VOP_UNLOCK(dvp);
    	    return 0;
    	}
    	/*
    	 * 이름의 변환의 스텝의 전모입니다. 기호 연결이 현재의
    	 * 디렉토리로부터의 상대인 경우에는, 재차 필요하게 되므로,
    	 * 디렉토리를 'vput'하지 않습니다. 대신에 "pdp" 로서
    	 * 언로크 된 디렉토리를 보존합니다. 취득하기 전에 그
    	 * inode 가 삭제되지 않는 것을 프로텍션하기 위해서, 그 디렉토리를
    	 * 언로크 하기 전에 목적의 inode 를 취득하지 않으면 안됩니다.
    	 * 루트로부터 디렉토리 트리를 내릴 방향으로 inode 를 취득한다
    	 * 일로, 데드 록을 항상 예방합니다. 종이는, 역방향의
    	 * 포인터 ".." (을)를 더듬을 때는, 요구된 디렉토리를 취득한다
    	 * 전에 친디렉토리를 언로크 하지 않으면 안됩니다. ".." 에
    	 * 관련지을 수 있었던 inode 를 위한 VFS_VGET 가 돌아오기 전에, 현재의
    	 * 및 친디렉토리의 양쪽 모두가 삭제되었을 경우에는, 여기에 잠재적인
    	 * 경합 상태가 있습니다. 극히 복잡한 데드 록 검출 알고리즘
    	 * 의 실장없이 이 경합 상태를 피할 수가 없기 때문에, 이
    	 * 경합 상태의 발생이 드문 것을 기대하고 있습니다. 파일 시스템이,
    	 *  ".." 이외로, 디렉토리 구조안에 소를 가리키는 하드 링크를
    	 * 가지는 경우, 이 간단한 데드 록 검출 기구가 일하지 않는 것에도 주의
    	 * 해 주세요.
    	 */
    	if (flags & ISDOTDOT) {
    	    VOP_UNLOCK(dvp);	/* inode 를 취득하기 위한 경합입니다 */
    	    error = VFS_VGET(dvp->v_mount, ..., &vp);
    	    if (error) {
    		VOP_LOCK(dvp);
    		return (error);
    	    }
    	    if (lockparent && islastcn) {
    		error = VOP_LOCK(dvp);
    		if (error) {
    		    vput(vp);
    		    return error;
    		}
    	    }
    	    *vpp = vp;
    	} else if (found entry is same as dvp) {
    	    VREF(dvp);	/* 예를 들면 ". " 등, 자기 자신이 필요합니다 */
    	    *vpp = dvp;
    	} else {
    	    error = VFS_VGET(dvp->v_mount, ..., &vp);
    	    if (error)
    		return (error);
    	    if (! lockparent || ! islastcn)
    		VOP_UNLOCK(dvp);
    	    *vpp = vp;
    	}
    	/*
    	 * 적절하면 이름을 캐쉬에 삽입합니다.
    	 */
    	if (cnp->cn_flags & MAKEENTRY)
    	    cache_enter(dvp, *vpp, cnp);
    	return (0);
        }
    }

에러

[ENOTDIR]
    vnode dvp 하지만 디렉토리를 나타내고 있지 않습니다.

[ENOENT]
    요소 dvp 하지만 그 디렉토리에는 발견되지 않습니다.

[EACCES]
    명시된 조작을 위한 액세스가 거부되었습니다.

[EJUSTRETURN]
    CREATE 또는 RENAME 의 조작은 성공입니다.

관련 항목
VOP_ACCESS(9), VOP_CREATE(9), VOP_MKDIR(9), VOP_MKNOD(9), VOP_RENAME(9), VOP_SYMLINK(9), vnode(9)

역사
함수 VOP_LOOKUP 하 4.3BSD 그리고 등장했습니다.

저자
이 메뉴얼 페이지는 ufs_lookup.c 안의 코멘트로부터의 텍스트를 사용해, Doug Rabson 하지만 썼습니다.