hpfs_vfsops.c revision 130585
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 130585 2004-06-16 09:47:26Z phk $ 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 5892727Salfredstatic int hpfs_mountfs(register struct vnode *, struct mount *, 5992727Salfred struct hpfs_args *, struct thread *); 6054371Ssemenu 61116271Sphkstatic vfs_init_t hpfs_init; 62116271Sphkstatic vfs_uninit_t hpfs_uninit; 63116271Sphkstatic vfs_fhtovp_t hpfs_fhtovp; 64116271Sphkstatic vfs_vget_t hpfs_vget; 65116271Sphkstatic vfs_mount_t hpfs_mount; 66116271Sphkstatic vfs_root_t hpfs_root; 67116271Sphkstatic vfs_statfs_t hpfs_statfs; 68116271Sphkstatic vfs_unmount_t hpfs_unmount; 69116271Sphkstatic vfs_vptofh_t hpfs_vptofh; 70116271Sphk 7154371Ssemenustatic int 7254371Ssemenuhpfs_init ( 7354371Ssemenu struct vfsconf *vcp ) 7454371Ssemenu{ 7554371Ssemenu dprintf(("hpfs_init():\n")); 7654371Ssemenu 7754371Ssemenu hpfs_hphashinit(); 7854371Ssemenu return 0; 7954371Ssemenu} 8054371Ssemenu 8154371Ssemenustatic int 8266615Sjasonehpfs_uninit (vfsp) 8366615Sjasone struct vfsconf *vfsp; 8466615Sjasone{ 8566615Sjasone hpfs_hphashdestroy(); 8666615Sjasone return 0;; 8766615Sjasone} 8866615Sjasone 8966615Sjasonestatic int 9054371Ssemenuhpfs_mount ( 9154371Ssemenu struct mount *mp, 9254371Ssemenu char *path, 9354371Ssemenu caddr_t data, 9483366Sjulian struct nameidata *ndp, 9586931Sjhb struct thread *td ) 9654371Ssemenu{ 97106594Sjhb size_t size; 9854371Ssemenu int err = 0; 9954371Ssemenu struct vnode *devvp; 10054371Ssemenu struct hpfs_args args; 10154371Ssemenu struct hpfsmount *hpmp = 0; 10254371Ssemenu 10354371Ssemenu dprintf(("hpfs_mount():\n")); 10454371Ssemenu /* 10554371Ssemenu *** 10696755Strhodes * Mounting non-root filesystem or updating a filesystem 10754371Ssemenu *** 10854371Ssemenu */ 10954371Ssemenu 11054371Ssemenu /* copy in user arguments*/ 11154371Ssemenu err = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args)); 11254371Ssemenu if (err) 11354371Ssemenu goto error_1; /* can't get arguments*/ 11454371Ssemenu 11554371Ssemenu /* 11654371Ssemenu * If updating, check whether changing from read-only to 11754371Ssemenu * read/write; if there is no device name, that's all we do. 11854371Ssemenu */ 11954371Ssemenu if (mp->mnt_flag & MNT_UPDATE) { 12054371Ssemenu dprintf(("hpfs_mount: MNT_UPDATE: ")); 12154371Ssemenu 12254371Ssemenu hpmp = VFSTOHPFS(mp); 12354371Ssemenu 12454371Ssemenu if (args.fspec == 0) { 12554371Ssemenu dprintf(("export 0x%x\n",args.export.ex_flags)); 12675934Sphk err = vfs_export(mp, &args.export); 12754371Ssemenu if (err) { 12854371Ssemenu printf("hpfs_mount: vfs_export failed %d\n", 12954371Ssemenu err); 13054371Ssemenu } 13154371Ssemenu goto success; 13254371Ssemenu } else { 13354371Ssemenu dprintf(("name [FAILED]\n")); 13454371Ssemenu err = EINVAL; 13554371Ssemenu goto success; 13654371Ssemenu } 13754371Ssemenu dprintf(("\n")); 13854371Ssemenu } 13954371Ssemenu 14054371Ssemenu /* 14154371Ssemenu * Not an update, or updating the name: look up the name 14254371Ssemenu * and verify that it refers to a sensible block device. 14354371Ssemenu */ 14486931Sjhb NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td); 14554371Ssemenu err = namei(ndp); 14654371Ssemenu if (err) { 14754371Ssemenu /* can't get devvp!*/ 14854371Ssemenu goto error_1; 14954371Ssemenu } 15054371Ssemenu 15154371Ssemenu devvp = ndp->ni_vp; 15254371Ssemenu 15355756Sphk if (!vn_isdisk(devvp, &err)) 15454371Ssemenu goto error_2; 15554371Ssemenu 15654371Ssemenu /* 15754371Ssemenu ******************** 15854371Ssemenu * NEW MOUNT 15954371Ssemenu ******************** 16054371Ssemenu */ 16154371Ssemenu 16254371Ssemenu /* 16354371Ssemenu * Since this is a new mount, we want the names for 16454371Ssemenu * the device and the mount point copied in. If an 16573286Sadrian * error occurs, the mountpoint is discarded by the 16673286Sadrian * upper level code. Note that vfs_mount() handles 16773286Sadrian * copying the mountpoint f_mntonname for us, so we 16873286Sadrian * don't have to do it here unless we want to set it 16973286Sadrian * to something other than "path" for some rason. 17054371Ssemenu */ 17154371Ssemenu /* Save "mounted from" info for mount point (NULL pad)*/ 17254371Ssemenu copyinstr( args.fspec, /* device name*/ 17354371Ssemenu mp->mnt_stat.f_mntfromname, /* save area*/ 17454371Ssemenu MNAMELEN - 1, /* max size*/ 17554371Ssemenu &size); /* real size*/ 17654371Ssemenu bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 17754371Ssemenu 17886931Sjhb err = hpfs_mountfs(devvp, mp, &args, td); 17954371Ssemenu if (err) 18054371Ssemenu goto error_2; 18154371Ssemenu 18254371Ssemenu /* 18354371Ssemenu * Initialize FS stat information in mount struct; uses both 18454371Ssemenu * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 18554371Ssemenu * 18654371Ssemenu * This code is common to root and non-root mounts 18754371Ssemenu */ 18886931Sjhb (void)VFS_STATFS(mp, &mp->mnt_stat, td); 18954371Ssemenu 19054371Ssemenu goto success; 19154371Ssemenu 19254371Ssemenu 19354371Ssemenuerror_2: /* error with devvp held*/ 19454371Ssemenu 19554371Ssemenu /* release devvp before failing*/ 19654371Ssemenu vrele(devvp); 19754371Ssemenu 19854371Ssemenuerror_1: /* no state to back out*/ 19954371Ssemenu 20054371Ssemenusuccess: 20154371Ssemenu return( err); 20254371Ssemenu} 20354371Ssemenu 20454371Ssemenu/* 20554371Ssemenu * Common code for mount and mountroot 20654371Ssemenu */ 20754371Ssemenuint 20886931Sjhbhpfs_mountfs(devvp, mp, argsp, td) 20954371Ssemenu register struct vnode *devvp; 21054371Ssemenu struct mount *mp; 21154371Ssemenu struct hpfs_args *argsp; 21286931Sjhb struct thread *td; 21354371Ssemenu{ 21454371Ssemenu int error, ncount, ronly; 21554371Ssemenu struct sublock *sup; 21654371Ssemenu struct spblock *spp; 21754371Ssemenu struct hpfsmount *hpmp; 21854371Ssemenu struct buf *bp = NULL; 21954371Ssemenu struct vnode *vp; 220130585Sphk struct cdev *dev = devvp->v_rdev; 22154371Ssemenu 22254371Ssemenu dprintf(("hpfs_mountfs():\n")); 22354371Ssemenu /* 22454371Ssemenu * Disallow multiple mounts of the same device. 22554371Ssemenu * Disallow mounting of a device that is currently in use 22654371Ssemenu * (except for root, which might share swap device for miniroot). 22754371Ssemenu * Flush out any old buffers remaining from a previous use. 22854371Ssemenu */ 22954371Ssemenu error = vfs_mountedon(devvp); 23054371Ssemenu if (error) 23154371Ssemenu return (error); 23254371Ssemenu ncount = vcount(devvp); 23354371Ssemenu if (devvp->v_object) 23454371Ssemenu ncount -= 1; 23554371Ssemenu if (ncount > 1 && devvp != rootvp) 23654371Ssemenu return (EBUSY); 23754371Ssemenu 23886931Sjhb vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 23991406Sjhb error = vinvalbuf(devvp, V_SAVE, td->td_ucred, td, 0, 0); 24086931Sjhb VOP_UNLOCK(devvp, 0, td); 24154371Ssemenu if (error) 24254371Ssemenu return (error); 24354371Ssemenu 24454371Ssemenu ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 24586931Sjhb vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 246118047Sphk error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td, -1); 24786931Sjhb VOP_UNLOCK(devvp, 0, td); 24854371Ssemenu if (error) 24954371Ssemenu return (error); 25054371Ssemenu 25154371Ssemenu /* 25254371Ssemenu * Do actual mount 25354371Ssemenu */ 254111119Simp hpmp = malloc(sizeof(struct hpfsmount), M_HPFSMNT, M_WAITOK | M_ZERO); 25554371Ssemenu 25654371Ssemenu /* Read in SuperBlock */ 25754371Ssemenu error = bread(devvp, SUBLOCK, SUSIZE, NOCRED, &bp); 25854371Ssemenu if (error) 25954371Ssemenu goto failed; 26054371Ssemenu bcopy(bp->b_data, &hpmp->hpm_su, sizeof(struct sublock)); 26154371Ssemenu brelse(bp); bp = NULL; 26254371Ssemenu 26354371Ssemenu /* Read in SpareBlock */ 26454371Ssemenu error = bread(devvp, SPBLOCK, SPSIZE, NOCRED, &bp); 26554371Ssemenu if (error) 26654371Ssemenu goto failed; 26754371Ssemenu bcopy(bp->b_data, &hpmp->hpm_sp, sizeof(struct spblock)); 26854371Ssemenu brelse(bp); bp = NULL; 26954371Ssemenu 27054371Ssemenu sup = &hpmp->hpm_su; 27154371Ssemenu spp = &hpmp->hpm_sp; 27254371Ssemenu 27354371Ssemenu /* Check magic */ 27454371Ssemenu if (sup->su_magic != SU_MAGIC) { 27554371Ssemenu printf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n"); 27654371Ssemenu error = EINVAL; 27754371Ssemenu goto failed; 27854371Ssemenu } 27954371Ssemenu if (spp->sp_magic != SP_MAGIC) { 28054371Ssemenu printf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n"); 28154371Ssemenu error = EINVAL; 28254371Ssemenu goto failed; 28354371Ssemenu } 28454371Ssemenu 28554371Ssemenu mp->mnt_data = (qaddr_t)hpmp; 28654371Ssemenu hpmp->hpm_devvp = devvp; 28754371Ssemenu hpmp->hpm_dev = devvp->v_rdev; 28854371Ssemenu hpmp->hpm_mp = mp; 28954371Ssemenu hpmp->hpm_uid = argsp->uid; 29054371Ssemenu hpmp->hpm_gid = argsp->gid; 29154371Ssemenu hpmp->hpm_mode = argsp->mode; 29254371Ssemenu 29354371Ssemenu error = hpfs_bminit(hpmp); 29454371Ssemenu if (error) 29554371Ssemenu goto failed; 29654371Ssemenu 29754371Ssemenu error = hpfs_cpinit(hpmp, argsp); 29854371Ssemenu if (error) { 29954371Ssemenu hpfs_bmdeinit(hpmp); 30054371Ssemenu goto failed; 30154371Ssemenu } 30254371Ssemenu 30354371Ssemenu error = hpfs_root(mp, &vp); 30454371Ssemenu if (error) { 30554371Ssemenu hpfs_cpdeinit(hpmp); 30654371Ssemenu hpfs_bmdeinit(hpmp); 30754371Ssemenu goto failed; 30854371Ssemenu } 30954371Ssemenu 31054371Ssemenu vput(vp); 31154371Ssemenu 31254371Ssemenu mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(dev); 31354371Ssemenu mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 31454371Ssemenu mp->mnt_maxsymlinklen = 0; 31554371Ssemenu mp->mnt_flag |= MNT_LOCAL; 31666886Seivind devvp->v_rdev->si_mountpoint = mp; 31754371Ssemenu return (0); 31854371Ssemenu 31954371Ssemenufailed: 32054371Ssemenu if (bp) 32154371Ssemenu brelse (bp); 32254371Ssemenu mp->mnt_data = (qaddr_t)NULL; 32366886Seivind devvp->v_rdev->si_mountpoint = NULL; 32486931Sjhb (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, td); 32554371Ssemenu return (error); 32654371Ssemenu} 32754371Ssemenu 32854371Ssemenustatic int 32954371Ssemenuhpfs_unmount( 33054371Ssemenu struct mount *mp, 33154371Ssemenu int mntflags, 33286931Sjhb struct thread *td) 33354371Ssemenu{ 33454371Ssemenu int error, flags, ronly; 33554371Ssemenu register struct hpfsmount *hpmp = VFSTOHPFS(mp); 33654371Ssemenu 33754371Ssemenu dprintf(("hpfs_unmount():\n")); 33854371Ssemenu 33954371Ssemenu ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 34054371Ssemenu 34154371Ssemenu flags = 0; 34254371Ssemenu if(mntflags & MNT_FORCE) 34354371Ssemenu flags |= FORCECLOSE; 34454371Ssemenu 34554371Ssemenu dprintf(("hpfs_unmount: vflushing...\n")); 34654371Ssemenu 34776688Siedowse error = vflush(mp, 0, flags); 34854371Ssemenu if (error) { 34954371Ssemenu printf("hpfs_unmount: vflush failed: %d\n",error); 35054371Ssemenu return (error); 35154371Ssemenu } 35254371Ssemenu 35366886Seivind hpmp->hpm_devvp->v_rdev->si_mountpoint = NULL; 35454371Ssemenu 35586931Sjhb vinvalbuf(hpmp->hpm_devvp, V_SAVE, NOCRED, td, 0, 0); 35654371Ssemenu error = VOP_CLOSE(hpmp->hpm_devvp, ronly ? FREAD : FREAD|FWRITE, 35786931Sjhb NOCRED, td); 35854371Ssemenu 35954371Ssemenu vrele(hpmp->hpm_devvp); 36054371Ssemenu 36154371Ssemenu dprintf(("hpfs_umount: freeing memory...\n")); 36254371Ssemenu hpfs_cpdeinit(hpmp); 36354371Ssemenu hpfs_bmdeinit(hpmp); 36454371Ssemenu mp->mnt_data = (qaddr_t)0; 36554371Ssemenu mp->mnt_flag &= ~MNT_LOCAL; 36654371Ssemenu FREE(hpmp, M_HPFSMNT); 36754371Ssemenu 36854371Ssemenu return (0); 36954371Ssemenu} 37054371Ssemenu 37154371Ssemenustatic int 37254371Ssemenuhpfs_root( 37354371Ssemenu struct mount *mp, 37454371Ssemenu struct vnode **vpp ) 37554371Ssemenu{ 37654371Ssemenu int error = 0; 37754371Ssemenu struct hpfsmount *hpmp = VFSTOHPFS(mp); 37854371Ssemenu 37954371Ssemenu dprintf(("hpfs_root():\n")); 38092462Smckusick error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, LK_EXCLUSIVE, vpp); 38154371Ssemenu if(error) { 38254371Ssemenu printf("hpfs_root: VFS_VGET failed: %d\n",error); 38354371Ssemenu return (error); 38454371Ssemenu } 38554371Ssemenu 38654371Ssemenu return (error); 38754371Ssemenu} 38854371Ssemenu 38954371Ssemenustatic int 39054371Ssemenuhpfs_statfs( 39154371Ssemenu struct mount *mp, 39254371Ssemenu struct statfs *sbp, 39386931Sjhb struct thread *td) 39454371Ssemenu{ 39554371Ssemenu struct hpfsmount *hpmp = VFSTOHPFS(mp); 39654371Ssemenu 39754371Ssemenu dprintf(("hpfs_statfs(): HPFS%d.%d\n", 39854371Ssemenu hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver)); 39954371Ssemenu 40054371Ssemenu sbp->f_type = mp->mnt_vfc->vfc_typenum; 40154371Ssemenu sbp->f_bsize = DEV_BSIZE; 40254371Ssemenu sbp->f_iosize = DEV_BSIZE; 40354371Ssemenu sbp->f_blocks = hpmp->hpm_su.su_btotal; 40454371Ssemenu sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail; 40554371Ssemenu sbp->f_ffree = 0; 40654371Ssemenu sbp->f_files = 0; 40754371Ssemenu if (sbp != &mp->mnt_stat) { 40854371Ssemenu bcopy((caddr_t)mp->mnt_stat.f_mntonname, 40954371Ssemenu (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 41054371Ssemenu bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 41154371Ssemenu (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 41254371Ssemenu } 41354371Ssemenu sbp->f_flags = mp->mnt_flag; 41454371Ssemenu 41554371Ssemenu return (0); 41654371Ssemenu} 41754371Ssemenu 41854371Ssemenu/*ARGSUSED*/ 41954371Ssemenustatic int 42054371Ssemenuhpfs_fhtovp( 42154371Ssemenu struct mount *mp, 42254371Ssemenu struct fid *fhp, 42354371Ssemenu struct vnode **vpp) 42454371Ssemenu{ 42554371Ssemenu struct vnode *nvp; 42654371Ssemenu struct hpfid *hpfhp = (struct hpfid *)fhp; 42754371Ssemenu int error; 42854371Ssemenu 42992462Smckusick if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, LK_EXCLUSIVE, &nvp)) != 0) { 43054371Ssemenu *vpp = NULLVP; 43154371Ssemenu return (error); 43254371Ssemenu } 43354371Ssemenu /* XXX as unlink/rmdir/mkdir/creat are not currently possible 43454371Ssemenu * with HPFS, we don't need to check anything else for now */ 43554371Ssemenu *vpp = nvp; 43654371Ssemenu 43754371Ssemenu return (0); 43854371Ssemenu} 43954371Ssemenu 44054371Ssemenustatic int 44154371Ssemenuhpfs_vptofh( 44254371Ssemenu struct vnode *vp, 44354371Ssemenu struct fid *fhp) 44454371Ssemenu{ 44554371Ssemenu register struct hpfsnode *hpp; 44654371Ssemenu register struct hpfid *hpfhp; 44754371Ssemenu 44854371Ssemenu hpp = VTOHP(vp); 44954371Ssemenu hpfhp = (struct hpfid *)fhp; 45054371Ssemenu hpfhp->hpfid_len = sizeof(struct hpfid); 45154371Ssemenu hpfhp->hpfid_ino = hpp->h_no; 45254371Ssemenu /* hpfhp->hpfid_gen = hpp->h_gen; */ 45354371Ssemenu return (0); 45454371Ssemenu} 45554371Ssemenu 45654371Ssemenustatic int 45754371Ssemenuhpfs_vget( 45854371Ssemenu struct mount *mp, 45954371Ssemenu ino_t ino, 46092462Smckusick int flags, 46154371Ssemenu struct vnode **vpp) 46254371Ssemenu{ 46354371Ssemenu struct hpfsmount *hpmp = VFSTOHPFS(mp); 46454371Ssemenu struct vnode *vp; 46554371Ssemenu struct hpfsnode *hp; 46654371Ssemenu struct buf *bp; 46786931Sjhb struct thread *td = curthread; /* XXX */ 46854371Ssemenu int error; 46954371Ssemenu 47054371Ssemenu dprintf(("hpfs_vget(0x%x): ",ino)); 47154371Ssemenu 47254371Ssemenu *vpp = NULL; 47354371Ssemenu hp = NULL; 47454371Ssemenu vp = NULL; 47554371Ssemenu 47692462Smckusick if ((error = hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td)) != 0) 47792462Smckusick return (error); 47892462Smckusick if (*vpp != 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), 496111119Simp M_HPFSNO, M_WAITOK); 49754371Ssemenu 498103314Snjl error = getnewvnode("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) 510101308Sjeff vp->v_vflag |= VV_ROOT; 51154371Ssemenu 51271576Sjasone 51393818Sjhb mtx_init(&hp->h_interlock, "hpfsnode interlock", NULL, MTX_DEF); 51454371Ssemenu 51554371Ssemenu hp->h_flag = H_INVAL; 51654371Ssemenu hp->h_vp = vp; 51754371Ssemenu hp->h_hpmp = hpmp; 51854371Ssemenu hp->h_no = ino; 51954371Ssemenu hp->h_dev = hpmp->hpm_dev; 52054371Ssemenu hp->h_uid = hpmp->hpm_uid; 52154371Ssemenu hp->h_gid = hpmp->hpm_uid; 52254371Ssemenu hp->h_mode = hpmp->hpm_mode; 52354371Ssemenu hp->h_devvp = hpmp->hpm_devvp; 52454371Ssemenu VREF(hp->h_devvp); 52554371Ssemenu 52686931Sjhb error = vn_lock(vp, LK_EXCLUSIVE, td); 52754371Ssemenu if (error) { 52854371Ssemenu vput(vp); 52954371Ssemenu return (error); 53054371Ssemenu } 53154371Ssemenu 53254371Ssemenu do { 53392462Smckusick if ((error = 53492462Smckusick hpfs_hphashvget(hpmp->hpm_dev, ino, flags, vpp, td))) { 53592462Smckusick vput(vp); 53692462Smckusick return (error); 53792462Smckusick } 53892462Smckusick if (*vpp != NULL) { 53954371Ssemenu dprintf(("hashed2\n")); 54054371Ssemenu vput(vp); 54154371Ssemenu return (0); 54254371Ssemenu } 54386929Sjhb } while(lockmgr(&hpfs_hphash_lock,LK_EXCLUSIVE|LK_SLEEPFAIL,NULL,NULL)); 54454371Ssemenu 54554371Ssemenu hpfs_hphashins(hp); 54654371Ssemenu 54786929Sjhb lockmgr(&hpfs_hphash_lock, LK_RELEASE, NULL, NULL); 54854371Ssemenu 54954371Ssemenu error = bread(hpmp->hpm_devvp, ino, FNODESIZE, NOCRED, &bp); 55054371Ssemenu if (error) { 55154371Ssemenu printf("hpfs_vget: can't read ino %d\n",ino); 55254371Ssemenu vput(vp); 55354371Ssemenu return (error); 55454371Ssemenu } 55554371Ssemenu bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode)); 55654371Ssemenu brelse(bp); 55754371Ssemenu 55854371Ssemenu if (hp->h_fn.fn_magic != FN_MAGIC) { 55954371Ssemenu printf("hpfs_vget: MAGIC DOESN'T MATCH\n"); 56054371Ssemenu vput(vp); 56154371Ssemenu return (EINVAL); 56254371Ssemenu } 56354371Ssemenu 56454371Ssemenu vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG; 56554371Ssemenu hp->h_flag &= ~H_INVAL; 56654371Ssemenu 56754371Ssemenu *vpp = vp; 56854371Ssemenu 56954371Ssemenu return (0); 57054371Ssemenu} 57154371Ssemenu 57254371Ssemenustatic struct vfsops hpfs_vfsops = { 573116271Sphk .vfs_fhtovp = hpfs_fhtovp, 574116271Sphk .vfs_init = hpfs_init, 575116271Sphk .vfs_mount = hpfs_mount, 576116271Sphk .vfs_root = hpfs_root, 577116271Sphk .vfs_statfs = hpfs_statfs, 578116271Sphk .vfs_uninit = hpfs_uninit, 579116271Sphk .vfs_unmount = hpfs_unmount, 580116271Sphk .vfs_vget = hpfs_vget, 581116271Sphk .vfs_vptofh = hpfs_vptofh, 58254371Ssemenu}; 58354371SsemenuVFS_SET(hpfs_vfsops, hpfs, 0); 584