2 * Copyright (c) 2000-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@
30 /* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */
34 * 17-Aug-1999 Pat Dirks New today.
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/namei.h>
41 #include <sys/filedesc.h>
42 #include <sys/proc_internal.h>
43 #include <sys/kernel.h>
44 #include <mach/machine/vm_types.h>
45 #include <sys/vnode_internal.h>
46 #include <sys/socket.h>
47 #include <sys/mount_internal.h>
51 #include <sys/ioctl.h>
52 #include <sys/errno.h>
53 #include <sys/malloc.h>
55 #include <sys/uio_internal.h>
57 #include <miscfs/specfs/specdev.h>
65 struct vfsops synthfs_vfsops
= {
80 #define ROOTMPMODE 0755
81 #define ROOTPLACEHOLDERMODE 0700
82 static char synthfs_fs_name
[MFSTYPENAMELEN
] = "synthfs";
83 static char synthfs_fake_mntfromname
[] = "<synthfs>";
86 extern struct vnodeopv_desc synthfs_vnodeop_opv_desc
;
88 /* The following refer to kernel global variables used in the loading/initialization: */
89 extern int maxvfsslots
; /* Total number of slots in the system's vfsconf table */
90 extern int maxvfsconf
; /* The highest fs type number [old-style ID] in use [dispite its name] */
91 extern int vfs_opv_numops
; /* The total number of defined vnode operations */
93 int vn_mkdir(struct proc
*p
, char *path
, int mode
);
94 int vn_symlink(struct proc
*p
, char *path
, char *link
);
101 synthfs_load(int loadArgument
) {
102 /* Should use vfs_fsadd kpi */
107 int synthfs_unload(void) {
109 /* should use fs_fsremove kpi */
122 synthfs_mount_fs(struct mount
*mp
, vnode_t devvp
, __unused user_addr_t data
, struct proc
*p
)
124 struct synthfs_mntdata
*priv_mnt_data
;
128 DBG_VOP(("synthfs_mount_fs called.\n"));
129 MALLOC(priv_mnt_data
, struct synthfs_mntdata
*, sizeof(struct synthfs_mntdata
), M_SYNTHFS
, M_WAITOK
);
130 DBG_VOP(("MALLOC succeeded...\n"));
132 strncpy(mp
->mnt_vfsstat
.f_fstypename
, synthfs_fs_name
, sizeof(mp
->mnt_vfsstat
.f_fstypename
));
133 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, synthfs_fake_mntfromname
, sizeof(mp
->mnt_vfsstat
.f_mntfromname
));
134 priv_mnt_data
->synthfs_mounteddev
= (dev_t
)0;
135 priv_mnt_data
->synthfs_nextid
= FIRST_SYNTHFS_ID
;
136 priv_mnt_data
->synthfs_filecount
= 0;
137 priv_mnt_data
->synthfs_dircount
= 0;
138 priv_mnt_data
->synthfs_encodingsused
= 0x00000001;
141 Set up the root vnode for fast reference in the future.
142 Note that synthfs_new_directory() returns the vnode with a refcount of +2.
143 The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount.
145 error
= synthfs_new_directory(mp
, NULL
, "", ROOT_DIRID
, (S_IRWXU
|S_IRWXG
|S_IROTH
|S_IXOTH
), p
, &priv_mnt_data
->synthfs_rootvp
);
147 DBG_VOP(("Attempt to create root directory failed with error %d.\n", error
));
150 priv_mnt_data
->synthfs_rootvp
->v_flag
|= VROOT
;
152 priv_mnt_data
->synthfs_mp
= mp
;
153 mp
->mnt_data
= (void *)priv_mnt_data
;
155 /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent
156 the vnode from beeing freed: */
157 vnode_put(priv_mnt_data
->synthfs_rootvp
);
165 synthfs_mount(mp
, devvp
, data
, context
)
166 register struct mount
*mp
;
169 vfs_context_t context
;
173 return (synthfs_mount_fs(mp
, devvp
, data
, vfs_context_proc(context
)));
182 * Initialize the filesystem
186 struct vfsconf
*vfsp
;
188 DBG_VOP(("synthfs_init called.\n"));
193 synthfs_start(mp
, flags
, context
)
196 vfs_context_t context
;
198 DBG_VOP(("synthfs_start called.\n"));
203 * Return the root of a filesystem.
206 synthfs_root(mp
, vpp
, context
)
209 vfs_context_t context
;
211 unsigned long root_nodeid
= ROOT_DIRID
;
213 DBG_VOP(("synthfs_root called.\n"));
215 *vpp
= VFSTOSFS(mp
)->synthfs_rootvp
;
216 return vnode_get(VFSTOSFS(mp
)->synthfs_rootvp
);
220 * unmount system call
223 synthfs_unmount(mp
, mntflags
, context
)
226 vfs_context_t context
;
228 struct synthfs_mntdata
*synth
;
229 struct vnode
*root_vp
;
232 DBG_VOP(("synthfs_unmount called.\n"));
233 synth
= (struct synthfs_mntdata
*)mp
->mnt_data
;
235 root_vp
= synth
->synthfs_rootvp
;
236 retval
= vflush(mp
, root_vp
, (mntflags
& MNT_FORCE
) ? FORCECLOSE
: 0);
237 if (retval
&& ((mntflags
& MNT_FORCE
) == 0)) goto Err_Exit
;
239 /* Free the root vnode.
240 the ref. count has been maintained at +1 ever since mount time. */
242 if ((mntflags
& MNT_FORCE
) == 0) {
243 if (retval
) goto Err_Exit
;
245 if (root_vp
->v_usecount
> 1) {
246 DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp
, synth
->synthfs_rootvp
->v_usecount
));
252 synth
->synthfs_rootvp
= NULL
;
257 vnode_recycle(root_vp
);
258 vnode_put(root_vp
); /* This drops synthfs's own refcount */
262 /* All vnodes should be gone, and no errors, clean up the last */
265 FREE(synth
, M_SYNTHFS
);
269 if (mntflags
& MNT_FORCE
) retval
= 0;
275 * Get file system statistics.
278 synthfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t context
)
280 struct synthfs_mntdata
*synthfs_mp
= VFSTOSFS(mp
);
281 DBG_VOP(("synthfs_vfs_getattr called.\n"));
283 VFSATTR_RETURN(fsap
, f_bsize
, 512);
284 VFSATTR_RETURN(fsap
, f_iosize
, 512);
285 VFSATTR_RETURN(fsap
, f_blocks
, 1024);
286 VFSATTR_RETURN(fsap
, f_bfree
, 0);
287 VFSATTR_RETURN(fsap
, f_bavail
, 0);
288 VFSATTR_RETURN(fsap
, f_bused
, 1024);
289 VFSATTR_RETURN(fsap
, f_files
, synthfs_mp
->synthfs_filecount
+ synthfs_mp
->synthfs_dircount
);
290 VFSATTR_RETURN(fsap
, f_ffree
, 0);
291 VFSATTR_RETURN(fsap
, f_fssubtype
, 0);
297 * synthfs doesn't have any data or backing store and you can't write into any of the synthfs
298 * structures, so don't do anything
301 synthfs_sync(mp
, waitfor
, context
)
304 vfs_context_t context
;
306 // DBG_VOP(("synthfs_sync called\n"));
310 * Look up a synthfs node by node number.
313 synthfs_vget(mp
, ino
, vpp
, context
)
317 vfs_context_t context
;
322 // DBG_VOP(("synthfs_vget called\n"));
324 /* Check for unmount in progress */
325 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
331 TAILQ_FOREACH(vp
, &mp
->mnt_vnodelist
, v_mntvnodes
) {
332 if (VTOS(vp
)->s_nodeid
== (unsigned long)ino
) {
334 * doing a vnode_getwithvid isn't technically
335 * necessary since synthfs is an unsafe filesystem
336 * and we're running behind a funnel at this point
337 * however, vnode_get always succeeds, which isn't
338 * what we want if this vnode is in the process of
343 if (vnode_getwithvid(vp
, vid
) != 0) {
355 * fast filesystem related variables.
358 synthfs_sysctl(int *name
, u_int namelen
, user_addr_t oldp
, size_t *oldlenp
,
359 user_addr_t newp
, size_t newlen
, vfs_context_t context
)
361 DBG_VOP(("synthfs_sysctl called.\n"));
366 * File handle to vnode
370 synthfs_fhtovp(mp
, fhlen
, fhp
, vpp
, context
)
371 register struct mount
*mp
;
375 vfs_context_t context
;
377 DBG_VOP(("synthfs_fhtovp called.\n"));
382 * Vnode pointer to File handle
386 synthfs_vptofh(vp
, fhlenp
, fhp
, context
)
390 vfs_context_t context
;
392 DBG_VOP(("synthfs_vptofh called.\n"));
402 vn_mkdir(struct proc
*p
, char *path
, int mode
)
406 struct vnode_attr va
;
407 struct vfs_context context
;
411 context
.vc_ucred
= proc_ucred(p
); /* XXX kauth_cred_get() ??? proxy */
413 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(path
), &context
);
416 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error
));
423 VATTR_SET(&va
, va_type
, VDIR
);
424 VATTR_SET(&va
, va_mode
, (mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
);
426 error
= vn_create(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
, 0, &context
);
428 DBG_VOP(("vn_mkdir: error from vnop_mkdir (%d).\n", error
));
430 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
433 vnode_put(nd
.ni_dvp
);
444 vn_symlink(struct proc
*p
, char *path
, char *link
) {
446 struct vnode_attr va
;
447 struct vfs_context context
;
451 context
.vc_ucred
= proc_ucred(p
); /* XXX kauth_cred_get() ??? proxy */
453 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(link
), &context
);
454 if ((error
= namei(&nd
))) return error
;
456 if (nd
.ni_vp
== NULL
) {
458 VATTR_SET(&va
, va_type
, VLNK
);
459 VATTR_SET(&va
, va_mode
, ACCESSPERMS
&~ p
->p_fd
->fd_cmask
);
461 error
= VNOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
, path
, &context
);
465 vnode_put(nd
.ni_dvp
);