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