xref: /csrg-svn/sys/ufs/lfs/lfs_vfsops.c (revision 54693)
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*54693Sbostic  *	@(#)lfs_vfsops.c	7.76 (Berkeley) 07/05/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/specdev.h>
1751483Sbostic #include <sys/mount.h>
1851483Sbostic #include <sys/buf.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>
2412795Ssam 
2551501Sbostic #include <ufs/ufs/quota.h>
2651501Sbostic #include <ufs/ufs/inode.h>
2751501Sbostic #include <ufs/ufs/ufsmount.h>
2851501Sbostic #include <ufs/ufs/ufs_extern.h>
2947571Skarels 
3051501Sbostic #include <ufs/lfs/lfs.h>
3151501Sbostic #include <ufs/lfs/lfs_extern.h>
3251155Sbostic 
3351991Sbostic int lfs_mountfs __P((struct vnode *, struct mount *, struct proc *));
3451215Sbostic 
3551155Sbostic struct vfsops lfs_vfsops = {
3651155Sbostic 	lfs_mount,
3739043Smckusick 	ufs_start,
3851155Sbostic 	lfs_unmount,
3951559Smckusick 	lfs_root,
4041314Smckusick 	ufs_quotactl,
4151155Sbostic 	lfs_statfs,
4251155Sbostic 	lfs_sync,
43*54693Sbostic 	lfs_vget,
4451559Smckusick 	lfs_fhtovp,
4551559Smckusick 	lfs_vptofh,
4651483Sbostic 	lfs_init,
4737737Smckusick };
4837737Smckusick 
4951483Sbostic int
5051155Sbostic lfs_mountroot()
5112795Ssam {
5251483Sbostic 	panic("lfs_mountroot");		/* XXX -- implement */
5337737Smckusick }
5437737Smckusick 
5537737Smckusick /*
5637737Smckusick  * VFS Operations.
5737737Smckusick  *
5837737Smckusick  * mount system call
5937737Smckusick  */
6051155Sbostic lfs_mount(mp, path, data, ndp, p)
6140346Smckusick 	register struct mount *mp;
6237737Smckusick 	char *path;
6337737Smckusick 	caddr_t data;
6437737Smckusick 	struct nameidata *ndp;
6548036Smckusick 	struct proc *p;
6637737Smckusick {
6737737Smckusick 	struct vnode *devvp;
6837737Smckusick 	struct ufs_args args;
6937737Smckusick 	struct ufsmount *ump;
7051501Sbostic 	register struct lfs *fs;				/* LFS */
7137737Smckusick 	u_int size;
7237737Smckusick 	int error;
7337737Smckusick 
7437737Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
7537737Smckusick 		return (error);
7651483Sbostic 
7751483Sbostic 	/* Until LFS can do NFS right.		XXX */
7851483Sbostic 	if (args.exflags & MNT_EXPORTED)
7951483Sbostic 		return (EINVAL);
8040371Smckusick 	/*
8150264Skarels 	 * If updating, check whether changing from read-only to
8250264Skarels 	 * read/write; if there is no device name, that's all we do.
8350264Skarels 	 */
8450264Skarels 	if (mp->mnt_flag & MNT_UPDATE) {
8539336Smckusick 		ump = VFSTOUFS(mp);
8651155Sbostic #ifdef NOTLFS							/* LFS */
8739336Smckusick 		fs = ump->um_fs;
8841397Smckusick 		if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
8939336Smckusick 			fs->fs_ronly = 0;
9051155Sbostic #else
9151155Sbostic 		fs = ump->um_lfs;
9251155Sbostic 		if (fs->lfs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
9351155Sbostic 			fs->lfs_ronly = 0;
9451155Sbostic #endif
9552175Smckusick 		if (args.fspec == 0) {
9652175Smckusick 			/*
9752175Smckusick 			 * Process export requests.
9852175Smckusick 			 */
9952175Smckusick 			if (args.exflags & MNT_EXPORTED) {
100*54693Sbostic 				if (error = ufs_hang_addrlist(mp, &args))
10152175Smckusick 					return (error);
10252175Smckusick 				mp->mnt_flag |= MNT_EXPORTED;
10352175Smckusick 			}
10452175Smckusick 			if (args.exflags & MNT_DELEXPORT) {
105*54693Sbostic 				ufs_free_addrlist(ump);
10652175Smckusick 				mp->mnt_flag &=
10752175Smckusick 				    ~(MNT_EXPORTED | MNT_DEFEXPORTED);
10852175Smckusick 			}
10940371Smckusick 			return (0);
11052175Smckusick 		}
11150264Skarels 	}
11250264Skarels 	/*
11350264Skarels 	 * Not an update, or updating the name: look up the name
11450264Skarels 	 * and verify that it refers to a sensible block device.
11550264Skarels 	 */
11652333Smckusick 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
11752333Smckusick 	if (error = namei(ndp))
11850264Skarels 		return (error);
11950264Skarels 	devvp = ndp->ni_vp;
12050264Skarels 	if (devvp->v_type != VBLK) {
12150264Skarels 		vrele(devvp);
12250264Skarels 		return (ENOTBLK);
12350264Skarels 	}
12450264Skarels 	if (major(devvp->v_rdev) >= nblkdev) {
12550264Skarels 		vrele(devvp);
12650264Skarels 		return (ENXIO);
12750264Skarels 	}
12850264Skarels 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
12951155Sbostic 		error = lfs_mountfs(devvp, mp, p);		/* LFS */
13050264Skarels 	else {
13139336Smckusick 		if (devvp != ump->um_devvp)
13239336Smckusick 			error = EINVAL;	/* needs translation */
13342858Smckusick 		else
13442858Smckusick 			vrele(devvp);
13539336Smckusick 	}
13637737Smckusick 	if (error) {
13737737Smckusick 		vrele(devvp);
13837737Smckusick 		return (error);
13932721Smckusick 	}
14037737Smckusick 	ump = VFSTOUFS(mp);
14151155Sbostic 	fs = ump->um_lfs;					/* LFS */
14251155Sbostic #ifdef NOTLFS							/* LFS */
14337737Smckusick 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
14437737Smckusick 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
14541397Smckusick 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
14641397Smckusick 	    MNAMELEN);
14751991Sbostic 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
14841397Smckusick 	    &size);
14941397Smckusick 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
15048036Smckusick 	(void) ufs_statfs(mp, &mp->mnt_stat, p);
15151155Sbostic #else
15251155Sbostic 	(void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size);
15351155Sbostic 	bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size);
15451155Sbostic 	bcopy((caddr_t)fs->lfs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
15551155Sbostic 	    MNAMELEN);
15651991Sbostic 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
15751155Sbostic 	    &size);
15851155Sbostic 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
15951155Sbostic 	(void) lfs_statfs(mp, &mp->mnt_stat, p);
16051155Sbostic #endif
16137737Smckusick 	return (0);
16212795Ssam }
16312795Ssam 
16437737Smckusick /*
16537737Smckusick  * Common code for mount and mountroot
16651155Sbostic  * LFS specific
16737737Smckusick  */
16851991Sbostic int
16951155Sbostic lfs_mountfs(devvp, mp, p)
17040376Smckusick 	register struct vnode *devvp;
17137737Smckusick 	struct mount *mp;
17248036Smckusick 	struct proc *p;
17312795Ssam {
17451155Sbostic 	extern struct vnode *rootvp;
17551501Sbostic 	register struct lfs *fs;
17651155Sbostic 	register struct ufsmount *ump;
17751155Sbostic 	struct vnode *vp;
17851155Sbostic 	struct buf *bp;
17930749Skarels 	struct partinfo dpart;
18051155Sbostic 	dev_t dev;
18151155Sbostic 	int error, i, ronly, size;
18212795Ssam 
18340376Smckusick 	/*
18440376Smckusick 	 * Disallow multiple mounts of the same device.
18545652Smckusick 	 * Disallow mounting of a device that is currently in use
18645652Smckusick 	 * (except for root, which might share swap device for miniroot).
18740376Smckusick 	 * Flush out any old buffers remaining from a previous use.
18840376Smckusick 	 */
18951483Sbostic 	if (error = ufs_mountedon(devvp))
19040376Smckusick 		return (error);
19145652Smckusick 	if (vcount(devvp) > 1 && devvp != rootvp)
19240376Smckusick 		return (EBUSY);
193*54693Sbostic 	if (error = vinvalbuf(devvp, 1, p->p_ucred, p))
194*54693Sbostic 		return (error);
19551155Sbostic 
19651155Sbostic 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
19748036Smckusick 	if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
19837737Smckusick 		return (error);
19951155Sbostic 
20048036Smckusick 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
20137737Smckusick 		size = DEV_BSIZE;
20248036Smckusick 	else {
20330749Skarels 		size = dpart.disklab->d_secsize;
20451155Sbostic #ifdef NEVER_USED
20551155Sbostic 		dpart.part->p_fstype = FS_LFS;
20651155Sbostic 		dpart.part->p_fsize = fs->lfs_fsize;	/* frag size */
20751155Sbostic 		dpart.part->p_frag = fs->lfs_frag;	/* frags per block */
20851155Sbostic 		dpart.part->p_cpg = fs->lfs_segshift;	/* segment shift */
20951155Sbostic #endif
21037737Smckusick 	}
21151155Sbostic 
21251155Sbostic 	/* Don't free random space on error. */
21351155Sbostic 	bp = NULL;
21451155Sbostic 	ump = NULL;
21551155Sbostic 
21651155Sbostic 	/* Read in the superblock. */
21751155Sbostic 	if (error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, NOCRED, &bp))
21812795Ssam 		goto out;
21951155Sbostic 	fs = bp->b_un.b_lfs;
22051155Sbostic 
22151155Sbostic 	/* Check the basics. */
22251155Sbostic 	if (fs->lfs_magic != LFS_MAGIC || fs->lfs_bsize > MAXBSIZE ||
22351501Sbostic 	    fs->lfs_bsize < sizeof(struct lfs)) {
22441314Smckusick 		error = EINVAL;		/* XXX needs translation */
22516639Skarels 		goto out;
22616639Skarels 	}
22751155Sbostic #ifdef DEBUG
22851483Sbostic 	lfs_dump_super(fs);
22951155Sbostic #endif
23051155Sbostic 
23151155Sbostic 	/* Allocate the mount structure, copy the superblock into it. */
23241314Smckusick 	ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
23351989Smckusick 	ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK);
23451501Sbostic 	bcopy(bp->b_un.b_addr, ump->um_lfs, sizeof(struct lfs));
23551501Sbostic 	if (sizeof(struct lfs) < LFS_SBPAD)			/* XXX why? */
23639675Smckusick 		bp->b_flags |= B_INVAL;
23734421Skarels 	brelse(bp);
23834421Skarels 	bp = NULL;
23951155Sbostic 
24051183Sbostic 	/* Set up the I/O information */
24151183Sbostic 	fs->lfs_iocount = 0;
24251183Sbostic 
24354264Sbostic 	/* Set up the ifile flags */
24454264Sbostic 	fs->lfs_doifile = 0;
24554264Sbostic 	fs->lfs_writer = 0;
24654264Sbostic 	fs->lfs_dirops = 0;
24754264Sbostic 
24851155Sbostic 	/* Set the file system readonly/modify bits. */
24951155Sbostic 	fs = ump->um_lfs;
25051155Sbostic 	fs->lfs_ronly = ronly;
25112795Ssam 	if (ronly == 0)
25251155Sbostic 		fs->lfs_fmod = 1;
25351155Sbostic 
25451155Sbostic 	/* Initialize the mount structure. */
25551155Sbostic 	dev = devvp->v_rdev;
25641397Smckusick 	mp->mnt_data = (qaddr_t)ump;
25741397Smckusick 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
25851991Sbostic 	mp->mnt_stat.f_fsid.val[1] = MOUNT_LFS;
25941397Smckusick 	mp->mnt_flag |= MNT_LOCAL;
26037737Smckusick 	ump->um_mountp = mp;
26137737Smckusick 	ump->um_dev = dev;
26237737Smckusick 	ump->um_devvp = devvp;
26341314Smckusick 	for (i = 0; i < MAXQUOTAS; i++)
26441314Smckusick 		ump->um_quotas[i] = NULLVP;
26552221Sbostic 	devvp->v_specflags |= SI_MOUNTEDON;
26651155Sbostic 
26752221Sbostic 	/*
26852221Sbostic 	 * We use the ifile vnode for almost every operation.  Instead of
26952221Sbostic 	 * retrieving it from the hash table each time we retrieve it here,
27052221Sbostic 	 * artificially increment the reference count and keep a pointer
27152221Sbostic 	 * to it in the incore copy of the superblock.
27252221Sbostic 	 */
273*54693Sbostic 	if (error = VFS_VGET(mp, LFS_IFILE_INUM, &vp))
27451155Sbostic 		goto out;
27551155Sbostic 	fs->lfs_ivnode = vp;
27652221Sbostic 	VREF(vp);
27752221Sbostic 	vput(vp);
27851155Sbostic 
27937737Smckusick 	return (0);
28012795Ssam out:
28140872Smckusick 	if (bp)
28240872Smckusick 		brelse(bp);
28351155Sbostic 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
28441314Smckusick 	if (ump) {
28551989Smckusick 		free(ump->um_lfs, M_UFSMNT);
28651501Sbostic 		free(ump, M_UFSMNT);
28741397Smckusick 		mp->mnt_data = (qaddr_t)0;
28832721Smckusick 	}
28937737Smckusick 	return (error);
29012795Ssam }
29112795Ssam 
29239043Smckusick /*
29337737Smckusick  * unmount system call
29437737Smckusick  */
29551155Sbostic lfs_unmount(mp, mntflags, p)
29637737Smckusick 	struct mount *mp;
29741314Smckusick 	int mntflags;
29848036Smckusick 	struct proc *p;
29912795Ssam {
30051501Sbostic 	extern int doforce;
30137737Smckusick 	register struct ufsmount *ump;
30251501Sbostic 	register struct lfs *fs;				/* LFS */
303*54693Sbostic 	int i, error, flags, ronly;
30412795Ssam 
30551853Sbostic #ifdef VERBOSE
30651853Sbostic 	printf("lfs_unmount\n");
30751853Sbostic #endif
308*54693Sbostic 	flags = 0;
30948065Smckusick 	if (mntflags & MNT_FORCE) {
31048359Smckusick 		if (!doforce || mp == rootfs)
31148065Smckusick 			return (EINVAL);
31241314Smckusick 		flags |= FORCECLOSE;
31348065Smckusick 	}
31454264Sbostic 
31554264Sbostic 	ump = VFSTOUFS(mp);
31654264Sbostic 	fs = ump->um_lfs;
31712795Ssam #ifdef QUOTA
31841397Smckusick 	if (mp->mnt_flag & MNT_QUOTA) {
31954264Sbostic 		if (error = vflush(mp, fs->lfs_ivnode, SKIPSYSTEM|flags))
32039898Smckusick 			return (error);
32141314Smckusick 		for (i = 0; i < MAXQUOTAS; i++) {
32241314Smckusick 			if (ump->um_quotas[i] == NULLVP)
32341314Smckusick 				continue;
32450114Smckusick 			quotaoff(p, mp, i);
32541314Smckusick 		}
32639898Smckusick 		/*
32741314Smckusick 		 * Here we fall through to vflush again to ensure
32841314Smckusick 		 * that we have gotten rid of all the system vnodes.
32939898Smckusick 		 */
33041314Smckusick 	}
33112795Ssam #endif
33254264Sbostic 	vrele(fs->lfs_ivnode);
333*54693Sbostic 	if (error = vflush(mp, fs->lfs_ivnode, flags))
33439898Smckusick 		return (error);
335*54693Sbostic 	if (error = VFS_SYNC(mp, 1, p->p_ucred, p))
336*54693Sbostic 		return (error);
337*54693Sbostic 	if (fs->lfs_ivnode->v_dirtyblkhd)
338*54693Sbostic 		panic("lfs_unmount: still dirty blocks on ifile vnode\n");
339*54693Sbostic 	vgone(fs->lfs_ivnode);
340*54693Sbostic 
34151155Sbostic 	ronly = !fs->lfs_ronly;
34240653Smckusick 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
343*54693Sbostic 	error = VOP_CLOSE(ump->um_devvp,
344*54693Sbostic 	    ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
34537737Smckusick 	vrele(ump->um_devvp);
34651989Smckusick 	free(fs, M_UFSMNT);
34751501Sbostic 	free(ump, M_UFSMNT);
34841397Smckusick 	mp->mnt_data = (qaddr_t)0;
34941397Smckusick 	mp->mnt_flag &= ~MNT_LOCAL;
35030749Skarels 	return (error);
35112795Ssam }
35212795Ssam 
35337737Smckusick /*
35451559Smckusick  * Return root of a filesystem
35551559Smckusick  */
35651559Smckusick int
35751559Smckusick lfs_root(mp, vpp)
35851559Smckusick 	struct mount *mp;
35951559Smckusick 	struct vnode **vpp;
36051559Smckusick {
36151559Smckusick 	struct vnode *nvp;
36251559Smckusick 	int error;
36351559Smckusick 
36451853Sbostic #ifdef VERBOSE
36551853Sbostic 	printf("lfs_root\n");
36651853Sbostic #endif
367*54693Sbostic 	if (error = VFS_VGET(mp, (ino_t)ROOTINO, &nvp))
36851559Smckusick 		return (error);
36951559Smckusick 	*vpp = nvp;
37051559Smckusick 	return (0);
37151559Smckusick }
37251559Smckusick 
37351559Smckusick /*
37437737Smckusick  * Get file system statistics.
37537737Smckusick  */
37651155Sbostic lfs_statfs(mp, sbp, p)
37737737Smckusick 	struct mount *mp;
37837737Smckusick 	register struct statfs *sbp;
37948036Smckusick 	struct proc *p;
38037737Smckusick {
38151501Sbostic 	register struct lfs *fs;
38237737Smckusick 	register struct ufsmount *ump;
38337737Smckusick 
38437737Smckusick 	ump = VFSTOUFS(mp);
38551155Sbostic 	fs = ump->um_lfs;
38651155Sbostic 	if (fs->lfs_magic != LFS_MAGIC)
38751155Sbostic 		panic("lfs_statfs: magic");
38851155Sbostic 	sbp->f_type = MOUNT_LFS;
38951155Sbostic 	sbp->f_bsize = fs->lfs_bsize;
39051943Smckusick 	sbp->f_iosize = fs->lfs_bsize;
39151155Sbostic 	sbp->f_blocks = fs->lfs_dsize;
39251155Sbostic 	sbp->f_bfree = fs->lfs_bfree;
39351155Sbostic 	sbp->f_bavail = (fs->lfs_dsize * (100 - fs->lfs_minfree) / 100) -
39451155Sbostic 		(fs->lfs_dsize - sbp->f_bfree);
39551155Sbostic 	sbp->f_files = fs->lfs_nfiles;
39651155Sbostic 	sbp->f_ffree = fs->lfs_bfree * INOPB(fs);
39741397Smckusick 	if (sbp != &mp->mnt_stat) {
39841397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
39940346Smckusick 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
40041397Smckusick 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
40140346Smckusick 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
40240346Smckusick 	}
40337737Smckusick 	return (0);
40437737Smckusick }
40537737Smckusick 
40637737Smckusick /*
40737737Smckusick  * Go through the disk queues to initiate sandbagged IO;
40837737Smckusick  * go through the inodes to write those that have been modified;
40937737Smckusick  * initiate the writing of the super block if it has been modified.
41041314Smckusick  *
41141314Smckusick  * Note: we are always called with the filesystem marked `MPBUSY'.
41237737Smckusick  */
413*54693Sbostic lfs_sync(mp, waitfor, cred, p)
41437737Smckusick 	struct mount *mp;
41537737Smckusick 	int waitfor;
416*54693Sbostic 	struct ucred *cred;
417*54693Sbostic 	struct proc *p;
41837737Smckusick {
41951914Sbostic 	extern int crashandburn, syncprt;
42051215Sbostic 	int error;
42137737Smckusick 
42251853Sbostic #ifdef VERBOSE
42351853Sbostic 	printf("lfs_sync\n");
42451853Sbostic #endif
42551215Sbostic 
42651914Sbostic #ifdef DIAGNOSTIC
42751914Sbostic 	if (crashandburn)
42851914Sbostic 		return (0);
42951914Sbostic #endif
43051310Sbostic 
43151310Sbostic 	/* All syncs must be checkpoints until roll-forward is implemented. */
43251991Sbostic 	error = lfs_segwrite(mp, 1);
43341314Smckusick #ifdef QUOTA
43441314Smckusick 	qsync(mp);
43541314Smckusick #endif
43651215Sbostic 	return (error);
43737737Smckusick }
43851559Smckusick 
43951559Smckusick /*
440*54693Sbostic  * Look up an LFS dinode number to find its incore vnode.  If not already
441*54693Sbostic  * in core, read it in from the specified device.  Return the inode locked.
442*54693Sbostic  * Detection and handling of mount points must be done by the calling routine.
443*54693Sbostic  */
444*54693Sbostic int
445*54693Sbostic lfs_vget(mp, ino, vpp)
446*54693Sbostic 	struct mount *mp;
447*54693Sbostic 	ino_t ino;
448*54693Sbostic 	struct vnode **vpp;
449*54693Sbostic {
450*54693Sbostic 	register struct lfs *fs;
451*54693Sbostic 	register struct inode *ip;
452*54693Sbostic 	struct buf *bp;
453*54693Sbostic 	struct ifile *ifp;
454*54693Sbostic 	struct vnode *vp;
455*54693Sbostic 	struct ufsmount *ump;
456*54693Sbostic 	daddr_t daddr;
457*54693Sbostic 	dev_t dev;
458*54693Sbostic 	int error;
459*54693Sbostic 
460*54693Sbostic #ifdef VERBOSE
461*54693Sbostic 	printf("lfs_vget\n");
462*54693Sbostic #endif
463*54693Sbostic 	ump = VFSTOUFS(mp);
464*54693Sbostic 	dev = ump->um_dev;
465*54693Sbostic 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
466*54693Sbostic 		return (0);
467*54693Sbostic 
468*54693Sbostic 	/* Translate the inode number to a disk address. */
469*54693Sbostic 	fs = ump->um_lfs;
470*54693Sbostic 	if (ino == LFS_IFILE_INUM)
471*54693Sbostic 		daddr = fs->lfs_idaddr;
472*54693Sbostic 	else {
473*54693Sbostic 		LFS_IENTRY(ifp, fs, ino, bp);
474*54693Sbostic 		daddr = ifp->if_daddr;
475*54693Sbostic 		brelse(bp);
476*54693Sbostic 		if (daddr == LFS_UNUSED_DADDR)
477*54693Sbostic 			return (ENOENT);
478*54693Sbostic 	}
479*54693Sbostic 
480*54693Sbostic 	/* Allocate new vnode/inode. */
481*54693Sbostic 	if (error = lfs_vcreate(mp, ino, &vp)) {
482*54693Sbostic 		*vpp = NULL;
483*54693Sbostic 		return (error);
484*54693Sbostic 	}
485*54693Sbostic 
486*54693Sbostic 	/*
487*54693Sbostic 	 * Put it onto its hash chain and lock it so that other requests for
488*54693Sbostic 	 * this inode will block if they arrive while we are sleeping waiting
489*54693Sbostic 	 * for old data structures to be purged or for the contents of the
490*54693Sbostic 	 * disk portion of this inode to be read.
491*54693Sbostic 	 */
492*54693Sbostic 	ip = VTOI(vp);
493*54693Sbostic 	ufs_ihashins(ip);
494*54693Sbostic 
495*54693Sbostic 	/*
496*54693Sbostic 	 * XXX
497*54693Sbostic 	 * This may not need to be here, logically it should go down with
498*54693Sbostic 	 * the i_devvp initialization.
499*54693Sbostic 	 * Ask Kirk.
500*54693Sbostic 	 */
501*54693Sbostic 	ip->i_lfs = ump->um_lfs;
502*54693Sbostic 
503*54693Sbostic 	/* Read in the disk contents for the inode, copy into the inode. */
504*54693Sbostic 	if (error =
505*54693Sbostic 	    bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) {
506*54693Sbostic 		/*
507*54693Sbostic 		 * The inode does not contain anything useful, so it
508*54693Sbostic 		 * would be misleading to leave it on its hash chain.
509*54693Sbostic 		 * Iput() will return it to the free list.
510*54693Sbostic 		 */
511*54693Sbostic 		remque(ip);
512*54693Sbostic 		ip->i_forw = ip;
513*54693Sbostic 		ip->i_back = ip;
514*54693Sbostic 
515*54693Sbostic 		/* Unlock and discard unneeded inode. */
516*54693Sbostic 		ufs_iput(ip);
517*54693Sbostic 		brelse(bp);
518*54693Sbostic 		*vpp = NULL;
519*54693Sbostic 		return (error);
520*54693Sbostic 	}
521*54693Sbostic 	ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino);
522*54693Sbostic 	brelse(bp);
523*54693Sbostic 
524*54693Sbostic 	/*
525*54693Sbostic 	 * Initialize the vnode from the inode, check for aliases.  In all
526*54693Sbostic 	 * cases re-init ip, the underlying vnode/inode may have changed.
527*54693Sbostic 	 */
528*54693Sbostic 	if (error = ufs_vinit(mp, lfs_specop_p, LFS_FIFOOPS, &vp)) {
529*54693Sbostic 		ufs_iput(ip);
530*54693Sbostic 		*vpp = NULL;
531*54693Sbostic 		return (error);
532*54693Sbostic 	}
533*54693Sbostic 	/*
534*54693Sbostic 	 * Finish inode initialization now that aliasing has been resolved.
535*54693Sbostic 	 */
536*54693Sbostic 	ip->i_devvp = ump->um_devvp;
537*54693Sbostic 	VREF(ip->i_devvp);
538*54693Sbostic 	*vpp = vp;
539*54693Sbostic 	return (0);
540*54693Sbostic }
541*54693Sbostic 
542*54693Sbostic /*
54351559Smckusick  * File handle to vnode
54451559Smckusick  *
54551559Smckusick  * Have to be really careful about stale file handles:
54651559Smckusick  * - check that the inode number is valid
54751559Smckusick  * - call lfs_vget() to get the locked inode
54851559Smckusick  * - check for an unallocated inode (i_mode == 0)
54951559Smckusick  * - check that the generation number matches
55051559Smckusick  *
55151559Smckusick  * XXX
55251559Smckusick  * use ifile to see if inode is allocated instead of reading off disk
55351559Smckusick  * what is the relationship between my generational number and the NFS
55451559Smckusick  * generational number.
55551559Smckusick  */
55651559Smckusick int
557*54693Sbostic lfs_fhtovp(mp, fhp, vpp)
55851559Smckusick 	register struct mount *mp;
55951559Smckusick 	struct fid *fhp;
56051559Smckusick 	struct vnode **vpp;
56151559Smckusick {
56251559Smckusick 	register struct inode *ip;
56351559Smckusick 	register struct ufid *ufhp;
56451559Smckusick 	struct vnode *nvp;
56551559Smckusick 	int error;
56651559Smckusick 
56751559Smckusick 	ufhp = (struct ufid *)fhp;
56851559Smckusick 	if (ufhp->ufid_ino < ROOTINO)
56951559Smckusick 		return (EINVAL);
570*54693Sbostic 	if (error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) {
57151559Smckusick 		*vpp = NULLVP;
57251559Smckusick 		return (error);
57351559Smckusick 	}
57451559Smckusick 	ip = VTOI(nvp);
575*54693Sbostic 	if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) {
57651559Smckusick 		ufs_iput(ip);
57751559Smckusick 		*vpp = NULLVP;
57851559Smckusick 		return (EINVAL);
57951559Smckusick 	}
58051559Smckusick 	*vpp = nvp;
58151559Smckusick 	return (0);
58251559Smckusick }
58351559Smckusick 
58451559Smckusick /*
58551559Smckusick  * Vnode pointer to File handle
58651559Smckusick  */
58751559Smckusick /* ARGSUSED */
58851559Smckusick lfs_vptofh(vp, fhp)
58951559Smckusick 	struct vnode *vp;
59051559Smckusick 	struct fid *fhp;
59151559Smckusick {
59251559Smckusick 	register struct inode *ip;
59351559Smckusick 	register struct ufid *ufhp;
59451559Smckusick 
59551559Smckusick 	ip = VTOI(vp);
59651559Smckusick 	ufhp = (struct ufid *)fhp;
59751559Smckusick 	ufhp->ufid_len = sizeof(struct ufid);
59851559Smckusick 	ufhp->ufid_ino = ip->i_number;
59951559Smckusick 	ufhp->ufid_gen = ip->i_gen;
60051559Smckusick 	return (0);
60151559Smckusick }
602