xref: /csrg-svn/sys/ufs/ffs/ffs_vfsops.c (revision 69580)
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*69580Smckusick  *	@(#)ffs_vfsops.c	8.31 (Berkeley) 05/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,
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  */
ffs_mountroot()5851473Sbostic ffs_mountroot()
5912795Ssam {
6051473Sbostic 	extern struct vnode *rootvp;
6169366Smckusick 	struct fs *fs;
6269366Smckusick 	struct mount *mp;
6348036Smckusick 	struct proc *p = curproc;	/* XXX */
6437737Smckusick 	struct ufsmount *ump;
6537737Smckusick 	u_int size;
6637737Smckusick 	int error;
6756332Smckusick 
6856332Smckusick 	/*
6956332Smckusick 	 * Get vnodes for swapdev and rootdev.
7056332Smckusick 	 */
7169372Smckusick 	if ((error = bdevvp(swapdev, &swapdev_vp)) ||
7269372Smckusick 	    (error = bdevvp(rootdev, &rootvp))) {
7369372Smckusick 		printf("ffs_mountroot: can't setup bdevvp's");
7469372Smckusick 		return (error);
7569372Smckusick 	}
7669366Smckusick 	if (error = vfs_rootmountalloc("ufs", "root_device", &mp))
7769366Smckusick 		return (error);
7851473Sbostic 	if (error = ffs_mountfs(rootvp, mp, p)) {
7969366Smckusick 		mp->mnt_vfc->vfc_refcount--;
80*69580Smckusick 		vfs_unbusy(mp, p);
8151473Sbostic 		free(mp, M_MOUNT);
8237737Smckusick 		return (error);
8312795Ssam 	}
84*69580Smckusick 	simple_lock(&mountlist_slock);
8569318Smckusick 	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
86*69580Smckusick 	simple_unlock(&mountlist_slock);
8737737Smckusick 	ump = VFSTOUFS(mp);
8837737Smckusick 	fs = ump->um_fs;
8969366Smckusick 	(void) copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0);
9051473Sbostic 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
91*69580Smckusick 	vfs_unbusy(mp, p);
9237737Smckusick 	inittodr(fs->fs_time);
9337737Smckusick 	return (0);
9437737Smckusick }
9537737Smckusick 
9637737Smckusick /*
9737737Smckusick  * VFS Operations.
9837737Smckusick  *
9937737Smckusick  * mount system call
10037737Smckusick  */
10151942Smckusick int
ffs_mount(mp,path,data,ndp,p)10251473Sbostic ffs_mount(mp, path, data, ndp, p)
10340346Smckusick 	register struct mount *mp;
10437737Smckusick 	char *path;
10537737Smckusick 	caddr_t data;
10637737Smckusick 	struct nameidata *ndp;
10748036Smckusick 	struct proc *p;
10837737Smckusick {
10937737Smckusick 	struct vnode *devvp;
11037737Smckusick 	struct ufs_args args;
11137737Smckusick 	struct ufsmount *ump;
11237737Smckusick 	register struct fs *fs;
11337737Smckusick 	u_int size;
11457051Smckusick 	int error, flags;
11567534Smckusick 	mode_t accessmode;
11637737Smckusick 
11737737Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
11837737Smckusick 		return (error);
11940371Smckusick 	/*
12050264Skarels 	 * If updating, check whether changing from read-only to
12150264Skarels 	 * read/write; if there is no device name, that's all we do.
12250264Skarels 	 */
12350264Skarels 	if (mp->mnt_flag & MNT_UPDATE) {
12439336Smckusick 		ump = VFSTOUFS(mp);
12539336Smckusick 		fs = ump->um_fs;
12657051Smckusick 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
12757051Smckusick 			flags = WRITECLOSE;
12857051Smckusick 			if (mp->mnt_flag & MNT_FORCE)
12957051Smckusick 				flags |= FORCECLOSE;
130*69580Smckusick 			if (error = ffs_flushfiles(mp, flags, p))
13169318Smckusick 				return (error);
13269318Smckusick 			fs->fs_clean = 1;
13369318Smckusick 			fs->fs_ronly = 1;
13469318Smckusick 			if (error = ffs_sbupdate(ump, MNT_WAIT)) {
13569318Smckusick 				fs->fs_clean = 0;
13669318Smckusick 				fs->fs_ronly = 0;
13769318Smckusick 				return (error);
13869318Smckusick 			}
13957051Smckusick 		}
14069318Smckusick 		if ((mp->mnt_flag & MNT_RELOAD) &&
14169318Smckusick 		    (error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p)))
14257051Smckusick 			return (error);
14367534Smckusick 		if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
14467534Smckusick 			/*
14567534Smckusick 			 * If upgrade to read-write by non-root, then verify
14667534Smckusick 			 * that user has necessary permissions on the device.
14767534Smckusick 			 */
14867534Smckusick 			if (p->p_ucred->cr_uid != 0) {
14967534Smckusick 				devvp = ump->um_devvp;
15069417Smckusick 				vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
15167534Smckusick 				if (error = VOP_ACCESS(devvp, VREAD | VWRITE,
15267534Smckusick 				    p->p_ucred, p)) {
15369417Smckusick 					VOP_UNLOCK(devvp, 0, p);
15467534Smckusick 					return (error);
15567534Smckusick 				}
15669417Smckusick 				VOP_UNLOCK(devvp, 0, p);
15767534Smckusick 			}
15839336Smckusick 			fs->fs_ronly = 0;
15969318Smckusick 			fs->fs_clean = 0;
16069318Smckusick 			(void) ffs_sbupdate(ump, MNT_WAIT);
16167534Smckusick 		}
16252177Smckusick 		if (args.fspec == 0) {
16352177Smckusick 			/*
16452177Smckusick 			 * Process export requests.
16552177Smckusick 			 */
16665672Shibler 			return (vfs_export(mp, &ump->um_export, &args.export));
16752177Smckusick 		}
16850264Skarels 	}
16950264Skarels 	/*
17050264Skarels 	 * Not an update, or updating the name: look up the name
17150264Skarels 	 * and verify that it refers to a sensible block device.
17250264Skarels 	 */
17352332Smckusick 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
17452332Smckusick 	if (error = namei(ndp))
17550264Skarels 		return (error);
17650264Skarels 	devvp = ndp->ni_vp;
17751473Sbostic 
17850264Skarels 	if (devvp->v_type != VBLK) {
17950264Skarels 		vrele(devvp);
18050264Skarels 		return (ENOTBLK);
18150264Skarels 	}
18250264Skarels 	if (major(devvp->v_rdev) >= nblkdev) {
18350264Skarels 		vrele(devvp);
18450264Skarels 		return (ENXIO);
18550264Skarels 	}
18667534Smckusick 	/*
18767534Smckusick 	 * If mount by non-root, then verify that user has necessary
18867534Smckusick 	 * permissions on the device.
18967534Smckusick 	 */
19067534Smckusick 	if (p->p_ucred->cr_uid != 0) {
19167534Smckusick 		accessmode = VREAD;
19267534Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
19367534Smckusick 			accessmode |= VWRITE;
19469417Smckusick 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
19567534Smckusick 		if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) {
19667534Smckusick 			vput(devvp);
19767534Smckusick 			return (error);
19867534Smckusick 		}
19969417Smckusick 		VOP_UNLOCK(devvp, 0, p);
20067534Smckusick 	}
20150264Skarels 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
20251473Sbostic 		error = ffs_mountfs(devvp, mp, p);
20350264Skarels 	else {
20439336Smckusick 		if (devvp != ump->um_devvp)
20539336Smckusick 			error = EINVAL;	/* needs translation */
20642858Smckusick 		else
20742858Smckusick 			vrele(devvp);
20839336Smckusick 	}
20937737Smckusick 	if (error) {
21037737Smckusick 		vrele(devvp);
21137737Smckusick 		return (error);
21232721Smckusick 	}
21337737Smckusick 	ump = VFSTOUFS(mp);
21437737Smckusick 	fs = ump->um_fs;
21537737Smckusick 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
21637737Smckusick 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
21741397Smckusick 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
21841397Smckusick 	    MNAMELEN);
21941397Smckusick 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
22041397Smckusick 	    &size);
22141397Smckusick 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
22251473Sbostic 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
22337737Smckusick 	return (0);
22412795Ssam }
22512795Ssam 
22637737Smckusick /*
22757051Smckusick  * Reload all incore data for a filesystem (used after running fsck on
22857051Smckusick  * the root filesystem and finding things to fix). The filesystem must
22957051Smckusick  * be mounted read-only.
23057051Smckusick  *
23157051Smckusick  * Things to do to update the mount:
23257051Smckusick  *	1) invalidate all cached meta-data.
23357051Smckusick  *	2) re-read superblock from disk.
23457051Smckusick  *	3) re-read summary information from disk.
23557051Smckusick  *	4) invalidate all inactive vnodes.
23657051Smckusick  *	5) invalidate all cached file data.
23757051Smckusick  *	6) re-read inode data for all active vnodes.
23857051Smckusick  */
ffs_reload(mountp,cred,p)23957051Smckusick ffs_reload(mountp, cred, p)
24057051Smckusick 	register struct mount *mountp;
24157051Smckusick 	struct ucred *cred;
24257051Smckusick 	struct proc *p;
24357051Smckusick {
24457051Smckusick 	register struct vnode *vp, *nvp, *devvp;
24557051Smckusick 	struct inode *ip;
24657051Smckusick 	struct csum *space;
24757051Smckusick 	struct buf *bp;
24868545Smckusick 	struct fs *fs, *newfs;
24968115Smckusick 	struct partinfo dpart;
25057051Smckusick 	int i, blks, size, error;
25169245Smckusick 	int32_t *lp;
25257051Smckusick 
25357051Smckusick 	if ((mountp->mnt_flag & MNT_RDONLY) == 0)
25457051Smckusick 		return (EINVAL);
25557051Smckusick 	/*
25657051Smckusick 	 * Step 1: invalidate all cached meta-data.
25757051Smckusick 	 */
25857051Smckusick 	devvp = VFSTOUFS(mountp)->um_devvp;
25957801Smckusick 	if (vinvalbuf(devvp, 0, cred, p, 0, 0))
26057051Smckusick 		panic("ffs_reload: dirty1");
26157051Smckusick 	/*
26257051Smckusick 	 * Step 2: re-read superblock from disk.
26357051Smckusick 	 */
26468115Smckusick 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
26568115Smckusick 		size = DEV_BSIZE;
26668115Smckusick 	else
26768115Smckusick 		size = dpart.disklab->d_secsize;
26868554Smckusick 	if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp))
26957051Smckusick 		return (error);
27068545Smckusick 	newfs = (struct fs *)bp->b_data;
27168545Smckusick 	if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE ||
27268545Smckusick 	    newfs->fs_bsize < sizeof(struct fs)) {
27357051Smckusick 		brelse(bp);
27457051Smckusick 		return (EIO);		/* XXX needs translation */
27557051Smckusick 	}
27657051Smckusick 	fs = VFSTOUFS(mountp)->um_fs;
27768580Smckusick 	/*
27868580Smckusick 	 * Copy pointer fields back into superblock before copying in	XXX
27968580Smckusick 	 * new superblock. These should really be in the ufsmount.	XXX
28068580Smckusick 	 * Note that important parameters (eg fs_ncg) are unchanged.
28168580Smckusick 	 */
28268545Smckusick 	bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp));
28368545Smckusick 	newfs->fs_maxcluster = fs->fs_maxcluster;
28468545Smckusick 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
28557051Smckusick 	if (fs->fs_sbsize < SBSIZE)
28657051Smckusick 		bp->b_flags |= B_INVAL;
28757051Smckusick 	brelse(bp);
28867460Smckusick 	mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
28957051Smckusick 	ffs_oldfscompat(fs);
29057051Smckusick 	/*
29157051Smckusick 	 * Step 3: re-read summary information from disk.
29257051Smckusick 	 */
29357051Smckusick 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
29457051Smckusick 	space = fs->fs_csp[0];
29557051Smckusick 	for (i = 0; i < blks; i += fs->fs_frag) {
29657051Smckusick 		size = fs->fs_bsize;
29757051Smckusick 		if (i + fs->fs_frag > blks)
29857051Smckusick 			size = (blks - i) * fs->fs_fsize;
29957051Smckusick 		if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
30057051Smckusick 		    NOCRED, &bp))
30157051Smckusick 			return (error);
30264511Sbostic 		bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
30357051Smckusick 		brelse(bp);
30457051Smckusick 	}
30568580Smckusick 	/*
30668580Smckusick 	 * We no longer know anything about clusters per cylinder group.
30768580Smckusick 	 */
30868580Smckusick 	if (fs->fs_contigsumsize > 0) {
30968580Smckusick 		lp = fs->fs_maxcluster;
31068580Smckusick 		for (i = 0; i < fs->fs_ncg; i++)
31168580Smckusick 			*lp++ = fs->fs_contigsumsize;
31268580Smckusick 	}
31369417Smckusick 
31457051Smckusick loop:
31569417Smckusick 	simple_lock(&mntvnode_slock);
31665236Smckusick 	for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
31769417Smckusick 		if (vp->v_mount != mountp) {
31869417Smckusick 			simple_unlock(&mntvnode_slock);
31969417Smckusick 			goto loop;
32069417Smckusick 		}
32165236Smckusick 		nvp = vp->v_mntvnodes.le_next;
32257051Smckusick 		/*
32357051Smckusick 		 * Step 4: invalidate all inactive vnodes.
32457051Smckusick 		 */
32569417Smckusick 		if (vrecycle(vp, &mntvnode_slock, p))
32669417Smckusick 			goto loop;
32757051Smckusick 		/*
32857051Smckusick 		 * Step 5: invalidate all cached file data.
32957051Smckusick 		 */
33069417Smckusick 		simple_lock(&vp->v_interlock);
33169417Smckusick 		simple_unlock(&mntvnode_slock);
33269417Smckusick 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
33357051Smckusick 			goto loop;
33469417Smckusick 		}
33557801Smckusick 		if (vinvalbuf(vp, 0, cred, p, 0, 0))
33657051Smckusick 			panic("ffs_reload: dirty2");
33757051Smckusick 		/*
33857051Smckusick 		 * Step 6: re-read inode data for all active vnodes.
33957051Smckusick 		 */
34057051Smckusick 		ip = VTOI(vp);
34164605Sbostic 		if (error =
34264605Sbostic 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
34357051Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
34457051Smckusick 			vput(vp);
34557051Smckusick 			return (error);
34657051Smckusick 		}
34764605Sbostic 		ip->i_din = *((struct dinode *)bp->b_data +
34864605Sbostic 		    ino_to_fsbo(fs, ip->i_number));
34957051Smckusick 		brelse(bp);
35057051Smckusick 		vput(vp);
35169417Smckusick 		simple_lock(&mntvnode_slock);
35257051Smckusick 	}
35369417Smckusick 	simple_unlock(&mntvnode_slock);
35457051Smckusick 	return (0);
35557051Smckusick }
35657051Smckusick 
35757051Smckusick /*
35837737Smckusick  * Common code for mount and mountroot
35937737Smckusick  */
36051473Sbostic int
ffs_mountfs(devvp,mp,p)36151473Sbostic ffs_mountfs(devvp, mp, p)
36240376Smckusick 	register struct vnode *devvp;
36337737Smckusick 	struct mount *mp;
36448036Smckusick 	struct proc *p;
36512795Ssam {
36654461Smckusick 	register struct ufsmount *ump;
36754461Smckusick 	struct buf *bp;
36812795Ssam 	register struct fs *fs;
36968004Smckusick 	dev_t dev;
37030749Skarels 	struct partinfo dpart;
37137737Smckusick 	caddr_t base, space;
37268115Smckusick 	int error, i, blks, size, ronly;
37367868Smckusick 	int32_t *lp;
37468004Smckusick 	struct ucred *cred;
37545652Smckusick 	extern struct vnode *rootvp;
37668115Smckusick 	u_int64_t maxfilesize;					/* XXX */
37712795Ssam 
37868004Smckusick 	dev = devvp->v_rdev;
37968004Smckusick 	cred = p ? p->p_ucred : NOCRED;
38040376Smckusick 	/*
38140376Smckusick 	 * Disallow multiple mounts of the same device.
38245652Smckusick 	 * Disallow mounting of a device that is currently in use
38345652Smckusick 	 * (except for root, which might share swap device for miniroot).
38440376Smckusick 	 * Flush out any old buffers remaining from a previous use.
38540376Smckusick 	 */
38665672Shibler 	if (error = vfs_mountedon(devvp))
38740376Smckusick 		return (error);
38845652Smckusick 	if (vcount(devvp) > 1 && devvp != rootvp)
38940376Smckusick 		return (EBUSY);
39068004Smckusick 	if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0))
39154461Smckusick 		return (error);
39254461Smckusick 
39354461Smckusick 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
39459472Smckusick 	if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))
39537737Smckusick 		return (error);
39668004Smckusick 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
39737737Smckusick 		size = DEV_BSIZE;
39868115Smckusick 	else
39930749Skarels 		size = dpart.disklab->d_secsize;
40054461Smckusick 
40154461Smckusick 	bp = NULL;
40254461Smckusick 	ump = NULL;
40368554Smckusick 	if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, cred, &bp))
40412795Ssam 		goto out;
40564511Sbostic 	fs = (struct fs *)bp->b_data;
40630749Skarels 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
40730749Skarels 	    fs->fs_bsize < sizeof(struct fs)) {
40841314Smckusick 		error = EINVAL;		/* XXX needs translation */
40916639Skarels 		goto out;
41016639Skarels 	}
41168116Smckusick 	/* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
41268116Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
41368116Smckusick 		error = EROFS;          /* needs translation */
41468116Smckusick 		goto out;
41568116Smckusick 	}
41651473Sbostic 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
41752538Smckusick 	bzero((caddr_t)ump, sizeof *ump);
41851982Smckusick 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
41934473Smckusick 	    M_WAITOK);
42064511Sbostic 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
42139675Smckusick 	if (fs->fs_sbsize < SBSIZE)
42239675Smckusick 		bp->b_flags |= B_INVAL;
42334421Skarels 	brelse(bp);
42434421Skarels 	bp = NULL;
42537737Smckusick 	fs = ump->um_fs;
42637737Smckusick 	fs->fs_ronly = ronly;
42767868Smckusick 	size = fs->fs_cssize;
42868116Smckusick 	blks = howmany(size, fs->fs_fsize);
42967868Smckusick 	if (fs->fs_contigsumsize > 0)
43067868Smckusick 		size += fs->fs_ncg * sizeof(int32_t);
43167868Smckusick 	base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
43212795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
43312795Ssam 		size = fs->fs_bsize;
43412795Ssam 		if (i + fs->fs_frag > blks)
43512795Ssam 			size = (blks - i) * fs->fs_fsize;
43668004Smckusick 		if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
43768004Smckusick 		    cred, &bp)) {
43851982Smckusick 			free(base, M_UFSMNT);
43912795Ssam 			goto out;
44012795Ssam 		}
44164511Sbostic 		bcopy(bp->b_data, space, (u_int)size);
44217225Smckusick 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
44312795Ssam 		space += size;
44434421Skarels 		brelse(bp);
44534421Skarels 		bp = NULL;
44612795Ssam 	}
44767868Smckusick 	if (fs->fs_contigsumsize > 0) {
44867868Smckusick 		fs->fs_maxcluster = lp = (int32_t *)space;
44967868Smckusick 		for (i = 0; i < fs->fs_ncg; i++)
45067868Smckusick 			*lp++ = fs->fs_contigsumsize;
45167868Smckusick 	}
45241397Smckusick 	mp->mnt_data = (qaddr_t)ump;
45341397Smckusick 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
45468668Smckusick 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
45554305Smckusick 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
45637737Smckusick 	ump->um_mountp = mp;
45737737Smckusick 	ump->um_dev = dev;
45837737Smckusick 	ump->um_devvp = devvp;
45956446Smargo 	ump->um_nindir = fs->fs_nindir;
46056446Smargo 	ump->um_bptrtodb = fs->fs_fsbtodb;
46156446Smargo 	ump->um_seqinc = fs->fs_frag;
46241314Smckusick 	for (i = 0; i < MAXQUOTAS; i++)
46341314Smckusick 		ump->um_quotas[i] = NULLVP;
46440653Smckusick 	devvp->v_specflags |= SI_MOUNTEDON;
46557051Smckusick 	ffs_oldfscompat(fs);
46667868Smckusick 	ump->um_savedmaxfilesize = fs->fs_maxfilesize;		/* XXX */
46768115Smckusick 	maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1;	/* XXX */
46868115Smckusick 	if (fs->fs_maxfilesize > maxfilesize)			/* XXX */
46968115Smckusick 		fs->fs_maxfilesize = maxfilesize;		/* XXX */
47069318Smckusick 	if (ronly == 0) {
47169318Smckusick 		fs->fs_clean = 0;
47269318Smckusick 		(void) ffs_sbupdate(ump, MNT_WAIT);
47369318Smckusick 	}
47457051Smckusick 	return (0);
47557051Smckusick out:
47657051Smckusick 	if (bp)
47757051Smckusick 		brelse(bp);
47868004Smckusick 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
47957051Smckusick 	if (ump) {
48057051Smckusick 		free(ump->um_fs, M_UFSMNT);
48157051Smckusick 		free(ump, M_UFSMNT);
48257051Smckusick 		mp->mnt_data = (qaddr_t)0;
48357051Smckusick 	}
48457051Smckusick 	return (error);
48557051Smckusick }
48637737Smckusick 
48757051Smckusick /*
48857051Smckusick  * Sanity checks for old file systems.
48957051Smckusick  *
49057051Smckusick  * XXX - goes away some day.
49157051Smckusick  */
49257051Smckusick ffs_oldfscompat(fs)
49357051Smckusick 	struct fs *fs;
49457051Smckusick {
49557051Smckusick 	int i;
49657051Smckusick 
49755056Spendry 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
49855056Spendry 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
49934145Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
50034145Smckusick 		fs->fs_nrpos = 8;				/* XXX */
50153913Smckusick 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
50268122Smckusick 		u_int64_t sizepb = fs->fs_bsize;		/* XXX */
50353913Smckusick 								/* XXX */
50453913Smckusick 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
50553913Smckusick 		for (i = 0; i < NIADDR; i++) {			/* XXX */
50653913Smckusick 			sizepb *= NINDIR(fs);			/* XXX */
50753913Smckusick 			fs->fs_maxfilesize += sizepb;		/* XXX */
50853913Smckusick 		}						/* XXX */
50953913Smckusick 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
51053913Smckusick 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
51153913Smckusick 	}							/* XXX */
51237737Smckusick 	return (0);
51312795Ssam }
51412795Ssam 
51539043Smckusick /*
51637737Smckusick  * unmount system call
51737737Smckusick  */
51851473Sbostic int
ffs_unmount(mp,mntflags,p)51951473Sbostic ffs_unmount(mp, mntflags, p)
52037737Smckusick 	struct mount *mp;
52141314Smckusick 	int mntflags;
52248036Smckusick 	struct proc *p;
52312795Ssam {
52437737Smckusick 	register struct ufsmount *ump;
52537737Smckusick 	register struct fs *fs;
52667861Smckusick 	int error, flags;
52712795Ssam 
52854461Smckusick 	flags = 0;
52969342Smckusick 	if (mntflags & MNT_FORCE)
53041314Smckusick 		flags |= FORCECLOSE;
53157051Smckusick 	if (error = ffs_flushfiles(mp, flags, p))
53257051Smckusick 		return (error);
53337737Smckusick 	ump = VFSTOUFS(mp);
53457051Smckusick 	fs = ump->um_fs;
53569318Smckusick 	if (fs->fs_ronly == 0) {
53669318Smckusick 		fs->fs_clean = 1;
53769318Smckusick 		if (error = ffs_sbupdate(ump, MNT_WAIT)) {
53869318Smckusick 			fs->fs_clean = 0;
53969318Smckusick 			return (error);
54069318Smckusick 		}
54169318Smckusick 	}
54257051Smckusick 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
54367861Smckusick 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
54457051Smckusick 		NOCRED, p);
54557051Smckusick 	vrele(ump->um_devvp);
54657051Smckusick 	free(fs->fs_csp[0], M_UFSMNT);
54757051Smckusick 	free(fs, M_UFSMNT);
54857051Smckusick 	free(ump, M_UFSMNT);
54957051Smckusick 	mp->mnt_data = (qaddr_t)0;
55057051Smckusick 	return (error);
55157051Smckusick }
55257051Smckusick 
55357051Smckusick /*
55457051Smckusick  * Flush out all the files in a filesystem.
55557051Smckusick  */
ffs_flushfiles(mp,flags,p)55657051Smckusick ffs_flushfiles(mp, flags, p)
55757051Smckusick 	register struct mount *mp;
55857051Smckusick 	int flags;
55957051Smckusick 	struct proc *p;
56057051Smckusick {
56157051Smckusick 	register struct ufsmount *ump;
56257051Smckusick 	int i, error;
56357051Smckusick 
56457051Smckusick 	ump = VFSTOUFS(mp);
56512795Ssam #ifdef QUOTA
56641397Smckusick 	if (mp->mnt_flag & MNT_QUOTA) {
56741314Smckusick 		if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
56839898Smckusick 			return (error);
56941314Smckusick 		for (i = 0; i < MAXQUOTAS; i++) {
57041314Smckusick 			if (ump->um_quotas[i] == NULLVP)
57141314Smckusick 				continue;
57250114Smckusick 			quotaoff(p, mp, i);
57341314Smckusick 		}
57439898Smckusick 		/*
57541314Smckusick 		 * Here we fall through to vflush again to ensure
57641314Smckusick 		 * that we have gotten rid of all the system vnodes.
57739898Smckusick 		 */
57841314Smckusick 	}
57912795Ssam #endif
58057051Smckusick 	error = vflush(mp, NULLVP, flags);
58130749Skarels 	return (error);
58212795Ssam }
58312795Ssam 
58437737Smckusick /*
58537737Smckusick  * Get file system statistics.
58637737Smckusick  */
58751473Sbostic int
ffs_statfs(mp,sbp,p)58851473Sbostic ffs_statfs(mp, sbp, p)
58937737Smckusick 	struct mount *mp;
59037737Smckusick 	register struct statfs *sbp;
59148036Smckusick 	struct proc *p;
59237737Smckusick {
59337737Smckusick 	register struct ufsmount *ump;
59437737Smckusick 	register struct fs *fs;
59537737Smckusick 
59637737Smckusick 	ump = VFSTOUFS(mp);
59737737Smckusick 	fs = ump->um_fs;
59837737Smckusick 	if (fs->fs_magic != FS_MAGIC)
59951473Sbostic 		panic("ffs_statfs");
60051942Smckusick 	sbp->f_bsize = fs->fs_fsize;
60151942Smckusick 	sbp->f_iosize = fs->fs_bsize;
60237737Smckusick 	sbp->f_blocks = fs->fs_dsize;
60337737Smckusick 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
60437737Smckusick 		fs->fs_cstotal.cs_nffree;
60537737Smckusick 	sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
60637737Smckusick 		(fs->fs_dsize - sbp->f_bfree);
60739350Smckusick 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
60837737Smckusick 	sbp->f_ffree = fs->fs_cstotal.cs_nifree;
60941397Smckusick 	if (sbp != &mp->mnt_stat) {
61068668Smckusick 		sbp->f_type = mp->mnt_vfc->vfc_typenum;
61141397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
61240346Smckusick 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
61341397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
61440346Smckusick 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
61540346Smckusick 	}
61637737Smckusick 	return (0);
61737737Smckusick }
61837737Smckusick 
61937737Smckusick /*
62037737Smckusick  * Go through the disk queues to initiate sandbagged IO;
62137737Smckusick  * go through the inodes to write those that have been modified;
62237737Smckusick  * initiate the writing of the super block if it has been modified.
62341314Smckusick  *
62441314Smckusick  * Note: we are always called with the filesystem marked `MPBUSY'.
62537737Smckusick  */
62651473Sbostic int
ffs_sync(mp,waitfor,cred,p)62754461Smckusick ffs_sync(mp, waitfor, cred, p)
62837737Smckusick 	struct mount *mp;
62937737Smckusick 	int waitfor;
63054461Smckusick 	struct ucred *cred;
63154461Smckusick 	struct proc *p;
63237737Smckusick {
63369417Smckusick 	struct vnode *nvp, *vp;
63469417Smckusick 	struct inode *ip;
63569417Smckusick 	struct ufsmount *ump = VFSTOUFS(mp);
63669417Smckusick 	struct fs *fs;
63739596Smckusick 	int error, allerror = 0;
63837737Smckusick 
63937737Smckusick 	fs = ump->um_fs;
64069342Smckusick 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
64169318Smckusick 		printf("fs = %s\n", fs->fs_fsmnt);
64269318Smckusick 		panic("update: rofs mod");
64337737Smckusick 	}
64437737Smckusick 	/*
64537737Smckusick 	 * Write back each (modified) inode.
64637737Smckusick 	 */
64769417Smckusick 	simple_lock(&mntvnode_slock);
64839877Smckusick loop:
64965236Smckusick 	for (vp = mp->mnt_vnodelist.lh_first;
65065236Smckusick 	     vp != NULL;
65169417Smckusick 	     vp = nvp) {
65241462Smckusick 		/*
65341462Smckusick 		 * If the vnode that we are about to sync is no longer
65441462Smckusick 		 * associated with this mount point, start over.
65541462Smckusick 		 */
65641462Smckusick 		if (vp->v_mount != mp)
65741462Smckusick 			goto loop;
65869417Smckusick 		simple_lock(&vp->v_interlock);
65969417Smckusick 		nvp = vp->v_mntvnodes.le_next;
66039390Smckusick 		ip = VTOI(vp);
66164511Sbostic 		if ((ip->i_flag &
66264605Sbostic 		    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
66369417Smckusick 		    vp->v_dirtyblkhd.lh_first == NULL) {
66469417Smckusick 			simple_unlock(&vp->v_interlock);
66537737Smckusick 			continue;
66669417Smckusick 		}
66769417Smckusick 		simple_unlock(&mntvnode_slock);
66869417Smckusick 		error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
66969417Smckusick 		if (error) {
67069417Smckusick 			simple_lock(&mntvnode_slock);
67169417Smckusick 			if (error == ENOENT)
67269417Smckusick 				goto loop;
67369417Smckusick 			continue;
67469417Smckusick 		}
67554461Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
67639596Smckusick 			allerror = error;
67769417Smckusick 		VOP_UNLOCK(vp, 0, p);
67869417Smckusick 		vrele(vp);
67969417Smckusick 		simple_lock(&mntvnode_slock);
68037737Smckusick 	}
68169417Smckusick 	simple_unlock(&mntvnode_slock);
68237737Smckusick 	/*
68339675Smckusick 	 * Force stale file system control information to be flushed.
68437737Smckusick 	 */
68554461Smckusick 	if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p))
68654461Smckusick 		allerror = error;
68741314Smckusick #ifdef QUOTA
68841314Smckusick 	qsync(mp);
68941314Smckusick #endif
69069318Smckusick 	/*
69169318Smckusick 	 * Write back modified superblock.
69269318Smckusick 	 */
69369318Smckusick 	if (fs->fs_fmod != 0) {
69469318Smckusick 		fs->fs_fmod = 0;
69569318Smckusick 		fs->fs_time = time.tv_sec;
69669318Smckusick 		if (error = ffs_sbupdate(ump, waitfor))
69769318Smckusick 			allerror = error;
69869318Smckusick 	}
69939596Smckusick 	return (allerror);
70037737Smckusick }
70137737Smckusick 
70237737Smckusick /*
70364605Sbostic  * Look up a FFS dinode number to find its incore vnode, otherwise read it
70464605Sbostic  * in from disk.  If it is in core, wait for the lock bit to clear, then
70564605Sbostic  * return the inode locked.  Detection and handling of mount points must be
70664605Sbostic  * done by the calling routine.
70754657Smckusick  */
70854657Smckusick int
ffs_vget(mp,ino,vpp)70954657Smckusick ffs_vget(mp, ino, vpp)
71054657Smckusick 	struct mount *mp;
71154657Smckusick 	ino_t ino;
71254657Smckusick 	struct vnode **vpp;
71354657Smckusick {
71469417Smckusick 	struct proc *p = curproc;		/* XXX */
71569417Smckusick 	struct fs *fs;
71669417Smckusick 	struct inode *ip;
71754657Smckusick 	struct ufsmount *ump;
71854657Smckusick 	struct buf *bp;
71954657Smckusick 	struct vnode *vp;
72054657Smckusick 	dev_t dev;
72154657Smckusick 	int i, type, error;
72254657Smckusick 
72354657Smckusick 	ump = VFSTOUFS(mp);
72454657Smckusick 	dev = ump->um_dev;
72554657Smckusick 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
72654657Smckusick 		return (0);
72754657Smckusick 
72854657Smckusick 	/* Allocate a new vnode/inode. */
72954657Smckusick 	if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) {
73054657Smckusick 		*vpp = NULL;
73154657Smckusick 		return (error);
73254657Smckusick 	}
73354657Smckusick 	type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
73454657Smckusick 	MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
73559819Smckusick 	bzero((caddr_t)ip, sizeof(struct inode));
73669417Smckusick 	lockinit(&ip->i_lock, PINOD, "inode", 0, 0);
73754657Smckusick 	vp->v_data = ip;
73854657Smckusick 	ip->i_vnode = vp;
73954657Smckusick 	ip->i_fs = fs = ump->um_fs;
74054657Smckusick 	ip->i_dev = dev;
74154657Smckusick 	ip->i_number = ino;
74254657Smckusick #ifdef QUOTA
74354657Smckusick 	for (i = 0; i < MAXQUOTAS; i++)
74454657Smckusick 		ip->i_dquot[i] = NODQUOT;
74554657Smckusick #endif
74654657Smckusick 	/*
74754657Smckusick 	 * Put it onto its hash chain and lock it so that other requests for
74854657Smckusick 	 * this inode will block if they arrive while we are sleeping waiting
74954657Smckusick 	 * for old data structures to be purged or for the contents of the
75054657Smckusick 	 * disk portion of this inode to be read.
75154657Smckusick 	 */
75254657Smckusick 	ufs_ihashins(ip);
75354657Smckusick 
75454657Smckusick 	/* Read in the disk contents for the inode, copy into the inode. */
75564605Sbostic 	if (error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
75654657Smckusick 	    (int)fs->fs_bsize, NOCRED, &bp)) {
75754657Smckusick 		/*
75854657Smckusick 		 * The inode does not contain anything useful, so it would
75959819Smckusick 		 * be misleading to leave it on its hash chain. With mode
76059819Smckusick 		 * still zero, it will be unlinked and returned to the free
76159819Smckusick 		 * list by vput().
76254657Smckusick 		 */
76356797Smckusick 		vput(vp);
76454657Smckusick 		brelse(bp);
76554657Smckusick 		*vpp = NULL;
76654657Smckusick 		return (error);
76754657Smckusick 	}
76864605Sbostic 	ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
76954657Smckusick 	brelse(bp);
77054657Smckusick 
77154657Smckusick 	/*
77254657Smckusick 	 * Initialize the vnode from the inode, check for aliases.
77354657Smckusick 	 * Note that the underlying vnode may have changed.
77454657Smckusick 	 */
77554657Smckusick 	if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) {
77656797Smckusick 		vput(vp);
77754657Smckusick 		*vpp = NULL;
77854657Smckusick 		return (error);
77954657Smckusick 	}
78054657Smckusick 	/*
78154657Smckusick 	 * Finish inode initialization now that aliasing has been resolved.
78254657Smckusick 	 */
78354657Smckusick 	ip->i_devvp = ump->um_devvp;
78454657Smckusick 	VREF(ip->i_devvp);
78554657Smckusick 	/*
78654657Smckusick 	 * Set up a generation number for this inode if it does not
78754657Smckusick 	 * already have one. This should only happen on old filesystems.
78854657Smckusick 	 */
78954657Smckusick 	if (ip->i_gen == 0) {
79054657Smckusick 		if (++nextgennumber < (u_long)time.tv_sec)
79154657Smckusick 			nextgennumber = time.tv_sec;
79254657Smckusick 		ip->i_gen = nextgennumber;
79354657Smckusick 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
79464605Sbostic 			ip->i_flag |= IN_MODIFIED;
79554657Smckusick 	}
79654657Smckusick 	/*
79754657Smckusick 	 * Ensure that uid and gid are correct. This is a temporary
79854657Smckusick 	 * fix until fsck has been changed to do the update.
79954657Smckusick 	 */
80054657Smckusick 	if (fs->fs_inodefmt < FS_44INODEFMT) {		/* XXX */
80154657Smckusick 		ip->i_uid = ip->i_din.di_ouid;		/* XXX */
80254657Smckusick 		ip->i_gid = ip->i_din.di_ogid;		/* XXX */
80354657Smckusick 	}						/* XXX */
80454657Smckusick 
80554657Smckusick 	*vpp = vp;
80654657Smckusick 	return (0);
80754657Smckusick }
80854657Smckusick 
80954657Smckusick /*
81051545Smckusick  * File handle to vnode
81151545Smckusick  *
81251545Smckusick  * Have to be really careful about stale file handles:
81351545Smckusick  * - check that the inode number is valid
81451545Smckusick  * - call ffs_vget() to get the locked inode
81551545Smckusick  * - check for an unallocated inode (i_mode == 0)
81654733Smckusick  * - check that the given client host has export rights and return
81754733Smckusick  *   those rights via. exflagsp and credanonp
81851545Smckusick  */
81951545Smckusick int
ffs_fhtovp(mp,fhp,nam,vpp,exflagsp,credanonp)82054733Smckusick ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
82151545Smckusick 	register struct mount *mp;
82251545Smckusick 	struct fid *fhp;
82354733Smckusick 	struct mbuf *nam;
82451545Smckusick 	struct vnode **vpp;
82554733Smckusick 	int *exflagsp;
82654733Smckusick 	struct ucred **credanonp;
82751545Smckusick {
82851545Smckusick 	register struct ufid *ufhp;
82951545Smckusick 	struct fs *fs;
83051545Smckusick 
83151545Smckusick 	ufhp = (struct ufid *)fhp;
83255890Smckusick 	fs = VFSTOUFS(mp)->um_fs;
83351545Smckusick 	if (ufhp->ufid_ino < ROOTINO ||
83451545Smckusick 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
83554733Smckusick 		return (ESTALE);
83656245Smckusick 	return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
83751545Smckusick }
83851545Smckusick 
83951545Smckusick /*
84051545Smckusick  * Vnode pointer to File handle
84151545Smckusick  */
84251545Smckusick /* ARGSUSED */
84351545Smckusick ffs_vptofh(vp, fhp)
84451545Smckusick 	struct vnode *vp;
84551545Smckusick 	struct fid *fhp;
84651545Smckusick {
84751545Smckusick 	register struct inode *ip;
84851545Smckusick 	register struct ufid *ufhp;
84951545Smckusick 
85051545Smckusick 	ip = VTOI(vp);
85151545Smckusick 	ufhp = (struct ufid *)fhp;
85251545Smckusick 	ufhp->ufid_len = sizeof(struct ufid);
85351545Smckusick 	ufhp->ufid_ino = ip->i_number;
85451545Smckusick 	ufhp->ufid_gen = ip->i_gen;
85551545Smckusick 	return (0);
85651545Smckusick }
85751545Smckusick 
85851545Smckusick /*
85968668Smckusick  * Initialize the filesystem; just use ufs_init.
86068668Smckusick  */
86168668Smckusick int
ffs_init(vfsp)86268668Smckusick ffs_init(vfsp)
86368668Smckusick 	struct vfsconf *vfsp;
86468668Smckusick {
86568668Smckusick 
86668668Smckusick 	return (ufs_init(vfsp));
86768668Smckusick }
86868668Smckusick 
86968668Smckusick /*
87068668Smckusick  * fast filesystem related variables.
87168668Smckusick  */
ffs_sysctl(name,namelen,oldp,oldlenp,newp,newlen,p)87268668Smckusick ffs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
87368668Smckusick 	int *name;
87468668Smckusick 	u_int namelen;
87568668Smckusick 	void *oldp;
87668668Smckusick 	size_t *oldlenp;
87768668Smckusick 	void *newp;
87868668Smckusick 	size_t newlen;
87968668Smckusick 	struct proc *p;
88068668Smckusick {
88168668Smckusick 	extern int doclusterread, doclusterwrite, doreallocblks, doasyncfree;
88268668Smckusick 
88368668Smckusick 	/* all sysctl names at this level are terminal */
88468668Smckusick 	if (namelen != 1)
88568668Smckusick 		return (ENOTDIR);		/* overloaded */
88668668Smckusick 
88768668Smckusick 	switch (name[0]) {
88868668Smckusick 	case FFS_CLUSTERREAD:
88968668Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen,
89068668Smckusick 		    &doclusterread));
89168668Smckusick 	case FFS_CLUSTERWRITE:
89268668Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen,
89368668Smckusick 		    &doclusterwrite));
89468668Smckusick 	case FFS_REALLOCBLKS:
89568668Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen,
89668668Smckusick 		    &doreallocblks));
89768668Smckusick 	case FFS_ASYNCFREE:
89868668Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &doasyncfree));
89968668Smckusick 	default:
90068668Smckusick 		return (EOPNOTSUPP);
90168668Smckusick 	}
90268668Smckusick 	/* NOTREACHED */
90368668Smckusick }
90468668Smckusick 
90568668Smckusick /*
90637737Smckusick  * Write a superblock and associated information back to disk.
90737737Smckusick  */
90851942Smckusick int
ffs_sbupdate(mp,waitfor)90951473Sbostic ffs_sbupdate(mp, waitfor)
91037737Smckusick 	struct ufsmount *mp;
91137737Smckusick 	int waitfor;
91237737Smckusick {
91367868Smckusick 	register struct fs *dfs, *fs = mp->um_fs;
91412795Ssam 	register struct buf *bp;
91512795Ssam 	int blks;
91612795Ssam 	caddr_t space;
91769318Smckusick 	int i, size, error, allerror = 0;
91812795Ssam 
91969318Smckusick 	/*
92069318Smckusick 	 * First write back the summary information.
92169318Smckusick 	 */
92269318Smckusick 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
92369318Smckusick 	space = (caddr_t)fs->fs_csp[0];
92469318Smckusick 	for (i = 0; i < blks; i += fs->fs_frag) {
92569318Smckusick 		size = fs->fs_bsize;
92669318Smckusick 		if (i + fs->fs_frag > blks)
92769318Smckusick 			size = (blks - i) * fs->fs_fsize;
92869318Smckusick 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
92969318Smckusick 		    size, 0, 0);
93069318Smckusick 		bcopy(space, bp->b_data, (u_int)size);
93169318Smckusick 		space += size;
93269318Smckusick 		if (waitfor != MNT_WAIT)
93369318Smckusick 			bawrite(bp);
93469318Smckusick 		else if (error = bwrite(bp))
93569318Smckusick 			allerror = error;
93669318Smckusick 	}
93769318Smckusick 	/*
93869318Smckusick 	 * Now write back the superblock itself. If any errors occurred
93969318Smckusick 	 * up to this point, then fail so that the superblock avoids
94069318Smckusick 	 * being written out as clean.
94169318Smckusick 	 */
94269318Smckusick 	if (allerror)
94369318Smckusick 		return (allerror);
94457801Smckusick 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0);
94564511Sbostic 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
94634145Smckusick 	/* Restore compatibility to old file systems.		   XXX */
94767868Smckusick 	dfs = (struct fs *)bp->b_data;				/* XXX */
94834145Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
94967868Smckusick 		dfs->fs_nrpos = -1;				/* XXX */
95067397Smkm 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
95168122Smckusick 		int32_t *lp, tmp;				/* XXX */
95267397Smkm 								/* XXX */
95368122Smckusick 		lp = (int32_t *)&dfs->fs_qbmask;		/* XXX */
95467397Smkm 		tmp = lp[4];					/* XXX */
95567397Smkm 		for (i = 4; i > 0; i--)				/* XXX */
95667397Smkm 			lp[i] = lp[i-1];			/* XXX */
95767397Smkm 		lp[0] = tmp;					/* XXX */
95867397Smkm 	}							/* XXX */
95967868Smckusick 	dfs->fs_maxfilesize = mp->um_savedmaxfilesize;		/* XXX */
96069318Smckusick 	if (waitfor != MNT_WAIT)
96137737Smckusick 		bawrite(bp);
96269318Smckusick 	else if (error = bwrite(bp))
96369318Smckusick 		allerror = error;
96469318Smckusick 	return (allerror);
96512795Ssam }
966