FreeBSD/sys/fs/pseudofs/pseudofs_vnops.c
/*
 * Look up a file or directory
 */
Look up a file or directory
Look up a file or directory
static int
pfs_lookup(struct vop_cachedlookup_args *va)
{
	struct vnode *vn = va->a_dvp;
	struct vnode **vpp = va->a_vpp;
	struct componentname *cnp = va->a_cnp;
	struct pfs_vdata *pvd = vn->v_data;
	struct pfs_node *pd = pvd->pvd_pn;
	struct pfs_node *pn, *pdn = NULL;
	struct mount *mp;
	pid_t pid = pvd->pvd_pid;
	char *pname;
	int error, i, namelen, visible;
	PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr));
	pfs_assert_not_owned(pd);
	if (vn->v_type != VDIR)
		PFS_RETURN (ENOTDIR);
	KASSERT_PN_IS_DIR(pd);
	error = VOP_ACCESS(vn, VEXEC, cnp->cn_cred, cnp->cn_thread);
	if (error)
		PFS_RETURN (error);
	if ((cnp->cn_flags & ISLASTCN) &&
	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
		PFS_RETURN (EOPNOTSUPP);
	if (cnp->cn_namelen >= PFS_NAMELEN)
		PFS_RETURN (ENOENT);
	if (!pfs_visible(curthread, pd, pvd->pvd_pid, false, NULL))
		PFS_RETURN (ENOENT);
	namelen = cnp->cn_namelen;
	pname = cnp->cn_nameptr;
	if (namelen == 1 && pname[0] == '.') {
		pn = pd;
		*vpp = vn;
		VREF(vn);
		PFS_RETURN (0);
	}
	mp = vn->v_mount;
	if (cnp->cn_flags & ISDOTDOT) {
		if (pd->pn_type == pfstype_root)
			PFS_RETURN (EIO);
		error = vfs_busy(mp, MBF_NOWAIT);
		if (error != 0) {
			vfs_ref(mp);
			VOP_UNLOCK(vn, 0);
			error = vfs_busy(mp, 0);
			vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
			vfs_rel(mp);
			if (error != 0)
				PFS_RETURN(ENOENT);
			if (vn->v_iflag & VI_DOOMED) {
				vfs_unbusy(mp);
				PFS_RETURN(ENOENT);
			}
		}
		VOP_UNLOCK(vn, 0);
		KASSERT(pd->pn_parent != NULL,
		    ("%s(): non-root directory has no parent", __func__));
		if (pd->pn_type == pfstype_procdir)
			pid = NO_PID;
		pfs_lock(pd);
		pn = pd->pn_parent;
		pfs_unlock(pd);
		goto got_pnode;
	}
	pfs_lock(pd);
	for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next)
		if (pn->pn_type == pfstype_procdir)
			pdn = pn;
		else if (pn->pn_name[namelen] == '\0' &&
		    bcmp(pname, pn->pn_name, namelen) == 0) {
			pfs_unlock(pd);
			goto got_pnode;
		}
	if ((pn = pdn) != NULL) {
		pid = 0;
		for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i)
			if ((pid = pid * 10 + pname[i] - '0') > PID_MAX)
				break;
		if (i == cnp->cn_namelen) {
			pfs_unlock(pd);
			goto got_pnode;
		}
	}
	pfs_unlock(pd);
	PFS_RETURN (ENOENT);
 got_pnode:
	pfs_assert_not_owned(pd);
	pfs_assert_not_owned(pn);
	visible = pfs_visible(curthread, pn, pid, false, NULL);
	if (!visible) {
		error = ENOENT;
		goto failed;
	}
	error = pfs_vncache_alloc(mp, vpp, pn, pid);
	if (error)
		goto failed;
	if (cnp->cn_flags & ISDOTDOT) {
		vfs_unbusy(mp);
		vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
		if (vn->v_iflag & VI_DOOMED) {
			vput(*vpp);
			*vpp = NULL;
			PFS_RETURN(ENOENT);
		}
	}
	if (cnp->cn_flags & MAKEENTRY && !(vn->v_iflag & VI_DOOMED))
		cache_enter(vn, *vpp, cnp);
	PFS_RETURN (0);
 failed:
	if (cnp->cn_flags & ISDOTDOT) {
		vfs_unbusy(mp);
		vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
		*vpp = NULL;
	}
	PFS_RETURN(error);
}
static int pfs_lookup ( struct vop_cachedlookup_args * va ) { struct vnode * vn = va -> a_dvp ; struct vnode * * vpp = va -> a_vpp ; struct componentname * cnp = va -> a_cnp ; struct pfs_vdata * pvd = vn -> v_data ; struct pfs_node * pd = pvd -> pvd_pn ; struct pfs_node * pn , * pdn = NULL ; struct mount * mp ; pid_t pid = pvd -> pvd_pid ; char * pname ; int error , i , namelen , visible ; PFS_TRACE ( ( " " , ( int ) cnp -> cn_namelen , cnp -> cn_nameptr ) ) ; pfs_assert_not_owned ( pd ) ; if ( vn -> v_type != VDIR ) PFS_RETURN ( ENOTDIR ) ; KASSERT_PN_IS_DIR ( pd ) ; error = VOP_ACCESS ( vn , VEXEC , cnp -> cn_cred , cnp -> cn_thread ) ; if ( error ) PFS_RETURN ( error ) ; if ( ( cnp -> cn_flags & ISLASTCN ) && ( cnp -> cn_nameiop == DELETE || cnp -> cn_nameiop == RENAME ) ) PFS_RETURN ( EOPNOTSUPP ) ; if ( cnp -> cn_namelen >= PFS_NAMELEN ) PFS_RETURN ( ENOENT ) ; if ( ! pfs_visible ( curthread , pd , pvd -> pvd_pid , false , NULL ) ) PFS_RETURN ( ENOENT ) ; namelen = cnp -> cn_namelen ; pname = cnp -> cn_nameptr ; if ( namelen == 1 && pname [ 0 ] == ' ' ) { pn = pd ; * vpp = vn ; VREF ( vn ) ; PFS_RETURN ( 0 ) ; } mp = vn -> v_mount ; if ( cnp -> cn_flags & ISDOTDOT ) { if ( pd -> pn_type == pfstype_root ) PFS_RETURN ( EIO ) ; error = vfs_busy ( mp , MBF_NOWAIT ) ; if ( error != 0 ) { vfs_ref ( mp ) ; VOP_UNLOCK ( vn , 0 ) ; error = vfs_busy ( mp , 0 ) ; vn_lock ( vn , LK_EXCLUSIVE | LK_RETRY ) ; vfs_rel ( mp ) ; if ( error != 0 ) PFS_RETURN ( ENOENT ) ; if ( vn -> v_iflag & VI_DOOMED ) { vfs_unbusy ( mp ) ; PFS_RETURN ( ENOENT ) ; } } VOP_UNLOCK ( vn , 0 ) ; KASSERT ( pd -> pn_parent != NULL , ( " " , __func__ ) ) ; if ( pd -> pn_type == pfstype_procdir ) pid = NO_PID ; pfs_lock ( pd ) ; pn = pd -> pn_parent ; pfs_unlock ( pd ) ; goto got_pnode ; } pfs_lock ( pd ) ; for ( pn = pd -> pn_nodes ; pn != NULL ; pn = pn -> pn_next ) if ( pn -> pn_type == pfstype_procdir ) pdn = pn ; else if ( pn -> pn_name [ namelen ] == ' \0 ' && bcmp ( pname , pn -> pn_name , namelen ) == 0 ) { pfs_unlock ( pd ) ; goto got_pnode ; } if ( ( pn = pdn ) != NULL ) { pid = 0 ; for ( pid = 0 , i = 0 ; i < namelen && isdigit ( pname [ i ] ) ; ++ i ) if ( ( pid = pid * 10 + pname [ i ] - ' ' ) > PID_MAX ) break ; if ( i == cnp -> cn_namelen ) { pfs_unlock ( pd ) ; goto got_pnode ; } } pfs_unlock ( pd ) ; PFS_RETURN ( ENOENT ) ; got_pnode : pfs_assert_not_owned ( pd ) ; pfs_assert_not_owned ( pn ) ; visible = pfs_visible ( curthread , pn , pid , false , NULL ) ; if ( ! visible ) { error = ENOENT ; goto failed ; } error = pfs_vncache_alloc ( mp , vpp , pn , pid ) ; if ( error ) goto failed ; if ( cnp -> cn_flags & ISDOTDOT ) { vfs_unbusy ( mp ) ; vn_lock ( vn , LK_EXCLUSIVE | LK_RETRY ) ; if ( vn -> v_iflag & VI_DOOMED ) { vput ( * vpp ) ; * vpp = NULL ; PFS_RETURN ( ENOENT ) ; } } if ( cnp -> cn_flags & MAKEENTRY && ! ( vn -> v_iflag & VI_DOOMED ) ) cache_enter ( vn , * vpp , cnp ) ; PFS_RETURN ( 0 ) ; failed : if ( cnp -> cn_flags & ISDOTDOT ) { vfs_unbusy ( mp ) ; vn_lock ( vn , LK_EXCLUSIVE | LK_RETRY ) ; * vpp = NULL ; } PFS_RETURN ( error ) ; }
Look up a file or directory
Look up a file or directory
/*
	 * Don't support DELETE or RENAME.  CREATE is supported so
	 * that O_CREAT will work, but the lookup will still fail if
	 * the file does not exist.
	 */ /* shortcut: check if the name is too long */ /* check that parent directory is visible... */ /* self */ /* parent */ /*
		 * This one is tricky.  Descendents of procdir nodes
		 * inherit their parent's process affinity, but
		 * there's no easy reverse mapping.  For simplicity,
		 * we assume that if this node is a procdir, its
		 * parent isn't (which is correct as long as
		 * descendents of procdir nodes are never procdir
		 * nodes themselves)
		 */ /* named node */ /* process dependent node */