xref: /csrg-svn/sys/ufs/ffs/ffs_vfsops.c (revision 69318)
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*69318Smckusick  *	@(#)ffs_vfsops.c	8.24 (Berkeley) 05/09/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,
5068668Smckusick 	ffs_sysctl,
5137737Smckusick };
5237737Smckusick 
5354657Smckusick extern u_long nextgennumber;
5454657Smckusick 
5537737Smckusick /*
5653045Sralph  * Called by main() when ufs is going to be mounted as root.
5737737Smckusick  *
5839336Smckusick  * Name is updated by mount(8) after booting.
5937737Smckusick  */
6039297Smckusick #define ROOTNAME	"root_device"
6137737Smckusick 
6251473Sbostic ffs_mountroot()
6312795Ssam {
6451473Sbostic 	extern struct vnode *rootvp;
6551473Sbostic 	register struct fs *fs;
6637737Smckusick 	register struct mount *mp;
6748036Smckusick 	struct proc *p = curproc;	/* XXX */
6837737Smckusick 	struct ufsmount *ump;
6968668Smckusick 	struct vfsconf *vfsp;
7037737Smckusick 	u_int size;
7137737Smckusick 	int error;
7256332Smckusick 
7356332Smckusick 	/*
7456332Smckusick 	 * Get vnodes for swapdev and rootdev.
7556332Smckusick 	 */
7656332Smckusick 	if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp))
7756332Smckusick 		panic("ffs_mountroot: can't setup bdevvp's");
7812795Ssam 
7968668Smckusick 	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
8068668Smckusick 		if (!strcmp(vfsp->vfc_name, "ufs"))
8168668Smckusick 			break;
8268668Smckusick 	if (vfsp == NULL)
8368668Smckusick 		return (ENODEV);
8453045Sralph 	mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
8554305Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
8668788Smckusick 	mp->mnt_vfc = vfsp;
8768668Smckusick 	mp->mnt_op = vfsp->vfc_vfsops;
8841397Smckusick 	mp->mnt_flag = MNT_RDONLY;
8951473Sbostic 	if (error = ffs_mountfs(rootvp, mp, p)) {
9051473Sbostic 		free(mp, M_MOUNT);
9137737Smckusick 		return (error);
9212795Ssam 	}
9339336Smckusick 	if (error = vfs_lock(mp)) {
9451473Sbostic 		(void)ffs_unmount(mp, 0, p);
9551473Sbostic 		free(mp, M_MOUNT);
9637737Smckusick 		return (error);
9721013Smckusick 	}
98*69318Smckusick 	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
9941397Smckusick 	mp->mnt_vnodecovered = NULLVP;
10068668Smckusick 	vfsp->vfc_refcount++;
10168668Smckusick 	mp->mnt_stat.f_type = vfsp->vfc_typenum;
10268668Smckusick 	mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK) | MNT_ROOTFS;
10368668Smckusick 	strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
10437737Smckusick 	ump = VFSTOUFS(mp);
10537737Smckusick 	fs = ump->um_fs;
10640346Smckusick 	bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
10737737Smckusick 	fs->fs_fsmnt[0] = '/';
10841397Smckusick 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
10941397Smckusick 	    MNAMELEN);
11041397Smckusick 	(void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
11141397Smckusick 	    &size);
11241397Smckusick 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
11351473Sbostic 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
11437737Smckusick 	vfs_unlock(mp);
11537737Smckusick 	inittodr(fs->fs_time);
11637737Smckusick 	return (0);
11737737Smckusick }
11837737Smckusick 
11937737Smckusick /*
12037737Smckusick  * VFS Operations.
12137737Smckusick  *
12237737Smckusick  * mount system call
12337737Smckusick  */
12451942Smckusick int
12551473Sbostic ffs_mount(mp, path, data, ndp, p)
12640346Smckusick 	register struct mount *mp;
12737737Smckusick 	char *path;
12837737Smckusick 	caddr_t data;
12937737Smckusick 	struct nameidata *ndp;
13048036Smckusick 	struct proc *p;
13137737Smckusick {
13237737Smckusick 	struct vnode *devvp;
13337737Smckusick 	struct ufs_args args;
13437737Smckusick 	struct ufsmount *ump;
13537737Smckusick 	register struct fs *fs;
13637737Smckusick 	u_int size;
13757051Smckusick 	int error, flags;
13867534Smckusick 	mode_t accessmode;
13937737Smckusick 
14037737Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
14137737Smckusick 		return (error);
14240371Smckusick 	/*
14350264Skarels 	 * If updating, check whether changing from read-only to
14450264Skarels 	 * read/write; if there is no device name, that's all we do.
14550264Skarels 	 */
14650264Skarels 	if (mp->mnt_flag & MNT_UPDATE) {
14739336Smckusick 		ump = VFSTOUFS(mp);
14839336Smckusick 		fs = ump->um_fs;
14957051Smckusick 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
15057051Smckusick 			flags = WRITECLOSE;
15157051Smckusick 			if (mp->mnt_flag & MNT_FORCE)
15257051Smckusick 				flags |= FORCECLOSE;
15357051Smckusick 			if (vfs_busy(mp))
15457051Smckusick 				return (EBUSY);
155*69318Smckusick 			if (error = ffs_flushfiles(mp, flags, p)) {
156*69318Smckusick 				vfs_unbusy(mp);
157*69318Smckusick 				return (error);
158*69318Smckusick 			}
159*69318Smckusick 			fs->fs_clean = 1;
160*69318Smckusick 			fs->fs_ronly = 1;
161*69318Smckusick 			if (error = ffs_sbupdate(ump, MNT_WAIT)) {
162*69318Smckusick 				fs->fs_clean = 0;
163*69318Smckusick 				fs->fs_ronly = 0;
164*69318Smckusick 				vfs_unbusy(mp);
165*69318Smckusick 				return (error);
166*69318Smckusick 			}
16757051Smckusick 			vfs_unbusy(mp);
16857051Smckusick 		}
169*69318Smckusick 		if ((mp->mnt_flag & MNT_RELOAD) &&
170*69318Smckusick 		    (error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p)))
17157051Smckusick 			return (error);
17267534Smckusick 		if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
17367534Smckusick 			/*
17467534Smckusick 			 * If upgrade to read-write by non-root, then verify
17567534Smckusick 			 * that user has necessary permissions on the device.
17667534Smckusick 			 */
17767534Smckusick 			if (p->p_ucred->cr_uid != 0) {
17867534Smckusick 				devvp = ump->um_devvp;
17967534Smckusick 				VOP_LOCK(devvp);
18067534Smckusick 				if (error = VOP_ACCESS(devvp, VREAD | VWRITE,
18167534Smckusick 				    p->p_ucred, p)) {
18267534Smckusick 					VOP_UNLOCK(devvp);
18367534Smckusick 					return (error);
18467534Smckusick 				}
18567534Smckusick 				VOP_UNLOCK(devvp);
18667534Smckusick 			}
18739336Smckusick 			fs->fs_ronly = 0;
188*69318Smckusick 			fs->fs_clean = 0;
189*69318Smckusick 			(void) ffs_sbupdate(ump, MNT_WAIT);
19067534Smckusick 		}
19152177Smckusick 		if (args.fspec == 0) {
19252177Smckusick 			/*
19352177Smckusick 			 * Process export requests.
19452177Smckusick 			 */
19565672Shibler 			return (vfs_export(mp, &ump->um_export, &args.export));
19652177Smckusick 		}
19750264Skarels 	}
19850264Skarels 	/*
19950264Skarels 	 * Not an update, or updating the name: look up the name
20050264Skarels 	 * and verify that it refers to a sensible block device.
20150264Skarels 	 */
20252332Smckusick 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
20352332Smckusick 	if (error = namei(ndp))
20450264Skarels 		return (error);
20550264Skarels 	devvp = ndp->ni_vp;
20651473Sbostic 
20750264Skarels 	if (devvp->v_type != VBLK) {
20850264Skarels 		vrele(devvp);
20950264Skarels 		return (ENOTBLK);
21050264Skarels 	}
21150264Skarels 	if (major(devvp->v_rdev) >= nblkdev) {
21250264Skarels 		vrele(devvp);
21350264Skarels 		return (ENXIO);
21450264Skarels 	}
21567534Smckusick 	/*
21667534Smckusick 	 * If mount by non-root, then verify that user has necessary
21767534Smckusick 	 * permissions on the device.
21867534Smckusick 	 */
21967534Smckusick 	if (p->p_ucred->cr_uid != 0) {
22067534Smckusick 		accessmode = VREAD;
22167534Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
22267534Smckusick 			accessmode |= VWRITE;
22367534Smckusick 		VOP_LOCK(devvp);
22467534Smckusick 		if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) {
22567534Smckusick 			vput(devvp);
22667534Smckusick 			return (error);
22767534Smckusick 		}
22867534Smckusick 		VOP_UNLOCK(devvp);
22967534Smckusick 	}
23050264Skarels 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
23151473Sbostic 		error = ffs_mountfs(devvp, mp, p);
23250264Skarels 	else {
23339336Smckusick 		if (devvp != ump->um_devvp)
23439336Smckusick 			error = EINVAL;	/* needs translation */
23542858Smckusick 		else
23642858Smckusick 			vrele(devvp);
23739336Smckusick 	}
23837737Smckusick 	if (error) {
23937737Smckusick 		vrele(devvp);
24037737Smckusick 		return (error);
24132721Smckusick 	}
24237737Smckusick 	ump = VFSTOUFS(mp);
24337737Smckusick 	fs = ump->um_fs;
24437737Smckusick 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
24537737Smckusick 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
24641397Smckusick 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
24741397Smckusick 	    MNAMELEN);
24841397Smckusick 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
24941397Smckusick 	    &size);
25041397Smckusick 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
25151473Sbostic 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
25237737Smckusick 	return (0);
25312795Ssam }
25412795Ssam 
25537737Smckusick /*
25657051Smckusick  * Reload all incore data for a filesystem (used after running fsck on
25757051Smckusick  * the root filesystem and finding things to fix). The filesystem must
25857051Smckusick  * be mounted read-only.
25957051Smckusick  *
26057051Smckusick  * Things to do to update the mount:
26157051Smckusick  *	1) invalidate all cached meta-data.
26257051Smckusick  *	2) re-read superblock from disk.
26357051Smckusick  *	3) re-read summary information from disk.
26457051Smckusick  *	4) invalidate all inactive vnodes.
26557051Smckusick  *	5) invalidate all cached file data.
26657051Smckusick  *	6) re-read inode data for all active vnodes.
26757051Smckusick  */
26857051Smckusick ffs_reload(mountp, cred, p)
26957051Smckusick 	register struct mount *mountp;
27057051Smckusick 	struct ucred *cred;
27157051Smckusick 	struct proc *p;
27257051Smckusick {
27357051Smckusick 	register struct vnode *vp, *nvp, *devvp;
27457051Smckusick 	struct inode *ip;
27557051Smckusick 	struct csum *space;
27657051Smckusick 	struct buf *bp;
27768545Smckusick 	struct fs *fs, *newfs;
27868115Smckusick 	struct partinfo dpart;
27957051Smckusick 	int i, blks, size, error;
28069245Smckusick 	int32_t *lp;
28157051Smckusick 
28257051Smckusick 	if ((mountp->mnt_flag & MNT_RDONLY) == 0)
28357051Smckusick 		return (EINVAL);
28457051Smckusick 	/*
28557051Smckusick 	 * Step 1: invalidate all cached meta-data.
28657051Smckusick 	 */
28757051Smckusick 	devvp = VFSTOUFS(mountp)->um_devvp;
28857801Smckusick 	if (vinvalbuf(devvp, 0, cred, p, 0, 0))
28957051Smckusick 		panic("ffs_reload: dirty1");
29057051Smckusick 	/*
29157051Smckusick 	 * Step 2: re-read superblock from disk.
29257051Smckusick 	 */
29368115Smckusick 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
29468115Smckusick 		size = DEV_BSIZE;
29568115Smckusick 	else
29668115Smckusick 		size = dpart.disklab->d_secsize;
29768554Smckusick 	if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp))
29857051Smckusick 		return (error);
29968545Smckusick 	newfs = (struct fs *)bp->b_data;
30068545Smckusick 	if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE ||
30168545Smckusick 	    newfs->fs_bsize < sizeof(struct fs)) {
30257051Smckusick 		brelse(bp);
30357051Smckusick 		return (EIO);		/* XXX needs translation */
30457051Smckusick 	}
30557051Smckusick 	fs = VFSTOUFS(mountp)->um_fs;
30668580Smckusick 	/*
30768580Smckusick 	 * Copy pointer fields back into superblock before copying in	XXX
30868580Smckusick 	 * new superblock. These should really be in the ufsmount.	XXX
30968580Smckusick 	 * Note that important parameters (eg fs_ncg) are unchanged.
31068580Smckusick 	 */
31168545Smckusick 	bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp));
31268545Smckusick 	newfs->fs_maxcluster = fs->fs_maxcluster;
31368545Smckusick 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
31457051Smckusick 	if (fs->fs_sbsize < SBSIZE)
31557051Smckusick 		bp->b_flags |= B_INVAL;
31657051Smckusick 	brelse(bp);
31767460Smckusick 	mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
31857051Smckusick 	ffs_oldfscompat(fs);
31957051Smckusick 	/*
32057051Smckusick 	 * Step 3: re-read summary information from disk.
32157051Smckusick 	 */
32257051Smckusick 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
32357051Smckusick 	space = fs->fs_csp[0];
32457051Smckusick 	for (i = 0; i < blks; i += fs->fs_frag) {
32557051Smckusick 		size = fs->fs_bsize;
32657051Smckusick 		if (i + fs->fs_frag > blks)
32757051Smckusick 			size = (blks - i) * fs->fs_fsize;
32857051Smckusick 		if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
32957051Smckusick 		    NOCRED, &bp))
33057051Smckusick 			return (error);
33164511Sbostic 		bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
33257051Smckusick 		brelse(bp);
33357051Smckusick 	}
33468580Smckusick 	/*
33568580Smckusick 	 * We no longer know anything about clusters per cylinder group.
33668580Smckusick 	 */
33768580Smckusick 	if (fs->fs_contigsumsize > 0) {
33868580Smckusick 		lp = fs->fs_maxcluster;
33968580Smckusick 		for (i = 0; i < fs->fs_ncg; i++)
34068580Smckusick 			*lp++ = fs->fs_contigsumsize;
34168580Smckusick 	}
34257051Smckusick loop:
34365236Smckusick 	for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
34465236Smckusick 		nvp = vp->v_mntvnodes.le_next;
34557051Smckusick 		/*
34657051Smckusick 		 * Step 4: invalidate all inactive vnodes.
34757051Smckusick 		 */
34857051Smckusick 		if (vp->v_usecount == 0) {
34957051Smckusick 			vgone(vp);
35057051Smckusick 			continue;
35157051Smckusick 		}
35257051Smckusick 		/*
35357051Smckusick 		 * Step 5: invalidate all cached file data.
35457051Smckusick 		 */
35565236Smckusick 		if (vget(vp, 1))
35657051Smckusick 			goto loop;
35757801Smckusick 		if (vinvalbuf(vp, 0, cred, p, 0, 0))
35857051Smckusick 			panic("ffs_reload: dirty2");
35957051Smckusick 		/*
36057051Smckusick 		 * Step 6: re-read inode data for all active vnodes.
36157051Smckusick 		 */
36257051Smckusick 		ip = VTOI(vp);
36364605Sbostic 		if (error =
36464605Sbostic 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
36557051Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
36657051Smckusick 			vput(vp);
36757051Smckusick 			return (error);
36857051Smckusick 		}
36964605Sbostic 		ip->i_din = *((struct dinode *)bp->b_data +
37064605Sbostic 		    ino_to_fsbo(fs, ip->i_number));
37157051Smckusick 		brelse(bp);
37257051Smckusick 		vput(vp);
37357051Smckusick 		if (vp->v_mount != mountp)
37457051Smckusick 			goto loop;
37557051Smckusick 	}
37657051Smckusick 	return (0);
37757051Smckusick }
37857051Smckusick 
37957051Smckusick /*
38037737Smckusick  * Common code for mount and mountroot
38137737Smckusick  */
38251473Sbostic int
38351473Sbostic ffs_mountfs(devvp, mp, p)
38440376Smckusick 	register struct vnode *devvp;
38537737Smckusick 	struct mount *mp;
38648036Smckusick 	struct proc *p;
38712795Ssam {
38854461Smckusick 	register struct ufsmount *ump;
38954461Smckusick 	struct buf *bp;
39012795Ssam 	register struct fs *fs;
39168004Smckusick 	dev_t dev;
39230749Skarels 	struct partinfo dpart;
39337737Smckusick 	caddr_t base, space;
39468115Smckusick 	int error, i, blks, size, ronly;
39567868Smckusick 	int32_t *lp;
39668004Smckusick 	struct ucred *cred;
39745652Smckusick 	extern struct vnode *rootvp;
39868115Smckusick 	u_int64_t maxfilesize;					/* XXX */
39912795Ssam 
40068004Smckusick 	dev = devvp->v_rdev;
40168004Smckusick 	cred = p ? p->p_ucred : NOCRED;
40240376Smckusick 	/*
40340376Smckusick 	 * Disallow multiple mounts of the same device.
40445652Smckusick 	 * Disallow mounting of a device that is currently in use
40545652Smckusick 	 * (except for root, which might share swap device for miniroot).
40640376Smckusick 	 * Flush out any old buffers remaining from a previous use.
40740376Smckusick 	 */
40865672Shibler 	if (error = vfs_mountedon(devvp))
40940376Smckusick 		return (error);
41045652Smckusick 	if (vcount(devvp) > 1 && devvp != rootvp)
41140376Smckusick 		return (EBUSY);
41268004Smckusick 	if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0))
41354461Smckusick 		return (error);
41454461Smckusick 
41554461Smckusick 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
41659472Smckusick 	if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))
41737737Smckusick 		return (error);
41868004Smckusick 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
41937737Smckusick 		size = DEV_BSIZE;
42068115Smckusick 	else
42130749Skarels 		size = dpart.disklab->d_secsize;
42254461Smckusick 
42354461Smckusick 	bp = NULL;
42454461Smckusick 	ump = NULL;
42568554Smckusick 	if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, cred, &bp))
42612795Ssam 		goto out;
42764511Sbostic 	fs = (struct fs *)bp->b_data;
42830749Skarels 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
42930749Skarels 	    fs->fs_bsize < sizeof(struct fs)) {
43041314Smckusick 		error = EINVAL;		/* XXX needs translation */
43116639Skarels 		goto out;
43216639Skarels 	}
43368116Smckusick 	/* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
43468116Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
43568116Smckusick 		error = EROFS;          /* needs translation */
43668116Smckusick 		goto out;
43768116Smckusick 	}
43851473Sbostic 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
43952538Smckusick 	bzero((caddr_t)ump, sizeof *ump);
44051982Smckusick 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
44134473Smckusick 	    M_WAITOK);
44264511Sbostic 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
44339675Smckusick 	if (fs->fs_sbsize < SBSIZE)
44439675Smckusick 		bp->b_flags |= B_INVAL;
44534421Skarels 	brelse(bp);
44634421Skarels 	bp = NULL;
44737737Smckusick 	fs = ump->um_fs;
44837737Smckusick 	fs->fs_ronly = ronly;
44967868Smckusick 	size = fs->fs_cssize;
45068116Smckusick 	blks = howmany(size, fs->fs_fsize);
45167868Smckusick 	if (fs->fs_contigsumsize > 0)
45267868Smckusick 		size += fs->fs_ncg * sizeof(int32_t);
45367868Smckusick 	base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
45412795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
45512795Ssam 		size = fs->fs_bsize;
45612795Ssam 		if (i + fs->fs_frag > blks)
45712795Ssam 			size = (blks - i) * fs->fs_fsize;
45868004Smckusick 		if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
45968004Smckusick 		    cred, &bp)) {
46051982Smckusick 			free(base, M_UFSMNT);
46112795Ssam 			goto out;
46212795Ssam 		}
46364511Sbostic 		bcopy(bp->b_data, space, (u_int)size);
46417225Smckusick 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
46512795Ssam 		space += size;
46634421Skarels 		brelse(bp);
46734421Skarels 		bp = NULL;
46812795Ssam 	}
46967868Smckusick 	if (fs->fs_contigsumsize > 0) {
47067868Smckusick 		fs->fs_maxcluster = lp = (int32_t *)space;
47167868Smckusick 		for (i = 0; i < fs->fs_ncg; i++)
47267868Smckusick 			*lp++ = fs->fs_contigsumsize;
47367868Smckusick 	}
47441397Smckusick 	mp->mnt_data = (qaddr_t)ump;
47541397Smckusick 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
47668668Smckusick 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
47754305Smckusick 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
47837737Smckusick 	ump->um_mountp = mp;
47937737Smckusick 	ump->um_dev = dev;
48037737Smckusick 	ump->um_devvp = devvp;
48156446Smargo 	ump->um_nindir = fs->fs_nindir;
48256446Smargo 	ump->um_bptrtodb = fs->fs_fsbtodb;
48356446Smargo 	ump->um_seqinc = fs->fs_frag;
48441314Smckusick 	for (i = 0; i < MAXQUOTAS; i++)
48541314Smckusick 		ump->um_quotas[i] = NULLVP;
48640653Smckusick 	devvp->v_specflags |= SI_MOUNTEDON;
48757051Smckusick 	ffs_oldfscompat(fs);
48867868Smckusick 	ump->um_savedmaxfilesize = fs->fs_maxfilesize;		/* XXX */
48968115Smckusick 	maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1;	/* XXX */
49068115Smckusick 	if (fs->fs_maxfilesize > maxfilesize)			/* XXX */
49168115Smckusick 		fs->fs_maxfilesize = maxfilesize;		/* XXX */
492*69318Smckusick 	if (ronly == 0) {
493*69318Smckusick 		fs->fs_clean = 0;
494*69318Smckusick 		(void) ffs_sbupdate(ump, MNT_WAIT);
495*69318Smckusick 	}
49657051Smckusick 	return (0);
49757051Smckusick out:
49857051Smckusick 	if (bp)
49957051Smckusick 		brelse(bp);
50068004Smckusick 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
50157051Smckusick 	if (ump) {
50257051Smckusick 		free(ump->um_fs, M_UFSMNT);
50357051Smckusick 		free(ump, M_UFSMNT);
50457051Smckusick 		mp->mnt_data = (qaddr_t)0;
50557051Smckusick 	}
50657051Smckusick 	return (error);
50757051Smckusick }
50837737Smckusick 
50957051Smckusick /*
51057051Smckusick  * Sanity checks for old file systems.
51157051Smckusick  *
51257051Smckusick  * XXX - goes away some day.
51357051Smckusick  */
51457051Smckusick ffs_oldfscompat(fs)
51557051Smckusick 	struct fs *fs;
51657051Smckusick {
51757051Smckusick 	int i;
51857051Smckusick 
51955056Spendry 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
52055056Spendry 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
52134145Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
52234145Smckusick 		fs->fs_nrpos = 8;				/* XXX */
52353913Smckusick 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
52468122Smckusick 		u_int64_t sizepb = fs->fs_bsize;		/* XXX */
52553913Smckusick 								/* XXX */
52653913Smckusick 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
52753913Smckusick 		for (i = 0; i < NIADDR; i++) {			/* XXX */
52853913Smckusick 			sizepb *= NINDIR(fs);			/* XXX */
52953913Smckusick 			fs->fs_maxfilesize += sizepb;		/* XXX */
53053913Smckusick 		}						/* XXX */
53153913Smckusick 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
53253913Smckusick 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
53353913Smckusick 	}							/* XXX */
53437737Smckusick 	return (0);
53512795Ssam }
53612795Ssam 
53739043Smckusick /*
53837737Smckusick  * unmount system call
53937737Smckusick  */
54051473Sbostic int
54151473Sbostic ffs_unmount(mp, mntflags, p)
54237737Smckusick 	struct mount *mp;
54341314Smckusick 	int mntflags;
54448036Smckusick 	struct proc *p;
54512795Ssam {
54637737Smckusick 	register struct ufsmount *ump;
54737737Smckusick 	register struct fs *fs;
54867861Smckusick 	int error, flags;
54912795Ssam 
55054461Smckusick 	flags = 0;
55148065Smckusick 	if (mntflags & MNT_FORCE) {
55265236Smckusick 		if (mp->mnt_flag & MNT_ROOTFS)
55348065Smckusick 			return (EINVAL);
55441314Smckusick 		flags |= FORCECLOSE;
55548065Smckusick 	}
55657051Smckusick 	if (error = ffs_flushfiles(mp, flags, p))
55757051Smckusick 		return (error);
55837737Smckusick 	ump = VFSTOUFS(mp);
55957051Smckusick 	fs = ump->um_fs;
560*69318Smckusick 	if (fs->fs_ronly == 0) {
561*69318Smckusick 		fs->fs_clean = 1;
562*69318Smckusick 		if (error = ffs_sbupdate(ump, MNT_WAIT)) {
563*69318Smckusick 			fs->fs_clean = 0;
564*69318Smckusick 			return (error);
565*69318Smckusick 		}
566*69318Smckusick 	}
56757051Smckusick 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
56867861Smckusick 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
56957051Smckusick 		NOCRED, p);
57057051Smckusick 	vrele(ump->um_devvp);
57157051Smckusick 	free(fs->fs_csp[0], M_UFSMNT);
57257051Smckusick 	free(fs, M_UFSMNT);
57357051Smckusick 	free(ump, M_UFSMNT);
57457051Smckusick 	mp->mnt_data = (qaddr_t)0;
57557051Smckusick 	return (error);
57657051Smckusick }
57757051Smckusick 
57857051Smckusick /*
57957051Smckusick  * Flush out all the files in a filesystem.
58057051Smckusick  */
58157051Smckusick ffs_flushfiles(mp, flags, p)
58257051Smckusick 	register struct mount *mp;
58357051Smckusick 	int flags;
58457051Smckusick 	struct proc *p;
58557051Smckusick {
58657051Smckusick 	extern int doforce;
58757051Smckusick 	register struct ufsmount *ump;
58857051Smckusick 	int i, error;
58957051Smckusick 
59057051Smckusick 	if (!doforce)
59157051Smckusick 		flags &= ~FORCECLOSE;
59257051Smckusick 	ump = VFSTOUFS(mp);
59312795Ssam #ifdef QUOTA
59441397Smckusick 	if (mp->mnt_flag & MNT_QUOTA) {
59541314Smckusick 		if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
59639898Smckusick 			return (error);
59741314Smckusick 		for (i = 0; i < MAXQUOTAS; i++) {
59841314Smckusick 			if (ump->um_quotas[i] == NULLVP)
59941314Smckusick 				continue;
60050114Smckusick 			quotaoff(p, mp, i);
60141314Smckusick 		}
60239898Smckusick 		/*
60341314Smckusick 		 * Here we fall through to vflush again to ensure
60441314Smckusick 		 * that we have gotten rid of all the system vnodes.
60539898Smckusick 		 */
60641314Smckusick 	}
60712795Ssam #endif
60857051Smckusick 	error = vflush(mp, NULLVP, flags);
60930749Skarels 	return (error);
61012795Ssam }
61112795Ssam 
61237737Smckusick /*
61337737Smckusick  * Get file system statistics.
61437737Smckusick  */
61551473Sbostic int
61651473Sbostic ffs_statfs(mp, sbp, p)
61737737Smckusick 	struct mount *mp;
61837737Smckusick 	register struct statfs *sbp;
61948036Smckusick 	struct proc *p;
62037737Smckusick {
62137737Smckusick 	register struct ufsmount *ump;
62237737Smckusick 	register struct fs *fs;
62337737Smckusick 
62437737Smckusick 	ump = VFSTOUFS(mp);
62537737Smckusick 	fs = ump->um_fs;
62637737Smckusick 	if (fs->fs_magic != FS_MAGIC)
62751473Sbostic 		panic("ffs_statfs");
62851942Smckusick 	sbp->f_bsize = fs->fs_fsize;
62951942Smckusick 	sbp->f_iosize = fs->fs_bsize;
63037737Smckusick 	sbp->f_blocks = fs->fs_dsize;
63137737Smckusick 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
63237737Smckusick 		fs->fs_cstotal.cs_nffree;
63337737Smckusick 	sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
63437737Smckusick 		(fs->fs_dsize - sbp->f_bfree);
63539350Smckusick 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
63637737Smckusick 	sbp->f_ffree = fs->fs_cstotal.cs_nifree;
63741397Smckusick 	if (sbp != &mp->mnt_stat) {
63868668Smckusick 		sbp->f_type = mp->mnt_vfc->vfc_typenum;
63941397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
64040346Smckusick 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
64141397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
64240346Smckusick 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
64340346Smckusick 	}
64437737Smckusick 	return (0);
64537737Smckusick }
64637737Smckusick 
64737737Smckusick /*
64837737Smckusick  * Go through the disk queues to initiate sandbagged IO;
64937737Smckusick  * go through the inodes to write those that have been modified;
65037737Smckusick  * initiate the writing of the super block if it has been modified.
65141314Smckusick  *
65241314Smckusick  * Note: we are always called with the filesystem marked `MPBUSY'.
65337737Smckusick  */
65451473Sbostic int
65554461Smckusick ffs_sync(mp, waitfor, cred, p)
65637737Smckusick 	struct mount *mp;
65737737Smckusick 	int waitfor;
65854461Smckusick 	struct ucred *cred;
65954461Smckusick 	struct proc *p;
66037737Smckusick {
66139390Smckusick 	register struct vnode *vp;
66237737Smckusick 	register struct inode *ip;
66337737Smckusick 	register struct ufsmount *ump = VFSTOUFS(mp);
66437737Smckusick 	register struct fs *fs;
66539596Smckusick 	int error, allerror = 0;
66637737Smckusick 
66737737Smckusick 	fs = ump->um_fs;
668*69318Smckusick 	if (fs->fs_ronly != 0) {		/* XXX */
669*69318Smckusick 		printf("fs = %s\n", fs->fs_fsmnt);
670*69318Smckusick 		panic("update: rofs mod");
67137737Smckusick 	}
67237737Smckusick 	/*
67337737Smckusick 	 * Write back each (modified) inode.
67437737Smckusick 	 */
67539877Smckusick loop:
67665236Smckusick 	for (vp = mp->mnt_vnodelist.lh_first;
67765236Smckusick 	     vp != NULL;
67865236Smckusick 	     vp = vp->v_mntvnodes.le_next) {
67941462Smckusick 		/*
68041462Smckusick 		 * If the vnode that we are about to sync is no longer
68141462Smckusick 		 * associated with this mount point, start over.
68241462Smckusick 		 */
68341462Smckusick 		if (vp->v_mount != mp)
68441462Smckusick 			goto loop;
68548359Smckusick 		if (VOP_ISLOCKED(vp))
68648359Smckusick 			continue;
68739390Smckusick 		ip = VTOI(vp);
68864511Sbostic 		if ((ip->i_flag &
68964605Sbostic 		    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
69065236Smckusick 		    vp->v_dirtyblkhd.lh_first == NULL)
69137737Smckusick 			continue;
69265236Smckusick 		if (vget(vp, 1))
69339877Smckusick 			goto loop;
69454461Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
69539596Smckusick 			allerror = error;
69639596Smckusick 		vput(vp);
69737737Smckusick 	}
69837737Smckusick 	/*
69939675Smckusick 	 * Force stale file system control information to be flushed.
70037737Smckusick 	 */
70154461Smckusick 	if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p))
70254461Smckusick 		allerror = error;
70341314Smckusick #ifdef QUOTA
70441314Smckusick 	qsync(mp);
70541314Smckusick #endif
706*69318Smckusick 	/*
707*69318Smckusick 	 * Write back modified superblock.
708*69318Smckusick 	 */
709*69318Smckusick 	if (fs->fs_fmod != 0) {
710*69318Smckusick 		fs->fs_fmod = 0;
711*69318Smckusick 		fs->fs_time = time.tv_sec;
712*69318Smckusick 		if (error = ffs_sbupdate(ump, waitfor))
713*69318Smckusick 			allerror = error;
714*69318Smckusick 	}
71539596Smckusick 	return (allerror);
71637737Smckusick }
71737737Smckusick 
71837737Smckusick /*
71964605Sbostic  * Look up a FFS dinode number to find its incore vnode, otherwise read it
72064605Sbostic  * in from disk.  If it is in core, wait for the lock bit to clear, then
72164605Sbostic  * return the inode locked.  Detection and handling of mount points must be
72264605Sbostic  * done by the calling routine.
72354657Smckusick  */
72454657Smckusick int
72554657Smckusick ffs_vget(mp, ino, vpp)
72654657Smckusick 	struct mount *mp;
72754657Smckusick 	ino_t ino;
72854657Smckusick 	struct vnode **vpp;
72954657Smckusick {
73054657Smckusick 	register struct fs *fs;
73154657Smckusick 	register struct inode *ip;
73254657Smckusick 	struct ufsmount *ump;
73354657Smckusick 	struct buf *bp;
73454657Smckusick 	struct vnode *vp;
73554657Smckusick 	dev_t dev;
73654657Smckusick 	int i, type, error;
73754657Smckusick 
73854657Smckusick 	ump = VFSTOUFS(mp);
73954657Smckusick 	dev = ump->um_dev;
74054657Smckusick 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
74154657Smckusick 		return (0);
74254657Smckusick 
74354657Smckusick 	/* Allocate a new vnode/inode. */
74454657Smckusick 	if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) {
74554657Smckusick 		*vpp = NULL;
74654657Smckusick 		return (error);
74754657Smckusick 	}
74854657Smckusick 	type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
74954657Smckusick 	MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
75059819Smckusick 	bzero((caddr_t)ip, sizeof(struct inode));
75154657Smckusick 	vp->v_data = ip;
75254657Smckusick 	ip->i_vnode = vp;
75354657Smckusick 	ip->i_fs = fs = ump->um_fs;
75454657Smckusick 	ip->i_dev = dev;
75554657Smckusick 	ip->i_number = ino;
75654657Smckusick #ifdef QUOTA
75754657Smckusick 	for (i = 0; i < MAXQUOTAS; i++)
75854657Smckusick 		ip->i_dquot[i] = NODQUOT;
75954657Smckusick #endif
76054657Smckusick 	/*
76154657Smckusick 	 * Put it onto its hash chain and lock it so that other requests for
76254657Smckusick 	 * this inode will block if they arrive while we are sleeping waiting
76354657Smckusick 	 * for old data structures to be purged or for the contents of the
76454657Smckusick 	 * disk portion of this inode to be read.
76554657Smckusick 	 */
76654657Smckusick 	ufs_ihashins(ip);
76754657Smckusick 
76854657Smckusick 	/* Read in the disk contents for the inode, copy into the inode. */
76964605Sbostic 	if (error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
77054657Smckusick 	    (int)fs->fs_bsize, NOCRED, &bp)) {
77154657Smckusick 		/*
77254657Smckusick 		 * The inode does not contain anything useful, so it would
77359819Smckusick 		 * be misleading to leave it on its hash chain. With mode
77459819Smckusick 		 * still zero, it will be unlinked and returned to the free
77559819Smckusick 		 * list by vput().
77654657Smckusick 		 */
77756797Smckusick 		vput(vp);
77854657Smckusick 		brelse(bp);
77954657Smckusick 		*vpp = NULL;
78054657Smckusick 		return (error);
78154657Smckusick 	}
78264605Sbostic 	ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
78354657Smckusick 	brelse(bp);
78454657Smckusick 
78554657Smckusick 	/*
78654657Smckusick 	 * Initialize the vnode from the inode, check for aliases.
78754657Smckusick 	 * Note that the underlying vnode may have changed.
78854657Smckusick 	 */
78954657Smckusick 	if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) {
79056797Smckusick 		vput(vp);
79154657Smckusick 		*vpp = NULL;
79254657Smckusick 		return (error);
79354657Smckusick 	}
79454657Smckusick 	/*
79554657Smckusick 	 * Finish inode initialization now that aliasing has been resolved.
79654657Smckusick 	 */
79754657Smckusick 	ip->i_devvp = ump->um_devvp;
79854657Smckusick 	VREF(ip->i_devvp);
79954657Smckusick 	/*
80054657Smckusick 	 * Set up a generation number for this inode if it does not
80154657Smckusick 	 * already have one. This should only happen on old filesystems.
80254657Smckusick 	 */
80354657Smckusick 	if (ip->i_gen == 0) {
80454657Smckusick 		if (++nextgennumber < (u_long)time.tv_sec)
80554657Smckusick 			nextgennumber = time.tv_sec;
80654657Smckusick 		ip->i_gen = nextgennumber;
80754657Smckusick 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
80864605Sbostic 			ip->i_flag |= IN_MODIFIED;
80954657Smckusick 	}
81054657Smckusick 	/*
81154657Smckusick 	 * Ensure that uid and gid are correct. This is a temporary
81254657Smckusick 	 * fix until fsck has been changed to do the update.
81354657Smckusick 	 */
81454657Smckusick 	if (fs->fs_inodefmt < FS_44INODEFMT) {		/* XXX */
81554657Smckusick 		ip->i_uid = ip->i_din.di_ouid;		/* XXX */
81654657Smckusick 		ip->i_gid = ip->i_din.di_ogid;		/* XXX */
81754657Smckusick 	}						/* XXX */
81854657Smckusick 
81954657Smckusick 	*vpp = vp;
82054657Smckusick 	return (0);
82154657Smckusick }
82254657Smckusick 
82354657Smckusick /*
82451545Smckusick  * File handle to vnode
82551545Smckusick  *
82651545Smckusick  * Have to be really careful about stale file handles:
82751545Smckusick  * - check that the inode number is valid
82851545Smckusick  * - call ffs_vget() to get the locked inode
82951545Smckusick  * - check for an unallocated inode (i_mode == 0)
83054733Smckusick  * - check that the given client host has export rights and return
83154733Smckusick  *   those rights via. exflagsp and credanonp
83251545Smckusick  */
83351545Smckusick int
83454733Smckusick ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
83551545Smckusick 	register struct mount *mp;
83651545Smckusick 	struct fid *fhp;
83754733Smckusick 	struct mbuf *nam;
83851545Smckusick 	struct vnode **vpp;
83954733Smckusick 	int *exflagsp;
84054733Smckusick 	struct ucred **credanonp;
84151545Smckusick {
84251545Smckusick 	register struct ufid *ufhp;
84351545Smckusick 	struct fs *fs;
84451545Smckusick 
84551545Smckusick 	ufhp = (struct ufid *)fhp;
84655890Smckusick 	fs = VFSTOUFS(mp)->um_fs;
84751545Smckusick 	if (ufhp->ufid_ino < ROOTINO ||
84851545Smckusick 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
84954733Smckusick 		return (ESTALE);
85056245Smckusick 	return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
85151545Smckusick }
85251545Smckusick 
85351545Smckusick /*
85451545Smckusick  * Vnode pointer to File handle
85551545Smckusick  */
85651545Smckusick /* ARGSUSED */
85751545Smckusick ffs_vptofh(vp, fhp)
85851545Smckusick 	struct vnode *vp;
85951545Smckusick 	struct fid *fhp;
86051545Smckusick {
86151545Smckusick 	register struct inode *ip;
86251545Smckusick 	register struct ufid *ufhp;
86351545Smckusick 
86451545Smckusick 	ip = VTOI(vp);
86551545Smckusick 	ufhp = (struct ufid *)fhp;
86651545Smckusick 	ufhp->ufid_len = sizeof(struct ufid);
86751545Smckusick 	ufhp->ufid_ino = ip->i_number;
86851545Smckusick 	ufhp->ufid_gen = ip->i_gen;
86951545Smckusick 	return (0);
87051545Smckusick }
87151545Smckusick 
87251545Smckusick /*
87368668Smckusick  * Initialize the filesystem; just use ufs_init.
87468668Smckusick  */
87568668Smckusick int
87668668Smckusick ffs_init(vfsp)
87768668Smckusick 	struct vfsconf *vfsp;
87868668Smckusick {
87968668Smckusick 
88068668Smckusick 	return (ufs_init(vfsp));
88168668Smckusick }
88268668Smckusick 
88368668Smckusick /*
88468668Smckusick  * fast filesystem related variables.
88568668Smckusick  */
88668668Smckusick ffs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
88768668Smckusick 	int *name;
88868668Smckusick 	u_int namelen;
88968668Smckusick 	void *oldp;
89068668Smckusick 	size_t *oldlenp;
89168668Smckusick 	void *newp;
89268668Smckusick 	size_t newlen;
89368668Smckusick 	struct proc *p;
89468668Smckusick {
89568668Smckusick 	extern int doclusterread, doclusterwrite, doreallocblks, doasyncfree;
89668668Smckusick 
89768668Smckusick 	/* all sysctl names at this level are terminal */
89868668Smckusick 	if (namelen != 1)
89968668Smckusick 		return (ENOTDIR);		/* overloaded */
90068668Smckusick 
90168668Smckusick 	switch (name[0]) {
90268668Smckusick 	case FFS_CLUSTERREAD:
90368668Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen,
90468668Smckusick 		    &doclusterread));
90568668Smckusick 	case FFS_CLUSTERWRITE:
90668668Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen,
90768668Smckusick 		    &doclusterwrite));
90868668Smckusick 	case FFS_REALLOCBLKS:
90968668Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen,
91068668Smckusick 		    &doreallocblks));
91168668Smckusick 	case FFS_ASYNCFREE:
91268668Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &doasyncfree));
91368668Smckusick 	default:
91468668Smckusick 		return (EOPNOTSUPP);
91568668Smckusick 	}
91668668Smckusick 	/* NOTREACHED */
91768668Smckusick }
91868668Smckusick 
91968668Smckusick /*
92037737Smckusick  * Write a superblock and associated information back to disk.
92137737Smckusick  */
92251942Smckusick int
92351473Sbostic ffs_sbupdate(mp, waitfor)
92437737Smckusick 	struct ufsmount *mp;
92537737Smckusick 	int waitfor;
92637737Smckusick {
92767868Smckusick 	register struct fs *dfs, *fs = mp->um_fs;
92812795Ssam 	register struct buf *bp;
92912795Ssam 	int blks;
93012795Ssam 	caddr_t space;
931*69318Smckusick 	int i, size, error, allerror = 0;
93212795Ssam 
933*69318Smckusick 	/*
934*69318Smckusick 	 * First write back the summary information.
935*69318Smckusick 	 */
936*69318Smckusick 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
937*69318Smckusick 	space = (caddr_t)fs->fs_csp[0];
938*69318Smckusick 	for (i = 0; i < blks; i += fs->fs_frag) {
939*69318Smckusick 		size = fs->fs_bsize;
940*69318Smckusick 		if (i + fs->fs_frag > blks)
941*69318Smckusick 			size = (blks - i) * fs->fs_fsize;
942*69318Smckusick 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
943*69318Smckusick 		    size, 0, 0);
944*69318Smckusick 		bcopy(space, bp->b_data, (u_int)size);
945*69318Smckusick 		space += size;
946*69318Smckusick 		if (waitfor != MNT_WAIT)
947*69318Smckusick 			bawrite(bp);
948*69318Smckusick 		else if (error = bwrite(bp))
949*69318Smckusick 			allerror = error;
950*69318Smckusick 	}
951*69318Smckusick 	/*
952*69318Smckusick 	 * Now write back the superblock itself. If any errors occurred
953*69318Smckusick 	 * up to this point, then fail so that the superblock avoids
954*69318Smckusick 	 * being written out as clean.
955*69318Smckusick 	 */
956*69318Smckusick 	if (allerror)
957*69318Smckusick 		return (allerror);
95857801Smckusick 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0);
95964511Sbostic 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
96034145Smckusick 	/* Restore compatibility to old file systems.		   XXX */
96167868Smckusick 	dfs = (struct fs *)bp->b_data;				/* XXX */
96234145Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
96367868Smckusick 		dfs->fs_nrpos = -1;				/* XXX */
96467397Smkm 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
96568122Smckusick 		int32_t *lp, tmp;				/* XXX */
96667397Smkm 								/* XXX */
96768122Smckusick 		lp = (int32_t *)&dfs->fs_qbmask;		/* XXX */
96867397Smkm 		tmp = lp[4];					/* XXX */
96967397Smkm 		for (i = 4; i > 0; i--)				/* XXX */
97067397Smkm 			lp[i] = lp[i-1];			/* XXX */
97167397Smkm 		lp[0] = tmp;					/* XXX */
97267397Smkm 	}							/* XXX */
97367868Smckusick 	dfs->fs_maxfilesize = mp->um_savedmaxfilesize;		/* XXX */
974*69318Smckusick 	if (waitfor != MNT_WAIT)
97537737Smckusick 		bawrite(bp);
976*69318Smckusick 	else if (error = bwrite(bp))
977*69318Smckusick 		allerror = error;
978*69318Smckusick 	return (allerror);
97912795Ssam }
980