コード例 #1
0
ファイル: fdesc_vnops.c プロジェクト: hmatyschok/MeshBSD
int
fdesc_allocvp(fdntype ftype, unsigned fd_fd, int ix, struct mount *mp,
    struct vnode **vpp)
{
	struct fdescmount *fmp;
	struct fdhashhead *fc;
	struct fdescnode *fd, *fd2;
	struct vnode *vp, *vp2;
	struct thread *td;
	int error = 0;

	td = curthread;
	fc = FD_NHASH(ix);
loop:
	mtx_lock(&fdesc_hashmtx);
	/*
	 * If a forced unmount is progressing, we need to drop it. The flags are
	 * protected by the hashmtx.
	 */
	fmp = (struct fdescmount *)mp->mnt_data;
	if (fmp == NULL || fmp->flags & FMNT_UNMOUNTF) {
		mtx_unlock(&fdesc_hashmtx);
		return (-1);
	}

	LIST_FOREACH(fd, fc, fd_hash) {
		if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
			/* Get reference to vnode in case it's being free'd */
			vp = fd->fd_vnode;
			VI_LOCK(vp);
			mtx_unlock(&fdesc_hashmtx);
			if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td))
				goto loop;
			*vpp = vp;
			return (0);
		}
	}
	mtx_unlock(&fdesc_hashmtx);

	fd = malloc(sizeof(struct fdescnode), M_TEMP, M_WAITOK);

	error = getnewvnode("fdescfs", mp, &fdesc_vnodeops, &vp);
	if (error) {
		free(fd, M_TEMP);
		return (error);
	}
	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
	vp->v_data = fd;
	fd->fd_vnode = vp;
	fd->fd_type = ftype;
	fd->fd_fd = fd_fd;
	fd->fd_ix = ix;
	error = insmntque1(vp, mp, fdesc_insmntque_dtr, NULL);
	if (error != 0) {
		*vpp = NULLVP;
		return (error);
	}

	/* Make sure that someone didn't beat us when inserting the vnode. */
	mtx_lock(&fdesc_hashmtx);
	/*
	 * If a forced unmount is progressing, we need to drop it. The flags are
	 * protected by the hashmtx.
	 */
	fmp = (struct fdescmount *)mp->mnt_data;
	if (fmp == NULL || fmp->flags & FMNT_UNMOUNTF) {
		mtx_unlock(&fdesc_hashmtx);
		vgone(vp);
		vput(vp);
		*vpp = NULLVP;
		return (-1);
	}

	LIST_FOREACH(fd2, fc, fd_hash) {
		if (fd2->fd_ix == ix && fd2->fd_vnode->v_mount == mp) {
			/* Get reference to vnode in case it's being free'd */
			vp2 = fd2->fd_vnode;
			VI_LOCK(vp2);
			mtx_unlock(&fdesc_hashmtx);
			error = vget(vp2, LK_EXCLUSIVE | LK_INTERLOCK, td);
			/* Someone beat us, dec use count and wait for reclaim */
			vgone(vp);
			vput(vp);
			/* If we didn't get it, return no vnode. */
			if (error)
				vp2 = NULLVP;
			*vpp = vp2;
			return (error);
		}
	}

	/* If we came here, we can insert it safely. */
	LIST_INSERT_HEAD(fc, fd, fd_hash);
	mtx_unlock(&fdesc_hashmtx);
	*vpp = vp;
	return (0);
}
コード例 #2
0
/*
 * Make a new or get existing pefs node.
 * vp is the alias vnode
 * lvp is the lower vnode
 * ldvp is the lower directory vnode, used if no key specified
 *
 * The lvp assumed to be locked and having "spare" reference. This routine
 * vrele lvp if pefs node was taken from hash. Otherwise it "transfers" the
 * caller's "spare" reference to created pefs vnode.
 */
static int
pefs_node_get(struct mount *mp, struct vnode *lvp, struct vnode **vpp,
    pefs_node_init_fn *init_fn, void *context)
{
	struct pefs_node *pn;
	struct vnode *vp;
	int error;

	ASSERT_VOP_LOCKED(lvp, "pefs_node_get");
	/* Lookup the hash firstly */
	*vpp = pefs_nodehash_get(mp, lvp);
	if (*vpp != NULL) {
		vrele(lvp);
		return (0);
	}

	/*
	 * We do not serialize vnode creation, instead we will check for
	 * duplicates later, when adding new vnode to hash.
	 *
	 * Note that duplicate can only appear in hash if the lvp is
	 * locked LK_SHARED.
	 */

	/*
	 * Do the MALLOC before the getnewvnode since doing so afterward
	 * might cause a bogus v_data pointer to get dereferenced
	 * elsewhere if MALLOC should block.
	 */
	pn = uma_zalloc(pefs_node_zone, M_WAITOK | M_ZERO);
	pn->pn_lowervp = lvp;

	/* pn->pn_lowervp should be initialized before calling init_fn. */
	error = init_fn(mp, pn, context);
	MPASS(!(((pn->pn_flags & PN_HASKEY) == 0) ^
	    (pn->pn_tkey.ptk_key == NULL)));
	if (error != 0) {
		uma_zfree(pefs_node_zone, pn);
		return (error);
	}

	error = getnewvnode("pefs", mp, &pefs_vnodeops, &vp);
	if (error != 0) {
		pefs_key_release(pn->pn_tkey.ptk_key);
		uma_zfree(pefs_node_zone, pn);
		return (error);
	}

	if (pn->pn_tkey.ptk_key == NULL)
		PEFSDEBUG("pefs_node_get: creating node without key: %p\n", pn);

	pn->pn_vnode = vp;
	vp->v_type = lvp->v_type;
	vp->v_data = pn;
	vp->v_vnlock = lvp->v_vnlock;
	if (vp->v_vnlock == NULL)
		panic("pefs_node_get: Passed a NULL vnlock.\n");
	error = insmntque1(vp, mp, pefs_insmntque_dtr, pn);
	if (error != 0)
		return (error);
	/*
	 * Atomically insert our new node into the hash or vget existing
	 * if someone else has beaten us to it.
	 */
	*vpp = pefs_nodehash_insert(mp, pn);
	if (*vpp != NULL) {
		vrele(lvp);
		vp->v_vnlock = &vp->v_lock;
		pn->pn_lowervp = NULL;
		vrele(vp);
		MPASS(PEFS_LOWERVP(*vpp) == lvp);
		ASSERT_VOP_LOCKED(*vpp, "pefs_node_get: duplicate");
		return (0);
	}
	if (vp->v_type == VDIR)
		pn->pn_dircache = pefs_dircache_get();
	*vpp = vp;
	MPASS(PEFS_LOWERVP(*vpp) == lvp);
	ASSERT_VOP_LOCKED(*vpp, "pefs_node_get");

	return (0);
}