1 /* $NetBSD: filecore_vfsops.c,v 1.60 2009/06/29 05:08:17 dholland Exp $ */
4 * Copyright (c) 1994 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * filecore_vfsops.c 1.1 1998/6/26
35 * Copyright (c) 1998 Andrew McMurry
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * filecore_vfsops.c 1.1 1998/6/26
68 #include <sys/cdefs.h>
69 __KERNEL_RCSID(0, "$NetBSD: filecore_vfsops.c,v 1.60 2009/06/29 05:08:17 dholland Exp $");
71 #if defined(_KERNEL_OPT)
72 #include "opt_compat_netbsd.h"
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/namei.h>
79 #include <sys/vnode.h>
80 #include <miscfs/genfs/genfs.h>
81 #include <miscfs/specfs/specdev.h>
82 #include <sys/mount.h>
85 #include <sys/device.h>
86 #include <sys/errno.h>
87 #include <sys/malloc.h>
90 #include <sys/sysctl.h>
91 #include <sys/kauth.h>
92 #include <sys/module.h>
94 #include <fs/filecorefs/filecore.h>
95 #include <fs/filecorefs/filecore_extern.h>
96 #include <fs/filecorefs/filecore_node.h>
97 #include <fs/filecorefs/filecore_mount.h>
99 MODULE(MODULE_CLASS_VFS
, filecorefs
, NULL
);
101 MALLOC_JUSTDEFINE(M_FILECOREMNT
,
102 "filecore mount", "Filecore FS mount structures");
103 MALLOC_JUSTDEFINE(M_FILECORETMP
,
104 "filecore temp", "Filecore FS temporary structures");
106 static struct sysctllog
*filecore_sysctl_log
;
108 extern const struct vnodeopv_desc filecore_vnodeop_opv_desc
;
110 const struct vnodeopv_desc
* const filecore_vnodeopv_descs
[] = {
111 &filecore_vnodeop_opv_desc
,
115 struct vfsops filecore_vfsops
= {
117 sizeof (struct filecore_args
),
122 (void *)eopnotsupp
, /* vfs_quotactl */
131 NULL
, /* filecore_mountroot */
132 (int (*)(struct mount
*, struct vnode
*, struct timespec
*)) eopnotsupp
,
134 (void *)eopnotsupp
, /* vfs_suspendctl */
135 genfs_renamelock_enter
,
136 genfs_renamelock_exit
,
138 filecore_vnodeopv_descs
,
143 static const struct genfs_ops filecore_genfsops
= {
144 .gop_size
= genfs_size
,
148 filecorefs_modcmd(modcmd_t cmd
, void *arg
)
153 case MODULE_CMD_INIT
:
154 error
= vfs_attach(&filecore_vfsops
);
157 sysctl_createv(&filecore_sysctl_log
, 0, NULL
, NULL
,
159 CTLTYPE_NODE
, "vfs", NULL
,
162 sysctl_createv(&filecore_sysctl_log
, 0, NULL
, NULL
,
164 CTLTYPE_NODE
, "filecore",
165 SYSCTL_DESCR("Acorn FILECORE file system"),
167 CTL_VFS
, 19, CTL_EOL
);
169 * XXX the "19" above could be dynamic, thereby eliminating
170 * one more instance of the "number to vfs" mapping problem,
171 * but "19" is the order as taken from sys/mount.h
174 case MODULE_CMD_FINI
:
175 error
= vfs_detach(&filecore_vfsops
);
178 sysctl_teardown(&filecore_sysctl_log
);
189 * Called by vfs_mountroot when iso is going to be mounted as root.
191 * Name is updated by mount(8) after booting.
194 static int filecore_mountfs(struct vnode
*devvp
, struct mount
*mp
,
195 struct lwp
*l
, struct filecore_args
*argp
);
199 filecore_mountroot(void)
202 extern struct vnode
*rootvp
;
203 struct proc
*p
= curproc
; /* XXX */
205 struct filecore_args args
;
207 if (device_class(root_device
) != DV_DISK
)
211 * Get vnodes for swapdev and rootdev.
213 if (bdevvp(rootdev
, &rootvp
))
214 panic("filecore_mountroot: can't setup rootvp");
216 if ((error
= vfs_rootmountalloc(MOUNT_FILECORE
, "root_device", &mp
)) != 0)
219 args
.flags
= FILECOREMNT_ROOT
;
220 if ((error
= filecore_mountfs(rootvp
, mp
, p
, &args
)) != 0) {
221 vfs_unbusy(mp
, false, NULL
);
225 simple_lock(&mountlist_slock
);
226 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
227 simple_unlock(&mountlist_slock
);
228 (void)filecore_statvfs(mp
, &mp
->mnt_stat
, p
);
229 vfs_unbusy(mp
, false, NULL
);
240 filecore_mount(struct mount
*mp
, const char *path
, void *data
, size_t *data_len
)
242 struct lwp
*l
= curlwp
;
244 struct filecore_args
*args
= data
;
246 struct filecore_mnt
*fcmp
= NULL
;
248 if (*data_len
< sizeof *args
)
251 if (mp
->mnt_flag
& MNT_GETARGS
) {
252 fcmp
= VFSTOFILECORE(mp
);
255 args
->flags
= fcmp
->fc_mntflags
;
256 args
->uid
= fcmp
->fc_uid
;
257 args
->gid
= fcmp
->fc_gid
;
259 *data_len
= sizeof *args
;
263 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
266 if ((mp
->mnt_flag
& MNT_UPDATE
) && args
->fspec
== NULL
)
270 * Not an update, or updating the name: look up the name
271 * and verify that it refers to a sensible block device.
273 error
= namei_simple_user(args
->fspec
,
274 NSM_FOLLOW_NOEMULROOT
, &devvp
);
278 if (devvp
->v_type
!= VBLK
) {
282 if (bdevsw_lookup(devvp
->v_rdev
) == NULL
) {
287 * If mount by non-root, then verify that user has necessary
288 * permissions on the device.
290 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
291 error
= genfs_can_mount(devvp
, VREAD
, l
->l_cred
);
292 VOP_UNLOCK(devvp
, 0);
297 if ((mp
->mnt_flag
& MNT_UPDATE
) == 0)
298 error
= filecore_mountfs(devvp
, mp
, l
, args
);
300 if (devvp
!= fcmp
->fc_devvp
)
301 error
= EINVAL
; /* needs translation */
309 fcmp
= VFSTOFILECORE(mp
);
310 return set_statvfs_info(path
, UIO_USERSPACE
, args
->fspec
, UIO_USERSPACE
,
311 mp
->mnt_op
->vfs_name
, mp
, l
);
315 * Common code for mount and mountroot
318 filecore_mountfs(struct vnode
*devvp
, struct mount
*mp
, struct lwp
*l
, struct filecore_args
*argp
)
320 struct filecore_mnt
*fcmp
= (struct filecore_mnt
*)0;
321 struct buf
*bp
= NULL
;
322 dev_t dev
= devvp
->v_rdev
;
324 int ronly
= (mp
->mnt_flag
& MNT_RDONLY
) != 0;
325 struct filecore_disc_record
*fcdr
;
327 unsigned log2secsize
;
332 if ((error
= vinvalbuf(devvp
, V_SAVE
, l
->l_cred
, l
, 0, 0)) != 0)
335 error
= VOP_OPEN(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, FSCRED
);
339 /* Read the filecore boot block to check FS validity and to find the map */
340 error
= bread(devvp
, FILECORE_BOOTBLOCK_BLKN
,
341 FILECORE_BOOTBLOCK_SIZE
, NOCRED
, 0, &bp
);
342 #ifdef FILECORE_DEBUG_BR
343 printf("bread(%p, %x, %d, CRED, %p)=%d\n", devvp
,
344 FILECORE_BOOTBLOCK_BLKN
, FILECORE_BOOTBLOCK_SIZE
,
351 if (filecore_bbchecksum(bp
->b_data
) != 0) {
355 fcdr
= (struct filecore_disc_record
*)((char *)(bp
->b_data
) +
356 FILECORE_BB_DISCREC
);
357 map
= ((((8 << fcdr
->log2secsize
) - fcdr
->zone_spare
)
358 * (fcdr
->nzones
/ 2) - 8 * FILECORE_DISCREC_SIZE
)
359 << fcdr
->log2bpmb
) >> fcdr
->log2secsize
;
360 log2secsize
= fcdr
->log2secsize
;
361 #ifdef FILECORE_DEBUG_BR
362 printf("brelse(%p) vf1\n", bp
);
367 /* Read the bootblock in the map */
368 error
= bread(devvp
, map
, 1 << log2secsize
, NOCRED
, 0, &bp
);
369 #ifdef FILECORE_DEBUG_BR
370 printf("bread(%p, %x, %d, CRED, %p)=%d\n", devvp
,
371 map
, 1 << log2secsize
, bp
, error
);
375 fcdr
= (struct filecore_disc_record
*)((char *)(bp
->b_data
) + 4);
376 fcmp
= malloc(sizeof *fcmp
, M_FILECOREMNT
, M_WAITOK
);
377 memset(fcmp
, 0, sizeof *fcmp
);
378 if (fcdr
->log2bpmb
> fcdr
->log2secsize
)
379 fcmp
->log2bsize
= fcdr
->log2bpmb
;
380 else fcmp
->log2bsize
= fcdr
->log2secsize
;
381 fcmp
->blksize
= 1 << fcmp
->log2bsize
;
382 memcpy(&fcmp
->drec
, fcdr
, sizeof(*fcdr
));
384 fcmp
->idspz
= ((8 << fcdr
->log2secsize
) - fcdr
->zone_spare
)
386 fcmp
->mask
= (1 << fcdr
->idlen
) - 1;
387 if (fcdr
->big_flag
& 1) {
388 fcmp
->nblks
= ((((u_int64_t
)fcdr
->disc_size_2
) << 32)
389 + fcdr
->disc_size
) / fcmp
->blksize
;
391 fcmp
->nblks
=fcdr
->disc_size
/ fcmp
->blksize
;
394 #ifdef FILECORE_DEBUG_BR
395 printf("brelse(%p) vf2\n", bp
);
401 mp
->mnt_stat
.f_fsidx
.__fsid_val
[0] = (long)dev
;
402 mp
->mnt_stat
.f_fsidx
.__fsid_val
[1] = makefstype(MOUNT_FILECORE
);
403 mp
->mnt_stat
.f_fsid
= mp
->mnt_stat
.f_fsidx
.__fsid_val
[0];
404 mp
->mnt_stat
.f_namemax
= 10;
405 mp
->mnt_flag
|= MNT_LOCAL
;
406 mp
->mnt_dev_bshift
= fcdr
->log2secsize
;
407 mp
->mnt_fs_bshift
= fcmp
->log2bsize
;
409 fcmp
->fc_mountp
= mp
;
411 fcmp
->fc_devvp
= devvp
;
412 fcmp
->fc_mntflags
= argp
->flags
;
413 if (argp
->flags
& FILECOREMNT_USEUID
) {
414 fcmp
->fc_uid
= kauth_cred_getuid(l
->l_cred
);
415 fcmp
->fc_gid
= kauth_cred_getgid(l
->l_cred
);
417 fcmp
->fc_uid
= argp
->uid
;
418 fcmp
->fc_gid
= argp
->gid
;
424 #ifdef FILECORE_DEBUG_BR
425 printf("brelse(%p) vf3\n", bp
);
429 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
430 (void)VOP_CLOSE(devvp
, ronly
? FREAD
: FREAD
|FWRITE
, NOCRED
);
431 VOP_UNLOCK(devvp
, 0);
436 * Make a filesystem operational.
437 * Nothing to do at the moment.
441 filecore_start(struct mount
*mp
, int flags
)
447 * unmount system call
450 filecore_unmount(struct mount
*mp
, int mntflags
)
452 struct filecore_mnt
*fcmp
;
453 int error
, flags
= 0;
455 if (mntflags
& MNT_FORCE
)
457 if ((error
= vflush(mp
, NULLVP
, flags
)) != 0)
460 fcmp
= VFSTOFILECORE(mp
);
462 if (fcmp
->fc_devvp
->v_type
!= VBAD
)
463 fcmp
->fc_devvp
->v_specmountpoint
= NULL
;
464 vn_lock(fcmp
->fc_devvp
, LK_EXCLUSIVE
| LK_RETRY
);
465 error
= VOP_CLOSE(fcmp
->fc_devvp
, FREAD
, NOCRED
);
466 vput(fcmp
->fc_devvp
);
467 free(fcmp
, M_FILECOREMNT
);
469 mp
->mnt_flag
&= ~MNT_LOCAL
;
474 * Return root of a filesystem
477 filecore_root(struct mount
*mp
, struct vnode
**vpp
)
482 if ((error
= VFS_VGET(mp
, FILECORE_ROOTINO
, &nvp
)) != 0)
489 * Get file system statistics.
492 filecore_statvfs(struct mount
*mp
, struct statvfs
*sbp
)
494 struct filecore_mnt
*fcmp
= VFSTOFILECORE(mp
);
496 sbp
->f_bsize
= fcmp
->blksize
;
497 sbp
->f_frsize
= sbp
->f_bsize
; /* XXX */
498 sbp
->f_iosize
= sbp
->f_bsize
; /* XXX */
499 sbp
->f_blocks
= fcmp
->nblks
;
500 sbp
->f_bfree
= 0; /* total free blocks */
501 sbp
->f_bavail
= 0; /* blocks free for non superuser */
502 sbp
->f_bresvd
= 0; /* reserved blocks */
503 sbp
->f_files
= 0; /* total files */
504 sbp
->f_ffree
= 0; /* free file nodes for non superuser */
505 sbp
->f_favail
= 0; /* free file nodes */
506 sbp
->f_fresvd
= 0; /* reserved file nodes */
507 copy_statvfs_info(sbp
, mp
);
513 filecore_sync(struct mount
*mp
, int waitfor
, kauth_cred_t cred
)
519 * File handle to vnode
521 * Have to be really careful about stale file handles:
522 * - check that the inode number is in range
523 * - call iget() to get the locked inode
524 * - check for an unallocated inode (i_mode == 0)
525 * - check that the generation number matches
536 filecore_fhtovp(struct mount
*mp
, struct fid
*fhp
, struct vnode
**vpp
)
540 struct filecore_node
*ip
;
543 if (fhp
->fid_len
!= sizeof(struct ifid
))
546 memcpy(&ifh
, fhp
, sizeof(ifh
));
547 if ((error
= VFS_VGET(mp
, ifh
.ifid_ino
, &nvp
)) != 0) {
552 if (filecore_staleinode(ip
)) {
561 /* This looks complicated. Look at other vgets as well as the iso9660 one.
563 * The filecore inode number is made up of 1 byte directory entry index and
564 * 3 bytes of the internal disc address of the directory. On a read-only
565 * filesystem this is unique. For a read-write version we may not be able to
566 * do vget, see msdosfs.
570 filecore_vget(struct mount
*mp
, ino_t ino
, struct vnode
**vpp
)
572 struct filecore_mnt
*fcmp
;
573 struct filecore_node
*ip
;
579 fcmp
= VFSTOFILECORE(mp
);
581 if ((*vpp
= filecore_ihashget(dev
, ino
)) != NULLVP
)
584 /* Allocate a new vnode/filecore_node. */
585 if ((error
= getnewvnode(VT_FILECORE
, mp
, filecore_vnodeop_p
, &vp
))
590 ip
= pool_get(&filecore_node_pool
, PR_WAITOK
);
591 memset(ip
, 0, sizeof(struct filecore_node
));
598 genfs_node_init(vp
, &filecore_genfsops
);
601 * Put it onto its hash chain and lock it so that other requests for
602 * this inode will block if they arrive while we are sleeping waiting
603 * for old data structures to be purged or for the contents of the
604 * disk portion of this inode to be read.
606 filecore_ihashins(ip
);
608 if (ino
== FILECORE_ROOTINO
) {
609 /* Here we need to construct a root directory inode */
610 memcpy(ip
->i_dirent
.name
, "root", 4);
611 ip
->i_dirent
.load
= 0;
612 ip
->i_dirent
.exec
= 0;
613 ip
->i_dirent
.len
= FILECORE_DIR_SIZE
;
614 ip
->i_dirent
.addr
= fcmp
->drec
.root
;
615 ip
->i_dirent
.attr
= FILECORE_ATTR_DIR
| FILECORE_ATTR_READ
;
618 /* Read in Data from Directory Entry */
619 if ((error
= filecore_bread(fcmp
, ino
& FILECORE_INO_MASK
,
620 FILECORE_DIR_SIZE
, NOCRED
, &bp
)) != 0) {
622 #ifdef FILECORE_DEBUG_BR
623 printf("brelse(%p) vf4\n", bp
);
630 memcpy(&ip
->i_dirent
,
631 fcdirentry(bp
->b_data
, ino
>> FILECORE_INO_INDEX
),
632 sizeof(struct filecore_direntry
));
633 #ifdef FILECORE_DEBUG_BR
634 printf("brelse(%p) vf5\n", bp
);
640 ip
->i_devvp
= fcmp
->fc_devvp
;
648 if (ip
->i_dirent
.attr
& FILECORE_ATTR_DIR
)
652 * Initialize the associated vnode
654 switch (vp
->v_type
) {
659 * Devices not supported.
672 if (ino
== FILECORE_ROOTINO
)
673 vp
->v_vflag
|= VV_ROOT
;
676 * XXX need generation number?
679 uvm_vnp_setsize(vp
, ip
->i_size
);
685 * Vnode pointer to File handle
689 filecore_vptofh(struct vnode
*vp
, struct fid
*fhp
, size_t *fh_size
)
691 struct filecore_node
*ip
= VTOI(vp
);
694 if (*fh_size
< sizeof(struct ifid
)) {
695 *fh_size
= sizeof(struct ifid
);
698 memset(&ifh
, 0, sizeof(ifh
));
699 ifh
.ifid_len
= sizeof(struct ifid
);
700 ifh
.ifid_ino
= ip
->i_number
;
701 memcpy(fhp
, &ifh
, sizeof(ifh
));