2 * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
26 * $FreeBSD: src/sys/fs/hpfs/hpfs_vfsops.c,v 1.3.2.2 2001/12/25 01:44:45 dillon Exp $
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/nlookup.h>
35 #include <sys/kernel.h>
36 #include <sys/vnode.h>
37 #include <sys/mount.h>
39 #include <sys/fcntl.h>
40 #include <sys/malloc.h>
42 #include <machine/inttypes.h>
45 #include <vm/vm_param.h>
46 #if defined(__NetBSD__)
47 #include <vm/vm_prot.h>
49 #include <vm/vm_page.h>
50 #include <vm/vm_object.h>
51 #include <vm/vm_extern.h>
55 #if defined(__NetBSD__)
56 #include <miscfs/specfs/specdev.h>
60 #include "hpfsmount.h"
61 #include "hpfs_subr.h"
63 extern struct vop_ops hpfs_vnode_vops
;
65 MALLOC_DEFINE(M_HPFSMNT
, "HPFS mount", "HPFS mount structure");
66 MALLOC_DEFINE(M_HPFSNO
, "HPFS node", "HPFS node structure");
68 static int hpfs_root (struct mount
*, struct vnode
**);
69 static int hpfs_statfs (struct mount
*, struct statfs
*, struct ucred
*);
70 static int hpfs_unmount (struct mount
*, int);
71 static int hpfs_vget (struct mount
*mp
, struct vnode
*,
72 ino_t ino
, struct vnode
**vpp
);
73 static int hpfs_mountfs (struct vnode
*, struct mount
*,
75 static int hpfs_vptofh (struct vnode
*, struct fid
*);
76 static int hpfs_fhtovp (struct mount
*, struct vnode
*,
77 struct fid
*, struct vnode
**);
81 static int hpfs_mount (struct mount
*, char *, caddr_t
, struct ucred
*);
82 static int hpfs_init (struct vfsconf
*);
83 static int hpfs_checkexp (struct mount
*, struct sockaddr
*,
84 int *, struct ucred
**);
88 hpfs_checkexp(struct mount
*mp
,
90 int *exflagsp
, struct ucred
**credanonp
)
93 struct hpfsmount
*hpm
= VFSTOHPFS(mp
);
96 * Get the export permission structure for this <mp, client> tuple.
98 np
= vfs_export_lookup(mp
, &hpm
->hpm_export
, nam
);
102 *exflagsp
= np
->netc_exflags
;
103 *credanonp
= &np
->netc_anon
;
108 hpfs_init(struct vfsconf
*vcp
)
110 dprintf(("hpfs_init():\n"));
117 hpfs_mount(struct mount
*mp
, char *path
, caddr_t data
, struct ucred
*cred
)
122 struct hpfs_args args
;
123 struct hpfsmount
*hpmp
= NULL
;
124 struct nlookupdata nd
;
126 dprintf(("hpfs_mount():\n"));
129 * Mounting non-root file system or updating a file system
133 /* copy in user arguments*/
134 error
= copyin(data
, (caddr_t
)&args
, sizeof (struct hpfs_args
));
136 goto error_1
; /* can't get arguments*/
139 * If updating, check whether changing from read-only to
140 * read/write; if there is no device name, that's all we do.
142 if (mp
->mnt_flag
& MNT_UPDATE
) {
143 dprintf(("hpfs_mount: MNT_UPDATE: "));
145 hpmp
= VFSTOHPFS(mp
);
147 if (args
.fspec
== NULL
) {
148 dprintf(("export 0x%x\n",args
.export
.ex_flags
));
149 error
= vfs_export(mp
, &hpmp
->hpm_export
, &args
.export
);
151 kprintf("hpfs_mount: vfs_export failed %d\n",
155 dprintf(("name [FAILED]\n"));
162 * Not an update, or updating the name: look up the name
163 * and verify that it refers to a sensible block device.
166 error
= nlookup_init(&nd
, args
.fspec
, UIO_USERSPACE
, NLC_FOLLOW
);
168 error
= nlookup(&nd
);
170 error
= cache_vref(&nd
.nl_nch
, nd
.nl_cred
, &devvp
);
175 if (!vn_isdisk(devvp
, &error
))
184 /* Save "mounted from" info for mount point (NULL pad)*/
185 copyinstr( args
.fspec
, /* device name*/
186 mp
->mnt_stat
.f_mntfromname
, /* save area*/
187 MNAMELEN
- 1, /* max size*/
188 &size
); /* real size*/
189 bzero( mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
191 error
= hpfs_mountfs(devvp
, mp
, &args
);
196 * Initialize FS stat information in mount struct; uses
197 * mp->mnt_stat.f_mntfromname.
199 * This code is common to root and non-root mounts
201 VFS_STATFS(mp
, &mp
->mnt_stat
, cred
);
204 error_2
: /* error with devvp held*/
206 /* release devvp before failing*/
209 error_1
: /* no state to back out*/
216 * Common code for mount and mountroot
219 hpfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct hpfs_args
*argsp
)
221 int error
, ncount
, ronly
;
224 struct hpfsmount
*hpmp
;
225 struct buf
*bp
= NULL
;
229 dprintf(("hpfs_mountfs():\n"));
231 * Disallow multiple mounts of the same device.
232 * Disallow mounting of a device that is currently in use
233 * (except for root, which might share swap device for miniroot).
234 * Flush out any old buffers remaining from a previous use.
236 error
= vfs_mountedon(devvp
);
239 ncount
= vcount(devvp
);
245 VN_LOCK(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
246 error
= vinvalbuf(devvp
, V_SAVE
, 0, 0);
247 VOP__UNLOCK(devvp
, 0);
251 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
252 VN_LOCK(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
253 error
= VOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, FSCRED
, NULL
);
254 VOP__UNLOCK(devvp
, 0);
262 hpmp
= kmalloc(sizeof(struct hpfsmount
), M_HPFSMNT
, M_WAITOK
| M_ZERO
);
264 /* Read in SuperBlock */
265 error
= bread(devvp
, dbtodoff(SUBLOCK
), SUSIZE
, &bp
);
268 bcopy(bp
->b_data
, &hpmp
->hpm_su
, sizeof(struct sublock
));
269 brelse(bp
); bp
= NULL
;
271 /* Read in SpareBlock */
272 error
= bread(devvp
, dbtodoff(SPBLOCK
), SPSIZE
, &bp
);
275 bcopy(bp
->b_data
, &hpmp
->hpm_sp
, sizeof(struct spblock
));
276 brelse(bp
); bp
= NULL
;
282 if (sup
->su_magic
!= SU_MAGIC
) {
283 kprintf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n");
287 if (spp
->sp_magic
!= SP_MAGIC
) {
288 kprintf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n");
293 mp
->mnt_data
= (qaddr_t
)hpmp
;
294 hpmp
->hpm_devvp
= devvp
;
297 hpmp
->hpm_uid
= argsp
->uid
;
298 hpmp
->hpm_gid
= argsp
->gid
;
299 hpmp
->hpm_mode
= argsp
->mode
;
301 error
= hpfs_bminit(hpmp
);
305 error
= hpfs_cpinit(hpmp
, argsp
);
310 vfs_add_vnodeops(mp
, &hpfs_vnode_vops
, &mp
->mnt_vn_norm_ops
);
312 error
= hpfs_root(mp
, &vp
);
321 mp
->mnt_stat
.f_fsid
.val
[0] = (long)devid_from_dev(dev
);
322 mp
->mnt_stat
.f_fsid
.val
[1] = mp
->mnt_vfc
->vfc_typenum
;
323 mp
->mnt_maxsymlinklen
= 0;
324 mp
->mnt_flag
|= MNT_LOCAL
;
325 dev
->si_mountpoint
= mp
;
332 dev
->si_mountpoint
= NULL
;
333 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
334 VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, NULL
);
341 hpfs_unmount(struct mount
*mp
, int mntflags
)
343 int error
, flags
, ronly
;
344 struct hpfsmount
*hpmp
= VFSTOHPFS(mp
);
346 dprintf(("hpfs_unmount():\n"));
348 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
351 if(mntflags
& MNT_FORCE
)
354 dprintf(("hpfs_unmount: vflushing...\n"));
356 error
= vflush(mp
, 0, flags
);
358 kprintf("hpfs_unmount: vflush failed: %d\n",error
);
362 hpmp
->hpm_devvp
->v_rdev
->si_mountpoint
= NULL
;
364 vn_lock(hpmp
->hpm_devvp
, LK_EXCLUSIVE
| LK_RETRY
);
365 vinvalbuf(hpmp
->hpm_devvp
, V_SAVE
, 0, 0);
366 error
= VOP_CLOSE(hpmp
->hpm_devvp
, ronly
? FREAD
: FREAD
|FWRITE
, NULL
);
367 vn_unlock(hpmp
->hpm_devvp
);
369 vrele(hpmp
->hpm_devvp
);
371 dprintf(("hpfs_umount: freeing memory...\n"));
374 mp
->mnt_data
= (qaddr_t
)0;
375 mp
->mnt_flag
&= ~MNT_LOCAL
;
376 kfree(hpmp
, M_HPFSMNT
);
382 hpfs_root(struct mount
*mp
, struct vnode
**vpp
)
385 struct hpfsmount
*hpmp
= VFSTOHPFS(mp
);
387 dprintf(("hpfs_root():\n"));
388 error
= VFS_VGET(mp
, NULL
, (ino_t
)hpmp
->hpm_su
.su_rootfno
, vpp
);
390 kprintf("hpfs_root: VFS_VGET failed: %d\n",error
);
398 hpfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
400 struct hpfsmount
*hpmp
= VFSTOHPFS(mp
);
402 dprintf(("hpfs_statfs(): HPFS%d.%d\n",
403 hpmp
->hpm_su
.su_hpfsver
, hpmp
->hpm_su
.su_fnctver
));
405 sbp
->f_type
= mp
->mnt_vfc
->vfc_typenum
;
406 sbp
->f_bsize
= DEV_BSIZE
;
407 sbp
->f_iosize
= DEV_BSIZE
;
408 sbp
->f_blocks
= hpmp
->hpm_su
.su_btotal
;
409 sbp
->f_bfree
= sbp
->f_bavail
= hpmp
->hpm_bavail
;
412 if (sbp
!= &mp
->mnt_stat
) {
413 bcopy((caddr_t
)mp
->mnt_stat
.f_mntfromname
,
414 (caddr_t
)&sbp
->f_mntfromname
[0], MNAMELEN
);
416 sbp
->f_flags
= mp
->mnt_flag
;
424 hpfs_fhtovp(struct mount
*mp
, struct vnode
*rootvp
,
425 struct fid
*fhp
, struct vnode
**vpp
)
428 struct hpfid
*hpfhp
= (struct hpfid
*)fhp
;
431 if ((error
= VFS_VGET(mp
, NULL
, hpfhp
->hpfid_ino
, &nvp
)) != 0) {
435 /* XXX as unlink/rmdir/mkdir/creat are not currently possible
436 * with HPFS, we don't need to check anything else for now */
443 hpfs_vptofh(struct vnode
*vp
, struct fid
*fhp
)
445 struct hpfsnode
*hpp
;
449 hpfhp
= (struct hpfid
*)fhp
;
450 hpfhp
->hpfid_len
= sizeof(struct hpfid
);
451 hpfhp
->hpfid_ino
= hpp
->h_no
;
452 /* hpfhp->hpfid_gen = hpp->h_gen; */
457 hpfs_vget(struct mount
*mp
, struct vnode
*dvp
, ino_t ino
, struct vnode
**vpp
)
459 struct hpfsmount
*hpmp
= VFSTOHPFS(mp
);
465 dprintf(("hpfs_vget(0x%jx): ", ino
));
471 if ((*vpp
= hpfs_hphashvget(hpmp
->hpm_dev
, ino
)) != NULL
) {
472 dprintf(("hashed\n"));
477 * We have to lock node creation for a while,
478 * but then we have to call getnewvnode(),
479 * this may cause hpfs_reclaim() to be called,
480 * this may need to VOP_VGET() parent dir for
481 * update reasons, and if parent is not in
482 * hash, we have to lock node creation...
483 * To solve this, we MALLOC, getnewvnode and init while
484 * not locked (probability of node appearence
485 * at that time is little, and anyway - we'll
488 hp
= kmalloc(sizeof(struct hpfsnode
), M_HPFSNO
, M_WAITOK
);
490 error
= getnewvnode(VT_HPFS
, hpmp
->hpm_mp
, &vp
, VLKTIMEOUT
, 0);
492 kprintf("hpfs_vget: can't get new vnode\n");
497 dprintf(("prenew "));
501 if (ino
== (ino_t
)hpmp
->hpm_su
.su_rootfno
)
502 vsetflags(vp
, VROOT
);
504 lwkt_token_init(&hp
->h_interlock
, "hpfsilock");
506 hp
->h_flag
= H_INVAL
;
510 hp
->h_dev
= hpmp
->hpm_dev
;
511 hp
->h_uid
= hpmp
->hpm_uid
;
512 hp
->h_gid
= hpmp
->hpm_uid
;
513 hp
->h_mode
= hpmp
->hpm_mode
;
514 hp
->h_devvp
= hpmp
->hpm_devvp
;
518 if ((*vpp
= hpfs_hphashvget(hpmp
->hpm_dev
, ino
)) != NULL
) {
519 dprintf(("hashed2\n"));
523 } while (LOCKMGR(&hpfs_hphash_lock
, LK_EXCLUSIVE
| LK_SLEEPFAIL
));
527 LOCKMGR(&hpfs_hphash_lock
, LK_RELEASE
);
529 error
= bread(hpmp
->hpm_devvp
, dbtodoff(ino
), FNODESIZE
, &bp
);
531 kprintf("hpfs_vget: can't read ino %"PRId64
"\n",ino
);
535 bcopy(bp
->b_data
, &hp
->h_fn
, sizeof(struct fnode
));
538 if (hp
->h_fn
.fn_magic
!= FN_MAGIC
) {
539 kprintf("hpfs_vget: MAGIC DOESN'T MATCH\n");
544 vp
->v_type
= hp
->h_fn
.fn_flag
? VDIR
:VREG
;
545 hp
->h_flag
&= ~H_INVAL
;
547 /* Return the locked and refd vnode */
554 static struct vfsops hpfs_vfsops
= {
556 .vfs_mount
= hpfs_mount
,
557 .vfs_unmount
= hpfs_unmount
,
558 .vfs_root
= hpfs_root
,
559 .vfs_statfs
= hpfs_statfs
,
560 .vfs_vget
= hpfs_vget
,
561 .vfs_fhtovp
= hpfs_fhtovp
,
562 .vfs_checkexp
= hpfs_checkexp
,
563 .vfs_vptofh
= hpfs_vptofh
,
564 .vfs_init
= hpfs_init
,
565 .vfs_uninit
= hpfs_hphash_uninit
568 VFS_SET(hpfs_vfsops
, hpfs
, 0);
569 MODULE_VERSION(hpfs
, 1);