union_subr.c

来自「早期freebsd实现」· C语言 代码 · 共 745 行 · 第 1/2 页

C
745
字号
	 * otherwise lock the vp list while we call getnewvnode	 * since that can block.	 */ 	hash = UNION_HASH(uppervp, lowervp);	if (union_list_lock(hash))		goto loop;	error = getnewvnode(VT_UNION, mp, union_vnodeop_p, vpp);	if (error) {		if (uppervp) {			if (dvp == uppervp)				vrele(uppervp);			else				vput(uppervp);		}		if (lowervp)			vrele(lowervp);		goto out;	}	MALLOC((*vpp)->v_data, void *, sizeof(struct union_node),		M_TEMP, M_WAITOK);	if (uppervp)		(*vpp)->v_type = uppervp->v_type;	else		(*vpp)->v_type = lowervp->v_type;	un = VTOUNION(*vpp);	un->un_vnode = *vpp;	un->un_uppervp = uppervp;	un->un_lowervp = lowervp;	un->un_openl = 0;	un->un_flags = UN_LOCKED;	if (un->un_uppervp)		un->un_flags |= UN_ULOCK;#ifdef DIAGNOSTIC	if (curproc)		un->un_pid = curproc->p_pid;	else		un->un_pid = -1;#endif	if (cnp && (lowervp != NULLVP) && (lowervp->v_type == VREG)) {		un->un_hash = cnp->cn_hash;		un->un_path = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK);		bcopy(cnp->cn_nameptr, un->un_path, cnp->cn_namelen);		un->un_path[cnp->cn_namelen] = '\0';		VREF(dvp);		un->un_dirvp = dvp;	} else {		un->un_hash = 0;		un->un_path = 0;		un->un_dirvp = 0;	}	LIST_INSERT_HEAD(&unhead[hash], un, un_cache);	if (xlowervp)		vrele(xlowervp);out:	union_list_unlock(hash);	return (error);}intunion_freevp(vp)	struct vnode *vp;{	struct union_node *un = VTOUNION(vp);	LIST_REMOVE(un, un_cache);	if (un->un_uppervp)		vrele(un->un_uppervp);	if (un->un_lowervp)		vrele(un->un_lowervp);	if (un->un_dirvp)		vrele(un->un_dirvp);	if (un->un_path)		free(un->un_path, M_TEMP);	FREE(vp->v_data, M_TEMP);	vp->v_data = 0;	return (0);}/* * copyfile.  copy the vnode (fvp) to the vnode (tvp) * using a sequence of reads and writes.  both (fvp) * and (tvp) are locked on entry and exit. */intunion_copyfile(p, cred, fvp, tvp)	struct proc *p;	struct ucred *cred;	struct vnode *fvp;	struct vnode *tvp;{	char *buf;	struct uio uio;	struct iovec iov;	int error = 0;	/*	 * strategy:	 * allocate a buffer of size MAXBSIZE.	 * loop doing reads and writes, keeping track	 * of the current uio offset.	 * give up at the first sign of trouble.	 */	uio.uio_procp = p;	uio.uio_segflg = UIO_SYSSPACE;	uio.uio_offset = 0;	VOP_UNLOCK(fvp);				/* XXX */	LEASE_CHECK(fvp, p, cred, LEASE_READ);	VOP_LOCK(fvp);					/* XXX */	VOP_UNLOCK(tvp);				/* XXX */	LEASE_CHECK(tvp, p, cred, LEASE_WRITE);	VOP_LOCK(tvp);					/* XXX */	buf = malloc(MAXBSIZE, M_TEMP, M_WAITOK);	/* ugly loop follows... */	do {		off_t offset = uio.uio_offset;		uio.uio_iov = &iov;		uio.uio_iovcnt = 1;		iov.iov_base = buf;		iov.iov_len = MAXBSIZE;		uio.uio_resid = iov.iov_len;		uio.uio_rw = UIO_READ;		error = VOP_READ(fvp, &uio, 0, cred);		if (error == 0) {			uio.uio_iov = &iov;			uio.uio_iovcnt = 1;			iov.iov_base = buf;			iov.iov_len = MAXBSIZE - uio.uio_resid;			uio.uio_offset = offset;			uio.uio_rw = UIO_WRITE;			uio.uio_resid = iov.iov_len;			if (uio.uio_resid == 0)				break;			do {				error = VOP_WRITE(tvp, &uio, 0, cred);			} while ((uio.uio_resid > 0) && (error == 0));		}	} while (error == 0);	free(buf, M_TEMP);	return (error);}/* * Create a shadow directory in the upper layer. * The new vnode is returned locked. * * (um) points to the union mount structure for access to the * the mounting process's credentials. * (dvp) is the directory in which to create the shadow directory. * it is unlocked on entry and exit. * (cnp) is the componentname to be created. * (vpp) is the returned newly created shadow directory, which * is returned locked. */intunion_mkshadow(um, dvp, cnp, vpp)	struct union_mount *um;	struct vnode *dvp;	struct componentname *cnp;	struct vnode **vpp;{	int error;	struct vattr va;	struct proc *p = cnp->cn_proc;	struct componentname cn;	/*	 * policy: when creating the shadow directory in the	 * upper layer, create it owned by the user who did	 * the mount, group from parent directory, and mode	 * 777 modified by umask (ie mostly identical to the	 * mkdir syscall).  (jsp, kb)	 */	/*	 * A new componentname structure must be faked up because	 * there is no way to know where the upper level cnp came	 * from or what it is being used for.  This must duplicate	 * some of the work done by NDINIT, some of the work done	 * by namei, some of the work done by lookup and some of	 * the work done by VOP_LOOKUP when given a CREATE flag.	 * Conclusion: Horrible.	 *	 * The pathname buffer will be FREEed by VOP_MKDIR.	 */	cn.cn_pnbuf = malloc(cnp->cn_namelen+1, M_NAMEI, M_WAITOK);	bcopy(cnp->cn_nameptr, cn.cn_pnbuf, cnp->cn_namelen);	cn.cn_pnbuf[cnp->cn_namelen] = '\0';	cn.cn_nameiop = CREATE;	cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);	cn.cn_proc = cnp->cn_proc;	if (um->um_op == UNMNT_ABOVE)		cn.cn_cred = cnp->cn_cred;	else		cn.cn_cred = um->um_cred;	cn.cn_nameptr = cn.cn_pnbuf;	cn.cn_namelen = cnp->cn_namelen;	cn.cn_hash = cnp->cn_hash;	cn.cn_consume = cnp->cn_consume;	VREF(dvp);	if (error = relookup(dvp, vpp, &cn))		return (error);	vrele(dvp);	if (*vpp) {		VOP_ABORTOP(dvp, &cn);		VOP_UNLOCK(dvp);		vrele(*vpp);		*vpp = NULLVP;		return (EEXIST);	}	VATTR_NULL(&va);	va.va_type = VDIR;	va.va_mode = um->um_cmode;	/* LEASE_CHECK: dvp is locked */	LEASE_CHECK(dvp, p, p->p_ucred, LEASE_WRITE);	error = VOP_MKDIR(dvp, vpp, &cn, &va);	return (error);}/* * union_vn_create: creates and opens a new shadow file * on the upper union layer.  this function is similar * in spirit to calling vn_open but it avoids calling namei(). * the problem with calling namei is that a) it locks too many * things, and b) it doesn't start at the "right" directory, * whereas relookup is told where to start. */intunion_vn_create(vpp, un, p)	struct vnode **vpp;	struct union_node *un;	struct proc *p;{	struct vnode *vp;	struct ucred *cred = p->p_ucred;	struct vattr vat;	struct vattr *vap = &vat;	int fmode = FFLAGS(O_WRONLY|O_CREAT|O_TRUNC|O_EXCL);	int error;	int cmode = UN_FILEMODE & ~p->p_fd->fd_cmask;	char *cp;	struct componentname cn;	*vpp = NULLVP;	/*	 * Build a new componentname structure (for the same	 * reasons outlines in union_mkshadow).	 * The difference here is that the file is owned by	 * the current user, rather than by the person who	 * did the mount, since the current user needs to be	 * able to write the file (that's why it is being	 * copied in the first place).	 */	cn.cn_namelen = strlen(un->un_path);	cn.cn_pnbuf = (caddr_t) malloc(cn.cn_namelen, M_NAMEI, M_WAITOK);	bcopy(un->un_path, cn.cn_pnbuf, cn.cn_namelen+1);	cn.cn_nameiop = CREATE;	cn.cn_flags = (LOCKPARENT|HASBUF|SAVENAME|SAVESTART|ISLASTCN);	cn.cn_proc = p;	cn.cn_cred = p->p_ucred;	cn.cn_nameptr = cn.cn_pnbuf;	cn.cn_hash = un->un_hash;	cn.cn_consume = 0;	VREF(un->un_dirvp);	if (error = relookup(un->un_dirvp, &vp, &cn))		return (error);	vrele(un->un_dirvp);	if (vp) {		VOP_ABORTOP(un->un_dirvp, &cn);		if (un->un_dirvp == vp)			vrele(un->un_dirvp);		else			vput(un->un_dirvp);		vrele(vp);		return (EEXIST);	}	/*	 * Good - there was no race to create the file	 * so go ahead and create it.  The permissions	 * on the file will be 0666 modified by the	 * current user's umask.  Access to the file, while	 * it is unioned, will require access to the top *and*	 * bottom files.  Access when not unioned will simply	 * require access to the top-level file.	 * TODO: confirm choice of access permissions.	 */	VATTR_NULL(vap);	vap->va_type = VREG;	vap->va_mode = cmode;	LEASE_CHECK(un->un_dirvp, p, cred, LEASE_WRITE);	if (error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap))		return (error);	if (error = VOP_OPEN(vp, fmode, cred, p)) {		vput(vp);		return (error);	}	vp->v_writecount++;	*vpp = vp;	return (0);}intunion_vn_close(vp, fmode, cred, p)	struct vnode *vp;	int fmode;	struct ucred *cred;	struct proc *p;{	if (fmode & FWRITE)		--vp->v_writecount;	return (VOP_CLOSE(vp, fmode));}voidunion_removed_upper(un)	struct union_node *un;{	if (un->un_flags & UN_ULOCK) {		un->un_flags &= ~UN_ULOCK;		VOP_UNLOCK(un->un_uppervp);	}	union_newupper(un, NULLVP);}struct vnode *union_lowervp(vp)	struct vnode *vp;{	struct union_node *un = VTOUNION(vp);	if (un->un_lowervp && (vp->v_type == un->un_lowervp->v_type)) {		if (vget(un->un_lowervp, 0))			return (NULLVP);	}	return (un->un_lowervp);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?