hpfs_vfsops.c revision 71576
1/*-
2 * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/fs/hpfs/hpfs_vfsops.c 71576 2001-01-24 12:35:55Z jasone $
27 */
28
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/namei.h>
33#include <sys/conf.h>
34#include <sys/proc.h>
35#include <sys/kernel.h>
36#include <sys/vnode.h>
37#include <sys/mount.h>
38#include <sys/bio.h>
39#include <sys/buf.h>
40#include <sys/fcntl.h>
41#include <sys/malloc.h>
42
43#include <vm/vm.h>
44#include <vm/vm_param.h>
45#if defined(__NetBSD__)
46#include <vm/vm_prot.h>
47#endif
48#include <vm/vm_page.h>
49#include <vm/vm_object.h>
50#include <vm/vm_extern.h>
51
52#if defined(__NetBSD__)
53#include <miscfs/specfs/specdev.h>
54#endif
55
56#include <fs/hpfs/hpfs.h>
57#include <fs/hpfs/hpfsmount.h>
58#include <fs/hpfs/hpfs_subr.h>
59
60#if defined(__FreeBSD__)
61MALLOC_DEFINE(M_HPFSMNT, "HPFS mount", "HPFS mount structure");
62MALLOC_DEFINE(M_HPFSNO, "HPFS node", "HPFS node structure");
63#endif
64
65static int	hpfs_root __P((struct mount *, struct vnode **));
66static int	hpfs_statfs __P((struct mount *, struct statfs *,
67				 struct proc *));
68static int	hpfs_unmount __P((struct mount *, int, struct proc *));
69static int	hpfs_vget __P((struct mount *mp, ino_t ino,
70			       struct vnode **vpp));
71static int	hpfs_mountfs __P((register struct vnode *, struct mount *,
72				  struct hpfs_args *, struct proc *));
73static int	hpfs_vptofh __P((struct vnode *, struct fid *));
74static int	hpfs_fhtovp __P((struct mount *, struct fid *,
75				 struct vnode **));
76
77#if !defined(__FreeBSD__)
78static int	hpfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
79				   struct proc *));
80static int	hpfs_start __P((struct mount *, int, struct proc *));
81static int	hpfs_sync __P((struct mount *, int, struct ucred *,
82			       struct proc *));
83#endif
84
85#if defined(__FreeBSD__)
86struct sockaddr;
87static int	hpfs_mount __P((struct mount *, char *, caddr_t,
88				struct nameidata *, struct proc *));
89static int	hpfs_init __P((struct vfsconf *));
90static int	hpfs_uninit __P((struct vfsconf *));
91static int	hpfs_checkexp __P((struct mount *, struct sockaddr *,
92				   int *, struct ucred **));
93#else /* defined(__NetBSD__) */
94static int	hpfs_mount __P((struct mount *, const char *, void *,
95				struct nameidata *, struct proc *));
96static void	hpfs_init __P((void));
97static int	hpfs_mountroot __P((void));
98static int	hpfs_sysctl __P((int *, u_int, void *, size_t *, void *,
99				 size_t, struct proc *));
100static int	hpfs_checkexp __P((struct mount *, struct mbuf *,
101				   int *, struct ucred **));
102#endif
103
104/*ARGSUSED*/
105static int
106hpfs_checkexp(mp, nam, exflagsp, credanonp)
107#if defined(__FreeBSD__)
108	register struct mount *mp;
109	struct sockaddr *nam;
110	int *exflagsp;
111	struct ucred **credanonp;
112#else /* defined(__NetBSD__) */
113	register struct mount *mp;
114	struct mbuf *nam;
115	int *exflagsp;
116	struct ucred **credanonp;
117#endif
118{
119	register struct netcred *np;
120	register struct hpfsmount *hpm = VFSTOHPFS(mp);
121
122	/*
123	 * Get the export permission structure for this <mp, client> tuple.
124	 */
125	np = vfs_export_lookup(mp, &hpm->hpm_export, nam);
126	if (np == NULL)
127		return (EACCES);
128
129	*exflagsp = np->netc_exflags;
130	*credanonp = &np->netc_anon;
131	return (0);
132}
133
134#if !defined(__FreeBSD__)
135/*ARGSUSED*/
136static int
137hpfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
138	int *name;
139	u_int namelen;
140	void *oldp;
141	size_t *oldlenp;
142	void *newp;
143	size_t newlen;
144	struct proc *p;
145{
146	return (EINVAL);
147}
148
149static int
150hpfs_mountroot()
151{
152	return (EINVAL);
153}
154#endif
155
156#if defined(__FreeBSD__)
157static int
158hpfs_init (
159	struct vfsconf *vcp )
160#else /* defined(__NetBSD__) */
161static void
162hpfs_init ()
163#endif
164{
165	dprintf(("hpfs_init():\n"));
166
167	hpfs_hphashinit();
168#if defined(__FreeBSD__)
169	return 0;
170#endif
171}
172
173#if defined(__FreeBSD__)
174static int
175hpfs_uninit (vfsp)
176	struct vfsconf *vfsp;
177{
178	hpfs_hphashdestroy();
179	return 0;;
180}
181#endif
182
183static int
184hpfs_mount (
185	struct mount *mp,
186#if defined(__FreeBSD__)
187	char *path,
188	caddr_t data,
189#else /* defined(__NetBSD__) */
190	const char *path,
191	void *data,
192#endif
193	struct nameidata *ndp,
194	struct proc *p )
195{
196	u_int		size;
197	int		err = 0;
198	struct vnode	*devvp;
199	struct hpfs_args args;
200	struct hpfsmount *hpmp = 0;
201
202	dprintf(("hpfs_mount():\n"));
203	/*
204	 ***
205	 * Mounting non-root file system or updating a file system
206	 ***
207	 */
208
209	/* copy in user arguments*/
210	err = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args));
211	if (err)
212		goto error_1;		/* can't get arguments*/
213
214	/*
215	 * If updating, check whether changing from read-only to
216	 * read/write; if there is no device name, that's all we do.
217	 */
218	if (mp->mnt_flag & MNT_UPDATE) {
219		dprintf(("hpfs_mount: MNT_UPDATE: "));
220
221		hpmp = VFSTOHPFS(mp);
222
223		if (args.fspec == 0) {
224			dprintf(("export 0x%x\n",args.export.ex_flags));
225			err = vfs_export(mp, &hpmp->hpm_export, &args.export);
226			if (err) {
227				printf("hpfs_mount: vfs_export failed %d\n",
228					err);
229			}
230			goto success;
231		} else {
232			dprintf(("name [FAILED]\n"));
233			err = EINVAL;
234			goto success;
235		}
236		dprintf(("\n"));
237	}
238
239	/*
240	 * Not an update, or updating the name: look up the name
241	 * and verify that it refers to a sensible block device.
242	 */
243	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
244	err = namei(ndp);
245	if (err) {
246		/* can't get devvp!*/
247		goto error_1;
248	}
249
250	devvp = ndp->ni_vp;
251
252#if defined(__FreeBSD__)
253	if (!vn_isdisk(devvp, &err))
254		goto error_2;
255#else /* defined(__NetBSD__) */
256	if (devvp->v_type != VBLK) {
257		err = ENOTBLK;
258		goto error_2;
259	}
260	if (major(devvp->v_rdev) >= nblkdev) {
261		err = ENXIO;
262		goto error_2;
263	}
264#endif
265
266	/*
267	 ********************
268	 * NEW MOUNT
269	 ********************
270	 */
271
272	/*
273	 * Since this is a new mount, we want the names for
274	 * the device and the mount point copied in.  If an
275	 * error occurs,  the mountpoint is discarded by the
276	 * upper level code.
277	 */
278	/* Save "last mounted on" info for mount point (NULL pad)*/
279	copyinstr(	path,				/* mount point*/
280			mp->mnt_stat.f_mntonname,	/* save area*/
281			MNAMELEN - 1,			/* max size*/
282			&size);				/* real size*/
283	bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
284
285	/* Save "mounted from" info for mount point (NULL pad)*/
286	copyinstr(	args.fspec,			/* device name*/
287			mp->mnt_stat.f_mntfromname,	/* save area*/
288			MNAMELEN - 1,			/* max size*/
289			&size);				/* real size*/
290	bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
291
292	err = hpfs_mountfs(devvp, mp, &args, p);
293	if (err)
294		goto error_2;
295
296	/*
297	 * Initialize FS stat information in mount struct; uses both
298	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
299	 *
300	 * This code is common to root and non-root mounts
301	 */
302	(void)VFS_STATFS(mp, &mp->mnt_stat, p);
303
304	goto success;
305
306
307error_2:	/* error with devvp held*/
308
309	/* release devvp before failing*/
310	vrele(devvp);
311
312error_1:	/* no state to back out*/
313
314success:
315	return( err);
316}
317
318/*
319 * Common code for mount and mountroot
320 */
321int
322hpfs_mountfs(devvp, mp, argsp, p)
323	register struct vnode *devvp;
324	struct mount *mp;
325	struct hpfs_args *argsp;
326	struct proc *p;
327{
328	int error, ncount, ronly;
329	struct sublock *sup;
330	struct spblock *spp;
331	struct hpfsmount *hpmp;
332	struct buf *bp = NULL;
333	struct vnode *vp;
334#if defined(__FreeBSD__)
335	struct ucred *uc;
336#endif
337	dev_t dev = devvp->v_rdev;
338
339	dprintf(("hpfs_mountfs():\n"));
340	/*
341	 * Disallow multiple mounts of the same device.
342	 * Disallow mounting of a device that is currently in use
343	 * (except for root, which might share swap device for miniroot).
344	 * Flush out any old buffers remaining from a previous use.
345	 */
346	error = vfs_mountedon(devvp);
347	if (error)
348		return (error);
349	ncount = vcount(devvp);
350#if defined(__FreeBSD__)
351	if (devvp->v_object)
352		ncount -= 1;
353#endif
354	if (ncount > 1 && devvp != rootvp)
355		return (EBUSY);
356
357#if defined(__FreeBSD__)
358	VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, p);
359	PROC_LOCK(p);
360	uc = p->p_ucred;
361	crhold(uc);
362	PROC_UNLOCK(p);
363	error = vinvalbuf(devvp, V_SAVE, uc, p, 0, 0);
364	crfree(uc);
365	VOP__UNLOCK(devvp, 0, p);
366#else
367	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
368#endif
369	if (error)
370		return (error);
371
372	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
373	VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, p);
374	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
375	VOP__UNLOCK(devvp, 0, p);
376	if (error)
377		return (error);
378
379	/*
380	 * Do actual mount
381	 */
382	hpmp = malloc(sizeof(struct hpfsmount), M_HPFSMNT, M_WAITOK | M_ZERO);
383
384	/* Read in SuperBlock */
385	error = bread(devvp, SUBLOCK, SUSIZE, NOCRED, &bp);
386	if (error)
387		goto failed;
388	bcopy(bp->b_data, &hpmp->hpm_su, sizeof(struct sublock));
389	brelse(bp); bp = NULL;
390
391	/* Read in SpareBlock */
392	error = bread(devvp, SPBLOCK, SPSIZE, NOCRED, &bp);
393	if (error)
394		goto failed;
395	bcopy(bp->b_data, &hpmp->hpm_sp, sizeof(struct spblock));
396	brelse(bp); bp = NULL;
397
398	sup = &hpmp->hpm_su;
399	spp = &hpmp->hpm_sp;
400
401	/* Check magic */
402	if (sup->su_magic != SU_MAGIC) {
403		printf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n");
404		error = EINVAL;
405		goto failed;
406	}
407	if (spp->sp_magic != SP_MAGIC) {
408		printf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n");
409		error = EINVAL;
410		goto failed;
411	}
412
413	mp->mnt_data = (qaddr_t)hpmp;
414	hpmp->hpm_devvp = devvp;
415	hpmp->hpm_dev = devvp->v_rdev;
416	hpmp->hpm_mp = mp;
417	hpmp->hpm_uid = argsp->uid;
418	hpmp->hpm_gid = argsp->gid;
419	hpmp->hpm_mode = argsp->mode;
420
421	error = hpfs_bminit(hpmp);
422	if (error)
423		goto failed;
424
425	error = hpfs_cpinit(hpmp, argsp);
426	if (error) {
427		hpfs_bmdeinit(hpmp);
428		goto failed;
429	}
430
431	error = hpfs_root(mp, &vp);
432	if (error) {
433		hpfs_cpdeinit(hpmp);
434		hpfs_bmdeinit(hpmp);
435		goto failed;
436	}
437
438	vput(vp);
439
440#if defined(__FreeBSD__)
441	mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(dev);
442	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
443#else
444	mp->mnt_stat.f_fsid.val[0] = (long)dev;
445	mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_HPFS);
446#endif
447	mp->mnt_maxsymlinklen = 0;
448	mp->mnt_flag |= MNT_LOCAL;
449	devvp->v_rdev->si_mountpoint = mp;
450	return (0);
451
452failed:
453	if (bp)
454		brelse (bp);
455	mp->mnt_data = (qaddr_t)NULL;
456#if defined(__FreeBSD__)
457	devvp->v_rdev->si_mountpoint = NULL;
458#else
459	devvp->v_specflags &= ~SI_MOUNTEDON;
460#endif
461	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
462	return (error);
463}
464
465#if !defined(__FreeBSD__)
466static int
467hpfs_start (
468	struct mount *mp,
469	int flags,
470	struct proc *p )
471{
472	return (0);
473}
474#endif
475
476static int
477hpfs_unmount(
478	struct mount *mp,
479	int mntflags,
480	struct proc *p)
481{
482	int error, flags, ronly;
483	register struct hpfsmount *hpmp = VFSTOHPFS(mp);
484
485	dprintf(("hpfs_unmount():\n"));
486
487	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
488
489	flags = 0;
490	if(mntflags & MNT_FORCE)
491		flags |= FORCECLOSE;
492
493	dprintf(("hpfs_unmount: vflushing...\n"));
494
495	error = vflush(mp,NULLVP,flags);
496	if (error) {
497		printf("hpfs_unmount: vflush failed: %d\n",error);
498		return (error);
499	}
500
501#if defined(__FreeBSD__)
502	hpmp->hpm_devvp->v_rdev->si_mountpoint = NULL;
503#else
504	hpmp->hpm_devvp->v_specflags &= ~SI_MOUNTEDON;
505#endif
506
507	vinvalbuf(hpmp->hpm_devvp, V_SAVE, NOCRED, p, 0, 0);
508	error = VOP_CLOSE(hpmp->hpm_devvp, ronly ? FREAD : FREAD|FWRITE,
509		NOCRED, p);
510
511	vrele(hpmp->hpm_devvp);
512
513	dprintf(("hpfs_umount: freeing memory...\n"));
514	hpfs_cpdeinit(hpmp);
515	hpfs_bmdeinit(hpmp);
516	mp->mnt_data = (qaddr_t)0;
517	mp->mnt_flag &= ~MNT_LOCAL;
518	FREE(hpmp, M_HPFSMNT);
519
520	return (0);
521}
522
523static int
524hpfs_root(
525	struct mount *mp,
526	struct vnode **vpp )
527{
528	int error = 0;
529	struct hpfsmount *hpmp = VFSTOHPFS(mp);
530
531	dprintf(("hpfs_root():\n"));
532	error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, vpp);
533	if(error) {
534		printf("hpfs_root: VFS_VGET failed: %d\n",error);
535		return (error);
536	}
537
538	return (error);
539}
540
541static int
542hpfs_statfs(
543	struct mount *mp,
544	struct statfs *sbp,
545	struct proc *p)
546{
547	struct hpfsmount *hpmp = VFSTOHPFS(mp);
548
549	dprintf(("hpfs_statfs(): HPFS%d.%d\n",
550		hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver));
551
552#if defined(__FreeBSD__)
553	sbp->f_type = mp->mnt_vfc->vfc_typenum;
554#else /* defined(__NetBSD__) */
555	sbp->f_type = 0;
556#endif
557	sbp->f_bsize = DEV_BSIZE;
558	sbp->f_iosize = DEV_BSIZE;
559	sbp->f_blocks = hpmp->hpm_su.su_btotal;
560	sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail;
561	sbp->f_ffree = 0;
562	sbp->f_files = 0;
563	if (sbp != &mp->mnt_stat) {
564		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
565			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
566		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
567			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
568	}
569	sbp->f_flags = mp->mnt_flag;
570
571	return (0);
572}
573
574#if !defined(__FreeBSD__)
575static int
576hpfs_sync (
577	struct mount *mp,
578	int waitfor,
579	struct ucred *cred,
580	struct proc *p)
581{
582	return (0);
583}
584
585static int
586hpfs_quotactl (
587	struct mount *mp,
588	int cmds,
589	uid_t uid,
590	caddr_t arg,
591	struct proc *p)
592{
593	printf("hpfs_quotactl():\n");
594	return (EOPNOTSUPP);
595}
596#endif
597
598/*ARGSUSED*/
599static int
600hpfs_fhtovp(
601	struct mount *mp,
602	struct fid *fhp,
603	struct vnode **vpp)
604{
605	struct vnode *nvp;
606	struct hpfid *hpfhp = (struct hpfid *)fhp;
607	int error;
608
609	if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, &nvp)) != 0) {
610		*vpp = NULLVP;
611		return (error);
612	}
613	/* XXX as unlink/rmdir/mkdir/creat are not currently possible
614	 * with HPFS, we don't need to check anything else for now */
615	*vpp = nvp;
616
617	return (0);
618}
619
620static int
621hpfs_vptofh(
622	struct vnode *vp,
623	struct fid *fhp)
624{
625	register struct hpfsnode *hpp;
626	register struct hpfid *hpfhp;
627
628	hpp = VTOHP(vp);
629	hpfhp = (struct hpfid *)fhp;
630	hpfhp->hpfid_len = sizeof(struct hpfid);
631	hpfhp->hpfid_ino = hpp->h_no;
632	/* hpfhp->hpfid_gen = hpp->h_gen; */
633	return (0);
634}
635
636static int
637hpfs_vget(
638	struct mount *mp,
639	ino_t ino,
640	struct vnode **vpp)
641{
642	struct hpfsmount *hpmp = VFSTOHPFS(mp);
643	struct vnode *vp;
644	struct hpfsnode *hp;
645	struct buf *bp;
646	struct proc *p = curproc;	/* XXX */
647	int error;
648
649	dprintf(("hpfs_vget(0x%x): ",ino));
650
651	*vpp = NULL;
652	hp = NULL;
653	vp = NULL;
654
655	if ((*vpp = hpfs_hphashvget(hpmp->hpm_dev, ino, p)) != NULL) {
656		dprintf(("hashed\n"));
657		return (0);
658	}
659
660	/*
661	 * We have to lock node creation for a while,
662	 * but then we have to call getnewvnode(),
663	 * this may cause hpfs_reclaim() to be called,
664	 * this may need to VOP_VGET() parent dir for
665	 * update reasons, and if parent is not in
666	 * hash, we have to lock node creation...
667	 * To solve this, we MALLOC, getnewvnode and init while
668	 * not locked (probability of node appearence
669	 * at that time is little, and anyway - we'll
670	 * check for it).
671	 */
672	MALLOC(hp, struct hpfsnode *, sizeof(struct hpfsnode),
673		M_HPFSNO, M_WAITOK);
674
675	error = getnewvnode(VT_HPFS, hpmp->hpm_mp, hpfs_vnodeop_p, &vp);
676	if (error) {
677		printf("hpfs_vget: can't get new vnode\n");
678		FREE(hp, M_HPFSNO);
679		return (error);
680	}
681
682	dprintf(("prenew "));
683
684	vp->v_data = hp;
685
686	if (ino == (ino_t)hpmp->hpm_su.su_rootfno)
687		vp->v_flag |= VROOT;
688
689
690	mtx_init(&hp->h_interlock, "hpfsnode interlock", MTX_DEF);
691	lockinit(&hp->h_lock, PINOD, "hpnode", 0, 0);
692
693	hp->h_flag = H_INVAL;
694	hp->h_vp = vp;
695	hp->h_hpmp = hpmp;
696	hp->h_no = ino;
697	hp->h_dev = hpmp->hpm_dev;
698	hp->h_uid = hpmp->hpm_uid;
699	hp->h_gid = hpmp->hpm_uid;
700	hp->h_mode = hpmp->hpm_mode;
701	hp->h_devvp = hpmp->hpm_devvp;
702	VREF(hp->h_devvp);
703
704	error = VN_LOCK(vp, LK_EXCLUSIVE, p);
705	if (error) {
706		vput(vp);
707		return (error);
708	}
709
710	do {
711		if ((*vpp = hpfs_hphashvget(hpmp->hpm_dev, ino, p)) != NULL) {
712			dprintf(("hashed2\n"));
713			vput(vp);
714			return (0);
715		}
716	} while(LOCKMGR(&hpfs_hphash_lock,LK_EXCLUSIVE|LK_SLEEPFAIL,NULL,NULL));
717
718	hpfs_hphashins(hp);
719
720	LOCKMGR(&hpfs_hphash_lock, LK_RELEASE, NULL, NULL);
721
722	error = bread(hpmp->hpm_devvp, ino, FNODESIZE, NOCRED, &bp);
723	if (error) {
724		printf("hpfs_vget: can't read ino %d\n",ino);
725		vput(vp);
726		return (error);
727	}
728	bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode));
729	brelse(bp);
730
731	if (hp->h_fn.fn_magic != FN_MAGIC) {
732		printf("hpfs_vget: MAGIC DOESN'T MATCH\n");
733		vput(vp);
734		return (EINVAL);
735	}
736
737	vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG;
738	hp->h_flag &= ~H_INVAL;
739
740	*vpp = vp;
741
742	return (0);
743}
744
745#if defined(__FreeBSD__)
746static struct vfsops hpfs_vfsops = {
747	hpfs_mount,
748	vfs_stdstart,
749	hpfs_unmount,
750	hpfs_root,
751	vfs_stdquotactl,
752	hpfs_statfs,
753	vfs_stdsync,
754	hpfs_vget,
755	hpfs_fhtovp,
756	hpfs_checkexp,
757	hpfs_vptofh,
758	hpfs_init,
759	hpfs_uninit,
760	vfs_stdextattrctl,
761};
762VFS_SET(hpfs_vfsops, hpfs, 0);
763#else /* defined(__NetBSD__) */
764extern struct vnodeopv_desc hpfs_vnodeop_opv_desc;
765
766struct vnodeopv_desc *hpfs_vnodeopv_descs[] = {
767	&hpfs_vnodeop_opv_desc,
768	NULL,
769};
770
771struct vfsops hpfs_vfsops = {
772	MOUNT_HPFS,
773	hpfs_mount,
774	hpfs_start,
775	hpfs_unmount,
776	hpfs_root,
777	hpfs_quotactl,
778	hpfs_statfs,
779	hpfs_sync,
780	hpfs_vget,
781	hpfs_fhtovp,
782	hpfs_vptofh,
783	hpfs_init,
784	hpfs_sysctl,
785	hpfs_mountroot,
786	hpfs_checkexp,
787	hpfs_vnodeopv_descs,
788};
789#endif
790