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 $
27 * $DragonFly: src/sys/vfs/hpfs/hpfs_vfsops.c,v 1.42 2008/01/05 14:02:41 swildner Exp $
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/nlookup.h>
36 #include <sys/kernel.h>
37 #include <sys/vnode.h>
38 #include <sys/mount.h>
40 #include <sys/fcntl.h>
41 #include <sys/malloc.h>
43 #include <machine/inttypes.h>
46 #include <vm/vm_param.h>
47 #if defined(__NetBSD__)
48 #include <vm/vm_prot.h>
50 #include <vm/vm_page.h>
51 #include <vm/vm_object.h>
52 #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
, ino_t ino
,
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 fid
*,
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
= 0;
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
== 0) {
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",
156 dprintf(("name [FAILED]\n"));
164 * Not an update, or updating the name: look up the name
165 * and verify that it refers to a sensible block device.
168 error
= nlookup_init(&nd
, args
.fspec
, UIO_USERSPACE
, NLC_FOLLOW
);
170 error
= nlookup(&nd
);
172 error
= cache_vref(&nd
.nl_nch
, nd
.nl_cred
, &devvp
);
177 if (!vn_isdisk(devvp
, &error
))
186 /* Save "mounted from" info for mount point (NULL pad)*/
187 copyinstr( args
.fspec
, /* device name*/
188 mp
->mnt_stat
.f_mntfromname
, /* save area*/
189 MNAMELEN
- 1, /* max size*/
190 &size
); /* real size*/
191 bzero( mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
193 error
= hpfs_mountfs(devvp
, mp
, &args
);
198 * Initialize FS stat information in mount struct; uses
199 * mp->mnt_stat.f_mntfromname.
201 * This code is common to root and non-root mounts
203 VFS_STATFS(mp
, &mp
->mnt_stat
, cred
);
206 error_2
: /* error with devvp held*/
208 /* release devvp before failing*/
211 error_1
: /* no state to back out*/
218 * Common code for mount and mountroot
221 hpfs_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct hpfs_args
*argsp
)
223 int error
, ncount
, ronly
;
226 struct hpfsmount
*hpmp
;
227 struct buf
*bp
= NULL
;
231 dprintf(("hpfs_mountfs():\n"));
233 * Disallow multiple mounts of the same device.
234 * Disallow mounting of a device that is currently in use
235 * (except for root, which might share swap device for miniroot).
236 * Flush out any old buffers remaining from a previous use.
238 error
= vfs_mountedon(devvp
);
241 ncount
= count_udev(devvp
->v_umajor
, devvp
->v_uminor
);
247 VN_LOCK(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
248 error
= vinvalbuf(devvp
, V_SAVE
, 0, 0);
249 VOP__UNLOCK(devvp
, 0);
253 ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
254 VN_LOCK(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
255 error
= VOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, FSCRED
, NULL
);
256 VOP__UNLOCK(devvp
, 0);
264 hpmp
= kmalloc(sizeof(struct hpfsmount
), M_HPFSMNT
, M_WAITOK
| M_ZERO
);
266 /* Read in SuperBlock */
267 error
= bread(devvp
, dbtodoff(SUBLOCK
), SUSIZE
, &bp
);
270 bcopy(bp
->b_data
, &hpmp
->hpm_su
, sizeof(struct sublock
));
271 brelse(bp
); bp
= NULL
;
273 /* Read in SpareBlock */
274 error
= bread(devvp
, dbtodoff(SPBLOCK
), SPSIZE
, &bp
);
277 bcopy(bp
->b_data
, &hpmp
->hpm_sp
, sizeof(struct spblock
));
278 brelse(bp
); bp
= NULL
;
284 if (sup
->su_magic
!= SU_MAGIC
) {
285 kprintf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n");
289 if (spp
->sp_magic
!= SP_MAGIC
) {
290 kprintf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n");
295 mp
->mnt_data
= (qaddr_t
)hpmp
;
296 hpmp
->hpm_devvp
= devvp
;
299 hpmp
->hpm_uid
= argsp
->uid
;
300 hpmp
->hpm_gid
= argsp
->gid
;
301 hpmp
->hpm_mode
= argsp
->mode
;
303 error
= hpfs_bminit(hpmp
);
307 error
= hpfs_cpinit(hpmp
, argsp
);
312 vfs_add_vnodeops(mp
, &hpfs_vnode_vops
, &mp
->mnt_vn_norm_ops
);
314 error
= hpfs_root(mp
, &vp
);
323 mp
->mnt_stat
.f_fsid
.val
[0] = (long)dev2udev(dev
);
324 mp
->mnt_stat
.f_fsid
.val
[1] = mp
->mnt_vfc
->vfc_typenum
;
325 mp
->mnt_maxsymlinklen
= 0;
326 mp
->mnt_flag
|= MNT_LOCAL
;
327 dev
->si_mountpoint
= mp
;
333 mp
->mnt_data
= (qaddr_t
)NULL
;
334 dev
->si_mountpoint
= NULL
;
335 VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
|FWRITE
);
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 vinvalbuf(hpmp
->hpm_devvp
, V_SAVE
, 0, 0);
365 error
= VOP_CLOSE(hpmp
->hpm_devvp
, ronly
? FREAD
: FREAD
|FWRITE
);
367 vrele(hpmp
->hpm_devvp
);
369 dprintf(("hpfs_umount: freeing memory...\n"));
372 mp
->mnt_data
= (qaddr_t
)0;
373 mp
->mnt_flag
&= ~MNT_LOCAL
;
374 FREE(hpmp
, M_HPFSMNT
);
380 hpfs_root(struct mount
*mp
, struct vnode
**vpp
)
383 struct hpfsmount
*hpmp
= VFSTOHPFS(mp
);
385 dprintf(("hpfs_root():\n"));
386 error
= VFS_VGET(mp
, (ino_t
)hpmp
->hpm_su
.su_rootfno
, vpp
);
388 kprintf("hpfs_root: VFS_VGET failed: %d\n",error
);
396 hpfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
398 struct hpfsmount
*hpmp
= VFSTOHPFS(mp
);
400 dprintf(("hpfs_statfs(): HPFS%d.%d\n",
401 hpmp
->hpm_su
.su_hpfsver
, hpmp
->hpm_su
.su_fnctver
));
403 sbp
->f_type
= mp
->mnt_vfc
->vfc_typenum
;
404 sbp
->f_bsize
= DEV_BSIZE
;
405 sbp
->f_iosize
= DEV_BSIZE
;
406 sbp
->f_blocks
= hpmp
->hpm_su
.su_btotal
;
407 sbp
->f_bfree
= sbp
->f_bavail
= hpmp
->hpm_bavail
;
410 if (sbp
!= &mp
->mnt_stat
) {
411 bcopy((caddr_t
)mp
->mnt_stat
.f_mntfromname
,
412 (caddr_t
)&sbp
->f_mntfromname
[0], MNAMELEN
);
414 sbp
->f_flags
= mp
->mnt_flag
;
422 hpfs_fhtovp(struct mount
*mp
, struct fid
*fhp
, struct vnode
**vpp
)
425 struct hpfid
*hpfhp
= (struct hpfid
*)fhp
;
428 if ((error
= VFS_VGET(mp
, hpfhp
->hpfid_ino
, &nvp
)) != 0) {
432 /* XXX as unlink/rmdir/mkdir/creat are not currently possible
433 * with HPFS, we don't need to check anything else for now */
440 hpfs_vptofh(struct vnode
*vp
, struct fid
*fhp
)
442 struct hpfsnode
*hpp
;
446 hpfhp
= (struct hpfid
*)fhp
;
447 hpfhp
->hpfid_len
= sizeof(struct hpfid
);
448 hpfhp
->hpfid_ino
= hpp
->h_no
;
449 /* hpfhp->hpfid_gen = hpp->h_gen; */
454 hpfs_vget(struct mount
*mp
, ino_t ino
, struct vnode
**vpp
)
456 struct hpfsmount
*hpmp
= VFSTOHPFS(mp
);
462 dprintf(("hpfs_vget(0x%x): ",ino
));
468 if ((*vpp
= hpfs_hphashvget(hpmp
->hpm_dev
, ino
)) != NULL
) {
469 dprintf(("hashed\n"));
474 * We have to lock node creation for a while,
475 * but then we have to call getnewvnode(),
476 * this may cause hpfs_reclaim() to be called,
477 * this may need to VOP_VGET() parent dir for
478 * update reasons, and if parent is not in
479 * hash, we have to lock node creation...
480 * To solve this, we MALLOC, getnewvnode and init while
481 * not locked (probability of node appearence
482 * at that time is little, and anyway - we'll
485 MALLOC(hp
, struct hpfsnode
*, sizeof(struct hpfsnode
),
488 error
= getnewvnode(VT_HPFS
, hpmp
->hpm_mp
, &vp
, VLKTIMEOUT
, 0);
490 kprintf("hpfs_vget: can't get new vnode\n");
495 dprintf(("prenew "));
499 if (ino
== (ino_t
)hpmp
->hpm_su
.su_rootfno
)
502 lwkt_token_init(&hp
->h_interlock
);
504 hp
->h_flag
= H_INVAL
;
508 hp
->h_dev
= hpmp
->hpm_dev
;
509 hp
->h_uid
= hpmp
->hpm_uid
;
510 hp
->h_gid
= hpmp
->hpm_uid
;
511 hp
->h_mode
= hpmp
->hpm_mode
;
512 hp
->h_devvp
= hpmp
->hpm_devvp
;
516 if ((*vpp
= hpfs_hphashvget(hpmp
->hpm_dev
, ino
)) != NULL
) {
517 dprintf(("hashed2\n"));
521 } while (LOCKMGR(&hpfs_hphash_lock
, LK_EXCLUSIVE
| LK_SLEEPFAIL
));
525 LOCKMGR(&hpfs_hphash_lock
, LK_RELEASE
);
527 error
= bread(hpmp
->hpm_devvp
, dbtodoff(ino
), FNODESIZE
, &bp
);
529 kprintf("hpfs_vget: can't read ino %"PRId64
"\n",ino
);
533 bcopy(bp
->b_data
, &hp
->h_fn
, sizeof(struct fnode
));
536 if (hp
->h_fn
.fn_magic
!= FN_MAGIC
) {
537 kprintf("hpfs_vget: MAGIC DOESN'T MATCH\n");
542 vp
->v_type
= hp
->h_fn
.fn_flag
? VDIR
:VREG
;
543 hp
->h_flag
&= ~H_INVAL
;
545 /* Return the locked and refd vnode */
551 static struct vfsops hpfs_vfsops
= {
552 .vfs_mount
= hpfs_mount
,
553 .vfs_unmount
= hpfs_unmount
,
554 .vfs_root
= hpfs_root
,
555 .vfs_statfs
= hpfs_statfs
,
556 .vfs_sync
= vfs_stdsync
,
557 .vfs_vget
= hpfs_vget
,
558 .vfs_fhtovp
= hpfs_fhtovp
,
559 .vfs_checkexp
= hpfs_checkexp
,
560 .vfs_vptofh
= hpfs_vptofh
,
561 .vfs_init
= hpfs_init
,
562 .vfs_uninit
= hpfs_hphash_uninit
565 VFS_SET(hpfs_vfsops
, hpfs
, 0);