xref: /csrg-svn/sys/ufs/ffs/ffs_vfsops.c (revision 59819)
123400Smckusick /*
250264Skarels  * Copyright (c) 1989, 1991 The Regents of the University of California.
337737Smckusick  * All rights reserved.
423400Smckusick  *
544539Sbostic  * %sccs.include.redist.c%
637737Smckusick  *
7*59819Smckusick  *	@(#)ffs_vfsops.c	7.86 (Berkeley) 05/09/93
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,
4251545Smckusick 	ffs_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 	}
9039336Smckusick 	rootfs = mp;
9141397Smckusick 	mp->mnt_next = mp;
9241397Smckusick 	mp->mnt_prev = mp;
9341397Smckusick 	mp->mnt_vnodecovered = NULLVP;
9437737Smckusick 	ump = VFSTOUFS(mp);
9537737Smckusick 	fs = ump->um_fs;
9640346Smckusick 	bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
9737737Smckusick 	fs->fs_fsmnt[0] = '/';
9841397Smckusick 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
9941397Smckusick 	    MNAMELEN);
10041397Smckusick 	(void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
10141397Smckusick 	    &size);
10241397Smckusick 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
10351473Sbostic 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
10437737Smckusick 	vfs_unlock(mp);
10537737Smckusick 	inittodr(fs->fs_time);
10637737Smckusick 	return (0);
10737737Smckusick }
10837737Smckusick 
10937737Smckusick /*
11037737Smckusick  * VFS Operations.
11137737Smckusick  *
11237737Smckusick  * mount system call
11337737Smckusick  */
11451942Smckusick int
11551473Sbostic ffs_mount(mp, path, data, ndp, p)
11640346Smckusick 	register struct mount *mp;
11737737Smckusick 	char *path;
11837737Smckusick 	caddr_t data;
11937737Smckusick 	struct nameidata *ndp;
12048036Smckusick 	struct proc *p;
12137737Smckusick {
12237737Smckusick 	struct vnode *devvp;
12337737Smckusick 	struct ufs_args args;
12437737Smckusick 	struct ufsmount *ump;
12537737Smckusick 	register struct fs *fs;
12637737Smckusick 	u_int size;
12757051Smckusick 	int error, flags;
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);
15257051Smckusick 		if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR))
15339336Smckusick 			fs->fs_ronly = 0;
15452177Smckusick 		if (args.fspec == 0) {
15552177Smckusick 			/*
15652177Smckusick 			 * Process export requests.
15752177Smckusick 			 */
15852177Smckusick 			if (args.exflags & MNT_EXPORTED) {
15954618Smckusick 				if (error = ufs_hang_addrlist(mp, &args))
16052177Smckusick 					return (error);
16152177Smckusick 				mp->mnt_flag |= MNT_EXPORTED;
16252177Smckusick 			}
16352177Smckusick 			if (args.exflags & MNT_DELEXPORT) {
16454618Smckusick 				ufs_free_addrlist(ump);
16552177Smckusick 				mp->mnt_flag &=
16652177Smckusick 				    ~(MNT_EXPORTED | MNT_DEFEXPORTED);
16752177Smckusick 			}
16840371Smckusick 			return (0);
16952177Smckusick 		}
17050264Skarels 	}
17150264Skarels 	/*
17250264Skarels 	 * Not an update, or updating the name: look up the name
17350264Skarels 	 * and verify that it refers to a sensible block device.
17450264Skarels 	 */
17552332Smckusick 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
17652332Smckusick 	if (error = namei(ndp))
17750264Skarels 		return (error);
17850264Skarels 	devvp = ndp->ni_vp;
17951473Sbostic 
18050264Skarels 	if (devvp->v_type != VBLK) {
18150264Skarels 		vrele(devvp);
18250264Skarels 		return (ENOTBLK);
18350264Skarels 	}
18450264Skarels 	if (major(devvp->v_rdev) >= nblkdev) {
18550264Skarels 		vrele(devvp);
18650264Skarels 		return (ENXIO);
18750264Skarels 	}
18850264Skarels 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
18951473Sbostic 		error = ffs_mountfs(devvp, mp, p);
19050264Skarels 	else {
19139336Smckusick 		if (devvp != ump->um_devvp)
19239336Smckusick 			error = EINVAL;	/* needs translation */
19342858Smckusick 		else
19442858Smckusick 			vrele(devvp);
19539336Smckusick 	}
19637737Smckusick 	if (error) {
19737737Smckusick 		vrele(devvp);
19837737Smckusick 		return (error);
19932721Smckusick 	}
20037737Smckusick 	ump = VFSTOUFS(mp);
20137737Smckusick 	fs = ump->um_fs;
20237737Smckusick 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
20337737Smckusick 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
20441397Smckusick 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
20541397Smckusick 	    MNAMELEN);
20641397Smckusick 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
20741397Smckusick 	    &size);
20841397Smckusick 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
20951473Sbostic 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
21037737Smckusick 	return (0);
21112795Ssam }
21212795Ssam 
21337737Smckusick /*
21457051Smckusick  * Reload all incore data for a filesystem (used after running fsck on
21557051Smckusick  * the root filesystem and finding things to fix). The filesystem must
21657051Smckusick  * be mounted read-only.
21757051Smckusick  *
21857051Smckusick  * Things to do to update the mount:
21957051Smckusick  *	1) invalidate all cached meta-data.
22057051Smckusick  *	2) re-read superblock from disk.
22157051Smckusick  *	3) re-read summary information from disk.
22257051Smckusick  *	4) invalidate all inactive vnodes.
22357051Smckusick  *	5) invalidate all cached file data.
22457051Smckusick  *	6) re-read inode data for all active vnodes.
22557051Smckusick  */
22657051Smckusick ffs_reload(mountp, cred, p)
22757051Smckusick 	register struct mount *mountp;
22857051Smckusick 	struct ucred *cred;
22957051Smckusick 	struct proc *p;
23057051Smckusick {
23157051Smckusick 	register struct vnode *vp, *nvp, *devvp;
23257051Smckusick 	struct inode *ip;
23357051Smckusick 	struct dinode *dp;
23457051Smckusick 	struct csum *space;
23557051Smckusick 	struct buf *bp;
23657051Smckusick 	struct fs *fs;
23757051Smckusick 	int i, blks, size, error;
23857051Smckusick 
23957051Smckusick 	if ((mountp->mnt_flag & MNT_RDONLY) == 0)
24057051Smckusick 		return (EINVAL);
24157051Smckusick 	/*
24257051Smckusick 	 * Step 1: invalidate all cached meta-data.
24357051Smckusick 	 */
24457051Smckusick 	devvp = VFSTOUFS(mountp)->um_devvp;
24557801Smckusick 	if (vinvalbuf(devvp, 0, cred, p, 0, 0))
24657051Smckusick 		panic("ffs_reload: dirty1");
24757051Smckusick 	/*
24857051Smckusick 	 * Step 2: re-read superblock from disk.
24957051Smckusick 	 */
25057051Smckusick 	if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp))
25157051Smckusick 		return (error);
25257051Smckusick 	fs = bp->b_un.b_fs;
25357051Smckusick 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
25457051Smckusick 	    fs->fs_bsize < sizeof(struct fs)) {
25557051Smckusick 		brelse(bp);
25657051Smckusick 		return (EIO);		/* XXX needs translation */
25757051Smckusick 	}
25857051Smckusick 	fs = VFSTOUFS(mountp)->um_fs;
25957051Smckusick 	bcopy((caddr_t)&fs->fs_csp[0], (caddr_t)&bp->b_un.b_fs->fs_csp[0],
26057051Smckusick 	    sizeof(fs->fs_csp));
26157051Smckusick 	bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)fs, (u_int)fs->fs_sbsize);
26257051Smckusick 	if (fs->fs_sbsize < SBSIZE)
26357051Smckusick 		bp->b_flags |= B_INVAL;
26457051Smckusick 	brelse(bp);
26557051Smckusick 	ffs_oldfscompat(fs);
26657051Smckusick 	/*
26757051Smckusick 	 * Step 3: re-read summary information from disk.
26857051Smckusick 	 */
26957051Smckusick 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
27057051Smckusick 	space = fs->fs_csp[0];
27157051Smckusick 	for (i = 0; i < blks; i += fs->fs_frag) {
27257051Smckusick 		size = fs->fs_bsize;
27357051Smckusick 		if (i + fs->fs_frag > blks)
27457051Smckusick 			size = (blks - i) * fs->fs_fsize;
27557051Smckusick 		if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
27657051Smckusick 		    NOCRED, &bp))
27757051Smckusick 			return (error);
27857051Smckusick 		bcopy((caddr_t)bp->b_un.b_addr, fs->fs_csp[fragstoblks(fs, i)],
27957051Smckusick 		    (u_int)size);
28057051Smckusick 		brelse(bp);
28157051Smckusick 	}
28257051Smckusick loop:
28357051Smckusick 	for (vp = mountp->mnt_mounth; vp; vp = nvp) {
28457051Smckusick 		nvp = vp->v_mountf;
28557051Smckusick 		/*
28657051Smckusick 		 * Step 4: invalidate all inactive vnodes.
28757051Smckusick 		 */
28857051Smckusick 		if (vp->v_usecount == 0) {
28957051Smckusick 			vgone(vp);
29057051Smckusick 			continue;
29157051Smckusick 		}
29257051Smckusick 		/*
29357051Smckusick 		 * Step 5: invalidate all cached file data.
29457051Smckusick 		 */
29557051Smckusick 		if (vget(vp))
29657051Smckusick 			goto loop;
29757801Smckusick 		if (vinvalbuf(vp, 0, cred, p, 0, 0))
29857051Smckusick 			panic("ffs_reload: dirty2");
29957051Smckusick 		/*
30057051Smckusick 		 * Step 6: re-read inode data for all active vnodes.
30157051Smckusick 		 */
30257051Smckusick 		ip = VTOI(vp);
30357051Smckusick 		if (error = bread(devvp, fsbtodb(fs, itod(fs, ip->i_number)),
30457051Smckusick 		    (int)fs->fs_bsize, NOCRED, &bp)) {
30557051Smckusick 			vput(vp);
30657051Smckusick 			return (error);
30757051Smckusick 		}
30857051Smckusick 		dp = bp->b_un.b_dino;
30957051Smckusick 		dp += itoo(fs, ip->i_number);
31057051Smckusick 		ip->i_din = *dp;
31157051Smckusick 		brelse(bp);
31257051Smckusick 		vput(vp);
31357051Smckusick 		if (vp->v_mount != mountp)
31457051Smckusick 			goto loop;
31557051Smckusick 	}
31657051Smckusick 	return (0);
31757051Smckusick }
31857051Smckusick 
31957051Smckusick /*
32037737Smckusick  * Common code for mount and mountroot
32137737Smckusick  */
32251473Sbostic int
32351473Sbostic ffs_mountfs(devvp, mp, p)
32440376Smckusick 	register struct vnode *devvp;
32537737Smckusick 	struct mount *mp;
32648036Smckusick 	struct proc *p;
32712795Ssam {
32854461Smckusick 	register struct ufsmount *ump;
32954461Smckusick 	struct buf *bp;
33012795Ssam 	register struct fs *fs;
33137737Smckusick 	dev_t dev = devvp->v_rdev;
33230749Skarels 	struct partinfo dpart;
33337737Smckusick 	caddr_t base, space;
33430749Skarels 	int havepart = 0, blks;
33537737Smckusick 	int error, i, size;
33654461Smckusick 	int ronly;
33745652Smckusick 	extern struct vnode *rootvp;
33812795Ssam 
33940376Smckusick 	/*
34040376Smckusick 	 * Disallow multiple mounts of the same device.
34145652Smckusick 	 * Disallow mounting of a device that is currently in use
34245652Smckusick 	 * (except for root, which might share swap device for miniroot).
34340376Smckusick 	 * Flush out any old buffers remaining from a previous use.
34440376Smckusick 	 */
34551473Sbostic 	if (error = ufs_mountedon(devvp))
34640376Smckusick 		return (error);
34745652Smckusick 	if (vcount(devvp) > 1 && devvp != rootvp)
34840376Smckusick 		return (EBUSY);
34957801Smckusick 	if (error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0))
35054461Smckusick 		return (error);
35154461Smckusick 
35254461Smckusick 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
35359472Smckusick 	if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))
35437737Smckusick 		return (error);
35548036Smckusick 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
35637737Smckusick 		size = DEV_BSIZE;
35748036Smckusick 	else {
35830749Skarels 		havepart = 1;
35930749Skarels 		size = dpart.disklab->d_secsize;
36037737Smckusick 	}
36154461Smckusick 
36254461Smckusick 	bp = NULL;
36354461Smckusick 	ump = NULL;
36441314Smckusick 	if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp))
36512795Ssam 		goto out;
36634421Skarels 	fs = bp->b_un.b_fs;
36730749Skarels 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
36830749Skarels 	    fs->fs_bsize < sizeof(struct fs)) {
36941314Smckusick 		error = EINVAL;		/* XXX needs translation */
37016639Skarels 		goto out;
37116639Skarels 	}
37251473Sbostic 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
37352538Smckusick 	bzero((caddr_t)ump, sizeof *ump);
37451982Smckusick 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
37534473Smckusick 	    M_WAITOK);
37637737Smckusick 	bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
37712795Ssam 	   (u_int)fs->fs_sbsize);
37839675Smckusick 	if (fs->fs_sbsize < SBSIZE)
37939675Smckusick 		bp->b_flags |= B_INVAL;
38034421Skarels 	brelse(bp);
38134421Skarels 	bp = NULL;
38237737Smckusick 	fs = ump->um_fs;
38337737Smckusick 	fs->fs_ronly = ronly;
38412795Ssam 	if (ronly == 0)
38512795Ssam 		fs->fs_fmod = 1;
38630749Skarels 	if (havepart) {
38730749Skarels 		dpart.part->p_fstype = FS_BSDFFS;
38830749Skarels 		dpart.part->p_fsize = fs->fs_fsize;
38930749Skarels 		dpart.part->p_frag = fs->fs_frag;
39031385Skarels 		dpart.part->p_cpg = fs->fs_cpg;
39130749Skarels 	}
39212795Ssam 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
39351982Smckusick 	base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT,
39434473Smckusick 	    M_WAITOK);
39512795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
39612795Ssam 		size = fs->fs_bsize;
39712795Ssam 		if (i + fs->fs_frag > blks)
39812795Ssam 			size = (blks - i) * fs->fs_fsize;
39938776Smckusick 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
40038776Smckusick 			NOCRED, &bp);
40137737Smckusick 		if (error) {
40251982Smckusick 			free(base, M_UFSMNT);
40312795Ssam 			goto out;
40412795Ssam 		}
40534421Skarels 		bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size);
40617225Smckusick 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
40712795Ssam 		space += size;
40834421Skarels 		brelse(bp);
40934421Skarels 		bp = NULL;
41012795Ssam 	}
41141397Smckusick 	mp->mnt_data = (qaddr_t)ump;
41241397Smckusick 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
41341397Smckusick 	mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS;
41454305Smckusick 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
41541397Smckusick 	mp->mnt_flag |= MNT_LOCAL;
41637737Smckusick 	ump->um_mountp = mp;
41737737Smckusick 	ump->um_dev = dev;
41837737Smckusick 	ump->um_devvp = devvp;
41956446Smargo 	ump->um_nindir = fs->fs_nindir;
42056446Smargo 	ump->um_bptrtodb = fs->fs_fsbtodb;
42156446Smargo 	ump->um_seqinc = fs->fs_frag;
42241314Smckusick 	for (i = 0; i < MAXQUOTAS; i++)
42341314Smckusick 		ump->um_quotas[i] = NULLVP;
42440653Smckusick 	devvp->v_specflags |= SI_MOUNTEDON;
42557051Smckusick 	ffs_oldfscompat(fs);
42657051Smckusick 	return (0);
42757051Smckusick out:
42857051Smckusick 	if (bp)
42957051Smckusick 		brelse(bp);
43057051Smckusick 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
43157051Smckusick 	if (ump) {
43257051Smckusick 		free(ump->um_fs, M_UFSMNT);
43357051Smckusick 		free(ump, M_UFSMNT);
43457051Smckusick 		mp->mnt_data = (qaddr_t)0;
43557051Smckusick 	}
43657051Smckusick 	return (error);
43757051Smckusick }
43837737Smckusick 
43957051Smckusick /*
44057051Smckusick  * Sanity checks for old file systems.
44157051Smckusick  *
44257051Smckusick  * XXX - goes away some day.
44357051Smckusick  */
44457051Smckusick ffs_oldfscompat(fs)
44557051Smckusick 	struct fs *fs;
44657051Smckusick {
44757051Smckusick 	int i;
44857051Smckusick 
44955056Spendry 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
45055056Spendry 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
45134145Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
45234145Smckusick 		fs->fs_nrpos = 8;				/* XXX */
45353913Smckusick 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
45453913Smckusick 		quad_t sizepb = fs->fs_bsize;			/* XXX */
45553913Smckusick 								/* XXX */
45653913Smckusick 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
45753913Smckusick 		for (i = 0; i < NIADDR; i++) {			/* XXX */
45853913Smckusick 			sizepb *= NINDIR(fs);			/* XXX */
45953913Smckusick 			fs->fs_maxfilesize += sizepb;		/* XXX */
46053913Smckusick 		}						/* XXX */
46153913Smckusick 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
46253913Smckusick 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
46353913Smckusick 	}							/* XXX */
46437737Smckusick 	return (0);
46512795Ssam }
46612795Ssam 
46739043Smckusick /*
46837737Smckusick  * unmount system call
46937737Smckusick  */
47051473Sbostic int
47151473Sbostic ffs_unmount(mp, mntflags, p)
47237737Smckusick 	struct mount *mp;
47341314Smckusick 	int mntflags;
47448036Smckusick 	struct proc *p;
47512795Ssam {
47637737Smckusick 	register struct ufsmount *ump;
47737737Smckusick 	register struct fs *fs;
47857051Smckusick 	int error, flags, ronly;
47912795Ssam 
48054461Smckusick 	flags = 0;
48148065Smckusick 	if (mntflags & MNT_FORCE) {
48257051Smckusick 		if (mp == rootfs)
48348065Smckusick 			return (EINVAL);
48441314Smckusick 		flags |= FORCECLOSE;
48548065Smckusick 	}
48657051Smckusick 	if (error = ffs_flushfiles(mp, flags, p))
48757051Smckusick 		return (error);
48837737Smckusick 	ump = VFSTOUFS(mp);
48957051Smckusick 	fs = ump->um_fs;
49057051Smckusick 	ronly = !fs->fs_ronly;
49157051Smckusick 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
49257051Smckusick 	error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
49357051Smckusick 		NOCRED, p);
49457051Smckusick 	vrele(ump->um_devvp);
49557051Smckusick 	free(fs->fs_csp[0], M_UFSMNT);
49657051Smckusick 	free(fs, M_UFSMNT);
49757051Smckusick 	free(ump, M_UFSMNT);
49857051Smckusick 	mp->mnt_data = (qaddr_t)0;
49957051Smckusick 	mp->mnt_flag &= ~MNT_LOCAL;
50057051Smckusick 	return (error);
50157051Smckusick }
50257051Smckusick 
50357051Smckusick /*
50457051Smckusick  * Flush out all the files in a filesystem.
50557051Smckusick  */
50657051Smckusick ffs_flushfiles(mp, flags, p)
50757051Smckusick 	register struct mount *mp;
50857051Smckusick 	int flags;
50957051Smckusick 	struct proc *p;
51057051Smckusick {
51157051Smckusick 	extern int doforce;
51257051Smckusick 	register struct ufsmount *ump;
51357051Smckusick 	int i, error;
51457051Smckusick 
51557051Smckusick 	if (!doforce)
51657051Smckusick 		flags &= ~FORCECLOSE;
51757051Smckusick 	ump = VFSTOUFS(mp);
51812795Ssam #ifdef QUOTA
51941397Smckusick 	if (mp->mnt_flag & MNT_QUOTA) {
52041314Smckusick 		if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
52139898Smckusick 			return (error);
52241314Smckusick 		for (i = 0; i < MAXQUOTAS; i++) {
52341314Smckusick 			if (ump->um_quotas[i] == NULLVP)
52441314Smckusick 				continue;
52550114Smckusick 			quotaoff(p, mp, i);
52641314Smckusick 		}
52739898Smckusick 		/*
52841314Smckusick 		 * Here we fall through to vflush again to ensure
52941314Smckusick 		 * that we have gotten rid of all the system vnodes.
53039898Smckusick 		 */
53141314Smckusick 	}
53212795Ssam #endif
53357051Smckusick 	error = vflush(mp, NULLVP, flags);
53430749Skarels 	return (error);
53512795Ssam }
53612795Ssam 
53737737Smckusick /*
53851545Smckusick  * Return root of a filesystem
53951545Smckusick  */
54051545Smckusick int
54151545Smckusick ffs_root(mp, vpp)
54251545Smckusick 	struct mount *mp;
54351545Smckusick 	struct vnode **vpp;
54451545Smckusick {
54551545Smckusick 	struct vnode *nvp;
54651545Smckusick 	int error;
54751545Smckusick 
54854657Smckusick 	if (error = VFS_VGET(mp, (ino_t)ROOTINO, &nvp))
54951545Smckusick 		return (error);
55051545Smckusick 	*vpp = nvp;
55151545Smckusick 	return (0);
55251545Smckusick }
55351545Smckusick 
55451545Smckusick /*
55537737Smckusick  * Get file system statistics.
55637737Smckusick  */
55751473Sbostic int
55851473Sbostic ffs_statfs(mp, sbp, p)
55937737Smckusick 	struct mount *mp;
56037737Smckusick 	register struct statfs *sbp;
56148036Smckusick 	struct proc *p;
56237737Smckusick {
56337737Smckusick 	register struct ufsmount *ump;
56437737Smckusick 	register struct fs *fs;
56537737Smckusick 
56637737Smckusick 	ump = VFSTOUFS(mp);
56737737Smckusick 	fs = ump->um_fs;
56837737Smckusick 	if (fs->fs_magic != FS_MAGIC)
56951473Sbostic 		panic("ffs_statfs");
57037737Smckusick 	sbp->f_type = MOUNT_UFS;
57151942Smckusick 	sbp->f_bsize = fs->fs_fsize;
57251942Smckusick 	sbp->f_iosize = fs->fs_bsize;
57337737Smckusick 	sbp->f_blocks = fs->fs_dsize;
57437737Smckusick 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
57537737Smckusick 		fs->fs_cstotal.cs_nffree;
57637737Smckusick 	sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
57737737Smckusick 		(fs->fs_dsize - sbp->f_bfree);
57839350Smckusick 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
57937737Smckusick 	sbp->f_ffree = fs->fs_cstotal.cs_nifree;
58041397Smckusick 	if (sbp != &mp->mnt_stat) {
58141397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
58240346Smckusick 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
58341397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
58440346Smckusick 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
58540346Smckusick 	}
58637737Smckusick 	return (0);
58737737Smckusick }
58837737Smckusick 
58937737Smckusick /*
59037737Smckusick  * Go through the disk queues to initiate sandbagged IO;
59137737Smckusick  * go through the inodes to write those that have been modified;
59237737Smckusick  * initiate the writing of the super block if it has been modified.
59341314Smckusick  *
59441314Smckusick  * Note: we are always called with the filesystem marked `MPBUSY'.
59537737Smckusick  */
59651473Sbostic int
59754461Smckusick ffs_sync(mp, waitfor, cred, p)
59837737Smckusick 	struct mount *mp;
59937737Smckusick 	int waitfor;
60054461Smckusick 	struct ucred *cred;
60154461Smckusick 	struct proc *p;
60237737Smckusick {
60339390Smckusick 	register struct vnode *vp;
60437737Smckusick 	register struct inode *ip;
60537737Smckusick 	register struct ufsmount *ump = VFSTOUFS(mp);
60637737Smckusick 	register struct fs *fs;
60739596Smckusick 	int error, allerror = 0;
60837737Smckusick 
60937737Smckusick 	fs = ump->um_fs;
61037737Smckusick 	/*
61137737Smckusick 	 * Write back modified superblock.
61237737Smckusick 	 * Consistency check that the superblock
61337737Smckusick 	 * is still in the buffer cache.
61437737Smckusick 	 */
61537737Smckusick 	if (fs->fs_fmod != 0) {
61637737Smckusick 		if (fs->fs_ronly != 0) {		/* XXX */
61737737Smckusick 			printf("fs = %s\n", fs->fs_fsmnt);
61837737Smckusick 			panic("update: rofs mod");
61937737Smckusick 		}
62037737Smckusick 		fs->fs_fmod = 0;
62137737Smckusick 		fs->fs_time = time.tv_sec;
62251473Sbostic 		allerror = ffs_sbupdate(ump, waitfor);
62337737Smckusick 	}
62437737Smckusick 	/*
62537737Smckusick 	 * Write back each (modified) inode.
62637737Smckusick 	 */
62739877Smckusick loop:
62841462Smckusick 	for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
62941462Smckusick 		/*
63041462Smckusick 		 * If the vnode that we are about to sync is no longer
63141462Smckusick 		 * associated with this mount point, start over.
63241462Smckusick 		 */
63341462Smckusick 		if (vp->v_mount != mp)
63441462Smckusick 			goto loop;
63548359Smckusick 		if (VOP_ISLOCKED(vp))
63648359Smckusick 			continue;
63739390Smckusick 		ip = VTOI(vp);
63839877Smckusick 		if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 &&
63956465Smckusick 		    vp->v_dirtyblkhd.le_next == NULL)
64037737Smckusick 			continue;
64139877Smckusick 		if (vget(vp))
64239877Smckusick 			goto loop;
64354461Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
64439596Smckusick 			allerror = error;
64539596Smckusick 		vput(vp);
64637737Smckusick 	}
64737737Smckusick 	/*
64839675Smckusick 	 * Force stale file system control information to be flushed.
64937737Smckusick 	 */
65054461Smckusick 	if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p))
65154461Smckusick 		allerror = error;
65241314Smckusick #ifdef QUOTA
65341314Smckusick 	qsync(mp);
65441314Smckusick #endif
65539596Smckusick 	return (allerror);
65637737Smckusick }
65737737Smckusick 
65837737Smckusick /*
65954657Smckusick  * Look up a FFS dinode number to find its incore vnode.
66054657Smckusick  * If it is not in core, read it in from the specified device.
66154657Smckusick  * If it is in core, wait for the lock bit to clear, then
66254657Smckusick  * return the inode locked. Detection and handling of mount
66354657Smckusick  * points must be done by the calling routine.
66454657Smckusick  */
66554657Smckusick int
66654657Smckusick ffs_vget(mp, ino, vpp)
66754657Smckusick 	struct mount *mp;
66854657Smckusick 	ino_t ino;
66954657Smckusick 	struct vnode **vpp;
67054657Smckusick {
67154657Smckusick 	register struct fs *fs;
67254657Smckusick 	register struct inode *ip;
67354657Smckusick 	struct ufsmount *ump;
67454657Smckusick 	struct buf *bp;
67554657Smckusick 	struct dinode *dp;
67654657Smckusick 	struct vnode *vp;
67754657Smckusick 	union ihead *ih;
67854657Smckusick 	dev_t dev;
67954657Smckusick 	int i, type, error;
68054657Smckusick 
68154657Smckusick 	ump = VFSTOUFS(mp);
68254657Smckusick 	dev = ump->um_dev;
68354657Smckusick 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
68454657Smckusick 		return (0);
68554657Smckusick 
68654657Smckusick 	/* Allocate a new vnode/inode. */
68754657Smckusick 	if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) {
68854657Smckusick 		*vpp = NULL;
68954657Smckusick 		return (error);
69054657Smckusick 	}
69154657Smckusick 	type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
69254657Smckusick 	MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
693*59819Smckusick 	bzero((caddr_t)ip, sizeof(struct inode));
69454657Smckusick 	vp->v_data = ip;
69554657Smckusick 	ip->i_vnode = vp;
69654657Smckusick 	ip->i_fs = fs = ump->um_fs;
69754657Smckusick 	ip->i_dev = dev;
69854657Smckusick 	ip->i_number = ino;
69954657Smckusick #ifdef QUOTA
70054657Smckusick 	for (i = 0; i < MAXQUOTAS; i++)
70154657Smckusick 		ip->i_dquot[i] = NODQUOT;
70254657Smckusick #endif
70354657Smckusick 	/*
70454657Smckusick 	 * Put it onto its hash chain and lock it so that other requests for
70554657Smckusick 	 * this inode will block if they arrive while we are sleeping waiting
70654657Smckusick 	 * for old data structures to be purged or for the contents of the
70754657Smckusick 	 * disk portion of this inode to be read.
70854657Smckusick 	 */
70954657Smckusick 	ufs_ihashins(ip);
71054657Smckusick 
71154657Smckusick 	/* Read in the disk contents for the inode, copy into the inode. */
71254657Smckusick 	if (error = bread(ump->um_devvp, fsbtodb(fs, itod(fs, ino)),
71354657Smckusick 	    (int)fs->fs_bsize, NOCRED, &bp)) {
71454657Smckusick 		/*
71554657Smckusick 		 * The inode does not contain anything useful, so it would
716*59819Smckusick 		 * be misleading to leave it on its hash chain. With mode
717*59819Smckusick 		 * still zero, it will be unlinked and returned to the free
718*59819Smckusick 		 * list by vput().
71954657Smckusick 		 */
72056797Smckusick 		vput(vp);
72154657Smckusick 		brelse(bp);
72254657Smckusick 		*vpp = NULL;
72354657Smckusick 		return (error);
72454657Smckusick 	}
72554657Smckusick 	dp = bp->b_un.b_dino;
72654657Smckusick 	dp += itoo(fs, ino);
72754657Smckusick 	ip->i_din = *dp;
72854657Smckusick 	brelse(bp);
72954657Smckusick 
73054657Smckusick 	/*
73154657Smckusick 	 * Initialize the vnode from the inode, check for aliases.
73254657Smckusick 	 * Note that the underlying vnode may have changed.
73354657Smckusick 	 */
73454657Smckusick 	if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) {
73556797Smckusick 		vput(vp);
73654657Smckusick 		*vpp = NULL;
73754657Smckusick 		return (error);
73854657Smckusick 	}
73954657Smckusick 	/*
74054657Smckusick 	 * Finish inode initialization now that aliasing has been resolved.
74154657Smckusick 	 */
74254657Smckusick 	ip->i_devvp = ump->um_devvp;
74354657Smckusick 	VREF(ip->i_devvp);
74454657Smckusick 	/*
74554657Smckusick 	 * Set up a generation number for this inode if it does not
74654657Smckusick 	 * already have one. This should only happen on old filesystems.
74754657Smckusick 	 */
74854657Smckusick 	if (ip->i_gen == 0) {
74954657Smckusick 		if (++nextgennumber < (u_long)time.tv_sec)
75054657Smckusick 			nextgennumber = time.tv_sec;
75154657Smckusick 		ip->i_gen = nextgennumber;
75254657Smckusick 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
75354657Smckusick 			ip->i_flag |= IMOD;
75454657Smckusick 	}
75554657Smckusick 	/*
75654657Smckusick 	 * Ensure that uid and gid are correct. This is a temporary
75754657Smckusick 	 * fix until fsck has been changed to do the update.
75854657Smckusick 	 */
75954657Smckusick 	if (fs->fs_inodefmt < FS_44INODEFMT) {		/* XXX */
76054657Smckusick 		ip->i_uid = ip->i_din.di_ouid;		/* XXX */
76154657Smckusick 		ip->i_gid = ip->i_din.di_ogid;		/* XXX */
76254657Smckusick 	}						/* XXX */
76354657Smckusick 
76454657Smckusick 	*vpp = vp;
76554657Smckusick 	return (0);
76654657Smckusick }
76754657Smckusick 
76854657Smckusick /*
76951545Smckusick  * File handle to vnode
77051545Smckusick  *
77151545Smckusick  * Have to be really careful about stale file handles:
77251545Smckusick  * - check that the inode number is valid
77351545Smckusick  * - call ffs_vget() to get the locked inode
77451545Smckusick  * - check for an unallocated inode (i_mode == 0)
77554733Smckusick  * - check that the given client host has export rights and return
77654733Smckusick  *   those rights via. exflagsp and credanonp
77751545Smckusick  */
77851545Smckusick int
77954733Smckusick ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
78051545Smckusick 	register struct mount *mp;
78151545Smckusick 	struct fid *fhp;
78254733Smckusick 	struct mbuf *nam;
78351545Smckusick 	struct vnode **vpp;
78454733Smckusick 	int *exflagsp;
78554733Smckusick 	struct ucred **credanonp;
78651545Smckusick {
78751545Smckusick 	register struct ufid *ufhp;
78851545Smckusick 	struct fs *fs;
78951545Smckusick 
79051545Smckusick 	ufhp = (struct ufid *)fhp;
79155890Smckusick 	fs = VFSTOUFS(mp)->um_fs;
79251545Smckusick 	if (ufhp->ufid_ino < ROOTINO ||
79351545Smckusick 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
79454733Smckusick 		return (ESTALE);
79556245Smckusick 	return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
79651545Smckusick }
79751545Smckusick 
79851545Smckusick /*
79951545Smckusick  * Vnode pointer to File handle
80051545Smckusick  */
80151545Smckusick /* ARGSUSED */
80251545Smckusick ffs_vptofh(vp, fhp)
80351545Smckusick 	struct vnode *vp;
80451545Smckusick 	struct fid *fhp;
80551545Smckusick {
80651545Smckusick 	register struct inode *ip;
80751545Smckusick 	register struct ufid *ufhp;
80851545Smckusick 
80951545Smckusick 	ip = VTOI(vp);
81051545Smckusick 	ufhp = (struct ufid *)fhp;
81151545Smckusick 	ufhp->ufid_len = sizeof(struct ufid);
81251545Smckusick 	ufhp->ufid_ino = ip->i_number;
81351545Smckusick 	ufhp->ufid_gen = ip->i_gen;
81451545Smckusick 	return (0);
81551545Smckusick }
81651545Smckusick 
81751545Smckusick /*
81837737Smckusick  * Write a superblock and associated information back to disk.
81937737Smckusick  */
82051942Smckusick int
82151473Sbostic ffs_sbupdate(mp, waitfor)
82237737Smckusick 	struct ufsmount *mp;
82337737Smckusick 	int waitfor;
82437737Smckusick {
82537737Smckusick 	register struct fs *fs = mp->um_fs;
82612795Ssam 	register struct buf *bp;
82712795Ssam 	int blks;
82812795Ssam 	caddr_t space;
82937737Smckusick 	int i, size, error = 0;
83012795Ssam 
83157801Smckusick 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0);
83212795Ssam 	bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
83334145Smckusick 	/* Restore compatibility to old file systems.		   XXX */
83434145Smckusick 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
83534145Smckusick 		bp->b_un.b_fs->fs_nrpos = -1;			/* XXX */
83637737Smckusick 	if (waitfor == MNT_WAIT)
83737737Smckusick 		error = bwrite(bp);
83837737Smckusick 	else
83937737Smckusick 		bawrite(bp);
84012795Ssam 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
84112795Ssam 	space = (caddr_t)fs->fs_csp[0];
84212795Ssam 	for (i = 0; i < blks; i += fs->fs_frag) {
84312795Ssam 		size = fs->fs_bsize;
84412795Ssam 		if (i + fs->fs_frag > blks)
84512795Ssam 			size = (blks - i) * fs->fs_fsize;
84657801Smckusick 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
84757801Smckusick 		    size, 0, 0);
84812795Ssam 		bcopy(space, bp->b_un.b_addr, (u_int)size);
84912795Ssam 		space += size;
85037737Smckusick 		if (waitfor == MNT_WAIT)
85137737Smckusick 			error = bwrite(bp);
85237737Smckusick 		else
85337737Smckusick 			bawrite(bp);
85412795Ssam 	}
85537737Smckusick 	return (error);
85612795Ssam }
857