2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/namei.h>
35 #include <sys/kernel.h>
36 #include <mach/machine/vm_types.h>
37 #include <sys/vnode.h>
38 #include <sys/socket.h>
39 #include <sys/mount_internal.h>
43 #include <sys/ioctl.h>
44 #include <sys/errno.h>
45 #include <sys/malloc.h>
48 #include <miscfs/specfs/specdev.h>
51 static int volfs_mount(struct mount
*, vnode_t
, user_addr_t
, vfs_context_t
);
52 static int volfs_start(struct mount
*, int, vfs_context_t
);
53 static int volfs_unmount(struct mount
*, int, vfs_context_t
);
54 static int volfs_root(struct mount
*, struct vnode
**, vfs_context_t
);
55 static int volfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t context
);
56 static int volfs_sync(struct mount
*, int, vfs_context_t
);
57 static int volfs_vget(struct mount
*, ino64_t
, struct vnode
**, vfs_context_t
);
58 static int volfs_fhtovp(struct mount
*, int, unsigned char *, struct vnode
**, vfs_context_t
);
59 static int volfs_vptofh(struct vnode
*, int *, unsigned char *, vfs_context_t
);
60 static int volfs_init(struct vfsconf
*);
61 static int volfs_sysctl(int *, u_int
, user_addr_t
, size_t *, user_addr_t
, size_t, vfs_context_t
);
62 void volfs_load(int loadArgument
);
65 struct vfsops volfs_vfsops
= {
80 // static char volfs_fs_name[MFSNAMELEN] = "volfs";
81 extern struct vnodeopv_desc volfs_vnodeop_opv_desc
;
83 extern int (**volfs_vnodeop_p
)(void *);
85 /* The following refer to kernel global variables used in the loading/initialization: */
86 extern int vfs_opv_numops
; /* The total number of defined vnode operations */
90 volfs_load(__unused
int loadArgument
)
93 struct vfsconf
*vfsconflistentry
;
95 struct vfsconf
*newvfsconf
= NULL
;
96 struct vfsconf
*lastentry
= NULL
;
98 int (***opv_desc_vector_p
)();
99 int (**opv_desc_vector
)();
100 struct vnodeopv_entry_desc
*opve_descp
;
103 * This routine is responsible for all the initialization that would
104 * ordinarily be done as part of the system startup; it calls volfs_init
105 * to do the initialization that is strictly volfs-specific.
109 prevvfsconf is supposed to be the entry preceding the new entry.
110 To make sure we can always get hooked in SOMEWHERE in the list,
111 start it out at the first entry of the list. This assumes the
112 first entry in the list will be non-empty and not volfs.
114 This becomes irrelevant when volfs is compiled into the list.
116 vfsconflistentry
= vfsconf
;
117 for (entriesRemaining
= maxvfsslots
; entriesRemaining
> 0; --entriesRemaining
) {
118 if (vfsconflistentry
->vfc_vfsops
!= NULL
) {
120 * Check to see if we're reloading a new version of volfs during debugging
121 * and overwrite the previously assigned entry if we find one:
123 if (strcmp(vfsconflistentry
->vfc_name
, volfs_fs_name
) == 0) {
124 newvfsconf
= vfsconflistentry
;
127 lastentry
= vfsconflistentry
;
131 * This is at least a POSSIBLE place to insert the new entry...
133 newvfsconf
= vfsconflistentry
;
139 newvfsconf
->vfc_vfsops
= &volfs_vfsops
;
140 strncpy(&newvfsconf
->vfc_name
[0], "volfs", MFSNAMELEN
);
141 newvfsconf
->vfc_typenum
= maxvfsconf
++;
142 newvfsconf
->vfc_refcount
= 0;
143 newvfsconf
->vfc_flags
= 0;
144 newvfsconf
->vfc_mountroot
= NULL
; /* Can't mount root of file system [yet] */
146 /* Hook into the list: */
147 newvfsconf
->vfc_next
= NULL
;
149 newvfsconf
->vfc_next
= lastentry
->vfc_next
;
150 lastentry
->vfc_next
= newvfsconf
;
153 /* Based on vfs_op_init and ... */
154 opv_desc_vector_p
= volfs_vnodeop_opv_desc
.opv_desc_vector_p
;
157 * Allocate and init the vector.
158 * Also handle backwards compatibility.
160 MALLOC(*opv_desc_vector_p
, PFI
*, vfs_opv_numops
*sizeof(PFI
), M_TEMP
, M_WAITOK
);
162 bzero (*opv_desc_vector_p
, vfs_opv_numops
*sizeof(PFI
));
164 opv_desc_vector
= *opv_desc_vector_p
;
165 for (j
=0; volfs_vnodeop_opv_desc
.opv_desc_ops
[j
].opve_op
; j
++) {
166 opve_descp
= &(volfs_vnodeop_opv_desc
.opv_desc_ops
[j
]);
169 * Sanity check: is this operation listed
170 * in the list of operations? We check this
171 * by seeing if its offest is zero. Since
172 * the default routine should always be listed
173 * first, it should be the only one with a zero
174 * offset. Any other operation with a zero
175 * offset is probably not listed in
176 * vfs_op_descs, and so is probably an error.
178 * A panic here means the layer programmer
179 * has committed the all-too common bug
180 * of adding a new operation to the layer's
181 * list of vnode operations but
182 * not adding the operation to the system-wide
183 * list of supported operations.
185 if (opve_descp
->opve_op
->vdesc_offset
== 0 &&
186 opve_descp
->opve_op
->vdesc_offset
!= VOFFSET(vnop_default
)) {
187 panic ("load_volfs: bad operation");
190 * Fill in this entry.
192 opv_desc_vector
[opve_descp
->opve_op
->vdesc_offset
] =
193 opve_descp
->opve_impl
;
197 * Finally, go back and replace unfilled routines
198 * with their default. (Sigh, an O(n^3) algorithm. I
199 * could make it better, but that'd be work, and n is small.)
201 opv_desc_vector_p
= volfs_vnodeop_opv_desc
.opv_desc_vector_p
;
204 * Force every operations vector to have a default routine.
206 opv_desc_vector
= *opv_desc_vector_p
;
207 if (opv_desc_vector
[VOFFSET(vnop_default
)]==NULL
) {
208 panic("load_vp;fs: operation vector without default routine.");
210 for (j
= 0;j
<vfs_opv_numops
; j
++)
211 if (opv_desc_vector
[j
] == NULL
)
213 opv_desc_vector
[VOFFSET(vnop_default
)];
215 volfs_init(newvfsconf
);
218 panic("volfs load not ported");
228 volfs_mount(struct mount
*mp
, __unused vnode_t devvp
, __unused user_addr_t data
, __unused vfs_context_t context
)
230 struct volfs_mntdata
*priv_mnt_data
;
231 struct vnode
*root_vp
;
232 struct volfs_vndata
*priv_vn_data
;
234 struct vnode_fsparam vfsp
;
236 MALLOC(priv_mnt_data
, struct volfs_mntdata
*, sizeof(struct volfs_mntdata
),
237 M_VOLFSMNT
, M_WAITOK
);
239 mp
->mnt_data
= (void *)priv_mnt_data
;
240 strcpy(mp
->mnt_vfsstat
.f_fstypename
, "volfs");
241 strcpy(mp
->mnt_vfsstat
.f_mntfromname
, "<volfs>");
243 /* Set up the root vnode for fast reference in the future.
244 Note that the root is maintained unlocked but with a pos. ref count until unmount. */
246 MALLOC(priv_vn_data
, struct volfs_vndata
*, sizeof(struct volfs_vndata
), M_VOLFSNODE
, M_WAITOK
);
248 priv_vn_data
->vnode_type
= VOLFS_ROOT
;
249 priv_vn_data
->nodeID
= ROOT_DIRID
;
250 priv_vn_data
->fs_mount
= mp
;
251 priv_vn_data
->fs_fsid
= mp
->mnt_vfsstat
.f_fsid
;
254 vfsp
.vnfs_vtype
= VDIR
;
255 vfsp
.vnfs_str
= "volfs";
257 vfsp
.vnfs_fsnode
= priv_vn_data
;
259 vfsp
.vnfs_vops
= volfs_vnodeop_p
;
261 vfsp
.vnfs_filesize
= 0;
262 vfsp
.vnfs_flags
= VNFS_NOCACHE
| VNFS_CANTCACHE
;
263 vfsp
.vnfs_marksystem
= 0;
264 vfsp
.vnfs_markroot
= 1;
266 error
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, &root_vp
);
268 FREE(priv_mnt_data
, M_VOLFSMNT
);
269 FREE(priv_vn_data
, M_VOLFSNODE
);
275 /* obtain a new fsid for the mount point */
278 vnode_settag(root_vp
, VT_VOLFS
);
280 priv_mnt_data
->volfs_rootvp
= root_vp
;
281 mp
->mnt_flag
&= ~MNT_RDONLY
;
283 mp
->mnt_vtable
->vfc_threadsafe
= TRUE
;
289 volfs_start(__unused
struct mount
* mp
, __unused
int flags
, __unused vfs_context_t context
)
295 * Return the root of a filesystem. For volfs the root vnode is a directory
296 * containing the list of all filesystems volfs can work with.
299 volfs_root(struct mount
*mp
, struct vnode
**vpp
, __unused vfs_context_t context
)
301 struct volfs_mntdata
*priv_data
;
303 priv_data
= (struct volfs_mntdata
*)mp
->mnt_data
;
305 if (priv_data
->volfs_rootvp
) {
306 vnode_get(priv_data
->volfs_rootvp
);
307 *vpp
= priv_data
->volfs_rootvp
;
309 panic("volfs: root vnode missing!");
316 * unmount system call
319 volfs_unmount(struct mount
*mp
, __unused
int mntflags
, __unused vfs_context_t context
)
321 struct volfs_mntdata
*priv_data
;
322 struct vnode
*root_vp
;
325 priv_data
= (struct volfs_mntdata
*)mp
->mnt_data
;
327 root_vp
= priv_data
->volfs_rootvp
;
328 retval
= vflush(mp
, root_vp
, 0);
329 if (retval
) goto Err_Exit
;
331 /* Free the root vnode.
332 Note that there's no need to vget() or vref() it before locking it here:
333 the ref. count has been maintained at +1 ever since mount time. */
335 if (vnode_isinuse(root_vp
, 1)) {
340 priv_data
->volfs_rootvp
= NULL
;
341 vnode_rele(root_vp
); /* This drops volfs's own refcount */
342 vnode_reclaim(root_vp
);
345 /* All vnodes should be gone, and no errors, clean up the last */
348 FREE(priv_data
, M_VOLFSMNT
);
356 * Get file system statistics.
359 volfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t context
)
361 VFSATTR_RETURN(fsap
, f_bsize
, 512);
362 VFSATTR_RETURN(fsap
, f_iosize
, 512);
363 VFSATTR_RETURN(fsap
, f_blocks
, 1024);
364 VFSATTR_RETURN(fsap
, f_bfree
, 0);
365 VFSATTR_RETURN(fsap
, f_bavail
, 0);
366 VFSATTR_RETURN(fsap
, f_bused
, 1024);
367 VFSATTR_RETURN(fsap
, f_files
, 0);
368 VFSATTR_RETURN(fsap
, f_ffree
, 0);
369 VFSATTR_RETURN(fsap
, f_fssubtype
, 0);
374 * volfs doesn't have any data and you can't write into any of the volfs
375 * structures, so don't do anything
378 volfs_sync(__unused
struct mount
*mp
, __unused
int waitfor
, __unused vfs_context_t context
)
387 volfs_vget(__unused
struct mount
*mp
, __unused ino64_t ino
,
388 __unused
struct vnode
**vpp
, __unused vfs_context_t context
)
394 * File handle to vnode
397 volfs_fhtovp(__unused
struct mount
*mp
, __unused
int fhlen
,
398 __unused
unsigned char *fhp
, __unused
struct vnode
**vpp
,
399 __unused vfs_context_t context
)
405 * Vnode pointer to File handle
408 volfs_vptofh(__unused
struct vnode
*vp
, __unused
int *fhlenp
, __unused
unsigned char *fhp
, __unused vfs_context_t context
)
414 * Initialize the filesystem
417 volfs_init(__unused
struct vfsconf
*vfsp
)
423 * fast filesystem related variables.
426 volfs_sysctl(__unused
int *name
, __unused u_int namelen
, __unused user_addr_t oldp
,
427 __unused
size_t *oldlenp
, __unused user_addr_t newp
, __unused
size_t newlen
,
428 __unused vfs_context_t context
)