vfs_subr.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,733 行 · 第 1/5 页

C
2,733
字号
		    "vgone", 0, &vp->v_interlock);		return;	}	/*	 * Clean out the filesystem specific data.	 */	vclean(vp, DOCLOSE, p);	/*	 * Delete from old mount point vnode list, if on one.	 */	if (vp->v_mount != NULL)		insmntque(vp, (struct mount *)0);	/*	 * If special device, remove it from special device alias list.	 * if it is on one.	 */	if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_specinfo != 0) {		simple_lock(&spechash_slock);		if (vp->v_hashchain != NULL) {			if (*vp->v_hashchain == vp) {				*vp->v_hashchain = vp->v_specnext;			} else {				for (vq = *vp->v_hashchain; vq;							vq = vq->v_specnext) {					if (vq->v_specnext != vp)						continue;					vq->v_specnext = vp->v_specnext;					break;				}				if (vq == NULL)					panic("missing bdev");			}			if (vp->v_flag & VALIASED) {				vx = NULL;				for (vq = *vp->v_hashchain; vq;							vq = vq->v_specnext) {					if (vq->v_rdev != vp->v_rdev ||					    vq->v_type != vp->v_type)						continue;					if (vx)						break;					vx = vq;				}				if (vx == NULL)					panic("missing alias");				if (vq == NULL)					vx->v_flag &= ~VALIASED;				vp->v_flag &= ~VALIASED;			}		}		simple_unlock(&spechash_slock);		FREE(vp->v_specinfo, M_VNODE);		vp->v_specinfo = NULL;	}	/*	 * If it is on the freelist and not already at the head,	 * move it to the head of the list. The test of the back	 * pointer and the reference count of zero is because	 * it will be removed from the free list by getnewvnode,	 * but will not have its reference count incremented until	 * after calling vgone. If the reference count were	 * incremented first, vgone would (incorrectly) try to	 * close the previous instance of the underlying object.	 * So, the back pointer is explicitly set to `0xdeadb' in	 * getnewvnode after removing it from the freelist to ensure	 * that we do not try to move it here.	 */	if (vp->v_usecount == 0) {		simple_lock(&vnode_free_list_slock);		if (vp->v_holdcnt > 0)			panic("vgonel: not clean, vp %p", vp);		if (vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb &&		    TAILQ_FIRST(&vnode_free_list) != vp) {			TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);			TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);		}		simple_unlock(&vnode_free_list_slock);	}	vp->v_type = VBAD;}/* * Lookup a vnode by device number. */intvfinddev(dev, type, vpp)	dev_t dev;	enum vtype type;	struct vnode **vpp;{	struct vnode *vp;	int rc = 0;	simple_lock(&spechash_slock);	for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {		if (dev != vp->v_rdev || type != vp->v_type)			continue;		*vpp = vp;		rc = 1;		break;	}	simple_unlock(&spechash_slock);	return (rc);}/* * Revoke all the vnodes corresponding to the specified minor number * range (endpoints inclusive) of the specified major. */voidvdevgone(maj, minl, minh, type)	int maj, minl, minh;	enum vtype type;{	struct vnode *vp;	int mn;	for (mn = minl; mn <= minh; mn++)		if (vfinddev(makedev(maj, mn), type, &vp))			VOP_REVOKE(vp, REVOKEALL);}/* * Calculate the total number of references to a special device. */intvcount(vp)	struct vnode *vp;{	struct vnode *vq, *vnext;	int count;loop:	if ((vp->v_flag & VALIASED) == 0)		return (vp->v_usecount);	simple_lock(&spechash_slock);	for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) {		vnext = vq->v_specnext;		if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)			continue;		/*		 * Alias, but not in use, so flush it out.		 */		if (vq->v_usecount == 0 && vq != vp) {			simple_unlock(&spechash_slock);			vgone(vq);			goto loop;		}		count += vq->v_usecount;	}	simple_unlock(&spechash_slock);	return (count);}#endif /*OSKIT*/#ifndef OSKIT/* * Print out a description of a vnode. */static char *typename[] =   { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };voidvprint(label, vp)	char *label;	struct vnode *vp;{	char buf[64];	if (label != NULL)		printf("%s: ", label);	printf("tag %d type %s, usecount %d, writecount %ld, refcount %ld,",	    vp->v_tag, typename[vp->v_type], vp->v_usecount, vp->v_writecount,	    vp->v_holdcnt);	buf[0] = '\0';	if (vp->v_flag & VROOT)		strcat(buf, "|VROOT");	if (vp->v_flag & VTEXT)		strcat(buf, "|VTEXT");	if (vp->v_flag & VSYSTEM)		strcat(buf, "|VSYSTEM");	if (vp->v_flag & VXLOCK)		strcat(buf, "|VXLOCK");	if (vp->v_flag & VXWANT)		strcat(buf, "|VXWANT");	if (vp->v_flag & VBWAIT)		strcat(buf, "|VBWAIT");	if (vp->v_flag & VALIASED)		strcat(buf, "|VALIASED");	if (buf[0] != '\0')		printf(" flags (%s)", &buf[1]);	if (vp->v_data == NULL) {		printf("\n");	} else {		printf("\n\t");#ifndef OSKIT		VOP_PRINT(vp);#endif	}}#ifdef DEBUG/* * List all of the locked vnodes in the system. * Called when debugging the kernel. */voidprintlockedvnodes(){	struct mount *mp, *nmp;	struct vnode *vp;	printf("Locked vnodes\n");	simple_lock(&mountlist_slock);	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {			nmp = mp->mnt_list.cqe_next;			continue;		}		for (vp = mp->mnt_vnodelist.lh_first;		     vp != NULL;		     vp = vp->v_mntvnodes.le_next) {			if (VOP_ISLOCKED(vp))				vprint((char *)0, vp);		}		simple_lock(&mountlist_slock);		nmp = mp->mnt_list.cqe_next;		vfs_unbusy(mp);	}	simple_unlock(&mountlist_slock);}#endifextern const char *mountcompatnames[];extern const int nmountcompatnames;/* * Top level filesystem related information gathering. */intvfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)	int *name;	u_int namelen;	void *oldp;	size_t *oldlenp;	void *newp;	size_t newlen;	struct proc *p;{#if defined(COMPAT_09) || defined(COMPAT_43) || defined(COMPAT_44)	struct vfsconf vfc;#endif	struct vfsops *vfsp;	/* all sysctl names at this level are at least name and field */	if (namelen < 2)		return (ENOTDIR);		/* overloaded */	/* Not generic: goes to file system. */	if (name[0] != VFS_GENERIC) {		if (name[0] >= nmountcompatnames || name[0] < 0 ||		    mountcompatnames[name[0]] == NULL)			return (EOPNOTSUPP);		vfsp = vfs_getopsbyname(mountcompatnames[name[0]]);		if (vfsp == NULL || vfsp->vfs_sysctl == NULL)			return (EOPNOTSUPP);		return ((*vfsp->vfs_sysctl)(&name[1], namelen - 1,		    oldp, oldlenp, newp, newlen, p));	}	/* The rest are generic vfs sysctls. */	switch (name[1]) {	case VFS_USERMOUNT:		return sysctl_int(oldp, oldlenp, newp, newlen, &dovfsusermount);#if defined(COMPAT_09) || defined(COMPAT_43) || defined(COMPAT_44)	case VFS_MAXTYPENUM:		/*		 * Provided for 4.4BSD-Lite2 compatibility.		 */		return (sysctl_rdint(oldp, oldlenp, newp, nmountcompatnames));	case VFS_CONF:		/*		 * Special: a node, next is a file system name.		 * Provided for 4.4BSD-Lite2 compatibility.		 */		if (namelen < 3)			return (ENOTDIR);	/* overloaded */		if (name[2] >= nmountcompatnames || name[2] < 0 ||		    mountcompatnames[name[2]] == NULL)			return (EOPNOTSUPP);		vfsp = vfs_getopsbyname(mountcompatnames[name[2]]);		if (vfsp == NULL)			return (EOPNOTSUPP);		vfc.vfc_vfsops = vfsp;		strncpy(vfc.vfc_name, vfsp->vfs_name, MFSNAMELEN);		vfc.vfc_typenum = name[2];		vfc.vfc_refcount = vfsp->vfs_refcount;		vfc.vfc_flags = 0;		vfc.vfc_mountroot = vfsp->vfs_mountroot;		vfc.vfc_next = NULL;		return (sysctl_rdstruct(oldp, oldlenp, newp, &vfc,		    sizeof(struct vfsconf)));#endif	default:		break;	}	return (EOPNOTSUPP);}int kinfo_vdebug = 1;int kinfo_vgetfailed;#define KINFO_VNODESLOP	10/* * Dump vnode list (via sysctl). * Copyout address of vnode followed by vnode. *//* ARGSUSED */intsysctl_vnode(where, sizep, p)	char *where;	size_t *sizep;	struct proc *p;{	struct mount *mp, *nmp;	struct vnode *nvp, *vp;	char *bp = where, *savebp;	char *ewhere;	int error;#define VPTRSZ	sizeof(struct vnode *)#define VNODESZ	sizeof(struct vnode)	if (where == NULL) {		*sizep = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);		return (0);	}	ewhere = where + *sizep;	simple_lock(&mountlist_slock);	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {			nmp = mp->mnt_list.cqe_next;			continue;		}		savebp = bp;again:		simple_lock(&mntvnode_slock);		for (vp = mp->mnt_vnodelist.lh_first;		     vp != NULL;		     vp = nvp) {			/*			 * Check that the vp is still associated with			 * this filesystem.  RACE: could have been			 * recycled onto the same filesystem.			 */			if (vp->v_mount != mp) {				simple_unlock(&mntvnode_slock);				if (kinfo_vdebug)					printf("kinfo: vp changed\n");				bp = savebp;				goto again;			}			nvp = vp->v_mntvnodes.le_next;			if (bp + VPTRSZ + VNODESZ > ewhere) {				simple_unlock(&mntvnode_slock);				*sizep = bp - where;				return (ENOMEM);			}			simple_unlock(&mntvnode_slock);			if ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||			   (error = copyout((caddr_t)vp, bp + VPTRSZ, VNODESZ)))				return (error);			bp += VPTRSZ + VNODESZ;			simple_lock(&mntvnode_slock);		}		simple_unlock(&mntvnode_slock);		simple_lock(&mountlist_slock);		nmp = mp->mnt_list.cqe_next;		vfs_unbusy(mp);	}	simple_unlock(&mountlist_slock);	*sizep = bp - where;	return (0);}/* * Check to see if a filesystem is mounted on a block device. */intvfs_mountedon(vp)	struct vnode *vp;{	struct vnode *vq;	int error = 0;	if (vp->v_specmountpoint != NULL)		return (EBUSY);	if (vp->v_flag & VALIASED) {		simple_lock(&spechash_slock);		for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {			if (vq->v_rdev != vp->v_rdev ||			    vq->v_type != vp->v_type)				continue;			if (vq->v_specmountpoint != NULL) {				error = EBUSY;				break;			}		}		simple_unlock(&spechash_slock);	}	return (error);}/* * Build hash lists of net addresses and hang them off the mount point. * Called by ufs_mount() to set up the lists of export addresses. */static intvfs_hang_addrlist(mp, nep, argp)	struct mount *mp;	struct netexport *nep;	struct export_args *argp;{	struct netcred *np, *enp;	struct radix_node_head *rnh;	int i;	struct radix_node *rn;	struct sockaddr *saddr, *smask = 0;	struct domain *dom;	int error;	if (argp->ex_addrlen == 0) {		if (mp->mnt_flag & MNT_DEFEXPORTED)			return (EPERM);		np = &nep->ne_defexported;		np->netc_exflags = argp->ex_flags;		np->netc_anon = argp->ex_anon;		np->netc_anon.cr_ref = 1;		mp->mnt_flag |= MNT_DEFEXPORTED;		return (0);	}	i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen;	np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK);	memset((caddr_t)np, 0, i);	saddr = (struct sockaddr *)(np + 1);	error = copyin(argp->ex_addr, (caddr_t)saddr, argp->ex_addrlen);	if (error)		goto out;	if (saddr->sa_len > argp->ex_addrlen)		saddr->sa_len = argp->ex_addrlen;	if (argp->ex_masklen) {		smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen);		error = copyin(argp->ex_mask, (caddr_t)smask, argp->ex_masklen);		if (error)			goto out;		if (smask->sa_len > argp->ex_masklen)			smask->sa_len = argp->ex_masklen;	}	i = saddr->sa_family;	if ((rnh = nep->ne_rtable[i]) == 0) {		/*		 * Seems silly to initialize every AF when most are not		 * used, do so on demand here		 */		for (dom = domains; dom; dom = dom->dom_next)			if (dom->dom_family == i && dom->dom_rtattach) {				dom->dom_rtattach((void **)&nep->ne_rtable[i],					dom->dom_rtoffset);				break;			}		if ((rnh = nep->ne_rtable[i]) == 0) {			error = ENOBUFS;			goto out;		}	}	rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh,		np->netc_rnodes);	if (rn == 0 || np != (struct netcred *)rn) { /* already exists */		if (rn == 0) {			enp = (struct netcred *)(*rnh->rnh_lookup)(saddr,				smask, rnh);			if (enp == 0) {				error = EPERM;				goto out;			}		} else 			enp = (struct netcred *)rn;		if (enp->netc_exflags != argp->ex_flags ||		    enp->netc_anon.cr_uid != argp->ex_anon.cr_uid ||		    enp->netc_anon.cr_gid != argp->ex_anon.cr_gid ||		    enp->netc_anon.cr_ngroups != argp->ex_anon.cr_ngroups ||		    memcmp(&enp->netc_anon.cr_groups, &argp->ex_anon.cr_groups,			enp->netc_anon.cr_ngroups))				error = EPERM;		else			error = 0;		goto out;	}	np->netc_exflags = argp->ex_flags;	np->netc_anon = argp->ex_anon;	np->netc_anon.cr_ref = 1;	return (0);out:	free(np, M_NETADDR);	return (error);}/* ARGSUSED */static intvfs_free_netcred(rn, w)	struct radix_node *rn;	void *w;{	struct radix_node_head *rnh = (struct radix_node_head *)w;	(*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);	free((caddr_t)rn, M_NETADDR);	return (0);}/* * Free the net address hash lists that are hanging off the mount points. */static voidvfs_free_addrlist(nep)	struct netexport *nep;{	int i;	struct radix_node_head *rnh;	for (i = 0; i <= AF_MAX; i++)		if ((rnh = nep->ne_rtable[i]) != NULL) {			(*rnh->rnh_walktree)(rnh, vfs_free_netcred, rnh);			free((caddr_t)rnh, M_RTABLE);			nep->ne_rtable[i] = 0;		}}intvfs_export(mp, nep, argp)	struct mount *mp;	struct netexport *nep;	struct export_args *argp;{	int error;

⌨️ 快捷键说明

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