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