vfs_subr.c

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

C
2,733
字号
	if (argp->ex_flags & MNT_DELEXPORT) {		if (mp->mnt_flag & MNT_EXPUBLIC) {			vfs_setpublicfs(NULL, NULL, NULL);			mp->mnt_flag &= ~MNT_EXPUBLIC;		}		vfs_free_addrlist(nep);		mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED);	}	if (argp->ex_flags & MNT_EXPORTED) {		if (argp->ex_flags & MNT_EXPUBLIC) {			if ((error = vfs_setpublicfs(mp, nep, argp)) != 0)				return (error);			mp->mnt_flag |= MNT_EXPUBLIC;		}		if ((error = vfs_hang_addrlist(mp, nep, argp)) != 0)			return (error);		mp->mnt_flag |= MNT_EXPORTED;	}	return (0);}/* * Set the publicly exported filesystem (WebNFS). Currently, only * one public filesystem is possible in the spec (RFC 2054 and 2055) */intvfs_setpublicfs(mp, nep, argp)	struct mount *mp;	struct netexport *nep;	struct export_args *argp;{	int error;	struct vnode *rvp;	char *cp;	/*	 * mp == NULL -> invalidate the current info, the FS is	 * no longer exported. May be called from either vfs_export	 * or unmount, so check if it hasn't already been done.	 */	if (mp == NULL) {		if (nfs_pub.np_valid) {			nfs_pub.np_valid = 0;			if (nfs_pub.np_index != NULL) {				FREE(nfs_pub.np_index, M_TEMP);				nfs_pub.np_index = NULL;			}		}		return (0);	}	/*	 * Only one allowed at a time.	 */	if (nfs_pub.np_valid != 0 && mp != nfs_pub.np_mount)		return (EBUSY);	/*	 * Get real filehandle for root of exported FS.	 */	memset((caddr_t)&nfs_pub.np_handle, 0, sizeof(nfs_pub.np_handle));	nfs_pub.np_handle.fh_fsid = mp->mnt_stat.f_fsid;	if ((error = VFS_ROOT(mp, &rvp)))		return (error);	if ((error = VFS_VPTOFH(rvp, &nfs_pub.np_handle.fh_fid)))		return (error);	vput(rvp);	/*	 * If an indexfile was specified, pull it in.	 */	if (argp->ex_indexfile != NULL) {		MALLOC(nfs_pub.np_index, char *, MAXNAMLEN + 1, M_TEMP,		    M_WAITOK);		error = copyinstr(argp->ex_indexfile, nfs_pub.np_index,		    MAXNAMLEN, (size_t *)0);		if (!error) {			/*			 * Check for illegal filenames.			 */			for (cp = nfs_pub.np_index; *cp; cp++) {				if (*cp == '/') {					error = EINVAL;					break;				}			}		}		if (error) {			FREE(nfs_pub.np_index, M_TEMP);			return (error);		}	}	nfs_pub.np_mount = mp;	nfs_pub.np_valid = 1;	return (0);}struct netcred *vfs_export_lookup(mp, nep, nam)	struct mount *mp;	struct netexport *nep;	struct mbuf *nam;{	struct netcred *np;	struct radix_node_head *rnh;	struct sockaddr *saddr;	np = NULL;	if (mp->mnt_flag & MNT_EXPORTED) {		/*		 * Lookup in the export list first.		 */		if (nam != NULL) {			saddr = mtod(nam, struct sockaddr *);			rnh = nep->ne_rtable[saddr->sa_family];			if (rnh != NULL) {				np = (struct netcred *)					(*rnh->rnh_matchaddr)((caddr_t)saddr,							      rnh);				if (np && np->netc_rnodes->rn_flags & RNF_ROOT)					np = NULL;			}		}		/*		 * If no address match, use the default if it exists.		 */		if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED)			np = &nep->ne_defexported;	}	return (np);}/* * Do the usual access checking. * file_mode, uid and gid are from the vnode in question, * while acc_mode and cred are from the VOP_ACCESS parameter list */intvaccess(type, file_mode, uid, gid, acc_mode, cred)	enum vtype type;	mode_t file_mode;	uid_t uid;	gid_t gid;	mode_t acc_mode;	struct ucred *cred;{	mode_t mask;		/*	 * Super-user always gets read/write access, but execute access depends	 * on at least one execute bit being set.	 */	if (cred->cr_uid == 0) {		if ((acc_mode & VEXEC) && type != VDIR &&		    (file_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)			return (EACCES);		return (0);	}		mask = 0;		/* Otherwise, check the owner. */	if (cred->cr_uid == uid) {		if (acc_mode & VEXEC)			mask |= S_IXUSR;		if (acc_mode & VREAD)			mask |= S_IRUSR;		if (acc_mode & VWRITE)			mask |= S_IWUSR;		return ((file_mode & mask) == mask ? 0 : EACCES);	}		/* Otherwise, check the groups. */	if (cred->cr_gid == gid || groupmember(gid, cred)) {		if (acc_mode & VEXEC)			mask |= S_IXGRP;		if (acc_mode & VREAD)			mask |= S_IRGRP;		if (acc_mode & VWRITE)			mask |= S_IWGRP;		return ((file_mode & mask) == mask ? 0 : EACCES);	}		/* Otherwise, check everyone else. */	if (acc_mode & VEXEC)		mask |= S_IXOTH;	if (acc_mode & VREAD)		mask |= S_IROTH;	if (acc_mode & VWRITE)		mask |= S_IWOTH;	return ((file_mode & mask) == mask ? 0 : EACCES);}/* * Unmount all file systems. * We traverse the list in reverse order under the assumption that doing so * will avoid needing to worry about dependencies. */voidvfs_unmountall(p)	struct proc *p;{	struct mount *mp, *nmp;	int allerror, error;	for (allerror = 0,	     mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) {		nmp = mp->mnt_list.cqe_prev;#ifdef DEBUG		printf("unmounting %s (%s)...\n",		    mp->mnt_stat.f_mntonname, mp->mnt_stat.f_mntfromname);#endif		if (vfs_busy(mp, 0, 0))			continue;		if ((error = dounmount(mp, MNT_FORCE, p)) != 0) {			printf("unmount of %s failed with error %d\n",			    mp->mnt_stat.f_mntonname, error);			allerror = 1;		}	}	if (allerror)		printf("WARNING: some file systems would not unmount\n");}/* * Sync and unmount file systems before shutting down. */voidvfs_shutdown(){	struct buf *bp;	int iter, nbusy, nbusy_prev = 0, dcount, s;	struct proc *p = curproc;	/* XXX we're certainly not running in proc0's context! */	if (p == NULL)		p = &proc0;		printf("syncing disks... ");	/* remove user process from run queue */	suspendsched();	(void) spl0();	/* avoid coming back this way again if we panic. */	doing_shutdown = 1;	sys_sync(p, NULL, NULL);	/* Wait for sync to finish. */	dcount = 10000;	for (iter = 0; iter < 20;) {		nbusy = 0;		for (bp = &buf[nbuf]; --bp >= buf; ) {			if ((bp->b_flags & (B_BUSY|B_INVAL|B_READ)) == B_BUSY)				nbusy++;			/*			 * With soft updates, some buffers that are			 * written will be remarked as dirty until other			 * buffers are written.			 */			if (bp->b_vp && bp->b_vp->v_mount			    && (bp->b_vp->v_mount->mnt_flag & MNT_SOFTDEP)			    && (bp->b_flags & B_DELWRI)) {				s = splbio();				bremfree(bp);				bp->b_flags |= B_BUSY;				splx(s);				nbusy++;				bawrite(bp);				if (dcount-- <= 0) {					printf("softdep ");					goto fail;				}			}		}		if (nbusy == 0)			break;		if (nbusy_prev == 0)			nbusy_prev = nbusy;		printf("%d ", nbusy);		tsleep(&nbusy, PRIBIO, "bflush",		    (iter == 0) ? 1 : hz / 25 * iter);		if (nbusy >= nbusy_prev) /* we didn't flush anything */			iter++;		else			nbusy_prev = nbusy;	}	if (nbusy) {fail:#if defined(DEBUG) || defined(DEBUG_HALT_BUSY)		printf("giving up\nPrinting vnodes for busy buffers\n");		for (bp = &buf[nbuf]; --bp >= buf; )			if ((bp->b_flags & (B_BUSY|B_INVAL|B_READ)) == B_BUSY)				vprint(NULL, bp->b_vp);#if defined(DDB) && defined(DEBUG_HALT_BUSY)		Debugger();#endif#else  /* defined(DEBUG) || defined(DEBUG_HALT_BUSY) */		printf("giving up\n");#endif /* defined(DEBUG) || defined(DEBUG_HALT_BUSY) */		return;	} else		printf("done\n");	/*	 * If we've panic'd, don't make the situation potentially	 * worse by unmounting the file systems.	 */	if (panicstr != NULL)		return;	/* Release inodes held by texts before update. */#ifdef notdef	vnshutdown();#endif	/* Unmount file systems. */	vfs_unmountall(p);}/* * Mount the root file system.  If the operator didn't specify a * file system to use, try all possible file systems until one * succeeds. */intvfs_mountroot(){	extern int (*mountroot) __P((void));	struct vfsops *v;	if (root_device == NULL)		panic("vfs_mountroot: root device unknown");	switch (root_device->dv_class) {	case DV_IFNET:		if (rootdev != NODEV)			panic("vfs_mountroot: rootdev set for DV_IFNET");		break;	case DV_DISK:		if (rootdev == NODEV)			panic("vfs_mountroot: rootdev not set for DV_DISK");		break;	default:		printf("%s: inappropriate for root file system\n",		    root_device->dv_xname);		return (ENODEV);	}	/*	 * If user specified a file system, use it.	 */	if (mountroot != NULL)		return ((*mountroot)());	/*	 * Try each file system currently configured into the kernel.	 */	for (v = LIST_FIRST(&vfs_list); v != NULL; v = LIST_NEXT(v, vfs_list)) {		if (v->vfs_mountroot == NULL)			continue;#ifdef DEBUG		printf("mountroot: trying %s...\n", v->vfs_name);#endif		if ((*v->vfs_mountroot)() == 0) {			printf("root file system type: %s\n", v->vfs_name);			break;		}	}	if (v == NULL) {		printf("no file system for %s", root_device->dv_xname);		if (root_device->dv_class == DV_DISK)			printf(" (dev 0x%x)", rootdev);		printf("\n");		return (EFTYPE);	}	return (0);}/* * Given a file system name, look up the vfsops for that * file system, or return NULL if file system isn't present * in the kernel. */struct vfsops *vfs_getopsbyname(name)	const char *name;{	struct vfsops *v;	for (v = LIST_FIRST(&vfs_list); v != NULL; v = LIST_NEXT(v, vfs_list)) {		if (strcmp(v->vfs_name, name) == 0)			break;	}	return (v);}/* * Establish a file system and initialize it. */intvfs_attach(vfs)	struct vfsops *vfs;{	struct vfsops *v;	int error = 0;	/*	 * Make sure this file system doesn't already exist.	 */	for (v = LIST_FIRST(&vfs_list); v != NULL; v = LIST_NEXT(v, vfs_list)) {		if (strcmp(vfs->vfs_name, v->vfs_name) == 0) {			error = EEXIST;			goto out;		}	}	/*	 * Initialize the vnode operations for this file system.	 */	vfs_opv_init(vfs->vfs_opv_descs);	/*	 * Now initialize the file system itself.	 */	(*vfs->vfs_init)();	/*	 * ...and link it into the kernel's list.	 */	LIST_INSERT_HEAD(&vfs_list, vfs, vfs_list);	/*	 * Sanity: make sure the reference count is 0.	 */	vfs->vfs_refcount = 0; out:	return (error);}/* * Remove a file system from the kernel. */intvfs_detach(vfs)	struct vfsops *vfs;{	struct vfsops *v;	/*	 * Make sure no one is using the filesystem.	 */	if (vfs->vfs_refcount != 0)		return (EBUSY);	/*	 * ...and remove it from the kernel's list.	 */	for (v = LIST_FIRST(&vfs_list); v != NULL; v = LIST_NEXT(v, vfs_list)) {		if (v == vfs) {			LIST_REMOVE(v, vfs_list);			break;		}	}	if (v == NULL)		return (ESRCH);	/*	 * Now run the file system-specific cleanups.	 */	(*vfs->vfs_done)();	/*	 * Free the vnode operations vector.	 */	vfs_opv_free(vfs->vfs_opv_descs);	return (0);}#ifdef DDBconst char buf_flagbits[] =	"\20\1AGE\2NEEDCOMMIT\3ASYNC\4BAD\5BUSY\6SCANNED\7CALL\10DELWRI"	"\11DIRTY\12DONE\13EINTR\14ERROR\15GATHERED\16INVAL\17LOCKED\20NOCACHE"	"\21ORDERED\22CACHE\23PHYS\24RAW\25READ\26TAPE\30WANTED"	"\32XXX\33VFLUSH";voidvfs_buf_print(bp, full, pr)	struct buf *bp;	int full;	void (*pr) __P((const char *, ...));{	char buf[1024];	(*pr)("  vp %p lblkno 0x%x blkno 0x%x dev 0x%x\n",		  bp->b_vp, bp->b_lblkno, bp->b_blkno, bp->b_dev);	bitmask_snprintf(bp->b_flags, buf_flagbits, buf, sizeof(buf));	(*pr)("  error %d flags 0x%s\n", bp->b_error, buf);	(*pr)("  bufsize 0x%x bcount 0x%x resid 0x%x\n",		  bp->b_bufsize, bp->b_bcount, bp->b_resid);	(*pr)("  data %p saveaddr %p dep %p\n",		  bp->b_data, bp->b_saveaddr, LIST_FIRST(&bp->b_dep));	(*pr)("  iodone %p\n", bp->b_iodone);}const char vnode_flagbits[] =	"\20\1ROOT\2TEXT\3SYSTEM\4ISTTY\11XLOCK\12XWANT\13BWAIT\14ALIASED"	"\15DIROP\17DIRTY";const char *vnode_types[] = {	"VNON",	"VREG",	"VDIR",	"VBLK",	"VCHR",	"VLNK",	"VSOCK",	"VFIFO",	"VBAD",};const char *vnode_tags[] = {	"VT_NON",	"VT_UFS",	"VT_NFS",	"VT_MFS",	"VT_MSDOSFS",	"VT_LFS",	"V

⌨️ 快捷键说明

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