2 * Copyright (c) 2000-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@
23 /* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */
27 * 17-Aug-1999 Pat Dirks New today.
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/namei.h>
34 #include <sys/filedesc.h>
35 #include <sys/proc_internal.h>
36 #include <sys/kernel.h>
37 #include <mach/machine/vm_types.h>
38 #include <sys/vnode_internal.h>
39 #include <sys/socket.h>
40 #include <sys/mount_internal.h>
44 #include <sys/ioctl.h>
45 #include <sys/errno.h>
46 #include <sys/malloc.h>
48 #include <sys/uio_internal.h>
50 #include <miscfs/specfs/specdev.h>
58 struct vfsops synthfs_vfsops
= {
73 #define ROOTMPMODE 0755
74 #define ROOTPLACEHOLDERMODE 0700
75 static char synthfs_fs_name
[MFSTYPENAMELEN
] = "synthfs";
76 static char synthfs_fake_mntfromname
[] = "<synthfs>";
79 extern struct vnodeopv_desc synthfs_vnodeop_opv_desc
;
81 /* The following refer to kernel global variables used in the loading/initialization: */
82 extern int maxvfsslots
; /* Total number of slots in the system's vfsconf table */
83 extern int maxvfsconf
; /* The highest fs type number [old-style ID] in use [dispite its name] */
84 extern int vfs_opv_numops
; /* The total number of defined vnode operations */
86 int vn_mkdir(struct proc
*p
, char *path
, int mode
);
87 int vn_symlink(struct proc
*p
, char *path
, char *link
);
94 synthfs_load(int loadArgument
) {
95 /* Should use vfs_fsadd kpi */
100 int synthfs_unload(void) {
102 /* should use fs_fsremove kpi */
115 synthfs_mount_fs(struct mount
*mp
, vnode_t devvp
, __unused user_addr_t data
, struct proc
*p
)
117 struct synthfs_mntdata
*priv_mnt_data
;
121 DBG_VOP(("synthfs_mount_fs called.\n"));
122 MALLOC(priv_mnt_data
, struct synthfs_mntdata
*, sizeof(struct synthfs_mntdata
), M_SYNTHFS
, M_WAITOK
);
123 DBG_VOP(("MALLOC succeeded...\n"));
125 strncpy(mp
->mnt_vfsstat
.f_fstypename
, synthfs_fs_name
, sizeof(mp
->mnt_vfsstat
.f_fstypename
));
126 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, synthfs_fake_mntfromname
, sizeof(mp
->mnt_vfsstat
.f_mntfromname
));
127 priv_mnt_data
->synthfs_mounteddev
= (dev_t
)0;
128 priv_mnt_data
->synthfs_nextid
= FIRST_SYNTHFS_ID
;
129 priv_mnt_data
->synthfs_filecount
= 0;
130 priv_mnt_data
->synthfs_dircount
= 0;
131 priv_mnt_data
->synthfs_encodingsused
= 0x00000001;
134 Set up the root vnode for fast reference in the future.
135 Note that synthfs_new_directory() returns the vnode with a refcount of +2.
136 The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount.
138 error
= synthfs_new_directory(mp
, NULL
, "", ROOT_DIRID
, (S_IRWXU
|S_IRWXG
|S_IROTH
|S_IXOTH
), p
, &priv_mnt_data
->synthfs_rootvp
);
140 DBG_VOP(("Attempt to create root directory failed with error %d.\n", error
));
143 priv_mnt_data
->synthfs_rootvp
->v_flag
|= VROOT
;
145 priv_mnt_data
->synthfs_mp
= mp
;
146 mp
->mnt_data
= (void *)priv_mnt_data
;
148 /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent
149 the vnode from beeing freed: */
150 vnode_put(priv_mnt_data
->synthfs_rootvp
);
158 synthfs_mount(mp
, devvp
, data
, context
)
159 register struct mount
*mp
;
162 vfs_context_t context
;
166 return (synthfs_mount_fs(mp
, devvp
, data
, vfs_context_proc(context
)));
175 * Initialize the filesystem
179 struct vfsconf
*vfsp
;
181 DBG_VOP(("synthfs_init called.\n"));
186 synthfs_start(mp
, flags
, context
)
189 vfs_context_t context
;
191 DBG_VOP(("synthfs_start called.\n"));
196 * Return the root of a filesystem.
199 synthfs_root(mp
, vpp
, context
)
202 vfs_context_t context
;
204 unsigned long root_nodeid
= ROOT_DIRID
;
206 DBG_VOP(("synthfs_root called.\n"));
208 *vpp
= VFSTOSFS(mp
)->synthfs_rootvp
;
209 return vnode_get(VFSTOSFS(mp
)->synthfs_rootvp
);
213 * unmount system call
216 synthfs_unmount(mp
, mntflags
, context
)
219 vfs_context_t context
;
221 struct synthfs_mntdata
*synth
;
222 struct vnode
*root_vp
;
225 DBG_VOP(("synthfs_unmount called.\n"));
226 synth
= (struct synthfs_mntdata
*)mp
->mnt_data
;
228 root_vp
= synth
->synthfs_rootvp
;
229 retval
= vflush(mp
, root_vp
, (mntflags
& MNT_FORCE
) ? FORCECLOSE
: 0);
230 if (retval
&& ((mntflags
& MNT_FORCE
) == 0)) goto Err_Exit
;
232 /* Free the root vnode.
233 the ref. count has been maintained at +1 ever since mount time. */
235 if ((mntflags
& MNT_FORCE
) == 0) {
236 if (retval
) goto Err_Exit
;
238 if (root_vp
->v_usecount
> 1) {
239 DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp
, synth
->synthfs_rootvp
->v_usecount
));
245 synth
->synthfs_rootvp
= NULL
;
250 vnode_recycle(root_vp
);
251 vnode_put(root_vp
); /* This drops synthfs's own refcount */
255 /* All vnodes should be gone, and no errors, clean up the last */
258 FREE(synth
, M_SYNTHFS
);
262 if (mntflags
& MNT_FORCE
) retval
= 0;
268 * Get file system statistics.
271 synthfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t context
)
273 struct synthfs_mntdata
*synthfs_mp
= VFSTOSFS(mp
);
274 DBG_VOP(("synthfs_vfs_getattr called.\n"));
276 VFSATTR_RETURN(fsap
, f_bsize
, 512);
277 VFSATTR_RETURN(fsap
, f_iosize
, 512);
278 VFSATTR_RETURN(fsap
, f_blocks
, 1024);
279 VFSATTR_RETURN(fsap
, f_bfree
, 0);
280 VFSATTR_RETURN(fsap
, f_bavail
, 0);
281 VFSATTR_RETURN(fsap
, f_bused
, 1024);
282 VFSATTR_RETURN(fsap
, f_files
, synthfs_mp
->synthfs_filecount
+ synthfs_mp
->synthfs_dircount
);
283 VFSATTR_RETURN(fsap
, f_ffree
, 0);
284 VFSATTR_RETURN(fsap
, f_fssubtype
, 0);
290 * synthfs doesn't have any data or backing store and you can't write into any of the synthfs
291 * structures, so don't do anything
294 synthfs_sync(mp
, waitfor
, context
)
297 vfs_context_t context
;
299 // DBG_VOP(("synthfs_sync called\n"));
303 * Look up a synthfs node by node number.
306 synthfs_vget(mp
, ino
, vpp
, context
)
310 vfs_context_t context
;
315 // DBG_VOP(("synthfs_vget called\n"));
317 /* Check for unmount in progress */
318 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
324 TAILQ_FOREACH(vp
, &mp
->mnt_vnodelist
, v_mntvnodes
) {
325 if (VTOS(vp
)->s_nodeid
== (unsigned long)ino
) {
327 * doing a vnode_getwithvid isn't technically
328 * necessary since synthfs is an unsafe filesystem
329 * and we're running behind a funnel at this point
330 * however, vnode_get always succeeds, which isn't
331 * what we want if this vnode is in the process of
336 if (vnode_getwithvid(vp
, vid
) != 0) {
348 * fast filesystem related variables.
351 synthfs_sysctl(int *name
, u_int namelen
, user_addr_t oldp
, size_t *oldlenp
,
352 user_addr_t newp
, size_t newlen
, vfs_context_t context
)
354 DBG_VOP(("synthfs_sysctl called.\n"));
359 * File handle to vnode
363 synthfs_fhtovp(mp
, fhlen
, fhp
, vpp
, context
)
364 register struct mount
*mp
;
368 vfs_context_t context
;
370 DBG_VOP(("synthfs_fhtovp called.\n"));
375 * Vnode pointer to File handle
379 synthfs_vptofh(vp
, fhlenp
, fhp
, context
)
383 vfs_context_t context
;
385 DBG_VOP(("synthfs_vptofh called.\n"));
395 vn_mkdir(struct proc
*p
, char *path
, int mode
)
399 struct vnode_attr va
;
400 struct vfs_context context
;
404 context
.vc_ucred
= proc_ucred(p
); /* XXX kauth_cred_get() ??? proxy */
406 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(path
), &context
);
409 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error
));
416 VATTR_SET(&va
, va_type
, VDIR
);
417 VATTR_SET(&va
, va_mode
, (mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
);
419 error
= vn_create(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
, 0, &context
);
421 DBG_VOP(("vn_mkdir: error from vnop_mkdir (%d).\n", error
));
423 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
426 vnode_put(nd
.ni_dvp
);
437 vn_symlink(struct proc
*p
, char *path
, char *link
) {
439 struct vnode_attr va
;
440 struct vfs_context context
;
444 context
.vc_ucred
= proc_ucred(p
); /* XXX kauth_cred_get() ??? proxy */
446 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(link
), &context
);
447 if ((error
= namei(&nd
))) return error
;
449 if (nd
.ni_vp
== NULL
) {
451 VATTR_SET(&va
, va_type
, VLNK
);
452 VATTR_SET(&va
, va_mode
, ACCESSPERMS
&~ p
->p_fd
->fd_cmask
);
454 error
= VNOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
, path
, &context
);
458 vnode_put(nd
.ni_dvp
);