xref: /dflybsd-src/sys/vfs/hpfs/hpfs_vfsops.c (revision 17ea22213f86a5c5966c1e6bf8e95f022ebb92b9)
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: src/sys/fs/hpfs/hpfs_vfsops.c,v 1.3.2.2 2001/12/25 01:44:45 dillon Exp $
27  * $DragonFly: src/sys/vfs/hpfs/hpfs_vfsops.c,v 1.25 2004/12/29 02:42:15 dillon Exp $
28  */
29 
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/nlookup.h>
34 #include <sys/conf.h>
35 #include <sys/proc.h>
36 #include <sys/kernel.h>
37 #include <sys/vnode.h>
38 #include <sys/mount.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 #include <sys/buf2.h>
52 
53 #if defined(__NetBSD__)
54 #include <miscfs/specfs/specdev.h>
55 #endif
56 
57 #include "hpfs.h"
58 #include "hpfsmount.h"
59 #include "hpfs_subr.h"
60 
61 extern struct vnodeopv_entry_desc hpfs_vnodeop_entries[];
62 
63 #if defined(__DragonFly__)
64 MALLOC_DEFINE(M_HPFSMNT, "HPFS mount", "HPFS mount structure");
65 MALLOC_DEFINE(M_HPFSNO, "HPFS node", "HPFS node structure");
66 #endif
67 
68 static int	hpfs_root (struct mount *, struct vnode **);
69 static int	hpfs_statfs (struct mount *, struct statfs *,
70 				 struct thread *);
71 static int	hpfs_unmount (struct mount *, int, struct thread *);
72 static int	hpfs_vget (struct mount *mp, ino_t ino,
73 			       struct vnode **vpp);
74 static int	hpfs_mountfs (struct vnode *, struct mount *,
75 				  struct hpfs_args *, struct thread *);
76 static int	hpfs_vptofh (struct vnode *, struct fid *);
77 static int	hpfs_fhtovp (struct mount *, struct fid *,
78 				 struct vnode **);
79 
80 #if !defined(__DragonFly__)
81 static int	hpfs_quotactl (struct mount *, int, uid_t, caddr_t,
82 				   struct proc *);
83 static int	hpfs_start (struct mount *, int, struct proc *);
84 static int	hpfs_sync (struct mount *, int, struct ucred *,
85 			       struct proc *);
86 #endif
87 
88 #if defined(__DragonFly__)
89 struct sockaddr;
90 static int	hpfs_mount (struct mount *, char *, caddr_t, struct thread *);
91 static int	hpfs_init (struct vfsconf *);
92 static int	hpfs_checkexp (struct mount *, struct sockaddr *,
93 				   int *, struct ucred **);
94 #else /* defined(__NetBSD__) */
95 static int	hpfs_mount (struct mount *, const char *, void *,
96 				struct nlookupdata *, struct proc *);
97 static void	hpfs_init (void);
98 static int	hpfs_sysctl (int *, u_int, void *, size_t *, void *,
99 				 size_t, struct proc *);
100 static int	hpfs_checkexp (struct mount *, struct mbuf *,
101 				   int *, struct ucred **);
102 #endif
103 
104 /*ARGSUSED*/
105 static int
106 hpfs_checkexp(struct mount *mp,
107 #if defined(__DragonFly__)
108 	      struct sockaddr *nam,
109 #else /* defined(__NetBSD__) */
110 	      struct mbuf *nam,
111 #endif
112 	      int *exflagsp, struct ucred **credanonp)
113 {
114 	struct netcred *np;
115 	struct hpfsmount *hpm = VFSTOHPFS(mp);
116 
117 	/*
118 	 * Get the export permission structure for this <mp, client> tuple.
119 	 */
120 	np = vfs_export_lookup(mp, &hpm->hpm_export, nam);
121 	if (np == NULL)
122 		return (EACCES);
123 
124 	*exflagsp = np->netc_exflags;
125 	*credanonp = &np->netc_anon;
126 	return (0);
127 }
128 
129 #if defined(__DragonFly__)
130 static int
131 hpfs_init(struct vfsconf *vcp)
132 #else /* defined(__NetBSD__) */
133 static void
134 hpfs_init(void)
135 #endif
136 {
137 	dprintf(("hpfs_init():\n"));
138 
139 	hpfs_hphashinit();
140 #if defined(__DragonFly__)
141 	return 0;
142 #endif
143 }
144 
145 static int
146 hpfs_mount(struct mount *mp,
147 #if defined(__DragonFly__)
148 	   char *path, caddr_t data,
149 #else /* defined(__NetBSD__) */
150 	   const char *path, void *data,
151 #endif
152 	   struct thread *td)
153 {
154 	u_int		size;
155 	int		error;
156 	struct vnode	*devvp;
157 	struct hpfs_args args;
158 	struct hpfsmount *hpmp = 0;
159 	struct nlookupdata nd;
160 
161 	dprintf(("hpfs_mount():\n"));
162 	/*
163 	 ***
164 	 * Mounting non-root file system or updating a file system
165 	 ***
166 	 */
167 
168 	/* copy in user arguments*/
169 	error = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args));
170 	if (error)
171 		goto error_1;		/* can't get arguments*/
172 
173 	/*
174 	 * If updating, check whether changing from read-only to
175 	 * read/write; if there is no device name, that's all we do.
176 	 */
177 	if (mp->mnt_flag & MNT_UPDATE) {
178 		dprintf(("hpfs_mount: MNT_UPDATE: "));
179 
180 		hpmp = VFSTOHPFS(mp);
181 
182 		if (args.fspec == 0) {
183 			dprintf(("export 0x%x\n",args.export.ex_flags));
184 			error = vfs_export(mp, &hpmp->hpm_export, &args.export);
185 			if (error) {
186 				printf("hpfs_mount: vfs_export failed %d\n",
187 					error);
188 			}
189 			goto success;
190 		} else {
191 			dprintf(("name [FAILED]\n"));
192 			error = EINVAL;
193 			goto success;
194 		}
195 		dprintf(("\n"));
196 	}
197 
198 	/*
199 	 * Not an update, or updating the name: look up the name
200 	 * and verify that it refers to a sensible block device.
201 	 */
202 	devvp = NULL;
203 	error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW);
204 	if (error == 0)
205 		error = nlookup(&nd);
206 	if (error == 0)
207 		error = cache_vref(nd.nl_ncp, nd.nl_cred, &devvp);
208 	nlookup_done(&nd);
209 	if (error)
210 		goto error_1;
211 
212 #if defined(__DragonFly__)
213 	if (!vn_isdisk(devvp, &error))
214 		goto error_2;
215 #else /* defined(__NetBSD__) */
216 	if (devvp->v_type != VBLK) {
217 		error = ENOTBLK;
218 		goto error_2;
219 	}
220 	if (umajor(devvp->v_udev) >= nblkdev) {
221 		error = ENXIO;
222 		goto error_2;
223 	}
224 #endif
225 
226 	/*
227 	 ********************
228 	 * NEW MOUNT
229 	 ********************
230 	 */
231 
232 	/*
233 	 * Since this is a new mount, we want the names for
234 	 * the device and the mount point copied in.  If an
235 	 * error occurs,  the mountpoint is discarded by the
236 	 * upper level code.
237 	 */
238 	/* Save "last mounted on" info for mount point (NULL pad)*/
239 	copyinstr(	path,				/* mount point*/
240 			mp->mnt_stat.f_mntonname,	/* save area*/
241 			MNAMELEN - 1,			/* max size*/
242 			&size);				/* real size*/
243 	bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
244 
245 	/* Save "mounted from" info for mount point (NULL pad)*/
246 	copyinstr(	args.fspec,			/* device name*/
247 			mp->mnt_stat.f_mntfromname,	/* save area*/
248 			MNAMELEN - 1,			/* max size*/
249 			&size);				/* real size*/
250 	bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
251 
252 	error = hpfs_mountfs(devvp, mp, &args, td);
253 	if (error)
254 		goto error_2;
255 
256 	/*
257 	 * Initialize FS stat information in mount struct; uses both
258 	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
259 	 *
260 	 * This code is common to root and non-root mounts
261 	 */
262 	VFS_STATFS(mp, &mp->mnt_stat, td);
263 	return (error);
264 
265 error_2:	/* error with devvp held*/
266 
267 	/* release devvp before failing*/
268 	vrele(devvp);
269 
270 error_1:	/* no state to back out*/
271 
272 success:
273 	return (error);
274 }
275 
276 /*
277  * Common code for mount and mountroot
278  */
279 int
280 hpfs_mountfs(struct vnode *devvp, struct mount *mp, struct hpfs_args *argsp,
281 	     struct thread *td)
282 {
283 	int error, ncount, ronly;
284 	struct sublock *sup;
285 	struct spblock *spp;
286 	struct hpfsmount *hpmp;
287 	struct buf *bp = NULL;
288 	struct vnode *vp;
289 	dev_t dev;
290 
291 	dprintf(("hpfs_mountfs():\n"));
292 	/*
293 	 * Disallow multiple mounts of the same device.
294 	 * Disallow mounting of a device that is currently in use
295 	 * (except for root, which might share swap device for miniroot).
296 	 * Flush out any old buffers remaining from a previous use.
297 	 */
298 	error = vfs_mountedon(devvp);
299 	if (error)
300 		return (error);
301 	ncount = count_udev(devvp->v_udev);
302 #if defined(__DragonFly__)
303 	if (devvp->v_object)
304 		ncount -= 1;
305 #endif
306 	if (ncount > 0)
307 		return (EBUSY);
308 
309 #if defined(__DragonFly__)
310 	VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, td);
311 	error = vinvalbuf(devvp, V_SAVE, td, 0, 0);
312 	VOP__UNLOCK(devvp, 0, td);
313 #else
314 	error = vinvalbuf(devvp, V_SAVE, td, 0, 0);
315 #endif
316 	if (error)
317 		return (error);
318 
319 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
320 	VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, td);
321 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL, td);
322 	VOP__UNLOCK(devvp, 0, td);
323 	if (error)
324 		return (error);
325 	dev = devvp->v_rdev;
326 
327 	/*
328 	 * Do actual mount
329 	 */
330 	hpmp = malloc(sizeof(struct hpfsmount), M_HPFSMNT, M_WAITOK);
331 	bzero(hpmp, sizeof(struct hpfsmount));
332 
333 	/* Read in SuperBlock */
334 	error = bread(devvp, SUBLOCK, SUSIZE, &bp);
335 	if (error)
336 		goto failed;
337 	bcopy(bp->b_data, &hpmp->hpm_su, sizeof(struct sublock));
338 	brelse(bp); bp = NULL;
339 
340 	/* Read in SpareBlock */
341 	error = bread(devvp, SPBLOCK, SPSIZE, &bp);
342 	if (error)
343 		goto failed;
344 	bcopy(bp->b_data, &hpmp->hpm_sp, sizeof(struct spblock));
345 	brelse(bp); bp = NULL;
346 
347 	sup = &hpmp->hpm_su;
348 	spp = &hpmp->hpm_sp;
349 
350 	/* Check magic */
351 	if (sup->su_magic != SU_MAGIC) {
352 		printf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n");
353 		error = EINVAL;
354 		goto failed;
355 	}
356 	if (spp->sp_magic != SP_MAGIC) {
357 		printf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n");
358 		error = EINVAL;
359 		goto failed;
360 	}
361 
362 	mp->mnt_data = (qaddr_t)hpmp;
363 	hpmp->hpm_devvp = devvp;
364 	hpmp->hpm_dev = dev;
365 	hpmp->hpm_mp = mp;
366 	hpmp->hpm_uid = argsp->uid;
367 	hpmp->hpm_gid = argsp->gid;
368 	hpmp->hpm_mode = argsp->mode;
369 
370 	error = hpfs_bminit(hpmp);
371 	if (error)
372 		goto failed;
373 
374 	error = hpfs_cpinit(hpmp, argsp);
375 	if (error) {
376 		hpfs_bmdeinit(hpmp);
377 		goto failed;
378 	}
379 	vfs_add_vnodeops(mp, &mp->mnt_vn_norm_ops, hpfs_vnodeop_entries);
380 
381 	error = hpfs_root(mp, &vp);
382 	if (error) {
383 		hpfs_cpdeinit(hpmp);
384 		hpfs_bmdeinit(hpmp);
385 		goto failed;
386 	}
387 
388 	vput(vp);
389 
390 #if defined(__DragonFly__)
391 	mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(dev);
392 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
393 #else
394 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
395 	mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_HPFS);
396 #endif
397 	mp->mnt_maxsymlinklen = 0;
398 	mp->mnt_flag |= MNT_LOCAL;
399 	dev->si_mountpoint = mp;
400 	return (0);
401 
402 failed:
403 	if (bp)
404 		brelse (bp);
405 	mp->mnt_data = (qaddr_t)NULL;
406 #if defined(__DragonFly__)
407 	dev->si_mountpoint = NULL;
408 #else
409 	devvp->v_specflags &= ~SI_MOUNTEDON;
410 #endif
411 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, td);
412 	return (error);
413 }
414 
415 #if !defined(__DragonFly__)
416 static int
417 hpfs_start(struct mount *mp, int flags, struct thread *td)
418 {
419 	return (0);
420 }
421 #endif
422 
423 static int
424 hpfs_unmount(struct mount *mp, int mntflags, struct thread *td)
425 {
426 	int error, flags, ronly;
427 	struct hpfsmount *hpmp = VFSTOHPFS(mp);
428 
429 	dprintf(("hpfs_unmount():\n"));
430 
431 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
432 
433 	flags = 0;
434 	if(mntflags & MNT_FORCE)
435 		flags |= FORCECLOSE;
436 
437 	dprintf(("hpfs_unmount: vflushing...\n"));
438 
439 	error = vflush(mp, 0, flags);
440 	if (error) {
441 		printf("hpfs_unmount: vflush failed: %d\n",error);
442 		return (error);
443 	}
444 
445 #if defined(__DragonFly__)
446 	hpmp->hpm_devvp->v_rdev->si_mountpoint = NULL;
447 #else
448 	hpmp->hpm_devvp->v_specflags &= ~SI_MOUNTEDON;
449 #endif
450 
451 	vinvalbuf(hpmp->hpm_devvp, V_SAVE, td, 0, 0);
452 	error = VOP_CLOSE(hpmp->hpm_devvp, ronly ? FREAD : FREAD|FWRITE, td);
453 
454 	vrele(hpmp->hpm_devvp);
455 
456 	dprintf(("hpfs_umount: freeing memory...\n"));
457 	hpfs_cpdeinit(hpmp);
458 	hpfs_bmdeinit(hpmp);
459 	mp->mnt_data = (qaddr_t)0;
460 	mp->mnt_flag &= ~MNT_LOCAL;
461 	FREE(hpmp, M_HPFSMNT);
462 
463 	return (0);
464 }
465 
466 static int
467 hpfs_root(struct mount *mp, struct vnode **vpp)
468 {
469 	int error = 0;
470 	struct hpfsmount *hpmp = VFSTOHPFS(mp);
471 
472 	dprintf(("hpfs_root():\n"));
473 	error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, vpp);
474 	if(error) {
475 		printf("hpfs_root: VFS_VGET failed: %d\n",error);
476 		return (error);
477 	}
478 
479 	return (error);
480 }
481 
482 static int
483 hpfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
484 {
485 	struct hpfsmount *hpmp = VFSTOHPFS(mp);
486 
487 	dprintf(("hpfs_statfs(): HPFS%d.%d\n",
488 		hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver));
489 
490 #if defined(__DragonFly__)
491 	sbp->f_type = mp->mnt_vfc->vfc_typenum;
492 #else /* defined(__NetBSD__) */
493 	sbp->f_type = 0;
494 #endif
495 	sbp->f_bsize = DEV_BSIZE;
496 	sbp->f_iosize = DEV_BSIZE;
497 	sbp->f_blocks = hpmp->hpm_su.su_btotal;
498 	sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail;
499 	sbp->f_ffree = 0;
500 	sbp->f_files = 0;
501 	if (sbp != &mp->mnt_stat) {
502 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
503 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
504 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
505 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
506 	}
507 	sbp->f_flags = mp->mnt_flag;
508 
509 	return (0);
510 }
511 
512 #if !defined(__DragonFly__)
513 static int
514 hpfs_sync(struct mount *mp, int waitfor, struct ucred *cred,
515 	  struct thread *td)
516 {
517 	return (0);
518 }
519 
520 static int
521 hpfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
522 	      struct thread *td)
523 {
524 	printf("hpfs_quotactl():\n");
525 	return (EOPNOTSUPP);
526 }
527 #endif
528 
529 /*ARGSUSED*/
530 static int
531 hpfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
532 {
533 	struct vnode *nvp;
534 	struct hpfid *hpfhp = (struct hpfid *)fhp;
535 	int error;
536 
537 	if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, &nvp)) != 0) {
538 		*vpp = NULLVP;
539 		return (error);
540 	}
541 	/* XXX as unlink/rmdir/mkdir/creat are not currently possible
542 	 * with HPFS, we don't need to check anything else for now */
543 	*vpp = nvp;
544 
545 	return (0);
546 }
547 
548 static int
549 hpfs_vptofh(struct vnode *vp, struct fid *fhp)
550 {
551 	struct hpfsnode *hpp;
552 	struct hpfid *hpfhp;
553 
554 	hpp = VTOHP(vp);
555 	hpfhp = (struct hpfid *)fhp;
556 	hpfhp->hpfid_len = sizeof(struct hpfid);
557 	hpfhp->hpfid_ino = hpp->h_no;
558 	/* hpfhp->hpfid_gen = hpp->h_gen; */
559 	return (0);
560 }
561 
562 static int
563 hpfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
564 {
565 	struct hpfsmount *hpmp = VFSTOHPFS(mp);
566 	struct vnode *vp;
567 	struct hpfsnode *hp;
568 	struct buf *bp;
569 	struct thread *td = curthread;	/* XXX */
570 	int error;
571 
572 	dprintf(("hpfs_vget(0x%x): ",ino));
573 
574 	*vpp = NULL;
575 	hp = NULL;
576 	vp = NULL;
577 
578 	if ((*vpp = hpfs_hphashvget(hpmp->hpm_dev, ino, td)) != NULL) {
579 		dprintf(("hashed\n"));
580 		return (0);
581 	}
582 
583 	/*
584 	 * We have to lock node creation for a while,
585 	 * but then we have to call getnewvnode(),
586 	 * this may cause hpfs_reclaim() to be called,
587 	 * this may need to VOP_VGET() parent dir for
588 	 * update reasons, and if parent is not in
589 	 * hash, we have to lock node creation...
590 	 * To solve this, we MALLOC, getnewvnode and init while
591 	 * not locked (probability of node appearence
592 	 * at that time is little, and anyway - we'll
593 	 * check for it).
594 	 */
595 	MALLOC(hp, struct hpfsnode *, sizeof(struct hpfsnode),
596 		M_HPFSNO, M_WAITOK);
597 
598 	error = getnewvnode(VT_HPFS, hpmp->hpm_mp, &vp, VLKTIMEOUT, 0);
599 	if (error) {
600 		printf("hpfs_vget: can't get new vnode\n");
601 		FREE(hp, M_HPFSNO);
602 		return (error);
603 	}
604 
605 	dprintf(("prenew "));
606 
607 	vp->v_data = hp;
608 
609 	if (ino == (ino_t)hpmp->hpm_su.su_rootfno)
610 		vp->v_flag |= VROOT;
611 
612 	lwkt_token_init(&hp->h_interlock);
613 
614 	hp->h_flag = H_INVAL;
615 	hp->h_vp = vp;
616 	hp->h_hpmp = hpmp;
617 	hp->h_no = ino;
618 	hp->h_dev = hpmp->hpm_dev;
619 	hp->h_uid = hpmp->hpm_uid;
620 	hp->h_gid = hpmp->hpm_uid;
621 	hp->h_mode = hpmp->hpm_mode;
622 	hp->h_devvp = hpmp->hpm_devvp;
623 	vref(hp->h_devvp);
624 
625 	do {
626 		if ((*vpp = hpfs_hphashvget(hpmp->hpm_dev, ino, td)) != NULL) {
627 			dprintf(("hashed2\n"));
628 			vx_put(vp);
629 			return (0);
630 		}
631 	} while(LOCKMGR(&hpfs_hphash_lock,LK_EXCLUSIVE|LK_SLEEPFAIL,NULL,NULL));
632 
633 	hpfs_hphashins(hp);
634 
635 	LOCKMGR(&hpfs_hphash_lock, LK_RELEASE, NULL, NULL);
636 
637 	error = bread(hpmp->hpm_devvp, ino, FNODESIZE, &bp);
638 	if (error) {
639 		printf("hpfs_vget: can't read ino %d\n",ino);
640 		vx_put(vp);
641 		return (error);
642 	}
643 	bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode));
644 	brelse(bp);
645 
646 	if (hp->h_fn.fn_magic != FN_MAGIC) {
647 		printf("hpfs_vget: MAGIC DOESN'T MATCH\n");
648 		vx_put(vp);
649 		return (EINVAL);
650 	}
651 
652 	vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG;
653 	hp->h_flag &= ~H_INVAL;
654 
655 	/* Return the locked and refd vnode */
656 	*vpp = vp;
657 
658 	return (0);
659 }
660 
661 static struct vfsops hpfs_vfsops = {
662 	hpfs_mount,
663 	vfs_stdstart,
664 	hpfs_unmount,
665 	hpfs_root,
666 	vfs_stdquotactl,
667 	hpfs_statfs,
668 	vfs_stdsync,
669 	hpfs_vget,
670 	hpfs_fhtovp,
671 	hpfs_checkexp,
672 	hpfs_vptofh,
673 	hpfs_init,
674 	hpfs_hphash_uninit,
675 	vfs_stdextattrctl,
676 };
677 
678 VFS_SET(hpfs_vfsops, hpfs, 0);
679 
680