xref: /csrg-svn/sys/ufs/ffs/ffs_vfsops.c (revision 68545)
123400Smckusick /*
266804Sbostic  * Copyright (c) 1989, 1991, 1993, 1994
363371Sbostic  *	The Regents of the University of California.  All rights reserved.
423400Smckusick  *
544539Sbostic  * %sccs.include.redist.c%
637737Smckusick  *
7*68545Smckusick  *	@(#)ffs_vfsops.c	8.18 (Berkeley) 03/20/95
823400Smckusick  */
912795Ssam 
1051473Sbostic #include <sys/param.h>
1151473Sbostic #include <sys/systm.h>
1251473Sbostic #include <sys/namei.h>
1351473Sbostic #include <sys/proc.h>
1451473Sbostic #include <sys/kernel.h>
1551473Sbostic #include <sys/vnode.h>
1655890Smckusick #include <sys/socket.h>
1751473Sbostic #include <sys/mount.h>
1851473Sbostic #include <sys/buf.h>
1954733Smckusick #include <sys/mbuf.h>
2051473Sbostic #include <sys/file.h>
2151473Sbostic #include <sys/disklabel.h>
2251473Sbostic #include <sys/ioctl.h>
2351473Sbostic #include <sys/errno.h>
2451473Sbostic #include <sys/malloc.h>
2512795Ssam 
2655045Smckusick #include <miscfs/specfs/specdev.h>
2755045Smckusick 
2851473Sbostic #include <ufs/ufs/quota.h>
2951473Sbostic #include <ufs/ufs/ufsmount.h>
3051473Sbostic #include <ufs/ufs/inode.h>
3151473Sbostic #include <ufs/ufs/ufs_extern.h>
3247571Skarels 
3351473Sbostic #include <ufs/ffs/fs.h>
3451473Sbostic #include <ufs/ffs/ffs_extern.h>
3551473Sbostic 
3651942Smckusick int ffs_sbupdate __P((struct ufsmount *, int));
3751473Sbostic 
3837737Smckusick struct vfsops ufs_vfsops = {
3951473Sbostic 	ffs_mount,
4039043Smckusick 	ufs_start,
4151473Sbostic 	ffs_unmount,
4266804Sbostic 	ufs_root,
4341314Smckusick 	ufs_quotactl,
4451473Sbostic 	ffs_statfs,
4551473Sbostic 	ffs_sync,
4654657Smckusick 	ffs_vget,
4751545Smckusick 	ffs_fhtovp,
4851545Smckusick 	ffs_vptofh,
4951473Sbostic 	ffs_init,
5037737Smckusick };
5137737Smckusick 
5254657Smckusick extern u_long nextgennumber;
5354657Smckusick 
5437737Smckusick /*
5553045Sralph  * Called by main() when ufs is going to be mounted as root.
5637737Smckusick  *
5739336Smckusick  * Name is updated by mount(8) after booting.
5837737Smckusick  */
5939297Smckusick #define ROOTNAME	"root_device"
6037737Smckusick 
6151473Sbostic ffs_mountroot()
6212795Ssam {
6351473Sbostic 	extern struct vnode *rootvp;
6451473Sbostic 	register struct fs *fs;
6537737Smckusick 	register struct mount *mp;
6648036Smckusick 	struct proc *p = curproc;	/* XXX */
6737737Smckusick 	struct ufsmount *ump;
6837737Smckusick 	u_int size;
6937737Smckusick 	int error;
7056332Smckusick 
7156332Smckusick 	/*
7256332Smckusick 	 * Get vnodes for swapdev and rootdev.
7356332Smckusick 	 */
7456332Smckusick 	if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp))
7556332Smckusick 		panic("ffs_mountroot: can't setup bdevvp's");
7612795Ssam 
7753045Sralph 	mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
7854305Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
7941397Smckusick 	mp->mnt_op = &ufs_vfsops;
8041397Smckusick 	mp->mnt_flag = MNT_RDONLY;
8151473Sbostic 	if (error = ffs_mountfs(rootvp, mp, p)) {
8251473Sbostic 		free(mp, M_MOUNT);
8337737Smckusick 		return (error);
8412795Ssam 	}
8539336Smckusick 	if (error = vfs_lock(mp)) {
8651473Sbostic 		(void)ffs_unmount(mp, 0, p);
8751473Sbostic 		free(mp, M_MOUNT);
8837737Smckusick 		return (error);
8921013Smckusick 	}
9065236Smckusick 	TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
9165236Smckusick 	mp->mnt_flag |= MNT_ROOTFS;
9241397Smckusick 	mp->mnt_vnodecovered = NULLVP;
9337737Smckusick 	ump = VFSTOUFS(mp);
9437737Smckusick 	fs = ump->um_fs;
9540346Smckusick 	bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
9637737Smckusick 	fs->fs_fsmnt[0] = '/';
9741397Smckusick 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
9841397Smckusick 	    MNAMELEN);
9941397Smckusick 	(void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
10041397Smckusick 	    &size);
10141397Smckusick 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
10251473Sbostic 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
10337737Smckusick 	vfs_unlock(mp);
10437737Smckusick 	inittodr(fs->fs_time);
10537737Smckusick 	return (0);
10637737Smckusick }
10737737Smckusick 
10837737Smckusick /*
10937737Smckusick  * VFS Operations.
11037737Smckusick  *
11137737Smckusick  * mount system call
11237737Smckusick  */
11351942Smckusick int
11451473Sbostic ffs_mount(mp, path, data, ndp, p)
11540346Smckusick 	register struct mount *mp;
11637737Smckusick 	char *path;
11737737Smckusick 	caddr_t data;
11837737Smckusick 	struct nameidata *ndp;
11948036Smckusick 	struct proc *p;
12037737Smckusick {
12137737Smckusick 	struct vnode *devvp;
12237737Smckusick 	struct ufs_args args;
12337737Smckusick 	struct ufsmount *ump;
12437737Smckusick 	register struct fs *fs;
12537737Smckusick 	u_int size;
12657051Smckusick 	int error, flags;
12767534Smckusick 	mode_t accessmode;
12837737Smckusick 
12937737Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
13037737Smckusick 		return (error);
13140371Smckusick 	/*
13250264Skarels 	 * If updating, check whether changing from read-only to
13350264Skarels 	 * read/write; if there is no device name, that's all we do.
13450264Skarels 	 */
13550264Skarels 	if (mp->mnt_flag & MNT_UPDATE) {
13639336Smckusick 		ump = VFSTOUFS(mp);
13739336Smckusick 		fs = ump->um_fs;
13857051Smckusick 		error = 0;
13957051Smckusick 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
14057051Smckusick 			flags = WRITECLOSE;
14157051Smckusick 			if (mp->mnt_flag & MNT_FORCE)
14257051Smckusick 				flags |= FORCECLOSE;
14357051Smckusick 			if (vfs_busy(mp))
14457051Smckusick 				return (EBUSY);
14557051Smckusick 			error = ffs_flushfiles(mp, flags, p);
14657051Smckusick 			vfs_unbusy(mp);
14757051Smckusick 		}
14857051Smckusick 		if (!error && (mp->mnt_flag & MNT_RELOAD))
14957051Smckusick 			error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
15057051Smckusick 		if (error)
15157051Smckusick 			return (error);
15267534Smckusick 		if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
15367534Smckusick 			/*
15467534Smckusick 			 * If upgrade to read-write by non-root, then verify
15567534Smckusick 			 * that user has necessary permissions on the device.
15667534Smckusick 			 */
15767534Smckusick 			if (p->p_ucred->cr_uid != 0) {
15867534Smckusick 				devvp = ump->um_devvp;
15967534Smckusick 				VOP_LOCK(devvp);
16067534Smckusick 				if (error = VOP_ACCESS(devvp, VREAD | VWRITE,
16167534Smckusick 				    p->p_ucred, p)) {
16267534Smckusick 					VOP_UNLOCK(devvp);
16367534Smckusick 					return (error);
16467534Smckusick 				}
16567534Smckusick 				VOP_UNLOCK(devvp);
16667534Smckusick 			}
16739336Smckusick 			fs->fs_ronly = 0;
16867534Smckusick 		}
16952177Smckusick 		if (args.fspec == 0) {
17052177Smckusick 			/*
17152177Smckusick 			 * Process export requests.
17252177Smckusick 			 */
17365672Shibler 			return (vfs_export(mp, &ump->um_export, &args.export));
17452177Smckusick 		}
17550264Skarels 	}
17650264Skarels 	/*
17750264Skarels 	 * Not an update, or updating the name: look up the name
17850264Skarels 	 * and verify that it refers to a sensible block device.
17950264Skarels 	 */
18052332Smckusick 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
18152332Smckusick 	if (error = namei(ndp))
18250264Skarels 		return (error);
18350264Skarels 	devvp = ndp->ni_vp;
18451473Sbostic 
18550264Skarels 	if (devvp->v_type != VBLK) {
18650264Skarels 		vrele(devvp);
18750264Skarels 		return (ENOTBLK);
18850264Skarels 	}
18950264Skarels 	if (major(devvp->v_rdev) >= nblkdev) {
19050264Skarels 		vrele(devvp);
19150264Skarels 		return (ENXIO);
19250264Skarels 	}
19367534Smckusick 	/*
19467534Smckusick 	 * If mount by non-root, then verify that user has necessary
19567534Smckusick 	 * permissions on the device.
19667534Smckusick 	 */
19767534Smckusick 	if (p->p_ucred->cr_uid != 0) {
19867534Smckusick 		accessmode = VREAD;
19967534Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
20067534Smckusick 			accessmode |= VWRITE;
20167534Smckusick 		VOP_LOCK(devvp);
20267534Smckusick 		if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) {
20367534Smckusick 			vput(devvp);
20467534Smckusick 			return (error);
20567534Smckusick 		}
20667534Smckusick 		VOP_UNLOCK(devvp);
20767534Smckusick 	}
20850264Skarels 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
20951473Sbostic 		error = ffs_mountfs(devvp, mp, p);
21050264Skarels 	else {
21139336Smckusick 		if (devvp != ump->um_devvp)
21239336Smckusick 			error = EINVAL;	/* needs translation */
21342858Smckusick 		else
21442858Smckusick 			vrele(devvp);
21539336Smckusick 	}
21637737Smckusick 	if (error) {
21737737Smckusick 		vrele(devvp);
21837737Smckusick 		return (error);
21932721Smckusick 	}
22037737Smckusick 	ump = VFSTOUFS(mp);
22137737Smckusick 	fs = ump->um_fs;
22237737Smckusick 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
22337737Smckusick 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
22441397Smckusick 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
22541397Smckusick 	    MNAMELEN);
22641397Smckusick 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
22741397Smckusick 	    &size);
22841397Smckusick 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
22951473Sbostic 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
23037737Smckusick 	return (0);
23112795Ssam }
23212795Ssam 
23337737Smckusick /*
23457051Smckusick  * Reload all incore data for a filesystem (used after running fsck on
23557051Smckusick  * the root filesystem and finding things to fix). The filesystem must
23657051Smckusick  * be mounted read-only.
23757051Smckusick  *
23857051Smckusick  * Things to do to update the mount:
23957051Smckusick  *	1) invalidate all cached meta-data.
24057051Smckusick  *	2) re-read superblock from disk.
24157051Smckusick  *	3) re-read summary information from disk.
24257051Smckusick  *	4) invalidate all inactive vnodes.
24357051Smckusick  *	5) invalidate all cached file data.
24457051Smckusick  *	6) re-read inode data for all active vnodes.
24557051Smckusick  */
24657051Smckusick ffs_reload(mountp, cred, p)
24757051Smckusick 	register struct mount *mountp;
24857051Smckusick 	struct ucred *cred;
24957051Smckusick 	struct proc *p;
25057051Smckusick {
25157051Smckusick 	register struct vnode *vp, *nvp, *devvp;
25257051Smckusick 	struct inode *ip;
25357051Smckusick 	struct csum *space;
25457051Smckusick 	struct buf *bp;
255*68545Smckusick 	struct fs *fs, *newfs;
25668115Smckusick 	struct partinfo dpart;
25757051Smckusick 	int i, blks, size, error;
25857051Smckusick 
25957051Smckusick 	if ((mountp->mnt_flag & MNT_RDONLY) == 0)
26057051Smckusick 		return (EINVAL);
26157051Smckusick 	/*
26257051Smckusick 	 * Step 1: invalidate all cached meta-data.
26357051Smckusick 	 */
26457051Smckusick 	devvp = VFSTOUFS(mountp)->um_devvp;
26557801Smckusick 	if (vinvalbuf(devvp, 0, cred, p, 0, 0))
26657051Smckusick 		panic("ffs_reload: dirty1");
26757051Smckusick 	/*
26857051Smckusick 	 * Step 2: re-read superblock from disk.
26957051Smckusick 	 */
27068115Smckusick 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
27168115Smckusick 		size = DEV_BSIZE;
27268115Smckusick 	else
27368115Smckusick 		size = dpart.disklab->d_secsize;
27468115Smckusick 	if (error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp))
27557051Smckusick 		return (error);
276*68545Smckusick 	newfs = (struct fs *)bp->b_data;
277*68545Smckusick 	if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE ||
278*68545Smckusick 	    newfs->fs_bsize < sizeof(struct fs)) {
27957051Smckusick 		brelse(bp);
28057051Smckusick 		return (EIO);		/* XXX needs translation */
28157051Smckusick 	}
28257051Smckusick 	fs = VFSTOUFS(mountp)->um_fs;
283*68545Smckusick 	bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp));
284*68545Smckusick 	newfs->fs_maxcluster = fs->fs_maxcluster;
285*68545Smckusick 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
28657051Smckusick 	if (fs->fs_sbsize < SBSIZE)
28757051Smckusick 		bp->b_flags |= B_INVAL;
28857051Smckusick 	brelse(bp);
28967460Smckusick 	mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
29057051Smckusick 	ffs_oldfscompat(fs);
29157051Smckusick 	/*
29257051Smckusick 	 * Step 3: re-read summary information from disk.
29357051Smckusick 	 */
29457051Smckusick 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
29557051Smckusick 	space = fs->fs_csp[0];
29657051Smckusick 	for (i = 0; i < blks; i += fs->fs_frag) {
29757051Smckusick 		size = fs->fs_bsize;
29857051Smckusick 		if (i + fs->fs_frag > blks)
29957051Smckusick 			size = (blks - i) * fs->fs_fsize;
30057051Smckusick 		if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
30157051Smckusick 		    NOCRED, &bp))
30257051Smckusick 			return (error);
30364511Sbostic 		bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
30457051Smckusick 		brelse(bp);
30557051Smckusick 	}
30657051Smckusick loop:
30765236Smckusick 	for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
30865236Smckusick 		nvp = vp->v_mntvnodes.le_next;
30957051Smckusick 		/*
31057051Smckusick 		 * Step 4: invalidate all inactive vnodes.
31157051Smckusick 		 */
31257051Smckusick 		if (vp->v_usecount == 0) {
31357051Smckusick 			vgone(vp);
31457051Smckusick 			continue;
31557051Smckusick 		}
31657051Smckusick 		/*
31757051Smckusick 		 * Step 5: invalidate all cached file data.
31857051Smckusick 		 */
31965236Smckusick 		if (vget(vp, 1))
32057051Smckusick 			goto loop;
32157801Smckusick 		if (vinvalbuf(vp, 0, cred, p, 0, 0))
32257051Smckusick 			panic("ffs_reload: dirty2");
32357051Smckusick 		/*
32457051Smckusick 		 * Step 6: re-read inode data for all active vnodes.
32557051Smckusick 		 */
32657051Smckusick 		ip = VTOI(vp);
32764605Sbostic 		if (error =
32864605Sbostic 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
32957051Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
33057051Smckusick 			vput(vp);
33157051Smckusick 			return (error);
33257051Smckusick 		}
33364605Sbostic 		ip->i_din = *((struct dinode *)bp->b_data +
33464605Sbostic 		    ino_to_fsbo(fs, ip->i_number));
33557051Smckusick 		brelse(bp);
33657051Smckusick 		vput(vp);
33757051Smckusick 		if (vp->v_mount != mountp)
33857051Smckusick 			goto loop;
33957051Smckusick 	}
34057051Smckusick 	return (0);
34157051Smckusick }
34257051Smckusick 
34357051Smckusick /*
34437737Smckusick  * Common code for mount and mountroot
34537737Smckusick  */
34651473Sbostic int
34751473Sbostic ffs_mountfs(devvp, mp, p)
34840376Smckusick 	register struct vnode *devvp;
34937737Smckusick 	struct mount *mp;
35048036Smckusick 	struct proc *p;
35112795Ssam {
35254461Smckusick 	register struct ufsmount *ump;
35354461Smckusick 	struct buf *bp;
35412795Ssam 	register struct fs *fs;
35568004Smckusick 	dev_t dev;
35630749Skarels 	struct partinfo dpart;
35737737Smckusick 	caddr_t base, space;
35868115Smckusick 	int error, i, blks, size, ronly;
35967868Smckusick 	int32_t *lp;
36068004Smckusick 	struct ucred *cred;
36145652Smckusick 	extern struct vnode *rootvp;
36268115Smckusick 	u_int64_t maxfilesize;					/* XXX */
36312795Ssam 
36468004Smckusick 	dev = devvp->v_rdev;
36568004Smckusick 	cred = p ? p->p_ucred : NOCRED;
36640376Smckusick 	/*
36740376Smckusick 	 * Disallow multiple mounts of the same device.
36845652Smckusick 	 * Disallow mounting of a device that is currently in use
36945652Smckusick 	 * (except for root, which might share swap device for miniroot).
37040376Smckusick 	 * Flush out any old buffers remaining from a previous use.
37140376Smckusick 	 */
37265672Shibler 	if (error = vfs_mountedon(devvp))
37340376Smckusick 		return (error);
37445652Smckusick 	if (vcount(devvp) > 1 && devvp != rootvp)
37540376Smckusick 		return (EBUSY);
37668004Smckusick 	if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0))
37754461Smckusick 		return (error);
37854461Smckusick 
37954461Smckusick 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
38059472Smckusick 	if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))
38137737Smckusick 		return (error);
38268004Smckusick 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
38337737Smckusick 		size = DEV_BSIZE;
38468115Smckusick 	else
38530749Skarels 		size = dpart.disklab->d_secsize;
38654461Smckusick 
38754461Smckusick 	bp = NULL;
38854461Smckusick 	ump = NULL;
38968115Smckusick 	if (error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, cred, &bp))
39012795Ssam 		goto out;
39164511Sbostic 	fs = (struct fs *)bp->b_data;
39230749Skarels 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
39330749Skarels 	    fs->fs_bsize < sizeof(struct fs)) {
39441314Smckusick 		error = EINVAL;		/* XXX needs translation */
39516639Skarels 		goto out;
39616639Skarels 	}
39768116Smckusick 	/* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
39868116Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
39968116Smckusick 		error = EROFS;          /* needs translation */
40068116Smckusick 		goto out;
40168116Smckusick 	}
40251473Sbostic 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
40352538Smckusick 	bzero((caddr_t)ump, sizeof *ump);
40451982Smckusick 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
40534473Smckusick 	    M_WAITOK);
40664511Sbostic 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
40739675Smckusick 	if (fs->fs_sbsize < SBSIZE)
40839675Smckusick 		bp->b_flags |= B_INVAL;
40934421Skarels 	brelse(bp);
41034421Skarels 	bp = NULL;
41137737Smckusick 	fs = ump->um_fs;
41237737Smckusick 	fs->fs_ronly = ronly;
41312795Ssam 	if (ronly == 0)
41412795Ssam 		fs->fs_fmod = 1;
41567868Smckusick 	size = fs->fs_cssize;
41668116Smckusick 	blks = howmany(size, fs->fs_fsize);
41767868Smckusick 	if (fs->fs_contigsumsize > 0)
41867868Smckusick 		size += fs->fs_ncg * sizeof(int32_t);
41967868Smckusick 	base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
42012795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
42112795Ssam 		size = fs->fs_bsize;
42212795Ssam 		if (i + fs->fs_frag > blks)
42312795Ssam 			size = (blks - i) * fs->fs_fsize;
42468004Smckusick 		if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
42568004Smckusick 		    cred, &bp)) {
42651982Smckusick 			free(base, M_UFSMNT);
42712795Ssam 			goto out;
42812795Ssam 		}
42964511Sbostic 		bcopy(bp->b_data, space, (u_int)size);
43017225Smckusick 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
43112795Ssam 		space += size;
43234421Skarels 		brelse(bp);
43334421Skarels 		bp = NULL;
43412795Ssam 	}
43567868Smckusick 	if (fs->fs_contigsumsize > 0) {
43667868Smckusick 		fs->fs_maxcluster = lp = (int32_t *)space;
43767868Smckusick 		for (i = 0; i < fs->fs_ncg; i++)
43867868Smckusick 			*lp++ = fs->fs_contigsumsize;
43967868Smckusick 	}
44041397Smckusick 	mp->mnt_data = (qaddr_t)ump;
44141397Smckusick 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
44241397Smckusick 	mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS;
44354305Smckusick 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
44441397Smckusick 	mp->mnt_flag |= MNT_LOCAL;
44537737Smckusick 	ump->um_mountp = mp;
44637737Smckusick 	ump->um_dev = dev;
44737737Smckusick 	ump->um_devvp = devvp;
44856446Smargo 	ump->um_nindir = fs->fs_nindir;
44956446Smargo 	ump->um_bptrtodb = fs->fs_fsbtodb;
45056446Smargo 	ump->um_seqinc = fs->fs_frag;
45141314Smckusick 	for (i = 0; i < MAXQUOTAS; i++)
45241314Smckusick 		ump->um_quotas[i] = NULLVP;
45340653Smckusick 	devvp->v_specflags |= SI_MOUNTEDON;
45457051Smckusick 	ffs_oldfscompat(fs);
45567868Smckusick 	ump->um_savedmaxfilesize = fs->fs_maxfilesize;		/* XXX */
45668115Smckusick 	maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1;	/* XXX */
45768115Smckusick 	if (fs->fs_maxfilesize > maxfilesize)			/* XXX */
45868115Smckusick 		fs->fs_maxfilesize = maxfilesize;		/* XXX */
45957051Smckusick 	return (0);
46057051Smckusick out:
46157051Smckusick 	if (bp)
46257051Smckusick 		brelse(bp);
46368004Smckusick 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
46457051Smckusick 	if (ump) {
46557051Smckusick 		free(ump->um_fs, M_UFSMNT);
46657051Smckusick 		free(ump, M_UFSMNT);
46757051Smckusick 		mp->mnt_data = (qaddr_t)0;
46857051Smckusick 	}
46957051Smckusick 	return (error);
47057051Smckusick }
47137737Smckusick 
47257051Smckusick /*
47357051Smckusick  * Sanity checks for old file systems.
47457051Smckusick  *
47557051Smckusick  * XXX - goes away some day.
47657051Smckusick  */
47757051Smckusick ffs_oldfscompat(fs)
47857051Smckusick 	struct fs *fs;
47957051Smckusick {
48057051Smckusick 	int i;
48157051Smckusick 
48255056Spendry 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
48355056Spendry 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
48434145Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
48534145Smckusick 		fs->fs_nrpos = 8;				/* XXX */
48653913Smckusick 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
48768122Smckusick 		u_int64_t sizepb = fs->fs_bsize;		/* XXX */
48853913Smckusick 								/* XXX */
48953913Smckusick 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
49053913Smckusick 		for (i = 0; i < NIADDR; i++) {			/* XXX */
49153913Smckusick 			sizepb *= NINDIR(fs);			/* XXX */
49253913Smckusick 			fs->fs_maxfilesize += sizepb;		/* XXX */
49353913Smckusick 		}						/* XXX */
49453913Smckusick 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
49553913Smckusick 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
49653913Smckusick 	}							/* XXX */
49737737Smckusick 	return (0);
49812795Ssam }
49912795Ssam 
50039043Smckusick /*
50137737Smckusick  * unmount system call
50237737Smckusick  */
50351473Sbostic int
50451473Sbostic ffs_unmount(mp, mntflags, p)
50537737Smckusick 	struct mount *mp;
50641314Smckusick 	int mntflags;
50748036Smckusick 	struct proc *p;
50812795Ssam {
50937737Smckusick 	register struct ufsmount *ump;
51037737Smckusick 	register struct fs *fs;
51167861Smckusick 	int error, flags;
51212795Ssam 
51354461Smckusick 	flags = 0;
51448065Smckusick 	if (mntflags & MNT_FORCE) {
51565236Smckusick 		if (mp->mnt_flag & MNT_ROOTFS)
51648065Smckusick 			return (EINVAL);
51741314Smckusick 		flags |= FORCECLOSE;
51848065Smckusick 	}
51957051Smckusick 	if (error = ffs_flushfiles(mp, flags, p))
52057051Smckusick 		return (error);
52137737Smckusick 	ump = VFSTOUFS(mp);
52257051Smckusick 	fs = ump->um_fs;
52357051Smckusick 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
52467861Smckusick 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
52557051Smckusick 		NOCRED, p);
52657051Smckusick 	vrele(ump->um_devvp);
52757051Smckusick 	free(fs->fs_csp[0], M_UFSMNT);
52857051Smckusick 	free(fs, M_UFSMNT);
52957051Smckusick 	free(ump, M_UFSMNT);
53057051Smckusick 	mp->mnt_data = (qaddr_t)0;
53157051Smckusick 	mp->mnt_flag &= ~MNT_LOCAL;
53257051Smckusick 	return (error);
53357051Smckusick }
53457051Smckusick 
53557051Smckusick /*
53657051Smckusick  * Flush out all the files in a filesystem.
53757051Smckusick  */
53857051Smckusick ffs_flushfiles(mp, flags, p)
53957051Smckusick 	register struct mount *mp;
54057051Smckusick 	int flags;
54157051Smckusick 	struct proc *p;
54257051Smckusick {
54357051Smckusick 	extern int doforce;
54457051Smckusick 	register struct ufsmount *ump;
54557051Smckusick 	int i, error;
54657051Smckusick 
54757051Smckusick 	if (!doforce)
54857051Smckusick 		flags &= ~FORCECLOSE;
54957051Smckusick 	ump = VFSTOUFS(mp);
55012795Ssam #ifdef QUOTA
55141397Smckusick 	if (mp->mnt_flag & MNT_QUOTA) {
55241314Smckusick 		if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
55339898Smckusick 			return (error);
55441314Smckusick 		for (i = 0; i < MAXQUOTAS; i++) {
55541314Smckusick 			if (ump->um_quotas[i] == NULLVP)
55641314Smckusick 				continue;
55750114Smckusick 			quotaoff(p, mp, i);
55841314Smckusick 		}
55939898Smckusick 		/*
56041314Smckusick 		 * Here we fall through to vflush again to ensure
56141314Smckusick 		 * that we have gotten rid of all the system vnodes.
56239898Smckusick 		 */
56341314Smckusick 	}
56412795Ssam #endif
56557051Smckusick 	error = vflush(mp, NULLVP, flags);
56630749Skarels 	return (error);
56712795Ssam }
56812795Ssam 
56937737Smckusick /*
57037737Smckusick  * Get file system statistics.
57137737Smckusick  */
57251473Sbostic int
57351473Sbostic ffs_statfs(mp, sbp, p)
57437737Smckusick 	struct mount *mp;
57537737Smckusick 	register struct statfs *sbp;
57648036Smckusick 	struct proc *p;
57737737Smckusick {
57837737Smckusick 	register struct ufsmount *ump;
57937737Smckusick 	register struct fs *fs;
58037737Smckusick 
58137737Smckusick 	ump = VFSTOUFS(mp);
58237737Smckusick 	fs = ump->um_fs;
58337737Smckusick 	if (fs->fs_magic != FS_MAGIC)
58451473Sbostic 		panic("ffs_statfs");
58537737Smckusick 	sbp->f_type = MOUNT_UFS;
58651942Smckusick 	sbp->f_bsize = fs->fs_fsize;
58751942Smckusick 	sbp->f_iosize = fs->fs_bsize;
58837737Smckusick 	sbp->f_blocks = fs->fs_dsize;
58937737Smckusick 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
59037737Smckusick 		fs->fs_cstotal.cs_nffree;
59137737Smckusick 	sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
59237737Smckusick 		(fs->fs_dsize - sbp->f_bfree);
59339350Smckusick 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
59437737Smckusick 	sbp->f_ffree = fs->fs_cstotal.cs_nifree;
59541397Smckusick 	if (sbp != &mp->mnt_stat) {
59641397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
59740346Smckusick 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
59841397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
59940346Smckusick 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
60040346Smckusick 	}
60137737Smckusick 	return (0);
60237737Smckusick }
60337737Smckusick 
60437737Smckusick /*
60537737Smckusick  * Go through the disk queues to initiate sandbagged IO;
60637737Smckusick  * go through the inodes to write those that have been modified;
60737737Smckusick  * initiate the writing of the super block if it has been modified.
60841314Smckusick  *
60941314Smckusick  * Note: we are always called with the filesystem marked `MPBUSY'.
61037737Smckusick  */
61151473Sbostic int
61254461Smckusick ffs_sync(mp, waitfor, cred, p)
61337737Smckusick 	struct mount *mp;
61437737Smckusick 	int waitfor;
61554461Smckusick 	struct ucred *cred;
61654461Smckusick 	struct proc *p;
61737737Smckusick {
61839390Smckusick 	register struct vnode *vp;
61937737Smckusick 	register struct inode *ip;
62037737Smckusick 	register struct ufsmount *ump = VFSTOUFS(mp);
62137737Smckusick 	register struct fs *fs;
62239596Smckusick 	int error, allerror = 0;
62337737Smckusick 
62437737Smckusick 	fs = ump->um_fs;
62537737Smckusick 	/*
62637737Smckusick 	 * Write back modified superblock.
62737737Smckusick 	 * Consistency check that the superblock
62837737Smckusick 	 * is still in the buffer cache.
62937737Smckusick 	 */
63037737Smckusick 	if (fs->fs_fmod != 0) {
63137737Smckusick 		if (fs->fs_ronly != 0) {		/* XXX */
63237737Smckusick 			printf("fs = %s\n", fs->fs_fsmnt);
63337737Smckusick 			panic("update: rofs mod");
63437737Smckusick 		}
63537737Smckusick 		fs->fs_fmod = 0;
63637737Smckusick 		fs->fs_time = time.tv_sec;
63751473Sbostic 		allerror = ffs_sbupdate(ump, waitfor);
63837737Smckusick 	}
63937737Smckusick 	/*
64037737Smckusick 	 * Write back each (modified) inode.
64137737Smckusick 	 */
64239877Smckusick loop:
64365236Smckusick 	for (vp = mp->mnt_vnodelist.lh_first;
64465236Smckusick 	     vp != NULL;
64565236Smckusick 	     vp = vp->v_mntvnodes.le_next) {
64641462Smckusick 		/*
64741462Smckusick 		 * If the vnode that we are about to sync is no longer
64841462Smckusick 		 * associated with this mount point, start over.
64941462Smckusick 		 */
65041462Smckusick 		if (vp->v_mount != mp)
65141462Smckusick 			goto loop;
65248359Smckusick 		if (VOP_ISLOCKED(vp))
65348359Smckusick 			continue;
65439390Smckusick 		ip = VTOI(vp);
65564511Sbostic 		if ((ip->i_flag &
65664605Sbostic 		    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
65765236Smckusick 		    vp->v_dirtyblkhd.lh_first == NULL)
65837737Smckusick 			continue;
65965236Smckusick 		if (vget(vp, 1))
66039877Smckusick 			goto loop;
66154461Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
66239596Smckusick 			allerror = error;
66339596Smckusick 		vput(vp);
66437737Smckusick 	}
66537737Smckusick 	/*
66639675Smckusick 	 * Force stale file system control information to be flushed.
66737737Smckusick 	 */
66854461Smckusick 	if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p))
66954461Smckusick 		allerror = error;
67041314Smckusick #ifdef QUOTA
67141314Smckusick 	qsync(mp);
67241314Smckusick #endif
67339596Smckusick 	return (allerror);
67437737Smckusick }
67537737Smckusick 
67637737Smckusick /*
67764605Sbostic  * Look up a FFS dinode number to find its incore vnode, otherwise read it
67864605Sbostic  * in from disk.  If it is in core, wait for the lock bit to clear, then
67964605Sbostic  * return the inode locked.  Detection and handling of mount points must be
68064605Sbostic  * done by the calling routine.
68154657Smckusick  */
68254657Smckusick int
68354657Smckusick ffs_vget(mp, ino, vpp)
68454657Smckusick 	struct mount *mp;
68554657Smckusick 	ino_t ino;
68654657Smckusick 	struct vnode **vpp;
68754657Smckusick {
68854657Smckusick 	register struct fs *fs;
68954657Smckusick 	register struct inode *ip;
69054657Smckusick 	struct ufsmount *ump;
69154657Smckusick 	struct buf *bp;
69254657Smckusick 	struct vnode *vp;
69354657Smckusick 	dev_t dev;
69454657Smckusick 	int i, type, error;
69554657Smckusick 
69654657Smckusick 	ump = VFSTOUFS(mp);
69754657Smckusick 	dev = ump->um_dev;
69854657Smckusick 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
69954657Smckusick 		return (0);
70054657Smckusick 
70154657Smckusick 	/* Allocate a new vnode/inode. */
70254657Smckusick 	if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) {
70354657Smckusick 		*vpp = NULL;
70454657Smckusick 		return (error);
70554657Smckusick 	}
70654657Smckusick 	type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
70754657Smckusick 	MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
70859819Smckusick 	bzero((caddr_t)ip, sizeof(struct inode));
70954657Smckusick 	vp->v_data = ip;
71054657Smckusick 	ip->i_vnode = vp;
71154657Smckusick 	ip->i_fs = fs = ump->um_fs;
71254657Smckusick 	ip->i_dev = dev;
71354657Smckusick 	ip->i_number = ino;
71454657Smckusick #ifdef QUOTA
71554657Smckusick 	for (i = 0; i < MAXQUOTAS; i++)
71654657Smckusick 		ip->i_dquot[i] = NODQUOT;
71754657Smckusick #endif
71854657Smckusick 	/*
71954657Smckusick 	 * Put it onto its hash chain and lock it so that other requests for
72054657Smckusick 	 * this inode will block if they arrive while we are sleeping waiting
72154657Smckusick 	 * for old data structures to be purged or for the contents of the
72254657Smckusick 	 * disk portion of this inode to be read.
72354657Smckusick 	 */
72454657Smckusick 	ufs_ihashins(ip);
72554657Smckusick 
72654657Smckusick 	/* Read in the disk contents for the inode, copy into the inode. */
72764605Sbostic 	if (error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
72854657Smckusick 	    (int)fs->fs_bsize, NOCRED, &bp)) {
72954657Smckusick 		/*
73054657Smckusick 		 * The inode does not contain anything useful, so it would
73159819Smckusick 		 * be misleading to leave it on its hash chain. With mode
73259819Smckusick 		 * still zero, it will be unlinked and returned to the free
73359819Smckusick 		 * list by vput().
73454657Smckusick 		 */
73556797Smckusick 		vput(vp);
73654657Smckusick 		brelse(bp);
73754657Smckusick 		*vpp = NULL;
73854657Smckusick 		return (error);
73954657Smckusick 	}
74064605Sbostic 	ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
74154657Smckusick 	brelse(bp);
74254657Smckusick 
74354657Smckusick 	/*
74454657Smckusick 	 * Initialize the vnode from the inode, check for aliases.
74554657Smckusick 	 * Note that the underlying vnode may have changed.
74654657Smckusick 	 */
74754657Smckusick 	if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) {
74856797Smckusick 		vput(vp);
74954657Smckusick 		*vpp = NULL;
75054657Smckusick 		return (error);
75154657Smckusick 	}
75254657Smckusick 	/*
75354657Smckusick 	 * Finish inode initialization now that aliasing has been resolved.
75454657Smckusick 	 */
75554657Smckusick 	ip->i_devvp = ump->um_devvp;
75654657Smckusick 	VREF(ip->i_devvp);
75754657Smckusick 	/*
75854657Smckusick 	 * Set up a generation number for this inode if it does not
75954657Smckusick 	 * already have one. This should only happen on old filesystems.
76054657Smckusick 	 */
76154657Smckusick 	if (ip->i_gen == 0) {
76254657Smckusick 		if (++nextgennumber < (u_long)time.tv_sec)
76354657Smckusick 			nextgennumber = time.tv_sec;
76454657Smckusick 		ip->i_gen = nextgennumber;
76554657Smckusick 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
76664605Sbostic 			ip->i_flag |= IN_MODIFIED;
76754657Smckusick 	}
76854657Smckusick 	/*
76954657Smckusick 	 * Ensure that uid and gid are correct. This is a temporary
77054657Smckusick 	 * fix until fsck has been changed to do the update.
77154657Smckusick 	 */
77254657Smckusick 	if (fs->fs_inodefmt < FS_44INODEFMT) {		/* XXX */
77354657Smckusick 		ip->i_uid = ip->i_din.di_ouid;		/* XXX */
77454657Smckusick 		ip->i_gid = ip->i_din.di_ogid;		/* XXX */
77554657Smckusick 	}						/* XXX */
77654657Smckusick 
77754657Smckusick 	*vpp = vp;
77854657Smckusick 	return (0);
77954657Smckusick }
78054657Smckusick 
78154657Smckusick /*
78251545Smckusick  * File handle to vnode
78351545Smckusick  *
78451545Smckusick  * Have to be really careful about stale file handles:
78551545Smckusick  * - check that the inode number is valid
78651545Smckusick  * - call ffs_vget() to get the locked inode
78751545Smckusick  * - check for an unallocated inode (i_mode == 0)
78854733Smckusick  * - check that the given client host has export rights and return
78954733Smckusick  *   those rights via. exflagsp and credanonp
79051545Smckusick  */
79151545Smckusick int
79254733Smckusick ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
79351545Smckusick 	register struct mount *mp;
79451545Smckusick 	struct fid *fhp;
79554733Smckusick 	struct mbuf *nam;
79651545Smckusick 	struct vnode **vpp;
79754733Smckusick 	int *exflagsp;
79854733Smckusick 	struct ucred **credanonp;
79951545Smckusick {
80051545Smckusick 	register struct ufid *ufhp;
80151545Smckusick 	struct fs *fs;
80251545Smckusick 
80351545Smckusick 	ufhp = (struct ufid *)fhp;
80455890Smckusick 	fs = VFSTOUFS(mp)->um_fs;
80551545Smckusick 	if (ufhp->ufid_ino < ROOTINO ||
80651545Smckusick 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
80754733Smckusick 		return (ESTALE);
80856245Smckusick 	return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
80951545Smckusick }
81051545Smckusick 
81151545Smckusick /*
81251545Smckusick  * Vnode pointer to File handle
81351545Smckusick  */
81451545Smckusick /* ARGSUSED */
81551545Smckusick ffs_vptofh(vp, fhp)
81651545Smckusick 	struct vnode *vp;
81751545Smckusick 	struct fid *fhp;
81851545Smckusick {
81951545Smckusick 	register struct inode *ip;
82051545Smckusick 	register struct ufid *ufhp;
82151545Smckusick 
82251545Smckusick 	ip = VTOI(vp);
82351545Smckusick 	ufhp = (struct ufid *)fhp;
82451545Smckusick 	ufhp->ufid_len = sizeof(struct ufid);
82551545Smckusick 	ufhp->ufid_ino = ip->i_number;
82651545Smckusick 	ufhp->ufid_gen = ip->i_gen;
82751545Smckusick 	return (0);
82851545Smckusick }
82951545Smckusick 
83051545Smckusick /*
83137737Smckusick  * Write a superblock and associated information back to disk.
83237737Smckusick  */
83351942Smckusick int
83451473Sbostic ffs_sbupdate(mp, waitfor)
83537737Smckusick 	struct ufsmount *mp;
83637737Smckusick 	int waitfor;
83737737Smckusick {
83867868Smckusick 	register struct fs *dfs, *fs = mp->um_fs;
83912795Ssam 	register struct buf *bp;
84012795Ssam 	int blks;
84112795Ssam 	caddr_t space;
84237737Smckusick 	int i, size, error = 0;
84312795Ssam 
84457801Smckusick 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0);
84564511Sbostic 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
84634145Smckusick 	/* Restore compatibility to old file systems.		   XXX */
84767868Smckusick 	dfs = (struct fs *)bp->b_data;				/* XXX */
84834145Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
84967868Smckusick 		dfs->fs_nrpos = -1;				/* XXX */
85067397Smkm 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
85168122Smckusick 		int32_t *lp, tmp;				/* XXX */
85267397Smkm 								/* XXX */
85368122Smckusick 		lp = (int32_t *)&dfs->fs_qbmask;		/* XXX */
85467397Smkm 		tmp = lp[4];					/* XXX */
85567397Smkm 		for (i = 4; i > 0; i--)				/* XXX */
85667397Smkm 			lp[i] = lp[i-1];			/* XXX */
85767397Smkm 		lp[0] = tmp;					/* XXX */
85867397Smkm 	}							/* XXX */
85967868Smckusick 	dfs->fs_maxfilesize = mp->um_savedmaxfilesize;		/* XXX */
86037737Smckusick 	if (waitfor == MNT_WAIT)
86137737Smckusick 		error = bwrite(bp);
86237737Smckusick 	else
86337737Smckusick 		bawrite(bp);
86412795Ssam 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
86512795Ssam 	space = (caddr_t)fs->fs_csp[0];
86612795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
86712795Ssam 		size = fs->fs_bsize;
86812795Ssam 		if (i + fs->fs_frag > blks)
86912795Ssam 			size = (blks - i) * fs->fs_fsize;
87057801Smckusick 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
87157801Smckusick 		    size, 0, 0);
87264511Sbostic 		bcopy(space, bp->b_data, (u_int)size);
87312795Ssam 		space += size;
87437737Smckusick 		if (waitfor == MNT_WAIT)
87537737Smckusick 			error = bwrite(bp);
87637737Smckusick 		else
87737737Smckusick 			bawrite(bp);
87812795Ssam 	}
87937737Smckusick 	return (error);
88012795Ssam }
881