2 * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 #include <sys/namei.h>
28 #include <sys/kernel.h>
29 #include <mach/machine/vm_types.h>
30 #include <sys/vnode.h>
31 #include <sys/socket.h>
32 #include <sys/mount_internal.h>
36 #include <sys/ioctl.h>
37 #include <sys/errno.h>
38 #include <sys/malloc.h>
41 #include <miscfs/specfs/specdev.h>
44 static int volfs_mount(struct mount
*, vnode_t
, user_addr_t
, vfs_context_t
);
45 static int volfs_start(struct mount
*, int, vfs_context_t
);
46 static int volfs_unmount(struct mount
*, int, vfs_context_t
);
47 static int volfs_root(struct mount
*, struct vnode
**, vfs_context_t
);
48 static int volfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t context
);
49 static int volfs_sync(struct mount
*, int, vfs_context_t
);
50 static int volfs_vget(struct mount
*, ino64_t
, struct vnode
**, vfs_context_t
);
51 static int volfs_fhtovp(struct mount
*, int, unsigned char *, struct vnode
**, vfs_context_t
);
52 static int volfs_vptofh(struct vnode
*, int *, unsigned char *, vfs_context_t
);
53 static int volfs_init(struct vfsconf
*);
54 static int volfs_sysctl(int *, u_int
, user_addr_t
, size_t *, user_addr_t
, size_t, vfs_context_t
);
55 void volfs_load(int loadArgument
);
58 struct vfsops volfs_vfsops
= {
73 // static char volfs_fs_name[MFSNAMELEN] = "volfs";
74 extern struct vnodeopv_desc volfs_vnodeop_opv_desc
;
76 extern int (**volfs_vnodeop_p
)(void *);
78 /* The following refer to kernel global variables used in the loading/initialization: */
79 extern int vfs_opv_numops
; /* The total number of defined vnode operations */
83 volfs_load(__unused
int loadArgument
)
86 struct vfsconf
*vfsconflistentry
;
88 struct vfsconf
*newvfsconf
= NULL
;
89 struct vfsconf
*lastentry
= NULL
;
91 int (***opv_desc_vector_p
)();
92 int (**opv_desc_vector
)();
93 struct vnodeopv_entry_desc
*opve_descp
;
96 * This routine is responsible for all the initialization that would
97 * ordinarily be done as part of the system startup; it calls volfs_init
98 * to do the initialization that is strictly volfs-specific.
102 prevvfsconf is supposed to be the entry preceding the new entry.
103 To make sure we can always get hooked in SOMEWHERE in the list,
104 start it out at the first entry of the list. This assumes the
105 first entry in the list will be non-empty and not volfs.
107 This becomes irrelevant when volfs is compiled into the list.
109 vfsconflistentry
= vfsconf
;
110 for (entriesRemaining
= maxvfsslots
; entriesRemaining
> 0; --entriesRemaining
) {
111 if (vfsconflistentry
->vfc_vfsops
!= NULL
) {
113 * Check to see if we're reloading a new version of volfs during debugging
114 * and overwrite the previously assigned entry if we find one:
116 if (strcmp(vfsconflistentry
->vfc_name
, volfs_fs_name
) == 0) {
117 newvfsconf
= vfsconflistentry
;
120 lastentry
= vfsconflistentry
;
124 * This is at least a POSSIBLE place to insert the new entry...
126 newvfsconf
= vfsconflistentry
;
132 newvfsconf
->vfc_vfsops
= &volfs_vfsops
;
133 strncpy(&newvfsconf
->vfc_name
[0], "volfs", MFSNAMELEN
);
134 newvfsconf
->vfc_typenum
= maxvfsconf
++;
135 newvfsconf
->vfc_refcount
= 0;
136 newvfsconf
->vfc_flags
= 0;
137 newvfsconf
->vfc_mountroot
= NULL
; /* Can't mount root of file system [yet] */
139 /* Hook into the list: */
140 newvfsconf
->vfc_next
= NULL
;
142 newvfsconf
->vfc_next
= lastentry
->vfc_next
;
143 lastentry
->vfc_next
= newvfsconf
;
146 /* Based on vfs_op_init and ... */
147 opv_desc_vector_p
= volfs_vnodeop_opv_desc
.opv_desc_vector_p
;
150 * Allocate and init the vector.
151 * Also handle backwards compatibility.
153 MALLOC(*opv_desc_vector_p
, PFI
*, vfs_opv_numops
*sizeof(PFI
), M_TEMP
, M_WAITOK
);
155 bzero (*opv_desc_vector_p
, vfs_opv_numops
*sizeof(PFI
));
157 opv_desc_vector
= *opv_desc_vector_p
;
158 for (j
=0; volfs_vnodeop_opv_desc
.opv_desc_ops
[j
].opve_op
; j
++) {
159 opve_descp
= &(volfs_vnodeop_opv_desc
.opv_desc_ops
[j
]);
162 * Sanity check: is this operation listed
163 * in the list of operations? We check this
164 * by seeing if its offest is zero. Since
165 * the default routine should always be listed
166 * first, it should be the only one with a zero
167 * offset. Any other operation with a zero
168 * offset is probably not listed in
169 * vfs_op_descs, and so is probably an error.
171 * A panic here means the layer programmer
172 * has committed the all-too common bug
173 * of adding a new operation to the layer's
174 * list of vnode operations but
175 * not adding the operation to the system-wide
176 * list of supported operations.
178 if (opve_descp
->opve_op
->vdesc_offset
== 0 &&
179 opve_descp
->opve_op
->vdesc_offset
!= VOFFSET(vnop_default
)) {
180 panic ("load_volfs: bad operation");
183 * Fill in this entry.
185 opv_desc_vector
[opve_descp
->opve_op
->vdesc_offset
] =
186 opve_descp
->opve_impl
;
190 * Finally, go back and replace unfilled routines
191 * with their default. (Sigh, an O(n^3) algorithm. I
192 * could make it better, but that'd be work, and n is small.)
194 opv_desc_vector_p
= volfs_vnodeop_opv_desc
.opv_desc_vector_p
;
197 * Force every operations vector to have a default routine.
199 opv_desc_vector
= *opv_desc_vector_p
;
200 if (opv_desc_vector
[VOFFSET(vnop_default
)]==NULL
) {
201 panic("load_vp;fs: operation vector without default routine.");
203 for (j
= 0;j
<vfs_opv_numops
; j
++)
204 if (opv_desc_vector
[j
] == NULL
)
206 opv_desc_vector
[VOFFSET(vnop_default
)];
208 volfs_init(newvfsconf
);
211 panic("volfs load not ported");
221 volfs_mount(struct mount
*mp
, __unused vnode_t devvp
, __unused user_addr_t data
, __unused vfs_context_t context
)
223 struct volfs_mntdata
*priv_mnt_data
;
224 struct vnode
*root_vp
;
225 struct volfs_vndata
*priv_vn_data
;
227 struct vnode_fsparam vfsp
;
229 MALLOC(priv_mnt_data
, struct volfs_mntdata
*, sizeof(struct volfs_mntdata
),
230 M_VOLFSMNT
, M_WAITOK
);
232 mp
->mnt_data
= (void *)priv_mnt_data
;
233 strcpy(mp
->mnt_vfsstat
.f_fstypename
, "volfs");
234 strcpy(mp
->mnt_vfsstat
.f_mntfromname
, "<volfs>");
236 /* Set up the root vnode for fast reference in the future.
237 Note that the root is maintained unlocked but with a pos. ref count until unmount. */
239 MALLOC(priv_vn_data
, struct volfs_vndata
*, sizeof(struct volfs_vndata
), M_VOLFSNODE
, M_WAITOK
);
241 priv_vn_data
->vnode_type
= VOLFS_ROOT
;
242 priv_vn_data
->nodeID
= ROOT_DIRID
;
243 priv_vn_data
->fs_mount
= mp
;
244 priv_vn_data
->fs_fsid
= mp
->mnt_vfsstat
.f_fsid
;
247 vfsp
.vnfs_vtype
= VDIR
;
248 vfsp
.vnfs_str
= "volfs";
250 vfsp
.vnfs_fsnode
= priv_vn_data
;
252 vfsp
.vnfs_vops
= volfs_vnodeop_p
;
254 vfsp
.vnfs_filesize
= 0;
255 vfsp
.vnfs_flags
= VNFS_NOCACHE
| VNFS_CANTCACHE
;
256 vfsp
.vnfs_marksystem
= 0;
257 vfsp
.vnfs_markroot
= 1;
259 error
= vnode_create(VNCREATE_FLAVOR
, VCREATESIZE
, &vfsp
, &root_vp
);
261 FREE(priv_mnt_data
, M_VOLFSMNT
);
262 FREE(priv_vn_data
, M_VOLFSNODE
);
268 /* obtain a new fsid for the mount point */
271 vnode_settag(root_vp
, VT_VOLFS
);
273 priv_mnt_data
->volfs_rootvp
= root_vp
;
274 mp
->mnt_flag
&= ~MNT_RDONLY
;
276 mp
->mnt_vtable
->vfc_threadsafe
= TRUE
;
282 volfs_start(__unused
struct mount
* mp
, __unused
int flags
, __unused vfs_context_t context
)
288 * Return the root of a filesystem. For volfs the root vnode is a directory
289 * containing the list of all filesystems volfs can work with.
292 volfs_root(struct mount
*mp
, struct vnode
**vpp
, __unused vfs_context_t context
)
294 struct volfs_mntdata
*priv_data
;
296 priv_data
= (struct volfs_mntdata
*)mp
->mnt_data
;
298 if (priv_data
->volfs_rootvp
) {
299 vnode_get(priv_data
->volfs_rootvp
);
300 *vpp
= priv_data
->volfs_rootvp
;
302 panic("volfs: root vnode missing!");
309 * unmount system call
312 volfs_unmount(struct mount
*mp
, __unused
int mntflags
, __unused vfs_context_t context
)
314 struct volfs_mntdata
*priv_data
;
315 struct vnode
*root_vp
;
318 priv_data
= (struct volfs_mntdata
*)mp
->mnt_data
;
320 root_vp
= priv_data
->volfs_rootvp
;
321 retval
= vflush(mp
, root_vp
, 0);
322 if (retval
) goto Err_Exit
;
324 /* Free the root vnode.
325 Note that there's no need to vget() or vref() it before locking it here:
326 the ref. count has been maintained at +1 ever since mount time. */
328 if (vnode_isinuse(root_vp
, 1)) {
333 priv_data
->volfs_rootvp
= NULL
;
334 vnode_rele(root_vp
); /* This drops volfs's own refcount */
335 vnode_reclaim(root_vp
);
338 /* All vnodes should be gone, and no errors, clean up the last */
341 FREE(priv_data
, M_VOLFSMNT
);
349 * Get file system statistics.
352 volfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t context
)
354 VFSATTR_RETURN(fsap
, f_bsize
, 512);
355 VFSATTR_RETURN(fsap
, f_iosize
, 512);
356 VFSATTR_RETURN(fsap
, f_blocks
, 1024);
357 VFSATTR_RETURN(fsap
, f_bfree
, 0);
358 VFSATTR_RETURN(fsap
, f_bavail
, 0);
359 VFSATTR_RETURN(fsap
, f_bused
, 1024);
360 VFSATTR_RETURN(fsap
, f_files
, 0);
361 VFSATTR_RETURN(fsap
, f_ffree
, 0);
362 VFSATTR_RETURN(fsap
, f_fssubtype
, 0);
367 * volfs doesn't have any data and you can't write into any of the volfs
368 * structures, so don't do anything
371 volfs_sync(__unused
struct mount
*mp
, __unused
int waitfor
, __unused vfs_context_t context
)
380 volfs_vget(__unused
struct mount
*mp
, __unused ino64_t ino
,
381 __unused
struct vnode
**vpp
, __unused vfs_context_t context
)
387 * File handle to vnode
390 volfs_fhtovp(__unused
struct mount
*mp
, __unused
int fhlen
,
391 __unused
unsigned char *fhp
, __unused
struct vnode
**vpp
,
392 __unused vfs_context_t context
)
398 * Vnode pointer to File handle
401 volfs_vptofh(__unused
struct vnode
*vp
, __unused
int *fhlenp
, __unused
unsigned char *fhp
, __unused vfs_context_t context
)
407 * Initialize the filesystem
410 volfs_init(__unused
struct vfsconf
*vfsp
)
416 * fast filesystem related variables.
419 volfs_sysctl(__unused
int *name
, __unused u_int namelen
, __unused user_addr_t oldp
,
420 __unused
size_t *oldlenp
, __unused user_addr_t newp
, __unused
size_t newlen
,
421 __unused vfs_context_t context
)