2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */
32 * 17-Aug-1999 Pat Dirks New today.
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/namei.h>
39 #include <sys/filedesc.h>
40 #include <sys/proc_internal.h>
41 #include <sys/kernel.h>
42 #include <mach/machine/vm_types.h>
43 #include <sys/vnode_internal.h>
44 #include <sys/socket.h>
45 #include <sys/mount_internal.h>
49 #include <sys/ioctl.h>
50 #include <sys/errno.h>
51 #include <sys/malloc.h>
53 #include <sys/uio_internal.h>
55 #include <miscfs/specfs/specdev.h>
63 struct vfsops synthfs_vfsops
= {
78 #define ROOTMPMODE 0755
79 #define ROOTPLACEHOLDERMODE 0700
80 static char synthfs_fs_name
[MFSTYPENAMELEN
] = "synthfs";
81 static char synthfs_fake_mntfromname
[] = "<synthfs>";
84 extern struct vnodeopv_desc synthfs_vnodeop_opv_desc
;
86 /* The following refer to kernel global variables used in the loading/initialization: */
87 extern int maxvfsslots
; /* Total number of slots in the system's vfsconf table */
88 extern int maxvfsconf
; /* The highest fs type number [old-style ID] in use [dispite its name] */
89 extern int vfs_opv_numops
; /* The total number of defined vnode operations */
91 int vn_mkdir(struct proc
*p
, char *path
, int mode
);
92 int vn_symlink(struct proc
*p
, char *path
, char *link
);
99 synthfs_load(int loadArgument
) {
100 /* Should use vfs_fsadd kpi */
105 int synthfs_unload(void) {
107 /* should use fs_fsremove kpi */
120 synthfs_mount_fs(struct mount
*mp
, vnode_t devvp
, __unused user_addr_t data
, struct proc
*p
)
122 struct synthfs_mntdata
*priv_mnt_data
;
126 DBG_VOP(("synthfs_mount_fs called.\n"));
127 MALLOC(priv_mnt_data
, struct synthfs_mntdata
*, sizeof(struct synthfs_mntdata
), M_SYNTHFS
, M_WAITOK
);
128 DBG_VOP(("MALLOC succeeded...\n"));
130 strlcpy(mp
->mnt_vfsstat
.f_fstypename
, synthfs_fs_name
, sizeof(mp
->mnt_vfsstat
.f_fstypename
));
131 strlcpy(mp
->mnt_vfsstat
.f_mntfromname
, synthfs_fake_mntfromname
, sizeof(mp
->mnt_vfsstat
.f_mntfromname
));
132 priv_mnt_data
->synthfs_mounteddev
= (dev_t
)0;
133 priv_mnt_data
->synthfs_nextid
= FIRST_SYNTHFS_ID
;
134 priv_mnt_data
->synthfs_filecount
= 0;
135 priv_mnt_data
->synthfs_dircount
= 0;
136 priv_mnt_data
->synthfs_encodingsused
= 0x00000001;
139 Set up the root vnode for fast reference in the future.
140 Note that synthfs_new_directory() returns the vnode with a refcount of +2.
141 The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount.
143 error
= synthfs_new_directory(mp
, NULL
, "", ROOT_DIRID
, (S_IRWXU
|S_IRWXG
|S_IROTH
|S_IXOTH
), p
, &priv_mnt_data
->synthfs_rootvp
);
145 DBG_VOP(("Attempt to create root directory failed with error %d.\n", error
));
148 priv_mnt_data
->synthfs_rootvp
->v_flag
|= VROOT
;
150 priv_mnt_data
->synthfs_mp
= mp
;
151 mp
->mnt_data
= (void *)priv_mnt_data
;
153 /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent
154 the vnode from beeing freed: */
155 vnode_put(priv_mnt_data
->synthfs_rootvp
);
163 synthfs_mount(mp
, devvp
, data
, context
)
164 register struct mount
*mp
;
167 vfs_context_t context
;
171 return (synthfs_mount_fs(mp
, devvp
, data
, vfs_context_proc(context
)));
180 * Initialize the filesystem
184 struct vfsconf
*vfsp
;
186 DBG_VOP(("synthfs_init called.\n"));
191 synthfs_start(mp
, flags
, context
)
194 vfs_context_t context
;
196 DBG_VOP(("synthfs_start called.\n"));
201 * Return the root of a filesystem.
204 synthfs_root(mp
, vpp
, context
)
207 vfs_context_t context
;
209 unsigned long root_nodeid
= ROOT_DIRID
;
211 DBG_VOP(("synthfs_root called.\n"));
213 *vpp
= VFSTOSFS(mp
)->synthfs_rootvp
;
214 return vnode_get(VFSTOSFS(mp
)->synthfs_rootvp
);
218 * unmount system call
221 synthfs_unmount(mp
, mntflags
, context
)
224 vfs_context_t context
;
226 struct synthfs_mntdata
*synth
;
227 struct vnode
*root_vp
;
230 DBG_VOP(("synthfs_unmount called.\n"));
231 synth
= (struct synthfs_mntdata
*)mp
->mnt_data
;
233 root_vp
= synth
->synthfs_rootvp
;
234 retval
= vflush(mp
, root_vp
, (mntflags
& MNT_FORCE
) ? FORCECLOSE
: 0);
235 if (retval
&& ((mntflags
& MNT_FORCE
) == 0)) goto Err_Exit
;
237 /* Free the root vnode.
238 the ref. count has been maintained at +1 ever since mount time. */
240 if ((mntflags
& MNT_FORCE
) == 0) {
241 if (retval
) goto Err_Exit
;
243 if (root_vp
->v_usecount
> 1) {
244 DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp
, synth
->synthfs_rootvp
->v_usecount
));
250 synth
->synthfs_rootvp
= NULL
;
255 vnode_recycle(root_vp
);
256 vnode_put(root_vp
); /* This drops synthfs's own refcount */
260 /* All vnodes should be gone, and no errors, clean up the last */
263 FREE(synth
, M_SYNTHFS
);
267 if (mntflags
& MNT_FORCE
) retval
= 0;
273 * Get file system statistics.
276 synthfs_vfs_getattr(mount_t mp
, struct vfs_attr
*fsap
, vfs_context_t context
)
278 struct synthfs_mntdata
*synthfs_mp
= VFSTOSFS(mp
);
279 DBG_VOP(("synthfs_vfs_getattr called.\n"));
281 VFSATTR_RETURN(fsap
, f_bsize
, 512);
282 VFSATTR_RETURN(fsap
, f_iosize
, 512);
283 VFSATTR_RETURN(fsap
, f_blocks
, 1024);
284 VFSATTR_RETURN(fsap
, f_bfree
, 0);
285 VFSATTR_RETURN(fsap
, f_bavail
, 0);
286 VFSATTR_RETURN(fsap
, f_bused
, 1024);
287 VFSATTR_RETURN(fsap
, f_files
, synthfs_mp
->synthfs_filecount
+ synthfs_mp
->synthfs_dircount
);
288 VFSATTR_RETURN(fsap
, f_ffree
, 0);
289 VFSATTR_RETURN(fsap
, f_fssubtype
, 0);
295 * synthfs doesn't have any data or backing store and you can't write into any of the synthfs
296 * structures, so don't do anything
299 synthfs_sync(mp
, waitfor
, context
)
302 vfs_context_t context
;
304 // DBG_VOP(("synthfs_sync called\n"));
308 * Look up a synthfs node by node number.
311 synthfs_vget(mp
, ino
, vpp
, context
)
315 vfs_context_t context
;
320 // DBG_VOP(("synthfs_vget called\n"));
322 /* Check for unmount in progress */
323 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
329 TAILQ_FOREACH(vp
, &mp
->mnt_vnodelist
, v_mntvnodes
) {
330 if (VTOS(vp
)->s_nodeid
== (unsigned long)ino
) {
332 * doing a vnode_getwithvid isn't technically
333 * necessary since synthfs is an unsafe filesystem
334 * and we're running behind a funnel at this point
335 * however, vnode_get always succeeds, which isn't
336 * what we want if this vnode is in the process of
341 if (vnode_getwithvid(vp
, vid
) != 0) {
353 * fast filesystem related variables.
356 synthfs_sysctl(int *name
, u_int namelen
, user_addr_t oldp
, size_t *oldlenp
,
357 user_addr_t newp
, size_t newlen
, vfs_context_t context
)
359 DBG_VOP(("synthfs_sysctl called.\n"));
364 * File handle to vnode
368 synthfs_fhtovp(mp
, fhlen
, fhp
, vpp
, context
)
369 register struct mount
*mp
;
373 vfs_context_t context
;
375 DBG_VOP(("synthfs_fhtovp called.\n"));
380 * Vnode pointer to File handle
384 synthfs_vptofh(vp
, fhlenp
, fhp
, context
)
388 vfs_context_t context
;
390 DBG_VOP(("synthfs_vptofh called.\n"));
400 vn_mkdir(struct proc
*p
, char *path
, int mode
)
404 struct vnode_attr va
;
405 vfs_context_t ctx
= vfs_context_kernel();
409 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(path
), ctx
);
412 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error
));
419 VATTR_SET(&va
, va_type
, VDIR
);
420 VATTR_SET(&va
, va_mode
, (mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
);
422 error
= vn_create(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
, 0, ctx
);
424 DBG_VOP(("vn_mkdir: error from vnop_mkdir (%d).\n", error
));
426 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
429 vnode_put(nd
.ni_dvp
);
440 vn_symlink(struct proc
*p
, char *path
, char *link
) {
442 struct vnode_attr va
;
443 vfs_context_t ctx
= vfs_context_kernel();
446 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE32
, CAST_USER_ADDR_T(link
), ctx
);
447 if ((error
= namei(&nd
))) {
451 if (nd
.ni_vp
== NULL
) {
453 VATTR_SET(&va
, va_type
, VLNK
);
454 VATTR_SET(&va
, va_mode
, ACCESSPERMS
&~ p
->p_fd
->fd_cmask
);
456 error
= VNOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
, path
, ctx
);
460 vnode_put(nd
.ni_dvp
);