Home | History | Annotate | Line # | Download | only in lfs
lfs_vfsops.c revision 1.15
      1 /*	$NetBSD: lfs_vfsops.c,v 1.15 1998/02/18 07:05:50 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1989, 1991, 1993, 1994
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  *
     35  *	@(#)lfs_vfsops.c	8.10 (Berkeley) 11/21/94
     36  */
     37 
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/namei.h>
     41 #include <sys/proc.h>
     42 #include <sys/kernel.h>
     43 #include <sys/vnode.h>
     44 #include <sys/mount.h>
     45 #include <sys/buf.h>
     46 #include <sys/mbuf.h>
     47 #include <sys/file.h>
     48 #include <sys/disklabel.h>
     49 #include <sys/ioctl.h>
     50 #include <sys/errno.h>
     51 #include <sys/malloc.h>
     52 #include <sys/socket.h>
     53 
     54 #include <miscfs/specfs/specdev.h>
     55 
     56 #include <ufs/ufs/quota.h>
     57 #include <ufs/ufs/inode.h>
     58 #include <ufs/ufs/ufsmount.h>
     59 #include <ufs/ufs/ufs_extern.h>
     60 
     61 #include <ufs/lfs/lfs.h>
     62 #include <ufs/lfs/lfs_extern.h>
     63 
     64 int lfs_mountfs __P((struct vnode *, struct mount *, struct proc *));
     65 
     66 extern struct vnodeopv_desc lfs_vnodeop_opv_desc;
     67 extern struct vnodeopv_desc lfs_specop_opv_desc;
     68 #ifdef FIFO
     69 extern struct vnodeopv_desc lfs_fifoop_opv_desc;
     70 #endif
     71 
     72 struct vnodeopv_desc *lfs_vnodeopv_descs[] = {
     73 	&lfs_vnodeop_opv_desc,
     74 	&lfs_specop_opv_desc,
     75 #ifdef FIFO
     76 	&lfs_fifoop_opv_desc,
     77 #endif
     78 	NULL,
     79 };
     80 
     81 struct vfsops lfs_vfsops = {
     82 	MOUNT_LFS,
     83 	lfs_mount,
     84 	ufs_start,
     85 	lfs_unmount,
     86 	ufs_root,
     87 	ufs_quotactl,
     88 	lfs_statfs,
     89 	lfs_sync,
     90 	lfs_vget,
     91 	lfs_fhtovp,
     92 	lfs_vptofh,
     93 	lfs_init,
     94 	NULL,				/* vfs_mountroot */
     95 	lfs_vnodeopv_descs,
     96 };
     97 
     98 int
     99 lfs_mountroot()
    100 {
    101 	panic("lfs_mountroot");		/* XXX -- implement */
    102 	return 0;
    103 }
    104 
    105 /*
    106  * VFS Operations.
    107  *
    108  * mount system call
    109  */
    110 int
    111 lfs_mount(mp, path, data, ndp, p)
    112 	register struct mount *mp;
    113 	const char *path;
    114 	void *data;
    115 	struct nameidata *ndp;
    116 	struct proc *p;
    117 {
    118 	struct vnode *devvp;
    119 	struct ufs_args args;
    120 	struct ufsmount *ump = NULL;
    121 	register struct lfs *fs = NULL;				/* LFS */
    122 	size_t size;
    123 	int error;
    124 	mode_t accessmode;
    125 
    126 	error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
    127 	if (error)
    128 		return (error);
    129 
    130 	/* Until LFS can do NFS right.		XXX */
    131 	if (args.export.ex_flags & MNT_EXPORTED)
    132 		return (EINVAL);
    133 
    134 	/*
    135 	 * If updating, check whether changing from read-only to
    136 	 * read/write; if there is no device name, that's all we do.
    137 	 */
    138 	if (mp->mnt_flag & MNT_UPDATE) {
    139 		ump = VFSTOUFS(mp);
    140 		if (fs->lfs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
    141 			/*
    142 			 * If upgrade to read-write by non-root, then verify
    143 			 * that user has necessary permissions on the device.
    144 			 */
    145 			if (p->p_ucred->cr_uid != 0) {
    146 				VOP_LOCK(ump->um_devvp);
    147 				error = VOP_ACCESS(ump->um_devvp, VREAD|VWRITE,
    148 						   p->p_ucred, p);
    149 				if (error) {
    150 					VOP_UNLOCK(ump->um_devvp);
    151 					return (error);
    152 				}
    153 				VOP_UNLOCK(ump->um_devvp);
    154 			}
    155 			fs->lfs_ronly = 0;
    156 		}
    157 		if (args.fspec == 0) {
    158 			/*
    159 			 * Process export requests.
    160 			 */
    161 			return (vfs_export(mp, &ump->um_export, &args.export));
    162 		}
    163 	}
    164 	/*
    165 	 * Not an update, or updating the name: look up the name
    166 	 * and verify that it refers to a sensible block device.
    167 	 */
    168 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
    169 	if ((error = namei(ndp)) != 0)
    170 		return (error);
    171 	devvp = ndp->ni_vp;
    172 	if (devvp->v_type != VBLK) {
    173 		vrele(devvp);
    174 		return (ENOTBLK);
    175 	}
    176 	if (major(devvp->v_rdev) >= nblkdev) {
    177 		vrele(devvp);
    178 		return (ENXIO);
    179 	}
    180 	/*
    181 	 * If mount by non-root, then verify that user has necessary
    182 	 * permissions on the device.
    183 	 */
    184 	if (p->p_ucred->cr_uid != 0) {
    185 		accessmode = VREAD;
    186 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
    187 			accessmode |= VWRITE;
    188 		VOP_LOCK(devvp);
    189 		error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
    190 		if (error) {
    191 			vput(devvp);
    192 			return (error);
    193 		}
    194 		VOP_UNLOCK(devvp);
    195 	}
    196 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
    197 		error = lfs_mountfs(devvp, mp, p);		/* LFS */
    198 	else {
    199 		if (devvp != ump->um_devvp)
    200 			error = EINVAL;	/* needs translation */
    201 		else
    202 			vrele(devvp);
    203 	}
    204 	if (error) {
    205 		vrele(devvp);
    206 		return (error);
    207 	}
    208 	ump = VFSTOUFS(mp);
    209 	fs = ump->um_lfs;					/* LFS */
    210 #ifdef NOTLFS							/* LFS */
    211 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
    212 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
    213 	bcopy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN);
    214 #else
    215 	(void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size);
    216 	bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size);
    217 	bcopy(fs->lfs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN);
    218 #endif
    219 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
    220 	    &size);
    221 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
    222 	return (0);
    223 }
    224 
    225 /*
    226  * Common code for mount and mountroot
    227  * LFS specific
    228  */
    229 int
    230 lfs_mountfs(devvp, mp, p)
    231 	register struct vnode *devvp;
    232 	struct mount *mp;
    233 	struct proc *p;
    234 {
    235 	extern struct vnode *rootvp;
    236 	register struct lfs *fs;
    237 	register struct ufsmount *ump;
    238 	struct vnode *vp;
    239 	struct buf *bp;
    240 	struct partinfo dpart;
    241 	dev_t dev;
    242 	int error, i, ronly, size;
    243 	struct ucred *cred;
    244 
    245 	cred = p ? p->p_ucred : NOCRED;
    246 	/*
    247 	 * Disallow multiple mounts of the same device.
    248 	 * Disallow mounting of a device that is currently in use
    249 	 * (except for root, which might share swap device for miniroot).
    250 	 * Flush out any old buffers remaining from a previous use.
    251 	 */
    252 	if ((error = vfs_mountedon(devvp)) != 0)
    253 		return (error);
    254 	if (vcount(devvp) > 1 && devvp != rootvp)
    255 		return (EBUSY);
    256 	if ((error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) != 0)
    257 		return (error);
    258 
    259 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
    260 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
    261 	if (error)
    262 		return (error);
    263 
    264 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
    265 		size = DEV_BSIZE;
    266 	else {
    267 		size = dpart.disklab->d_secsize;
    268 #ifdef NEVER_USED
    269 		dpart.part->p_fstype = FS_LFS;
    270 		dpart.part->p_fsize = fs->lfs_fsize;	/* frag size */
    271 		dpart.part->p_frag = fs->lfs_frag;	/* frags per block */
    272 		dpart.part->p_cpg = fs->lfs_segshift;	/* segment shift */
    273 #endif
    274 	}
    275 
    276 	/* Don't free random space on error. */
    277 	bp = NULL;
    278 	ump = NULL;
    279 
    280 	/* Read in the superblock. */
    281 	error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, cred, &bp);
    282 	if (error)
    283 		goto out;
    284 	fs = (struct lfs *)bp->b_data;
    285 
    286 	/* Check the basics. */
    287 	if (fs->lfs_magic != LFS_MAGIC || fs->lfs_bsize > MAXBSIZE ||
    288 	    fs->lfs_bsize < sizeof(struct lfs)) {
    289 		error = EINVAL;		/* XXX needs translation */
    290 		goto out;
    291 	}
    292 
    293 	/* Allocate the mount structure, copy the superblock into it. */
    294 	ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
    295 	fs = ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK);
    296 	bcopy(bp->b_data, fs, sizeof(struct lfs));
    297 	if (sizeof(struct lfs) < LFS_SBPAD)			/* XXX why? */
    298 		bp->b_flags |= B_INVAL;
    299 	brelse(bp);
    300 	bp = NULL;
    301 
    302 	/* Set up the I/O information */
    303 	fs->lfs_iocount = 0;
    304 
    305 	/* Set up the ifile and lock aflags */
    306 	fs->lfs_doifile = 0;
    307 	fs->lfs_writer = 0;
    308 	fs->lfs_dirops = 0;
    309 	fs->lfs_seglock = 0;
    310 
    311 	/* Set the file system readonly/modify bits. */
    312 	fs->lfs_ronly = ronly;
    313 	if (ronly == 0)
    314 		fs->lfs_fmod = 1;
    315 
    316 	/* Initialize the mount structure. */
    317 	dev = devvp->v_rdev;
    318 	mp->mnt_data = (qaddr_t)ump;
    319 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
    320 	mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_LFS);
    321 	mp->mnt_maxsymlinklen = fs->lfs_maxsymlinklen;
    322 	mp->mnt_flag |= MNT_LOCAL;
    323 	ump->um_mountp = mp;
    324 	ump->um_dev = dev;
    325 	ump->um_devvp = devvp;
    326 	ump->um_bptrtodb = 0;
    327 	ump->um_seqinc = 1 << fs->lfs_fsbtodb;
    328 	ump->um_nindir = fs->lfs_nindir;
    329 	for (i = 0; i < MAXQUOTAS; i++)
    330 		ump->um_quotas[i] = NULLVP;
    331 	devvp->v_specflags |= SI_MOUNTEDON;
    332 
    333 	/*
    334 	 * We use the ifile vnode for almost every operation.  Instead of
    335 	 * retrieving it from the hash table each time we retrieve it here,
    336 	 * artificially increment the reference count and keep a pointer
    337 	 * to it in the incore copy of the superblock.
    338 	 */
    339 	if ((error = VFS_VGET(mp, LFS_IFILE_INUM, &vp)) != 0)
    340 		goto out;
    341 	fs->lfs_ivnode = vp;
    342 	VREF(vp);
    343 	vput(vp);
    344 
    345 	return (0);
    346 out:
    347 	if (bp)
    348 		brelse(bp);
    349 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
    350 	if (ump) {
    351 		free(ump->um_lfs, M_UFSMNT);
    352 		free(ump, M_UFSMNT);
    353 		mp->mnt_data = (qaddr_t)0;
    354 	}
    355 	return (error);
    356 }
    357 
    358 /*
    359  * unmount system call
    360  */
    361 int
    362 lfs_unmount(mp, mntflags, p)
    363 	struct mount *mp;
    364 	int mntflags;
    365 	struct proc *p;
    366 {
    367 	register struct ufsmount *ump;
    368 	register struct lfs *fs;
    369 	int error, flags, ronly;
    370 
    371 	flags = 0;
    372 	if (mntflags & MNT_FORCE)
    373 		flags |= FORCECLOSE;
    374 
    375 	ump = VFSTOUFS(mp);
    376 	fs = ump->um_lfs;
    377 #ifdef QUOTA
    378 	if (mp->mnt_flag & MNT_QUOTA) {
    379 		int i;
    380 		error = vflush(mp, fs->lfs_ivnode, SKIPSYSTEM|flags);
    381 		if (error)
    382 			return (error);
    383 		for (i = 0; i < MAXQUOTAS; i++) {
    384 			if (ump->um_quotas[i] == NULLVP)
    385 				continue;
    386 			quotaoff(p, mp, i);
    387 		}
    388 		/*
    389 		 * Here we fall through to vflush again to ensure
    390 		 * that we have gotten rid of all the system vnodes.
    391 		 */
    392 	}
    393 #endif
    394 	if ((error = vflush(mp, fs->lfs_ivnode, flags)) != 0)
    395 		return (error);
    396 	fs->lfs_clean = 1;
    397 	if ((error = VFS_SYNC(mp, 1, p->p_ucred, p)) != 0)
    398 		return (error);
    399 	if (fs->lfs_ivnode->v_dirtyblkhd.lh_first)
    400 		panic("lfs_unmount: still dirty blocks on ifile vnode\n");
    401 	vrele(fs->lfs_ivnode);
    402 	vgone(fs->lfs_ivnode);
    403 
    404 	ronly = !fs->lfs_ronly;
    405 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
    406 	error = VOP_CLOSE(ump->um_devvp,
    407 	    ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
    408 	vrele(ump->um_devvp);
    409 	free(fs, M_UFSMNT);
    410 	free(ump, M_UFSMNT);
    411 	mp->mnt_data = (qaddr_t)0;
    412 	mp->mnt_flag &= ~MNT_LOCAL;
    413 	return (error);
    414 }
    415 
    416 /*
    417  * Get file system statistics.
    418  */
    419 int
    420 lfs_statfs(mp, sbp, p)
    421 	struct mount *mp;
    422 	register struct statfs *sbp;
    423 	struct proc *p;
    424 {
    425 	register struct lfs *fs;
    426 	register struct ufsmount *ump;
    427 
    428 	ump = VFSTOUFS(mp);
    429 	fs = ump->um_lfs;
    430 	if (fs->lfs_magic != LFS_MAGIC)
    431 		panic("lfs_statfs: magic");
    432 	sbp->f_type = 0;
    433 	sbp->f_bsize = fs->lfs_bsize;
    434 	sbp->f_iosize = fs->lfs_bsize;
    435 	sbp->f_blocks = dbtofsb(fs,fs->lfs_dsize);
    436 	sbp->f_bfree = dbtofsb(fs, fs->lfs_bfree);
    437         sbp->f_bavail = (long) (((u_int64_t) fs->lfs_dsize * (u_int64_t)
    438 		(100 - fs->lfs_minfree) / (u_int64_t) 100) -
    439 		(u_int64_t) (fs->lfs_dsize - sbp->f_bfree));
    440 	sbp->f_bavail = dbtofsb(fs, sbp->f_bavail);
    441 	sbp->f_files = fs->lfs_nfiles;
    442 	sbp->f_ffree = sbp->f_bfree * INOPB(fs);
    443 	if (sbp != &mp->mnt_stat) {
    444 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
    445 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
    446 	}
    447 	strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN);
    448 	return (0);
    449 }
    450 
    451 /*
    452  * Go through the disk queues to initiate sandbagged IO;
    453  * go through the inodes to write those that have been modified;
    454  * initiate the writing of the super block if it has been modified.
    455  *
    456  * Note: we are always called with the filesystem marked `MPBUSY'.
    457  */
    458 int
    459 lfs_sync(mp, waitfor, cred, p)
    460 	struct mount *mp;
    461 	int waitfor;
    462 	struct ucred *cred;
    463 	struct proc *p;
    464 {
    465 	int error;
    466 
    467 	/* All syncs must be checkpoints until roll-forward is implemented. */
    468 	error = lfs_segwrite(mp, SEGM_CKP | (waitfor ? SEGM_SYNC : 0));
    469 #ifdef QUOTA
    470 	qsync(mp);
    471 #endif
    472 	return (error);
    473 }
    474 
    475 /*
    476  * Look up an LFS dinode number to find its incore vnode.  If not already
    477  * in core, read it in from the specified device.  Return the inode locked.
    478  * Detection and handling of mount points must be done by the calling routine.
    479  */
    480 int
    481 lfs_vget(mp, ino, vpp)
    482 	struct mount *mp;
    483 	ino_t ino;
    484 	struct vnode **vpp;
    485 {
    486 	register struct lfs *fs;
    487 	register struct inode *ip;
    488 	struct buf *bp;
    489 	struct ifile *ifp;
    490 	struct vnode *vp;
    491 	struct ufsmount *ump;
    492 	daddr_t daddr;
    493 	dev_t dev;
    494 	int error;
    495 
    496 	ump = VFSTOUFS(mp);
    497 	dev = ump->um_dev;
    498 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
    499 		return (0);
    500 
    501 	/* Translate the inode number to a disk address. */
    502 	fs = ump->um_lfs;
    503 	if (ino == LFS_IFILE_INUM)
    504 		daddr = fs->lfs_idaddr;
    505 	else {
    506 		LFS_IENTRY(ifp, fs, ino, bp);
    507 		daddr = ifp->if_daddr;
    508 		brelse(bp);
    509 		if (daddr == LFS_UNUSED_DADDR)
    510 			return (ENOENT);
    511 	}
    512 
    513 	/* Allocate new vnode/inode. */
    514 	if ((error = lfs_vcreate(mp, ino, &vp)) != 0) {
    515 		*vpp = NULL;
    516 		return (error);
    517 	}
    518 
    519 	/*
    520 	 * Put it onto its hash chain and lock it so that other requests for
    521 	 * this inode will block if they arrive while we are sleeping waiting
    522 	 * for old data structures to be purged or for the contents of the
    523 	 * disk portion of this inode to be read.
    524 	 */
    525 	ip = VTOI(vp);
    526 	ufs_ihashins(ip);
    527 
    528 	/*
    529 	 * XXX
    530 	 * This may not need to be here, logically it should go down with
    531 	 * the i_devvp initialization.
    532 	 * Ask Kirk.
    533 	 */
    534 	ip->i_lfs = ump->um_lfs;
    535 
    536 	/* Read in the disk contents for the inode, copy into the inode. */
    537 	error = bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp);
    538 	if (error) {
    539 		/*
    540 		 * The inode does not contain anything useful, so it would
    541 		 * be misleading to leave it on its hash chain. With mode
    542 		 * still zero, it will be unlinked and returned to the free
    543 		 * list by vput().
    544 		 */
    545 		vput(vp);
    546 		brelse(bp);
    547 		*vpp = NULL;
    548 		return (error);
    549 	}
    550 	ip->i_din.ffs_din = *lfs_ifind(fs, ino, (struct dinode *)bp->b_data);
    551 	brelse(bp);
    552 
    553 	/*
    554 	 * Initialize the vnode from the inode, check for aliases.  In all
    555 	 * cases re-init ip, the underlying vnode/inode may have changed.
    556 	 */
    557 	error = ufs_vinit(mp, lfs_specop_p, LFS_FIFOOPS, &vp);
    558 	if (error) {
    559 		vput(vp);
    560 		*vpp = NULL;
    561 		return (error);
    562 	}
    563 	/*
    564 	 * Finish inode initialization now that aliasing has been resolved.
    565 	 */
    566 	ip->i_devvp = ump->um_devvp;
    567 	VREF(ip->i_devvp);
    568 	*vpp = vp;
    569 	return (0);
    570 }
    571 
    572 /*
    573  * File handle to vnode
    574  *
    575  * Have to be really careful about stale file handles:
    576  * - check that the inode number is valid
    577  * - call lfs_vget() to get the locked inode
    578  * - check for an unallocated inode (i_mode == 0)
    579  * - check that the given client host has export rights and return
    580  *   those rights via. exflagsp and credanonp
    581  *
    582  * XXX
    583  * use ifile to see if inode is allocated instead of reading off disk
    584  * what is the relationship between my generational number and the NFS
    585  * generational number.
    586  */
    587 int
    588 lfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
    589 	register struct mount *mp;
    590 	struct fid *fhp;
    591 	struct mbuf *nam;
    592 	struct vnode **vpp;
    593 	int *exflagsp;
    594 	struct ucred **credanonp;
    595 {
    596 	register struct ufid *ufhp;
    597 
    598 	ufhp = (struct ufid *)fhp;
    599 	if (ufhp->ufid_ino < ROOTINO)
    600 		return (ESTALE);
    601 	return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
    602 }
    603 
    604 /*
    605  * Vnode pointer to File handle
    606  */
    607 /* ARGSUSED */
    608 int
    609 lfs_vptofh(vp, fhp)
    610 	struct vnode *vp;
    611 	struct fid *fhp;
    612 {
    613 	register struct inode *ip;
    614 	register struct ufid *ufhp;
    615 
    616 	ip = VTOI(vp);
    617 	ufhp = (struct ufid *)fhp;
    618 	ufhp->ufid_len = sizeof(struct ufid);
    619 	ufhp->ufid_ino = ip->i_number;
    620 	ufhp->ufid_gen = ip->i_ffs_gen;
    621 	return (0);
    622 }
    623