2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */
26 * 17-Aug-1999 Pat Dirks New today.
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/namei.h>
33 #include <sys/filedesc.h>
34 #include <sys/proc_internal.h>
35 #include <sys/kernel.h>
36 #include <mach/machine/vm_types.h>
37 #include <sys/vnode_internal.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>
47 #include <sys/uio_internal.h>
49 #include <miscfs/specfs/specdev.h>
57 struct vfsops synthfs_vfsops
= {
72 #define ROOTMPMODE 0755
73 #define ROOTPLACEHOLDERMODE 0700
74 static char synthfs_fs_name
[MFSTYPENAMELEN
] = "synthfs";
75 static char synthfs_fake_mntfromname
[] = "<synthfs>";
78 extern struct vnodeopv_desc synthfs_vnodeop_opv_desc
;
80 /* The following refer to kernel global variables used in the loading/initialization: */
81 extern int maxvfsslots
; /* Total number of slots in the system's vfsconf table */
82 extern int maxvfsconf
; /* The highest fs type number [old-style ID] in use [dispite its name] */
83 extern int vfs_opv_numops
; /* The total number of defined vnode operations */
85 int vn_mkdir(struct proc
*p
, char *path
, int mode
);
86 int vn_symlink(struct proc
*p
, char *path
, char *link
);
93 synthfs_load(int loadArgument
) {
94 /* Should use vfs_fsadd kpi */
99 int synthfs_unload(void) {
101 /* should use fs_fsremove kpi */
114 synthfs_mount_fs(struct mount
*mp
, vnode_t devvp
, __unused user_addr_t data
, struct proc
*p
)
116 struct synthfs_mntdata
*priv_mnt_data
;
120 DBG_VOP(("synthfs_mount_fs called.\n"));
121 MALLOC(priv_mnt_data
, struct synthfs_mntdata
*, sizeof(struct synthfs_mntdata
), M_SYNTHFS
, M_WAITOK
);
122 DBG_VOP(("MALLOC succeeded...\n"));
124 strncpy(mp
->mnt_vfsstat
.f_fstypename
, synthfs_fs_name
, sizeof(mp
->mnt_vfsstat
.f_fstypename
));
125 strncpy(mp
->mnt_vfsstat
.f_mntfromname
, synthfs_fake_mntfromname
, sizeof(mp
->mnt_vfsstat
.f_mntfromname
));
126 priv_mnt_data
->synthfs_mounteddev
= (dev_t
)0;
127 priv_mnt_data
->synthfs_nextid
= FIRST_SYNTHFS_ID
;
128 priv_mnt_data
->synthfs_filecount
= 0;
129 priv_mnt_data
->synthfs_dircount
= 0;
130 priv_mnt_data
->synthfs_encodingsused
= 0x00000001;
133 Set up the root vnode for fast reference in the future.
134 Note that synthfs_new_directory() returns the vnode with a refcount of +2.
135 The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount.
137 error
= synthfs_new_directory(mp
, NULL
, "", ROOT_DIRID
, (S_IRWXU
|S_IRWXG
|S_IROTH
|S_IXOTH
), p
, &priv_mnt_data
->synthfs_rootvp
);
139 DBG_VOP(("Attempt to create root directory failed with error %d.\n", error
));
142 priv_mnt_data
->synthfs_rootvp
->v_flag
|= VROOT
;
144 priv_mnt_data
->synthfs_mp
= mp
;
145 mp
->mnt_data
= (void *)priv_mnt_data
;
147 /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent
148 the vnode from beeing freed: */
149 vnode_put(priv_mnt_data
->synthfs_rootvp
);
157 synthfs_mount(mp
, devvp
, data
, context
)
158 register struct mount
*mp
;
161 vfs_context_t context
;
165 return (synthfs_mount_fs(mp
, devvp
, data
, vfs_context_proc(context
)));
174 * Initialize the filesystem
178 struct vfsconf
*vfsp
;
180 DBG_VOP(("synthfs_init called.\n"));
185 synthfs_start(mp
, flags
, context
)
188 vfs_context_t context
;
190 DBG_VOP(("synthfs_start called.\n"));
195 * Return the root of a filesystem.
198 synthfs_root(mp
, vpp
, context
)
201 vfs_context_t context
;
203 unsigned long root_nodeid
= ROOT_DIRID
;
205 DBG_VOP(("synthfs_root called.\n"));
207 *vpp
= VFSTOSFS(mp
)->synthfs_rootvp
;
208 return vnode_get(VFSTOSFS(mp
)->synthfs_rootvp
);
212 * unmount system call
215 synthfs_unmount(mp
, mntflags
, context
)
218 vfs_context_t context
;
220 struct synthfs_mntdata
*synth
;
221 struct vnode
*root_vp
;
224 DBG_VOP(("synthfs_unmount called.\n"));
225 synth
= (struct synthfs_mntdata
*)mp
->mnt_data
;
227 root_vp
= synth
->synthfs_rootvp
;
228 retval
= vflush(mp
, root_vp
, (mntflags
& MNT_FORCE
) ? FORCECLOSE
: 0);
229 if (retval
&& ((mntflags
& MNT_FORCE
) == 0)) goto Err_Exit
;
231 /* Free the root vnode.
232 the ref. count has been maintained at +1 ever since mount time. */
234 if ((mntflags
& MNT_FORCE
) == 0) {
235 if (retval
) goto Err_Exit
;
237 if (root_vp
->v_usecount
> 1) {
238 DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp
, synth
->synthfs_rootvp
->v_usecount
));
244 synth
->synthfs_rootvp
= NULL
;
249 vnode_recycle(root_vp
);
250 vnode_put(root_vp
); /* This drops synthfs's own refcount */
254 /* All vnodes should be gone, and no errors, clean up the last */
257 FREE(synth
, M_SYNTHFS
);
261 if (mntflags
& MNT_FORCE
) retval
= 0;
267 * Get file system statistics.
270 synthfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t context
)
272 struct synthfs_mntdata
*synthfs_mp
= VFSTOSFS(mp
);
273 DBG_VOP(("synthfs_vfs_getattr called.\n"));
275 VFSATTR_RETURN(fsap
, f_bsize
, 512);
276 VFSATTR_RETURN(fsap
, f_iosize
, 512);
277 VFSATTR_RETURN(fsap
, f_blocks
, 1024);
278 VFSATTR_RETURN(fsap
, f_bfree
, 0);
279 VFSATTR_RETURN(fsap
, f_bavail
, 0);
280 VFSATTR_RETURN(fsap
, f_bused
, 1024);
281 VFSATTR_RETURN(fsap
, f_files
, synthfs_mp
->synthfs_filecount
+ synthfs_mp
->synthfs_dircount
);
282 VFSATTR_RETURN(fsap
, f_ffree
, 0);
283 VFSATTR_RETURN(fsap
, f_fssubtype
, 0);
289 * synthfs doesn't have any data or backing store and you can't write into any of the synthfs
290 * structures, so don't do anything
293 synthfs_sync(mp
, waitfor
, context
)
296 vfs_context_t context
;
298 // DBG_VOP(("synthfs_sync called\n"));
302 * Look up a synthfs node by node number.
305 synthfs_vget(mp
, ino
, vpp
, context
)
309 vfs_context_t context
;
314 // DBG_VOP(("synthfs_vget called\n"));
316 /* Check for unmount in progress */
317 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
323 TAILQ_FOREACH(vp
, &mp
->mnt_vnodelist
, v_mntvnodes
) {
324 if (VTOS(vp
)->s_nodeid
== (unsigned long)ino
) {
326 * doing a vnode_getwithvid isn't technically
327 * necessary since synthfs is an unsafe filesystem
328 * and we're running behind a funnel at this point
329 * however, vnode_get always succeeds, which isn't
330 * what we want if this vnode is in the process of
335 if (vnode_getwithvid(vp
, vid
) != 0) {
347 * fast filesystem related variables.
350 synthfs_sysctl(int *name
, u_int namelen
, user_addr_t oldp
, size_t *oldlenp
,
351 user_addr_t newp
, size_t newlen
, vfs_context_t context
)
353 DBG_VOP(("synthfs_sysctl called.\n"));
358 * File handle to vnode
362 synthfs_fhtovp(mp
, fhlen
, fhp
, vpp
, context
)
363 register struct mount
*mp
;
367 vfs_context_t context
;
369 DBG_VOP(("synthfs_fhtovp called.\n"));
374 * Vnode pointer to File handle
378 synthfs_vptofh(vp
, fhlenp
, fhp
, context
)
382 vfs_context_t context
;
384 DBG_VOP(("synthfs_vptofh called.\n"));
394 vn_mkdir(struct proc
*p
, char *path
, int mode
)
398 struct vnode_attr va
;
399 struct vfs_context context
;
403 context
.vc_ucred
= proc_ucred(p
); /* XXX kauth_cred_get() ??? proxy */
405 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(path
), &context
);
408 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error
));
415 VATTR_SET(&va
, va_type
, VDIR
);
416 VATTR_SET(&va
, va_mode
, (mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
);
418 error
= vn_create(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
, 0, &context
);
420 DBG_VOP(("vn_mkdir: error from vnop_mkdir (%d).\n", error
));
422 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
425 vnode_put(nd
.ni_dvp
);
436 vn_symlink(struct proc
*p
, char *path
, char *link
) {
438 struct vnode_attr va
;
439 struct vfs_context context
;
443 context
.vc_ucred
= proc_ucred(p
); /* XXX kauth_cred_get() ??? proxy */
445 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(link
), &context
);
446 if ((error
= namei(&nd
))) return error
;
448 if (nd
.ni_vp
== NULL
) {
450 VATTR_SET(&va
, va_type
, VLNK
);
451 VATTR_SET(&va
, va_mode
, ACCESSPERMS
&~ p
->p_fd
->fd_cmask
);
453 error
= VNOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
, path
, &context
);
457 vnode_put(nd
.ni_dvp
);