xref: /csrg-svn/sys/ufs/lfs/lfs_vfsops.c (revision 55588)
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*55588Sbostic  *	@(#)lfs_vfsops.c	7.81 (Berkeley) 07/23/92
823400Smckusick  */
912795Ssam 
1051483Sbostic #include <sys/param.h>
1151483Sbostic #include <sys/systm.h>
1251483Sbostic #include <sys/namei.h>
1351483Sbostic #include <sys/proc.h>
1451483Sbostic #include <sys/kernel.h>
1551483Sbostic #include <sys/vnode.h>
1651483Sbostic #include <sys/mount.h>
1751483Sbostic #include <sys/buf.h>
1854734Smckusick #include <sys/mbuf.h>
1951483Sbostic #include <sys/file.h>
2051483Sbostic #include <sys/disklabel.h>
2151483Sbostic #include <sys/ioctl.h>
2251483Sbostic #include <sys/errno.h>
2351483Sbostic #include <sys/malloc.h>
2454734Smckusick #include <sys/socket.h>
2512795Ssam 
2655047Smckusick #include <miscfs/specfs/specdev.h>
2755047Smckusick 
2851501Sbostic #include <ufs/ufs/quota.h>
2951501Sbostic #include <ufs/ufs/inode.h>
3051501Sbostic #include <ufs/ufs/ufsmount.h>
3151501Sbostic #include <ufs/ufs/ufs_extern.h>
3247571Skarels 
3351501Sbostic #include <ufs/lfs/lfs.h>
3451501Sbostic #include <ufs/lfs/lfs_extern.h>
3551155Sbostic 
3651991Sbostic int lfs_mountfs __P((struct vnode *, struct mount *, struct proc *));
3751215Sbostic 
3851155Sbostic struct vfsops lfs_vfsops = {
3951155Sbostic 	lfs_mount,
4039043Smckusick 	ufs_start,
4151155Sbostic 	lfs_unmount,
4251559Smckusick 	lfs_root,
4341314Smckusick 	ufs_quotactl,
4451155Sbostic 	lfs_statfs,
4551155Sbostic 	lfs_sync,
4654693Sbostic 	lfs_vget,
4751559Smckusick 	lfs_fhtovp,
4851559Smckusick 	lfs_vptofh,
4951483Sbostic 	lfs_init,
5037737Smckusick };
5137737Smckusick 
5251483Sbostic int
5351155Sbostic lfs_mountroot()
5412795Ssam {
5551483Sbostic 	panic("lfs_mountroot");		/* XXX -- implement */
5637737Smckusick }
5737737Smckusick 
5837737Smckusick /*
5937737Smckusick  * VFS Operations.
6037737Smckusick  *
6137737Smckusick  * mount system call
6237737Smckusick  */
6351155Sbostic lfs_mount(mp, path, data, ndp, p)
6440346Smckusick 	register struct mount *mp;
6537737Smckusick 	char *path;
6637737Smckusick 	caddr_t data;
6737737Smckusick 	struct nameidata *ndp;
6848036Smckusick 	struct proc *p;
6937737Smckusick {
7037737Smckusick 	struct vnode *devvp;
7137737Smckusick 	struct ufs_args args;
7237737Smckusick 	struct ufsmount *ump;
7351501Sbostic 	register struct lfs *fs;				/* LFS */
7437737Smckusick 	u_int size;
7537737Smckusick 	int error;
7637737Smckusick 
7737737Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
7837737Smckusick 		return (error);
7951483Sbostic 
8051483Sbostic 	/* Until LFS can do NFS right.		XXX */
8151483Sbostic 	if (args.exflags & MNT_EXPORTED)
8251483Sbostic 		return (EINVAL);
8340371Smckusick 	/*
8450264Skarels 	 * If updating, check whether changing from read-only to
8550264Skarels 	 * read/write; if there is no device name, that's all we do.
8650264Skarels 	 */
8750264Skarels 	if (mp->mnt_flag & MNT_UPDATE) {
8839336Smckusick 		ump = VFSTOUFS(mp);
8951155Sbostic #ifdef NOTLFS							/* LFS */
9039336Smckusick 		fs = ump->um_fs;
9141397Smckusick 		if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
9239336Smckusick 			fs->fs_ronly = 0;
9351155Sbostic #else
9451155Sbostic 		fs = ump->um_lfs;
9551155Sbostic 		if (fs->lfs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
9651155Sbostic 			fs->lfs_ronly = 0;
9751155Sbostic #endif
9852175Smckusick 		if (args.fspec == 0) {
9952175Smckusick 			/*
10052175Smckusick 			 * Process export requests.
10152175Smckusick 			 */
10252175Smckusick 			if (args.exflags & MNT_EXPORTED) {
10354693Sbostic 				if (error = ufs_hang_addrlist(mp, &args))
10452175Smckusick 					return (error);
10552175Smckusick 				mp->mnt_flag |= MNT_EXPORTED;
10652175Smckusick 			}
10752175Smckusick 			if (args.exflags & MNT_DELEXPORT) {
10854693Sbostic 				ufs_free_addrlist(ump);
10952175Smckusick 				mp->mnt_flag &=
11052175Smckusick 				    ~(MNT_EXPORTED | MNT_DEFEXPORTED);
11152175Smckusick 			}
11240371Smckusick 			return (0);
11352175Smckusick 		}
11450264Skarels 	}
11550264Skarels 	/*
11650264Skarels 	 * Not an update, or updating the name: look up the name
11750264Skarels 	 * and verify that it refers to a sensible block device.
11850264Skarels 	 */
11952333Smckusick 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
12052333Smckusick 	if (error = namei(ndp))
12150264Skarels 		return (error);
12250264Skarels 	devvp = ndp->ni_vp;
12350264Skarels 	if (devvp->v_type != VBLK) {
12450264Skarels 		vrele(devvp);
12550264Skarels 		return (ENOTBLK);
12650264Skarels 	}
12750264Skarels 	if (major(devvp->v_rdev) >= nblkdev) {
12850264Skarels 		vrele(devvp);
12950264Skarels 		return (ENXIO);
13050264Skarels 	}
13150264Skarels 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
13251155Sbostic 		error = lfs_mountfs(devvp, mp, p);		/* LFS */
13350264Skarels 	else {
13439336Smckusick 		if (devvp != ump->um_devvp)
13539336Smckusick 			error = EINVAL;	/* needs translation */
13642858Smckusick 		else
13742858Smckusick 			vrele(devvp);
13839336Smckusick 	}
13937737Smckusick 	if (error) {
14037737Smckusick 		vrele(devvp);
14137737Smckusick 		return (error);
14232721Smckusick 	}
14337737Smckusick 	ump = VFSTOUFS(mp);
14451155Sbostic 	fs = ump->um_lfs;					/* LFS */
14551155Sbostic #ifdef NOTLFS							/* LFS */
14637737Smckusick 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
14737737Smckusick 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
14841397Smckusick 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
14941397Smckusick 	    MNAMELEN);
15051991Sbostic 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
15141397Smckusick 	    &size);
15241397Smckusick 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
15348036Smckusick 	(void) ufs_statfs(mp, &mp->mnt_stat, p);
15451155Sbostic #else
15551155Sbostic 	(void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size);
15651155Sbostic 	bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size);
15751155Sbostic 	bcopy((caddr_t)fs->lfs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
15851155Sbostic 	    MNAMELEN);
15951991Sbostic 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
16051155Sbostic 	    &size);
16151155Sbostic 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
16251155Sbostic 	(void) lfs_statfs(mp, &mp->mnt_stat, p);
16351155Sbostic #endif
16437737Smckusick 	return (0);
16512795Ssam }
16612795Ssam 
16737737Smckusick /*
16837737Smckusick  * Common code for mount and mountroot
16951155Sbostic  * LFS specific
17037737Smckusick  */
17151991Sbostic int
17251155Sbostic lfs_mountfs(devvp, mp, p)
17340376Smckusick 	register struct vnode *devvp;
17437737Smckusick 	struct mount *mp;
17548036Smckusick 	struct proc *p;
17612795Ssam {
17751155Sbostic 	extern struct vnode *rootvp;
17851501Sbostic 	register struct lfs *fs;
17951155Sbostic 	register struct ufsmount *ump;
18051155Sbostic 	struct vnode *vp;
18151155Sbostic 	struct buf *bp;
18230749Skarels 	struct partinfo dpart;
18351155Sbostic 	dev_t dev;
18451155Sbostic 	int error, i, ronly, size;
18512795Ssam 
18640376Smckusick 	/*
18740376Smckusick 	 * Disallow multiple mounts of the same device.
18845652Smckusick 	 * Disallow mounting of a device that is currently in use
18945652Smckusick 	 * (except for root, which might share swap device for miniroot).
19040376Smckusick 	 * Flush out any old buffers remaining from a previous use.
19140376Smckusick 	 */
19251483Sbostic 	if (error = ufs_mountedon(devvp))
19340376Smckusick 		return (error);
19445652Smckusick 	if (vcount(devvp) > 1 && devvp != rootvp)
19540376Smckusick 		return (EBUSY);
19654693Sbostic 	if (error = vinvalbuf(devvp, 1, p->p_ucred, p))
19754693Sbostic 		return (error);
19851155Sbostic 
19951155Sbostic 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
20048036Smckusick 	if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
20137737Smckusick 		return (error);
20251155Sbostic 
20348036Smckusick 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
20437737Smckusick 		size = DEV_BSIZE;
20548036Smckusick 	else {
20630749Skarels 		size = dpart.disklab->d_secsize;
20751155Sbostic #ifdef NEVER_USED
20851155Sbostic 		dpart.part->p_fstype = FS_LFS;
20951155Sbostic 		dpart.part->p_fsize = fs->lfs_fsize;	/* frag size */
21051155Sbostic 		dpart.part->p_frag = fs->lfs_frag;	/* frags per block */
21151155Sbostic 		dpart.part->p_cpg = fs->lfs_segshift;	/* segment shift */
21251155Sbostic #endif
21337737Smckusick 	}
21451155Sbostic 
21551155Sbostic 	/* Don't free random space on error. */
21651155Sbostic 	bp = NULL;
21751155Sbostic 	ump = NULL;
21851155Sbostic 
21951155Sbostic 	/* Read in the superblock. */
22051155Sbostic 	if (error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, NOCRED, &bp))
22112795Ssam 		goto out;
22251155Sbostic 	fs = bp->b_un.b_lfs;
22351155Sbostic 
22451155Sbostic 	/* Check the basics. */
22551155Sbostic 	if (fs->lfs_magic != LFS_MAGIC || fs->lfs_bsize > MAXBSIZE ||
22651501Sbostic 	    fs->lfs_bsize < sizeof(struct lfs)) {
22741314Smckusick 		error = EINVAL;		/* XXX needs translation */
22816639Skarels 		goto out;
22916639Skarels 	}
23051155Sbostic #ifdef DEBUG
23151483Sbostic 	lfs_dump_super(fs);
23251155Sbostic #endif
23351155Sbostic 
23451155Sbostic 	/* Allocate the mount structure, copy the superblock into it. */
23541314Smckusick 	ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
23655548Sbostic 	fs = ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK);
23755548Sbostic 	bcopy(bp->b_un.b_addr, fs, sizeof(struct lfs));
23851501Sbostic 	if (sizeof(struct lfs) < LFS_SBPAD)			/* XXX why? */
23939675Smckusick 		bp->b_flags |= B_INVAL;
24034421Skarels 	brelse(bp);
24134421Skarels 	bp = NULL;
24251155Sbostic 
24351183Sbostic 	/* Set up the I/O information */
24451183Sbostic 	fs->lfs_iocount = 0;
24551183Sbostic 
24655548Sbostic 	/* Set up the ifile and lock aflags */
24754264Sbostic 	fs->lfs_doifile = 0;
24854264Sbostic 	fs->lfs_writer = 0;
24954264Sbostic 	fs->lfs_dirops = 0;
25055548Sbostic 	fs->lfs_seglock = 0;
25154264Sbostic 
25251155Sbostic 	/* Set the file system readonly/modify bits. */
25351155Sbostic 	fs->lfs_ronly = ronly;
25412795Ssam 	if (ronly == 0)
25551155Sbostic 		fs->lfs_fmod = 1;
25651155Sbostic 
25751155Sbostic 	/* Initialize the mount structure. */
25851155Sbostic 	dev = devvp->v_rdev;
25941397Smckusick 	mp->mnt_data = (qaddr_t)ump;
26041397Smckusick 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
26151991Sbostic 	mp->mnt_stat.f_fsid.val[1] = MOUNT_LFS;
26241397Smckusick 	mp->mnt_flag |= MNT_LOCAL;
26337737Smckusick 	ump->um_mountp = mp;
26437737Smckusick 	ump->um_dev = dev;
26537737Smckusick 	ump->um_devvp = devvp;
26641314Smckusick 	for (i = 0; i < MAXQUOTAS; i++)
26741314Smckusick 		ump->um_quotas[i] = NULLVP;
26852221Sbostic 	devvp->v_specflags |= SI_MOUNTEDON;
26951155Sbostic 
27052221Sbostic 	/*
27152221Sbostic 	 * We use the ifile vnode for almost every operation.  Instead of
27252221Sbostic 	 * retrieving it from the hash table each time we retrieve it here,
27352221Sbostic 	 * artificially increment the reference count and keep a pointer
27452221Sbostic 	 * to it in the incore copy of the superblock.
27552221Sbostic 	 */
27654693Sbostic 	if (error = VFS_VGET(mp, LFS_IFILE_INUM, &vp))
27751155Sbostic 		goto out;
27851155Sbostic 	fs->lfs_ivnode = vp;
27952221Sbostic 	VREF(vp);
28052221Sbostic 	vput(vp);
28151155Sbostic 
28237737Smckusick 	return (0);
28312795Ssam out:
28440872Smckusick 	if (bp)
28540872Smckusick 		brelse(bp);
28651155Sbostic 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
28741314Smckusick 	if (ump) {
28851989Smckusick 		free(ump->um_lfs, M_UFSMNT);
28951501Sbostic 		free(ump, M_UFSMNT);
29041397Smckusick 		mp->mnt_data = (qaddr_t)0;
29132721Smckusick 	}
29237737Smckusick 	return (error);
29312795Ssam }
29412795Ssam 
29539043Smckusick /*
29637737Smckusick  * unmount system call
29737737Smckusick  */
29851155Sbostic lfs_unmount(mp, mntflags, p)
29937737Smckusick 	struct mount *mp;
30041314Smckusick 	int mntflags;
30148036Smckusick 	struct proc *p;
30212795Ssam {
30351501Sbostic 	extern int doforce;
30437737Smckusick 	register struct ufsmount *ump;
30555548Sbostic 	register struct lfs *fs;
30654693Sbostic 	int i, error, flags, ronly;
30712795Ssam 
30851853Sbostic #ifdef VERBOSE
30951853Sbostic 	printf("lfs_unmount\n");
31051853Sbostic #endif
31154693Sbostic 	flags = 0;
31248065Smckusick 	if (mntflags & MNT_FORCE) {
31348359Smckusick 		if (!doforce || mp == rootfs)
31448065Smckusick 			return (EINVAL);
31541314Smckusick 		flags |= FORCECLOSE;
31648065Smckusick 	}
31754264Sbostic 
31854264Sbostic 	ump = VFSTOUFS(mp);
31954264Sbostic 	fs = ump->um_lfs;
32012795Ssam #ifdef QUOTA
32141397Smckusick 	if (mp->mnt_flag & MNT_QUOTA) {
32254264Sbostic 		if (error = vflush(mp, fs->lfs_ivnode, SKIPSYSTEM|flags))
32339898Smckusick 			return (error);
32441314Smckusick 		for (i = 0; i < MAXQUOTAS; i++) {
32541314Smckusick 			if (ump->um_quotas[i] == NULLVP)
32641314Smckusick 				continue;
32750114Smckusick 			quotaoff(p, mp, i);
32841314Smckusick 		}
32939898Smckusick 		/*
33041314Smckusick 		 * Here we fall through to vflush again to ensure
33141314Smckusick 		 * that we have gotten rid of all the system vnodes.
33239898Smckusick 		 */
33341314Smckusick 	}
33412795Ssam #endif
33554264Sbostic 	vrele(fs->lfs_ivnode);
33654693Sbostic 	if (error = vflush(mp, fs->lfs_ivnode, flags))
33739898Smckusick 		return (error);
33855548Sbostic 	fs->lfs_clean = 1;
33954693Sbostic 	if (error = VFS_SYNC(mp, 1, p->p_ucred, p))
34054693Sbostic 		return (error);
34154693Sbostic 	if (fs->lfs_ivnode->v_dirtyblkhd)
34254693Sbostic 		panic("lfs_unmount: still dirty blocks on ifile vnode\n");
34354693Sbostic 	vgone(fs->lfs_ivnode);
34454693Sbostic 
34551155Sbostic 	ronly = !fs->lfs_ronly;
34640653Smckusick 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
34754693Sbostic 	error = VOP_CLOSE(ump->um_devvp,
34854693Sbostic 	    ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
34937737Smckusick 	vrele(ump->um_devvp);
35051989Smckusick 	free(fs, M_UFSMNT);
35151501Sbostic 	free(ump, M_UFSMNT);
35241397Smckusick 	mp->mnt_data = (qaddr_t)0;
35341397Smckusick 	mp->mnt_flag &= ~MNT_LOCAL;
35430749Skarels 	return (error);
35512795Ssam }
35612795Ssam 
35737737Smckusick /*
35851559Smckusick  * Return root of a filesystem
35951559Smckusick  */
36051559Smckusick int
36151559Smckusick lfs_root(mp, vpp)
36251559Smckusick 	struct mount *mp;
36351559Smckusick 	struct vnode **vpp;
36451559Smckusick {
36551559Smckusick 	struct vnode *nvp;
36651559Smckusick 	int error;
36751559Smckusick 
36851853Sbostic #ifdef VERBOSE
36951853Sbostic 	printf("lfs_root\n");
37051853Sbostic #endif
37154693Sbostic 	if (error = VFS_VGET(mp, (ino_t)ROOTINO, &nvp))
37251559Smckusick 		return (error);
37351559Smckusick 	*vpp = nvp;
37451559Smckusick 	return (0);
37551559Smckusick }
37651559Smckusick 
37751559Smckusick /*
37837737Smckusick  * Get file system statistics.
37937737Smckusick  */
38051155Sbostic lfs_statfs(mp, sbp, p)
38137737Smckusick 	struct mount *mp;
38237737Smckusick 	register struct statfs *sbp;
38348036Smckusick 	struct proc *p;
38437737Smckusick {
38551501Sbostic 	register struct lfs *fs;
38637737Smckusick 	register struct ufsmount *ump;
38737737Smckusick 
38837737Smckusick 	ump = VFSTOUFS(mp);
38951155Sbostic 	fs = ump->um_lfs;
39051155Sbostic 	if (fs->lfs_magic != LFS_MAGIC)
39151155Sbostic 		panic("lfs_statfs: magic");
39251155Sbostic 	sbp->f_type = MOUNT_LFS;
39351155Sbostic 	sbp->f_bsize = fs->lfs_bsize;
39451943Smckusick 	sbp->f_iosize = fs->lfs_bsize;
39551155Sbostic 	sbp->f_blocks = fs->lfs_dsize;
396*55588Sbostic 	sbp->f_bfree = dbtofsb(fs, fs->lfs_bfree);
39751155Sbostic 	sbp->f_bavail = (fs->lfs_dsize * (100 - fs->lfs_minfree) / 100) -
39851155Sbostic 		(fs->lfs_dsize - sbp->f_bfree);
39951155Sbostic 	sbp->f_files = fs->lfs_nfiles;
400*55588Sbostic 	sbp->f_ffree = sbp->f_bfree * INOPB(fs);
40141397Smckusick 	if (sbp != &mp->mnt_stat) {
40241397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
40340346Smckusick 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
40441397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
40540346Smckusick 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
40640346Smckusick 	}
40737737Smckusick 	return (0);
40837737Smckusick }
40937737Smckusick 
41037737Smckusick /*
41137737Smckusick  * Go through the disk queues to initiate sandbagged IO;
41237737Smckusick  * go through the inodes to write those that have been modified;
41337737Smckusick  * initiate the writing of the super block if it has been modified.
41441314Smckusick  *
41541314Smckusick  * Note: we are always called with the filesystem marked `MPBUSY'.
41637737Smckusick  */
41754693Sbostic lfs_sync(mp, waitfor, cred, p)
41837737Smckusick 	struct mount *mp;
41937737Smckusick 	int waitfor;
42054693Sbostic 	struct ucred *cred;
42154693Sbostic 	struct proc *p;
42237737Smckusick {
42351914Sbostic 	extern int crashandburn, syncprt;
42451215Sbostic 	int error;
42537737Smckusick 
42651853Sbostic #ifdef VERBOSE
42751853Sbostic 	printf("lfs_sync\n");
42851853Sbostic #endif
42951215Sbostic 
43051914Sbostic #ifdef DIAGNOSTIC
43151914Sbostic 	if (crashandburn)
43251914Sbostic 		return (0);
43351914Sbostic #endif
43451310Sbostic 
43551310Sbostic 	/* All syncs must be checkpoints until roll-forward is implemented. */
43651991Sbostic 	error = lfs_segwrite(mp, 1);
43741314Smckusick #ifdef QUOTA
43841314Smckusick 	qsync(mp);
43941314Smckusick #endif
44051215Sbostic 	return (error);
44137737Smckusick }
44251559Smckusick 
44351559Smckusick /*
44454693Sbostic  * Look up an LFS dinode number to find its incore vnode.  If not already
44554693Sbostic  * in core, read it in from the specified device.  Return the inode locked.
44654693Sbostic  * Detection and handling of mount points must be done by the calling routine.
44754693Sbostic  */
44854693Sbostic int
44954693Sbostic lfs_vget(mp, ino, vpp)
45054693Sbostic 	struct mount *mp;
45154693Sbostic 	ino_t ino;
45254693Sbostic 	struct vnode **vpp;
45354693Sbostic {
45454693Sbostic 	register struct lfs *fs;
45554693Sbostic 	register struct inode *ip;
45654693Sbostic 	struct buf *bp;
45754693Sbostic 	struct ifile *ifp;
45854693Sbostic 	struct vnode *vp;
45954693Sbostic 	struct ufsmount *ump;
46054693Sbostic 	daddr_t daddr;
46154693Sbostic 	dev_t dev;
46254693Sbostic 	int error;
46354693Sbostic 
46454693Sbostic #ifdef VERBOSE
46554693Sbostic 	printf("lfs_vget\n");
46654693Sbostic #endif
46754693Sbostic 	ump = VFSTOUFS(mp);
46854693Sbostic 	dev = ump->um_dev;
46954693Sbostic 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
47054693Sbostic 		return (0);
47154693Sbostic 
47254693Sbostic 	/* Translate the inode number to a disk address. */
47354693Sbostic 	fs = ump->um_lfs;
47454693Sbostic 	if (ino == LFS_IFILE_INUM)
47554693Sbostic 		daddr = fs->lfs_idaddr;
47654693Sbostic 	else {
47754693Sbostic 		LFS_IENTRY(ifp, fs, ino, bp);
47854693Sbostic 		daddr = ifp->if_daddr;
47954693Sbostic 		brelse(bp);
48054693Sbostic 		if (daddr == LFS_UNUSED_DADDR)
48154693Sbostic 			return (ENOENT);
48254693Sbostic 	}
48354693Sbostic 
48454693Sbostic 	/* Allocate new vnode/inode. */
48554693Sbostic 	if (error = lfs_vcreate(mp, ino, &vp)) {
48654693Sbostic 		*vpp = NULL;
48754693Sbostic 		return (error);
48854693Sbostic 	}
48954693Sbostic 
49054693Sbostic 	/*
49154693Sbostic 	 * Put it onto its hash chain and lock it so that other requests for
49254693Sbostic 	 * this inode will block if they arrive while we are sleeping waiting
49354693Sbostic 	 * for old data structures to be purged or for the contents of the
49454693Sbostic 	 * disk portion of this inode to be read.
49554693Sbostic 	 */
49654693Sbostic 	ip = VTOI(vp);
49754693Sbostic 	ufs_ihashins(ip);
49854693Sbostic 
49954693Sbostic 	/*
50054693Sbostic 	 * XXX
50154693Sbostic 	 * This may not need to be here, logically it should go down with
50254693Sbostic 	 * the i_devvp initialization.
50354693Sbostic 	 * Ask Kirk.
50454693Sbostic 	 */
50554693Sbostic 	ip->i_lfs = ump->um_lfs;
50654693Sbostic 
50754693Sbostic 	/* Read in the disk contents for the inode, copy into the inode. */
50854693Sbostic 	if (error =
50954693Sbostic 	    bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) {
51054693Sbostic 		/*
51154693Sbostic 		 * The inode does not contain anything useful, so it
51254693Sbostic 		 * would be misleading to leave it on its hash chain.
51354693Sbostic 		 * Iput() will return it to the free list.
51454693Sbostic 		 */
51555407Smckusick 		ufs_ihashrem(ip);
51654693Sbostic 
51754693Sbostic 		/* Unlock and discard unneeded inode. */
51854693Sbostic 		ufs_iput(ip);
51954693Sbostic 		brelse(bp);
52054693Sbostic 		*vpp = NULL;
52154693Sbostic 		return (error);
52254693Sbostic 	}
52354693Sbostic 	ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino);
52454693Sbostic 	brelse(bp);
52554693Sbostic 
52654693Sbostic 	/*
52754693Sbostic 	 * Initialize the vnode from the inode, check for aliases.  In all
52854693Sbostic 	 * cases re-init ip, the underlying vnode/inode may have changed.
52954693Sbostic 	 */
53054693Sbostic 	if (error = ufs_vinit(mp, lfs_specop_p, LFS_FIFOOPS, &vp)) {
53154693Sbostic 		ufs_iput(ip);
53254693Sbostic 		*vpp = NULL;
53354693Sbostic 		return (error);
53454693Sbostic 	}
53554693Sbostic 	/*
53654693Sbostic 	 * Finish inode initialization now that aliasing has been resolved.
53754693Sbostic 	 */
53854693Sbostic 	ip->i_devvp = ump->um_devvp;
53954693Sbostic 	VREF(ip->i_devvp);
54054693Sbostic 	*vpp = vp;
54154693Sbostic 	return (0);
54254693Sbostic }
54354693Sbostic 
54454693Sbostic /*
54551559Smckusick  * File handle to vnode
54651559Smckusick  *
54751559Smckusick  * Have to be really careful about stale file handles:
54851559Smckusick  * - check that the inode number is valid
54951559Smckusick  * - call lfs_vget() to get the locked inode
55051559Smckusick  * - check for an unallocated inode (i_mode == 0)
55151559Smckusick  * - check that the generation number matches
55251559Smckusick  *
55351559Smckusick  * XXX
55451559Smckusick  * use ifile to see if inode is allocated instead of reading off disk
55551559Smckusick  * what is the relationship between my generational number and the NFS
55651559Smckusick  * generational number.
55751559Smckusick  */
55851559Smckusick int
55954734Smckusick lfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
56051559Smckusick 	register struct mount *mp;
56151559Smckusick 	struct fid *fhp;
56254734Smckusick 	struct mbuf *nam;
56351559Smckusick 	struct vnode **vpp;
56454734Smckusick 	int *exflagsp;
56554734Smckusick 	struct ucred **credanonp;
56651559Smckusick {
56751559Smckusick 	register struct inode *ip;
56851559Smckusick 	register struct ufid *ufhp;
56954734Smckusick 	register struct netaddrhash *np;
57054734Smckusick 	register struct ufsmount *ump = VFSTOUFS(mp);
57151559Smckusick 	struct vnode *nvp;
57254734Smckusick 	struct sockaddr *saddr;
57351559Smckusick 	int error;
57451559Smckusick 
57551559Smckusick 	ufhp = (struct ufid *)fhp;
57651559Smckusick 	if (ufhp->ufid_ino < ROOTINO)
57754734Smckusick 		return (ESTALE);
57854734Smckusick 	/*
57954734Smckusick 	 * Get the export permission structure for this <mp, client> tuple.
58054734Smckusick 	 */
58154734Smckusick 	if ((mp->mnt_flag & MNT_EXPORTED) == 0)
58254734Smckusick 		return (EACCES);
58354734Smckusick 	if (nam == NULL) {
58454734Smckusick 		np = (struct netaddrhash *)0;
58554734Smckusick 	} else {
58654734Smckusick 		/*
58754734Smckusick 		 * First search for a network match.
58854734Smckusick 		 */
58954734Smckusick 		np = ump->um_netaddr[NETMASK_HASH];
59054734Smckusick 		while (np) {
59154734Smckusick 			if (netaddr_match(np->neth_family, &np->neth_haddr,
59254734Smckusick 			    &np->neth_hmask, nam))
59354734Smckusick 				break;
59454734Smckusick 			np = np->neth_next;
59554734Smckusick 		}
59654734Smckusick 
59754734Smckusick 		/*
59854734Smckusick 		 * If not found, try for an address match.
59954734Smckusick 		 */
60054734Smckusick 		if (np == (struct netaddrhash *)0) {
60154734Smckusick 			saddr = mtod(nam, struct sockaddr *);
60254734Smckusick 			np = ump->um_netaddr[NETADDRHASH(saddr)];
60354734Smckusick 			while (np) {
60454734Smckusick 				if (netaddr_match(np->neth_family,
60554734Smckusick 				    &np->neth_haddr, (struct netaddrhash *)0,
60654734Smckusick 				    nam))
60754734Smckusick 					break;
60854734Smckusick 				np = np->neth_next;
60954734Smckusick 			}
61054734Smckusick 		}
61154734Smckusick 	}
61254734Smckusick 	if (np == (struct netaddrhash *)0) {
61354734Smckusick 		/*
61454734Smckusick 		 * If no address match, use the default if it exists.
61554734Smckusick 		 */
61654734Smckusick 		if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0)
61754734Smckusick 			return (EACCES);
61854734Smckusick 		np = &ump->um_defexported;
61954734Smckusick 	}
62054693Sbostic 	if (error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) {
62151559Smckusick 		*vpp = NULLVP;
62251559Smckusick 		return (error);
62351559Smckusick 	}
62451559Smckusick 	ip = VTOI(nvp);
62554693Sbostic 	if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) {
62651559Smckusick 		ufs_iput(ip);
62751559Smckusick 		*vpp = NULLVP;
62854734Smckusick 		return (ESTALE);
62951559Smckusick 	}
63051559Smckusick 	*vpp = nvp;
63154734Smckusick 	*exflagsp = np->neth_exflags;
63254734Smckusick 	*credanonp = &np->neth_anon;
63351559Smckusick 	return (0);
63451559Smckusick }
63551559Smckusick 
63651559Smckusick /*
63751559Smckusick  * Vnode pointer to File handle
63851559Smckusick  */
63951559Smckusick /* ARGSUSED */
64051559Smckusick lfs_vptofh(vp, fhp)
64151559Smckusick 	struct vnode *vp;
64251559Smckusick 	struct fid *fhp;
64351559Smckusick {
64451559Smckusick 	register struct inode *ip;
64551559Smckusick 	register struct ufid *ufhp;
64651559Smckusick 
64751559Smckusick 	ip = VTOI(vp);
64851559Smckusick 	ufhp = (struct ufid *)fhp;
64951559Smckusick 	ufhp->ufid_len = sizeof(struct ufid);
65051559Smckusick 	ufhp->ufid_ino = ip->i_number;
65151559Smckusick 	ufhp->ufid_gen = ip->i_gen;
65251559Smckusick 	return (0);
65351559Smckusick }
654