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