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