hpfs_vfsops.c revision 86931
154371Ssemenu/*- 254371Ssemenu * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org) 354371Ssemenu * All rights reserved. 454371Ssemenu * 554371Ssemenu * Redistribution and use in source and binary forms, with or without 654371Ssemenu * modification, are permitted provided that the following conditions 754371Ssemenu * are met: 854371Ssemenu * 1. Redistributions of source code must retain the above copyright 954371Ssemenu * notice, this list of conditions and the following disclaimer. 1054371Ssemenu * 2. Redistributions in binary form must reproduce the above copyright 1154371Ssemenu * notice, this list of conditions and the following disclaimer in the 1254371Ssemenu * documentation and/or other materials provided with the distribution. 1354371Ssemenu * 1454371Ssemenu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1554371Ssemenu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1654371Ssemenu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1754371Ssemenu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1854371Ssemenu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1954371Ssemenu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2054371Ssemenu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2154371Ssemenu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2254371Ssemenu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2354371Ssemenu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2454371Ssemenu * SUCH DAMAGE. 2554371Ssemenu * 2654371Ssemenu * $FreeBSD: head/sys/fs/hpfs/hpfs_vfsops.c 86931 2001-11-27 00:34:13Z jhb $ 2754371Ssemenu */ 2854371Ssemenu 2954371Ssemenu 3054371Ssemenu#include <sys/param.h> 3154371Ssemenu#include <sys/systm.h> 3254371Ssemenu#include <sys/namei.h> 3354371Ssemenu#include <sys/conf.h> 3454371Ssemenu#include <sys/proc.h> 3554371Ssemenu#include <sys/kernel.h> 3654371Ssemenu#include <sys/vnode.h> 3754371Ssemenu#include <sys/mount.h> 3860041Sphk#include <sys/bio.h> 3954371Ssemenu#include <sys/buf.h> 4054371Ssemenu#include <sys/fcntl.h> 4154371Ssemenu#include <sys/malloc.h> 4254371Ssemenu 4354371Ssemenu#include <vm/vm.h> 4454371Ssemenu#include <vm/vm_param.h> 4554371Ssemenu#include <vm/vm_page.h> 4654371Ssemenu#include <vm/vm_object.h> 4754371Ssemenu#include <vm/vm_extern.h> 4854371Ssemenu 4954371Ssemenu#include <fs/hpfs/hpfs.h> 5054371Ssemenu#include <fs/hpfs/hpfsmount.h> 5154371Ssemenu#include <fs/hpfs/hpfs_subr.h> 5254371Ssemenu 5354371SsemenuMALLOC_DEFINE(M_HPFSMNT, "HPFS mount", "HPFS mount structure"); 5454371SsemenuMALLOC_DEFINE(M_HPFSNO, "HPFS node", "HPFS node structure"); 5583384Sjhb 5686927Sjhbstruct sockaddr; 5786927Sjhb 5854371Ssemenustatic int hpfs_root __P((struct mount *, struct vnode **)); 5954371Ssemenustatic int hpfs_statfs __P((struct mount *, struct statfs *, 6086928Sjhb struct thread *)); 6186928Sjhbstatic int hpfs_unmount __P((struct mount *, int, struct thread *)); 6254371Ssemenustatic int hpfs_vget __P((struct mount *mp, ino_t ino, 6354371Ssemenu struct vnode **vpp)); 6454371Ssemenustatic int hpfs_mountfs __P((register struct vnode *, struct mount *, 6586928Sjhb struct hpfs_args *, struct thread *)); 6654371Ssemenustatic int hpfs_vptofh __P((struct vnode *, struct fid *)); 6754371Ssemenustatic int hpfs_fhtovp __P((struct mount *, struct fid *, 6854371Ssemenu struct vnode **)); 6954371Ssemenustatic int hpfs_mount __P((struct mount *, char *, caddr_t, 7083366Sjulian struct nameidata *, struct thread *)); 7154371Ssemenustatic int hpfs_init __P((struct vfsconf *)); 7266615Sjasonestatic int hpfs_uninit __P((struct vfsconf *)); 7354371Ssemenu 7454371Ssemenustatic int 7554371Ssemenuhpfs_init ( 7654371Ssemenu struct vfsconf *vcp ) 7754371Ssemenu{ 7854371Ssemenu dprintf(("hpfs_init():\n")); 7954371Ssemenu 8054371Ssemenu hpfs_hphashinit(); 8154371Ssemenu return 0; 8254371Ssemenu} 8354371Ssemenu 8454371Ssemenustatic int 8566615Sjasonehpfs_uninit (vfsp) 8666615Sjasone struct vfsconf *vfsp; 8766615Sjasone{ 8866615Sjasone hpfs_hphashdestroy(); 8966615Sjasone return 0;; 9066615Sjasone} 9166615Sjasone 9266615Sjasonestatic int 9354371Ssemenuhpfs_mount ( 9454371Ssemenu struct mount *mp, 9554371Ssemenu char *path, 9654371Ssemenu caddr_t data, 9783366Sjulian struct nameidata *ndp, 9886931Sjhb struct thread *td ) 9954371Ssemenu{ 10054371Ssemenu u_int size; 10154371Ssemenu int err = 0; 10254371Ssemenu struct vnode *devvp; 10354371Ssemenu struct hpfs_args args; 10454371Ssemenu struct hpfsmount *hpmp = 0; 10554371Ssemenu 10654371Ssemenu dprintf(("hpfs_mount():\n")); 10754371Ssemenu /* 10854371Ssemenu *** 10954371Ssemenu * Mounting non-root file system or updating a file system 11054371Ssemenu *** 11154371Ssemenu */ 11254371Ssemenu 11354371Ssemenu /* copy in user arguments*/ 11454371Ssemenu err = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args)); 11554371Ssemenu if (err) 11654371Ssemenu goto error_1; /* can't get arguments*/ 11754371Ssemenu 11854371Ssemenu /* 11954371Ssemenu * If updating, check whether changing from read-only to 12054371Ssemenu * read/write; if there is no device name, that's all we do. 12154371Ssemenu */ 12254371Ssemenu if (mp->mnt_flag & MNT_UPDATE) { 12354371Ssemenu dprintf(("hpfs_mount: MNT_UPDATE: ")); 12454371Ssemenu 12554371Ssemenu hpmp = VFSTOHPFS(mp); 12654371Ssemenu 12754371Ssemenu if (args.fspec == 0) { 12854371Ssemenu dprintf(("export 0x%x\n",args.export.ex_flags)); 12975934Sphk err = vfs_export(mp, &args.export); 13054371Ssemenu if (err) { 13154371Ssemenu printf("hpfs_mount: vfs_export failed %d\n", 13254371Ssemenu err); 13354371Ssemenu } 13454371Ssemenu goto success; 13554371Ssemenu } else { 13654371Ssemenu dprintf(("name [FAILED]\n")); 13754371Ssemenu err = EINVAL; 13854371Ssemenu goto success; 13954371Ssemenu } 14054371Ssemenu dprintf(("\n")); 14154371Ssemenu } 14254371Ssemenu 14354371Ssemenu /* 14454371Ssemenu * Not an update, or updating the name: look up the name 14554371Ssemenu * and verify that it refers to a sensible block device. 14654371Ssemenu */ 14786931Sjhb NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td); 14854371Ssemenu err = namei(ndp); 14954371Ssemenu if (err) { 15054371Ssemenu /* can't get devvp!*/ 15154371Ssemenu goto error_1; 15254371Ssemenu } 15354371Ssemenu 15454371Ssemenu devvp = ndp->ni_vp; 15554371Ssemenu 15655756Sphk if (!vn_isdisk(devvp, &err)) 15754371Ssemenu goto error_2; 15854371Ssemenu 15954371Ssemenu /* 16054371Ssemenu ******************** 16154371Ssemenu * NEW MOUNT 16254371Ssemenu ******************** 16354371Ssemenu */ 16454371Ssemenu 16554371Ssemenu /* 16654371Ssemenu * Since this is a new mount, we want the names for 16754371Ssemenu * the device and the mount point copied in. If an 16873286Sadrian * error occurs, the mountpoint is discarded by the 16973286Sadrian * upper level code. Note that vfs_mount() handles 17073286Sadrian * copying the mountpoint f_mntonname for us, so we 17173286Sadrian * don't have to do it here unless we want to set it 17273286Sadrian * to something other than "path" for some rason. 17354371Ssemenu */ 17454371Ssemenu /* Save "mounted from" info for mount point (NULL pad)*/ 17554371Ssemenu copyinstr( args.fspec, /* device name*/ 17654371Ssemenu mp->mnt_stat.f_mntfromname, /* save area*/ 17754371Ssemenu MNAMELEN - 1, /* max size*/ 17854371Ssemenu &size); /* real size*/ 17954371Ssemenu bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 18054371Ssemenu 18186931Sjhb err = hpfs_mountfs(devvp, mp, &args, td); 18254371Ssemenu if (err) 18354371Ssemenu goto error_2; 18454371Ssemenu 18554371Ssemenu /* 18654371Ssemenu * Initialize FS stat information in mount struct; uses both 18754371Ssemenu * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 18854371Ssemenu * 18954371Ssemenu * This code is common to root and non-root mounts 19054371Ssemenu */ 19186931Sjhb (void)VFS_STATFS(mp, &mp->mnt_stat, td); 19254371Ssemenu 19354371Ssemenu goto success; 19454371Ssemenu 19554371Ssemenu 19654371Ssemenuerror_2: /* error with devvp held*/ 19754371Ssemenu 19854371Ssemenu /* release devvp before failing*/ 19954371Ssemenu vrele(devvp); 20054371Ssemenu 20154371Ssemenuerror_1: /* no state to back out*/ 20254371Ssemenu 20354371Ssemenusuccess: 20454371Ssemenu return( err); 20554371Ssemenu} 20654371Ssemenu 20754371Ssemenu/* 20854371Ssemenu * Common code for mount and mountroot 20954371Ssemenu */ 21054371Ssemenuint 21186931Sjhbhpfs_mountfs(devvp, mp, argsp, td) 21254371Ssemenu register struct vnode *devvp; 21354371Ssemenu struct mount *mp; 21454371Ssemenu struct hpfs_args *argsp; 21586931Sjhb struct thread *td; 21654371Ssemenu{ 21754371Ssemenu int error, ncount, ronly; 21854371Ssemenu struct sublock *sup; 21954371Ssemenu struct spblock *spp; 22054371Ssemenu struct hpfsmount *hpmp; 22154371Ssemenu struct buf *bp = NULL; 22254371Ssemenu struct vnode *vp; 22354371Ssemenu dev_t dev = devvp->v_rdev; 22454371Ssemenu 22554371Ssemenu dprintf(("hpfs_mountfs():\n")); 22654371Ssemenu /* 22754371Ssemenu * Disallow multiple mounts of the same device. 22854371Ssemenu * Disallow mounting of a device that is currently in use 22954371Ssemenu * (except for root, which might share swap device for miniroot). 23054371Ssemenu * Flush out any old buffers remaining from a previous use. 23154371Ssemenu */ 23254371Ssemenu error = vfs_mountedon(devvp); 23354371Ssemenu if (error) 23454371Ssemenu return (error); 23554371Ssemenu ncount = vcount(devvp); 23654371Ssemenu if (devvp->v_object) 23754371Ssemenu ncount -= 1; 23854371Ssemenu if (ncount > 1 && devvp != rootvp) 23954371Ssemenu return (EBUSY); 24054371Ssemenu 24186931Sjhb vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 24286931Sjhb error = vinvalbuf(devvp, V_SAVE, td->td_proc->p_ucred, td, 0, 0); 24386931Sjhb VOP_UNLOCK(devvp, 0, td); 24454371Ssemenu if (error) 24554371Ssemenu return (error); 24654371Ssemenu 24754371Ssemenu ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 24886931Sjhb vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 24986931Sjhb error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td); 25086931Sjhb VOP_UNLOCK(devvp, 0, td); 25154371Ssemenu if (error) 25254371Ssemenu return (error); 25354371Ssemenu 25454371Ssemenu /* 25554371Ssemenu * Do actual mount 25654371Ssemenu */ 25769781Sdwmalone hpmp = malloc(sizeof(struct hpfsmount), M_HPFSMNT, M_WAITOK | M_ZERO); 25854371Ssemenu 25954371Ssemenu /* Read in SuperBlock */ 26054371Ssemenu error = bread(devvp, SUBLOCK, SUSIZE, NOCRED, &bp); 26154371Ssemenu if (error) 26254371Ssemenu goto failed; 26354371Ssemenu bcopy(bp->b_data, &hpmp->hpm_su, sizeof(struct sublock)); 26454371Ssemenu brelse(bp); bp = NULL; 26554371Ssemenu 26654371Ssemenu /* Read in SpareBlock */ 26754371Ssemenu error = bread(devvp, SPBLOCK, SPSIZE, NOCRED, &bp); 26854371Ssemenu if (error) 26954371Ssemenu goto failed; 27054371Ssemenu bcopy(bp->b_data, &hpmp->hpm_sp, sizeof(struct spblock)); 27154371Ssemenu brelse(bp); bp = NULL; 27254371Ssemenu 27354371Ssemenu sup = &hpmp->hpm_su; 27454371Ssemenu spp = &hpmp->hpm_sp; 27554371Ssemenu 27654371Ssemenu /* Check magic */ 27754371Ssemenu if (sup->su_magic != SU_MAGIC) { 27854371Ssemenu printf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n"); 27954371Ssemenu error = EINVAL; 28054371Ssemenu goto failed; 28154371Ssemenu } 28254371Ssemenu if (spp->sp_magic != SP_MAGIC) { 28354371Ssemenu printf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n"); 28454371Ssemenu error = EINVAL; 28554371Ssemenu goto failed; 28654371Ssemenu } 28754371Ssemenu 28854371Ssemenu mp->mnt_data = (qaddr_t)hpmp; 28954371Ssemenu hpmp->hpm_devvp = devvp; 29054371Ssemenu hpmp->hpm_dev = devvp->v_rdev; 29154371Ssemenu hpmp->hpm_mp = mp; 29254371Ssemenu hpmp->hpm_uid = argsp->uid; 29354371Ssemenu hpmp->hpm_gid = argsp->gid; 29454371Ssemenu hpmp->hpm_mode = argsp->mode; 29554371Ssemenu 29654371Ssemenu error = hpfs_bminit(hpmp); 29754371Ssemenu if (error) 29854371Ssemenu goto failed; 29954371Ssemenu 30054371Ssemenu error = hpfs_cpinit(hpmp, argsp); 30154371Ssemenu if (error) { 30254371Ssemenu hpfs_bmdeinit(hpmp); 30354371Ssemenu goto failed; 30454371Ssemenu } 30554371Ssemenu 30654371Ssemenu error = hpfs_root(mp, &vp); 30754371Ssemenu if (error) { 30854371Ssemenu hpfs_cpdeinit(hpmp); 30954371Ssemenu hpfs_bmdeinit(hpmp); 31054371Ssemenu goto failed; 31154371Ssemenu } 31254371Ssemenu 31354371Ssemenu vput(vp); 31454371Ssemenu 31554371Ssemenu mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(dev); 31654371Ssemenu mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 31754371Ssemenu mp->mnt_maxsymlinklen = 0; 31854371Ssemenu mp->mnt_flag |= MNT_LOCAL; 31966886Seivind devvp->v_rdev->si_mountpoint = mp; 32054371Ssemenu return (0); 32154371Ssemenu 32254371Ssemenufailed: 32354371Ssemenu if (bp) 32454371Ssemenu brelse (bp); 32554371Ssemenu mp->mnt_data = (qaddr_t)NULL; 32666886Seivind devvp->v_rdev->si_mountpoint = NULL; 32786931Sjhb (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, td); 32854371Ssemenu return (error); 32954371Ssemenu} 33054371Ssemenu 33154371Ssemenustatic int 33254371Ssemenuhpfs_unmount( 33354371Ssemenu struct mount *mp, 33454371Ssemenu int mntflags, 33586931Sjhb struct thread *td) 33654371Ssemenu{ 33754371Ssemenu int error, flags, ronly; 33854371Ssemenu register struct hpfsmount *hpmp = VFSTOHPFS(mp); 33954371Ssemenu 34054371Ssemenu dprintf(("hpfs_unmount():\n")); 34154371Ssemenu 34254371Ssemenu ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 34354371Ssemenu 34454371Ssemenu flags = 0; 34554371Ssemenu if(mntflags & MNT_FORCE) 34654371Ssemenu flags |= FORCECLOSE; 34754371Ssemenu 34854371Ssemenu dprintf(("hpfs_unmount: vflushing...\n")); 34954371Ssemenu 35076688Siedowse error = vflush(mp, 0, flags); 35154371Ssemenu if (error) { 35254371Ssemenu printf("hpfs_unmount: vflush failed: %d\n",error); 35354371Ssemenu return (error); 35454371Ssemenu } 35554371Ssemenu 35666886Seivind hpmp->hpm_devvp->v_rdev->si_mountpoint = NULL; 35754371Ssemenu 35886931Sjhb vinvalbuf(hpmp->hpm_devvp, V_SAVE, NOCRED, td, 0, 0); 35954371Ssemenu error = VOP_CLOSE(hpmp->hpm_devvp, ronly ? FREAD : FREAD|FWRITE, 36086931Sjhb NOCRED, td); 36154371Ssemenu 36254371Ssemenu vrele(hpmp->hpm_devvp); 36354371Ssemenu 36454371Ssemenu dprintf(("hpfs_umount: freeing memory...\n")); 36554371Ssemenu hpfs_cpdeinit(hpmp); 36654371Ssemenu hpfs_bmdeinit(hpmp); 36754371Ssemenu mp->mnt_data = (qaddr_t)0; 36854371Ssemenu mp->mnt_flag &= ~MNT_LOCAL; 36954371Ssemenu FREE(hpmp, M_HPFSMNT); 37054371Ssemenu 37154371Ssemenu return (0); 37254371Ssemenu} 37354371Ssemenu 37454371Ssemenustatic int 37554371Ssemenuhpfs_root( 37654371Ssemenu struct mount *mp, 37754371Ssemenu struct vnode **vpp ) 37854371Ssemenu{ 37954371Ssemenu int error = 0; 38054371Ssemenu struct hpfsmount *hpmp = VFSTOHPFS(mp); 38154371Ssemenu 38254371Ssemenu dprintf(("hpfs_root():\n")); 38354371Ssemenu error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, vpp); 38454371Ssemenu if(error) { 38554371Ssemenu printf("hpfs_root: VFS_VGET failed: %d\n",error); 38654371Ssemenu return (error); 38754371Ssemenu } 38854371Ssemenu 38954371Ssemenu return (error); 39054371Ssemenu} 39154371Ssemenu 39254371Ssemenustatic int 39354371Ssemenuhpfs_statfs( 39454371Ssemenu struct mount *mp, 39554371Ssemenu struct statfs *sbp, 39686931Sjhb struct thread *td) 39754371Ssemenu{ 39854371Ssemenu struct hpfsmount *hpmp = VFSTOHPFS(mp); 39954371Ssemenu 40054371Ssemenu dprintf(("hpfs_statfs(): HPFS%d.%d\n", 40154371Ssemenu hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver)); 40254371Ssemenu 40354371Ssemenu sbp->f_type = mp->mnt_vfc->vfc_typenum; 40454371Ssemenu sbp->f_bsize = DEV_BSIZE; 40554371Ssemenu sbp->f_iosize = DEV_BSIZE; 40654371Ssemenu sbp->f_blocks = hpmp->hpm_su.su_btotal; 40754371Ssemenu sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail; 40854371Ssemenu sbp->f_ffree = 0; 40954371Ssemenu sbp->f_files = 0; 41054371Ssemenu if (sbp != &mp->mnt_stat) { 41154371Ssemenu bcopy((caddr_t)mp->mnt_stat.f_mntonname, 41254371Ssemenu (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 41354371Ssemenu bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 41454371Ssemenu (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 41554371Ssemenu } 41654371Ssemenu sbp->f_flags = mp->mnt_flag; 41754371Ssemenu 41854371Ssemenu return (0); 41954371Ssemenu} 42054371Ssemenu 42154371Ssemenu/*ARGSUSED*/ 42254371Ssemenustatic int 42354371Ssemenuhpfs_fhtovp( 42454371Ssemenu struct mount *mp, 42554371Ssemenu struct fid *fhp, 42654371Ssemenu struct vnode **vpp) 42754371Ssemenu{ 42854371Ssemenu struct vnode *nvp; 42954371Ssemenu struct hpfid *hpfhp = (struct hpfid *)fhp; 43054371Ssemenu int error; 43154371Ssemenu 43254371Ssemenu if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, &nvp)) != 0) { 43354371Ssemenu *vpp = NULLVP; 43454371Ssemenu return (error); 43554371Ssemenu } 43654371Ssemenu /* XXX as unlink/rmdir/mkdir/creat are not currently possible 43754371Ssemenu * with HPFS, we don't need to check anything else for now */ 43854371Ssemenu *vpp = nvp; 43954371Ssemenu 44054371Ssemenu return (0); 44154371Ssemenu} 44254371Ssemenu 44354371Ssemenustatic int 44454371Ssemenuhpfs_vptofh( 44554371Ssemenu struct vnode *vp, 44654371Ssemenu struct fid *fhp) 44754371Ssemenu{ 44854371Ssemenu register struct hpfsnode *hpp; 44954371Ssemenu register struct hpfid *hpfhp; 45054371Ssemenu 45154371Ssemenu hpp = VTOHP(vp); 45254371Ssemenu hpfhp = (struct hpfid *)fhp; 45354371Ssemenu hpfhp->hpfid_len = sizeof(struct hpfid); 45454371Ssemenu hpfhp->hpfid_ino = hpp->h_no; 45554371Ssemenu /* hpfhp->hpfid_gen = hpp->h_gen; */ 45654371Ssemenu return (0); 45754371Ssemenu} 45854371Ssemenu 45954371Ssemenustatic int 46054371Ssemenuhpfs_vget( 46154371Ssemenu struct mount *mp, 46254371Ssemenu ino_t ino, 46354371Ssemenu struct vnode **vpp) 46454371Ssemenu{ 46554371Ssemenu struct hpfsmount *hpmp = VFSTOHPFS(mp); 46654371Ssemenu struct vnode *vp; 46754371Ssemenu struct hpfsnode *hp; 46854371Ssemenu struct buf *bp; 46986931Sjhb struct thread *td = curthread; /* XXX */ 47054371Ssemenu int error; 47154371Ssemenu 47254371Ssemenu dprintf(("hpfs_vget(0x%x): ",ino)); 47354371Ssemenu 47454371Ssemenu *vpp = NULL; 47554371Ssemenu hp = NULL; 47654371Ssemenu vp = NULL; 47754371Ssemenu 47886931Sjhb if ((*vpp = hpfs_hphashvget(hpmp->hpm_dev, ino, td)) != NULL) { 47954371Ssemenu dprintf(("hashed\n")); 48054371Ssemenu return (0); 48154371Ssemenu } 48254371Ssemenu 48354371Ssemenu /* 48454371Ssemenu * We have to lock node creation for a while, 48554371Ssemenu * but then we have to call getnewvnode(), 48654371Ssemenu * this may cause hpfs_reclaim() to be called, 48754371Ssemenu * this may need to VOP_VGET() parent dir for 48854371Ssemenu * update reasons, and if parent is not in 48954371Ssemenu * hash, we have to lock node creation... 49054371Ssemenu * To solve this, we MALLOC, getnewvnode and init while 49154371Ssemenu * not locked (probability of node appearence 49254371Ssemenu * at that time is little, and anyway - we'll 49354371Ssemenu * check for it). 49454371Ssemenu */ 49554371Ssemenu MALLOC(hp, struct hpfsnode *, sizeof(struct hpfsnode), 49654371Ssemenu M_HPFSNO, M_WAITOK); 49754371Ssemenu 49854371Ssemenu error = getnewvnode(VT_HPFS, hpmp->hpm_mp, hpfs_vnodeop_p, &vp); 49954371Ssemenu if (error) { 50054371Ssemenu printf("hpfs_vget: can't get new vnode\n"); 50154371Ssemenu FREE(hp, M_HPFSNO); 50254371Ssemenu return (error); 50354371Ssemenu } 50454371Ssemenu 50554371Ssemenu dprintf(("prenew ")); 50654371Ssemenu 50754371Ssemenu vp->v_data = hp; 50854371Ssemenu 50954371Ssemenu if (ino == (ino_t)hpmp->hpm_su.su_rootfno) 51054371Ssemenu vp->v_flag |= VROOT; 51154371Ssemenu 51271576Sjasone 51371576Sjasone mtx_init(&hp->h_interlock, "hpfsnode interlock", MTX_DEF); 51454371Ssemenu lockinit(&hp->h_lock, PINOD, "hpnode", 0, 0); 51554371Ssemenu 51654371Ssemenu hp->h_flag = H_INVAL; 51754371Ssemenu hp->h_vp = vp; 51854371Ssemenu hp->h_hpmp = hpmp; 51954371Ssemenu hp->h_no = ino; 52054371Ssemenu hp->h_dev = hpmp->hpm_dev; 52154371Ssemenu hp->h_uid = hpmp->hpm_uid; 52254371Ssemenu hp->h_gid = hpmp->hpm_uid; 52354371Ssemenu hp->h_mode = hpmp->hpm_mode; 52454371Ssemenu hp->h_devvp = hpmp->hpm_devvp; 52554371Ssemenu VREF(hp->h_devvp); 52654371Ssemenu 52786931Sjhb error = vn_lock(vp, LK_EXCLUSIVE, td); 52854371Ssemenu if (error) { 52954371Ssemenu vput(vp); 53054371Ssemenu return (error); 53154371Ssemenu } 53254371Ssemenu 53354371Ssemenu do { 53486931Sjhb if ((*vpp = hpfs_hphashvget(hpmp->hpm_dev, ino, td)) != NULL) { 53554371Ssemenu dprintf(("hashed2\n")); 53654371Ssemenu vput(vp); 53754371Ssemenu return (0); 53854371Ssemenu } 53986929Sjhb } while(lockmgr(&hpfs_hphash_lock,LK_EXCLUSIVE|LK_SLEEPFAIL,NULL,NULL)); 54054371Ssemenu 54154371Ssemenu hpfs_hphashins(hp); 54254371Ssemenu 54386929Sjhb lockmgr(&hpfs_hphash_lock, LK_RELEASE, NULL, NULL); 54454371Ssemenu 54554371Ssemenu error = bread(hpmp->hpm_devvp, ino, FNODESIZE, NOCRED, &bp); 54654371Ssemenu if (error) { 54754371Ssemenu printf("hpfs_vget: can't read ino %d\n",ino); 54854371Ssemenu vput(vp); 54954371Ssemenu return (error); 55054371Ssemenu } 55154371Ssemenu bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode)); 55254371Ssemenu brelse(bp); 55354371Ssemenu 55454371Ssemenu if (hp->h_fn.fn_magic != FN_MAGIC) { 55554371Ssemenu printf("hpfs_vget: MAGIC DOESN'T MATCH\n"); 55654371Ssemenu vput(vp); 55754371Ssemenu return (EINVAL); 55854371Ssemenu } 55954371Ssemenu 56054371Ssemenu vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG; 56154371Ssemenu hp->h_flag &= ~H_INVAL; 56254371Ssemenu 56354371Ssemenu *vpp = vp; 56454371Ssemenu 56554371Ssemenu return (0); 56654371Ssemenu} 56754371Ssemenu 56854371Ssemenustatic struct vfsops hpfs_vfsops = { 56954371Ssemenu hpfs_mount, 57054371Ssemenu vfs_stdstart, 57154371Ssemenu hpfs_unmount, 57254371Ssemenu hpfs_root, 57354371Ssemenu vfs_stdquotactl, 57454371Ssemenu hpfs_statfs, 57554371Ssemenu vfs_stdsync, 57654371Ssemenu hpfs_vget, 57754371Ssemenu hpfs_fhtovp, 57875934Sphk vfs_stdcheckexp, 57954371Ssemenu hpfs_vptofh, 58054371Ssemenu hpfs_init, 58166615Sjasone hpfs_uninit, 58254803Srwatson vfs_stdextattrctl, 58354371Ssemenu}; 58454371SsemenuVFS_SET(hpfs_vfsops, hpfs, 0); 585