1 /* $NetBSD: v7fs_vfsops.c,v 1.12 2014/12/29 15:29:38 hannken Exp $ */
4 * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: v7fs_vfsops.c,v 1.12 2014/12/29 15:29:38 hannken Exp $");
34 #if defined _KERNEL_OPT
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
43 #include <sys/ucred.h>
44 #include <sys/mount.h>
46 #include <sys/device.h>
47 #include <sys/fcntl.h>
49 #include <sys/kauth.h>
53 #include <sys/namei.h>
54 #include <sys/vnode.h>
58 #include "v7fs_extern.h"
60 #include "v7fs_impl.h"
61 #include "v7fs_inode.h"
62 #include "v7fs_superblock.h"
64 #ifdef V7FS_VFSOPS_DEBUG
65 #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
67 #define DPRINTF(arg...) ((void)0)
70 struct pool v7fs_node_pool
;
72 static int v7fs_mountfs(struct vnode
*, struct mount
*, int);
73 static int v7fs_openfs(struct vnode
*, struct mount
*, struct lwp
*);
74 static void v7fs_closefs(struct vnode
*, struct mount
*);
75 static int is_v7fs_partition(struct vnode
*);
76 static enum vtype
v7fs_mode_to_vtype(v7fs_mode_t mode
);
79 v7fs_mount(struct mount
*mp
, const char *path
, void *data
, size_t *data_len
)
81 struct lwp
*l
= curlwp
;
82 struct v7fs_args
*args
= data
;
83 struct v7fs_mount
*v7fsmount
= (void *)mp
->mnt_data
;
84 struct vnode
*devvp
= NULL
;
86 bool update
= mp
->mnt_flag
& MNT_UPDATE
;
88 DPRINTF("mnt_flag=%x %s\n", mp
->mnt_flag
, update
? "update" : "");
92 if (*data_len
< sizeof(*args
))
95 if (mp
->mnt_flag
& MNT_GETARGS
) {
99 args
->endian
= v7fsmount
->core
->endian
;
100 *data_len
= sizeof(*args
);
104 DPRINTF("args->fspec=%s endian=%d\n", args
->fspec
, args
->endian
);
105 if (args
->fspec
== NULL
) {
110 if (args
->fspec
!= NULL
) {
111 /* Look up the name and verify that it's sane. */
112 error
= namei_simple_user(args
->fspec
,
113 NSM_FOLLOW_NOEMULROOT
, &devvp
);
116 DPRINTF("mount device=%lx\n", (long)devvp
->v_rdev
);
120 * Be sure this is a valid block device
122 if (devvp
->v_type
!= VBLK
)
124 else if (bdevsw_lookup(devvp
->v_rdev
) == NULL
)
129 * Be sure we're still naming the same device
130 * used for our initial mount
132 if (devvp
!= v7fsmount
->devvp
) {
133 DPRINTF("devvp %p != %p rootvp=%p\n", devvp
,
134 v7fsmount
->devvp
, rootvp
);
135 if (rootvp
== v7fsmount
->devvp
) {
147 * If mount by non-root, then verify that user has necessary
148 * permissions on the device.
150 * Permission to update a mount is checked higher, so here we presume
151 * updating the mount is okay (for example, as far as securelevel goes)
152 * which leaves us with the normal check.
155 int accessmode
= VREAD
;
157 (mp
->mnt_iflag
& IMNT_WANTRDWR
) != 0 :
158 (mp
->mnt_flag
& MNT_RDONLY
) == 0)
159 accessmode
|= VWRITE
;
160 error
= kauth_authorize_system(l
->l_cred
, KAUTH_SYSTEM_MOUNT
,
161 KAUTH_REQ_SYSTEM_MOUNT_DEVICE
, mp
, devvp
,
162 KAUTH_ARG(accessmode
));
171 if ((error
= v7fs_openfs(devvp
, mp
, l
))) {
176 if ((error
= v7fs_mountfs(devvp
, mp
, args
->endian
))) {
177 v7fs_closefs(devvp
, mp
);
183 } else if (mp
->mnt_flag
& MNT_RDONLY
) {
184 /* XXX: r/w -> read only */
187 return set_statvfs_info(path
, UIO_USERSPACE
, args
->fspec
, UIO_USERSPACE
,
188 mp
->mnt_op
->vfs_name
, mp
, l
);
192 is_v7fs_partition(struct vnode
*devvp
)
194 struct dkwedge_info dkw
;
197 if ((error
= getdiskinfo(devvp
, &dkw
)) != 0) {
198 DPRINTF("getdiskinfo=%d\n", error
);
201 DPRINTF("ptype=%s size=%" PRIu64
"\n", dkw
.dkw_ptype
, dkw
->dkw_size
);
203 return strcmp(dkw
.dkw_ptype
, DKW_PTYPE_V7
) == 0 ? 0 : EINVAL
;
207 v7fs_openfs(struct vnode
*devvp
, struct mount
*mp
, struct lwp
*l
)
209 kauth_cred_t cred
= l
->l_cred
;
214 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
215 if ((error
= vinvalbuf(devvp
, V_SAVE
, cred
, l
, 0, 0)))
218 /* Open block device */
220 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
223 if ((error
= VOP_OPEN(devvp
, oflags
, NOCRED
)) != 0) {
224 DPRINTF("VOP_OPEN=%d\n", error
);
228 return 0; /* lock held */
237 v7fs_closefs(struct vnode
*devvp
, struct mount
*mp
)
241 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
244 VOP_CLOSE(devvp
, oflags
, NOCRED
);
248 v7fs_mountfs(struct vnode
*devvp
, struct mount
*mp
, int endian
)
250 struct v7fs_mount
*v7fsmount
;
252 struct v7fs_mount_device mount
;
254 DPRINTF("%d\n",endian
);
256 v7fsmount
= kmem_zalloc(sizeof(*v7fsmount
), KM_SLEEP
);
257 if (v7fsmount
== NULL
) {
260 v7fsmount
->devvp
= devvp
;
261 v7fsmount
->mountp
= mp
;
263 mount
.device
.vnode
= devvp
;
264 mount
.endian
= endian
;
266 if ((error
= v7fs_io_init(&v7fsmount
->core
, &mount
, V7FS_BSIZE
))) {
269 struct v7fs_self
*fs
= v7fsmount
->core
;
271 if ((error
= v7fs_superblock_load(fs
))) {
276 mp
->mnt_data
= v7fsmount
;
277 mp
->mnt_stat
.f_fsidx
.__fsid_val
[0] = (long)devvp
->v_rdev
;
278 mp
->mnt_stat
.f_fsidx
.__fsid_val
[1] = makefstype(MOUNT_V7FS
);
279 mp
->mnt_stat
.f_fsid
= mp
->mnt_stat
.f_fsidx
.__fsid_val
[0];
280 mp
->mnt_stat
.f_namemax
= V7FS_NAME_MAX
;
281 mp
->mnt_flag
|= MNT_LOCAL
;
282 mp
->mnt_dev_bshift
= V7FS_BSHIFT
;
283 mp
->mnt_fs_bshift
= V7FS_BSHIFT
;
288 kmem_free(v7fsmount
, sizeof(*v7fsmount
));
293 v7fs_start(struct mount
*mp
, int flags
)
302 v7fs_unmount(struct mount
*mp
, int mntflags
)
304 struct v7fs_mount
*v7fsmount
= (void *)mp
->mnt_data
;
307 DPRINTF("%p\n", v7fsmount
);
309 if ((error
= vflush(mp
, NULLVP
,
310 mntflags
& MNT_FORCE
? FORCECLOSE
: 0)) != 0)
313 vn_lock(v7fsmount
->devvp
, LK_EXCLUSIVE
| LK_RETRY
);
314 error
= VOP_CLOSE(v7fsmount
->devvp
, FREAD
, NOCRED
);
315 vput(v7fsmount
->devvp
);
317 v7fs_io_fini(v7fsmount
->core
);
319 kmem_free(v7fsmount
, sizeof(*v7fsmount
));
321 mp
->mnt_flag
&= ~MNT_LOCAL
;
327 v7fs_root(struct mount
*mp
, struct vnode
**vpp
)
333 if ((error
= VFS_VGET(mp
, V7FS_ROOT_INODE
, &vp
)) != 0) {
334 DPRINTF("error=%d\n", error
);
344 v7fs_statvfs(struct mount
*mp
, struct statvfs
*f
)
346 struct v7fs_mount
*v7fsmount
= mp
->mnt_data
;
347 struct v7fs_self
*fs
= v7fsmount
->core
;
349 DPRINTF("scratch remain=%d\n", fs
->scratch_remain
);
351 v7fs_superblock_status(fs
);
353 f
->f_bsize
= V7FS_BSIZE
;
354 f
->f_frsize
= V7FS_BSIZE
;
355 f
->f_iosize
= V7FS_BSIZE
;
356 f
->f_blocks
= fs
->stat
.total_blocks
;
357 f
->f_bfree
= fs
->stat
.free_blocks
;
358 f
->f_bavail
= fs
->stat
.free_blocks
;
360 f
->f_files
= fs
->stat
.total_files
;
361 f
->f_ffree
= fs
->stat
.free_inode
;
362 f
->f_favail
= f
->f_ffree
;
364 copy_statvfs_info(f
, mp
);
370 v7fs_sync_selector(void *cl
, struct vnode
*vp
)
372 struct v7fs_node
*v7fs_node
= vp
->v_data
;
374 if (v7fs_node
== NULL
)
376 if (!v7fs_inode_allocated(&v7fs_node
->inode
))
383 v7fs_sync(struct mount
*mp
, int waitfor
, kauth_cred_t cred
)
385 struct v7fs_mount
*v7fsmount
= mp
->mnt_data
;
386 struct v7fs_self
*fs
= v7fsmount
->core
;
387 struct vnode_iterator
*marker
;
393 v7fs_superblock_writeback(fs
);
395 vfs_vnode_iterator_init(mp
, &marker
);
396 while ((vp
= vfs_vnode_iterator_next(marker
,
397 v7fs_sync_selector
, NULL
)) != NULL
) {
398 err
= vn_lock(vp
, LK_EXCLUSIVE
);
403 err
= VOP_FSYNC(vp
, cred
, FSYNC_WAIT
, 0, 0);
408 vfs_vnode_iterator_destroy(marker
);
414 v7fs_mode_to_vtype (v7fs_mode_t mode
)
416 enum vtype table
[] = { VCHR
, VDIR
, VBLK
, VREG
, VLNK
, VSOCK
};
418 if ((mode
& V7FS_IFMT
) == V7FSBSD_IFFIFO
)
421 return table
[((mode
>> 13) & 7) - 1];
425 v7fs_loadvnode(struct mount
*mp
, struct vnode
*vp
,
426 const void *key
, size_t key_len
, const void **new_key
)
428 struct v7fs_mount
*v7fsmount
;
429 struct v7fs_self
*fs
;
430 struct v7fs_node
*v7fs_node
;
431 struct v7fs_inode inode
;
435 KASSERT(key_len
== sizeof(number
));
436 memcpy(&number
, key
, key_len
);
438 v7fsmount
= mp
->mnt_data
;
439 fs
= v7fsmount
->core
;
441 /* Lookup requested i-node */
442 if ((error
= v7fs_inode_load(fs
, &inode
, number
))) {
443 DPRINTF("v7fs_inode_load failed.\n");
447 v7fs_node
= pool_get(&v7fs_node_pool
, PR_WAITOK
);
448 memset(v7fs_node
, 0, sizeof(*v7fs_node
));
451 vp
->v_data
= v7fs_node
;
452 v7fs_node
->vnode
= vp
;
453 v7fs_node
->v7fsmount
= v7fsmount
;
454 v7fs_node
->inode
= inode
;/*structure copy */
455 v7fs_node
->lockf
= NULL
; /* advlock */
457 genfs_node_init(vp
, &v7fs_genfsops
);
458 uvm_vnp_setsize(vp
, v7fs_inode_filesize(&inode
));
460 if (number
== V7FS_ROOT_INODE
) {
462 vp
->v_vflag
|= VV_ROOT
;
463 vp
->v_op
= v7fs_vnodeop_p
;
465 vp
->v_type
= v7fs_mode_to_vtype(inode
.mode
);
467 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) {
468 dev_t rdev
= inode
.device
;
469 vp
->v_op
= v7fs_specop_p
;
470 spec_node_init(vp
, rdev
);
471 } else if (vp
->v_type
== VFIFO
) {
472 vp
->v_op
= v7fs_fifoop_p
;
474 vp
->v_op
= v7fs_vnodeop_p
;
478 *new_key
= &v7fs_node
->inode
.inode_number
;
485 v7fs_vget(struct mount
*mp
, ino_t ino
, struct vnode
**vpp
)
491 KASSERT(ino
<= UINT16_MAX
);
494 error
= vcache_get(mp
, &number
, sizeof(number
), &vp
);
497 error
= vn_lock(vp
, LK_EXCLUSIVE
);
509 v7fs_fhtovp(struct mount
*mp
, struct fid
*fid
, struct vnode
**vpp
)
518 v7fs_vptofh(struct vnode
*vpp
, struct fid
*fid
, size_t *fh_size
)
531 pool_init(&v7fs_node_pool
, sizeof(struct v7fs_node
), 0, 0, 0,
532 "v7fs_node_pool", &pool_allocator_nointr
, IPL_NONE
);
548 pool_destroy(&v7fs_node_pool
);
552 v7fs_gop_alloc(struct vnode
*vp
, off_t off
, off_t len
, int flags
,
567 /* On mountroot, devvp (rootdev) is opened by vfs_mountroot */
568 if ((error
= is_v7fs_partition (rootvp
)))
571 if ((error
= vfs_rootmountalloc(MOUNT_V7FS
, "root_device", &mp
))) {
572 DPRINTF("mountalloc error=%d\n", error
);
577 if ((error
= v7fs_mountfs(rootvp
, mp
, _BYTE_ORDER
))) {
578 DPRINTF("mountfs error=%d\n", error
);
579 vfs_unbusy(mp
, false, NULL
);
584 mountlist_append(mp
);
586 vfs_unbusy(mp
, false, NULL
);