2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */
29 * 17-Aug-1999 Pat Dirks New today.
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/namei.h>
36 #include <sys/filedesc.h>
38 #include <sys/kernel.h>
39 #include <mach/machine/vm_types.h>
40 #include <sys/vnode.h>
41 #include <sys/socket.h>
42 #include <sys/mount.h>
47 #include <sys/ioctl.h>
48 #include <sys/errno.h>
49 #include <sys/malloc.h>
52 #include <miscfs/specfs/specdev.h>
60 struct vfsops synthfs_vfsops
= {
75 #define ROOTMPMODE 0755
76 #define ROOTPLACEHOLDERMODE 0700
77 static char synthfs_fs_name
[MFSNAMELEN
] = "synthfs";
78 static char synthfs_fake_mntfromname
[] = "<synthfs>";
81 extern struct vnodeopv_desc synthfs_vnodeop_opv_desc
;
83 /* The following refer to kernel global variables used in the loading/initialization: */
84 extern int maxvfsslots
; /* Total number of slots in the system's vfsconf table */
85 extern int maxvfsconf
; /* The highest fs type number [old-style ID] in use [dispite its name] */
86 extern int vfs_opv_numops
; /* The total number of defined vnode operations */
88 int vn_mkdir(struct proc
*p
, char *path
, int mode
);
89 int vn_symlink(struct proc
*p
, char *path
, char *link
);
96 synthfs_load(int loadArgument
) {
97 struct vfsconf
*newvfsconf
= NULL
;
99 int (***opv_desc_vector_p
)() = NULL
;
100 int (**opv_desc_vector
)();
101 struct vnodeopv_entry_desc
*opve_descp
;
104 #pragma unused(loadArgument)
107 * This routine is responsible for all the initialization that would
108 * ordinarily be done as part of the system startup; it calls synthfs_init
109 * to do the initialization that is strictly synthfs-specific.
112 DBG_VOP(("load_synthfs: starting ...\n"));
114 MALLOC(newvfsconf
, void *, sizeof(struct vfsconf
), M_SYNTHFS
, M_WAITOK
);
115 DBG_VOP(("load_synthfs: Allocated new vfsconf list entry, newvfsconf = 0x%08lx.\n", (unsigned long)newvfsconf
));
116 bzero(newvfsconf
, sizeof(struct vfsconf
));
119 DBG_VOP(("load_synthfs: filling in newly allocated vfsconf entry at 0x%08lX.\n", (long)newvfsconf
));
120 newvfsconf
->vfc_vfsops
= &synthfs_vfsops
;
121 strncpy(&newvfsconf
->vfc_name
[0], synthfs_fs_name
, MFSNAMELEN
);
122 newvfsconf
->vfc_typenum
= maxvfsconf
++;
123 newvfsconf
->vfc_refcount
= 0;
124 newvfsconf
->vfc_flags
= 0;
125 newvfsconf
->vfc_mountroot
= NULL
; /* Can't mount root of file system [yet] */
127 newvfsconf
->vfc_next
= NULL
;
129 /* Based on vfs_op_init and ... */
130 opv_desc_vector_p
= synthfs_vnodeop_opv_desc
.opv_desc_vector_p
;
132 DBG_VOP(("load_synthfs: Allocating and initializing VNode ops vector...\n"));
135 * Allocate and init the vector.
136 * Also handle backwards compatibility.
139 MALLOC(*opv_desc_vector_p
, PFI
*, vfs_opv_numops
*sizeof(PFI
), M_SYNTHFS
, M_WAITOK
);
140 bzero (*opv_desc_vector_p
, vfs_opv_numops
*sizeof(PFI
));
141 opv_desc_vector
= *opv_desc_vector_p
;
142 for (j
=0; synthfs_vnodeop_opv_desc
.opv_desc_ops
[j
].opve_op
; j
++) {
143 opve_descp
= &(synthfs_vnodeop_opv_desc
.opv_desc_ops
[j
]);
146 * Sanity check: is this operation listed
147 * in the list of operations? We check this
148 * by seeing if its offest is zero. Since
149 * the default routine should always be listed
150 * first, it should be the only one with a zero
151 * offset. Any other operation with a zero
152 * offset is probably not listed in
153 * vfs_op_descs, and so is probably an error.
155 * A panic here means the layer programmer
156 * has committed the all-too common bug
157 * of adding a new operation to the layer's
158 * list of vnode operations but
159 * not adding the operation to the system-wide
160 * list of supported operations.
162 if (opve_descp
->opve_op
->vdesc_offset
== 0 &&
163 opve_descp
->opve_op
->vdesc_offset
!= VOFFSET(vop_default
)) {
164 DBG_VOP(("load_synthfs: operation %s not listed in %s.\n",
165 opve_descp
->opve_op
->vdesc_name
,
167 panic ("load_synthfs: bad operation");
170 * Fill in this entry.
172 opv_desc_vector
[opve_descp
->opve_op
->vdesc_offset
] =
173 opve_descp
->opve_impl
;
177 * Finally, go back and replace unfilled routines
178 * with their default. (Sigh, an O(n^3) algorithm. I
179 * could make it better, but that'd be work, and n is small.)
181 opv_desc_vector_p
= synthfs_vnodeop_opv_desc
.opv_desc_vector_p
;
184 * Force every operations vector to have a default routine.
186 opv_desc_vector
= *opv_desc_vector_p
;
187 if (opv_desc_vector
[VOFFSET(vop_default
)]==NULL
) {
188 panic("load_vp;fs: operation vector without default routine.");
190 for (j
= 0;j
<vfs_opv_numops
; j
++)
191 if (opv_desc_vector
[j
] == NULL
)
193 opv_desc_vector
[VOFFSET(vop_default
)];
195 if (error
= vfsconf_add(newvfsconf
)) {
202 if (opv_desc_vector_p
&& *opv_desc_vector_p
) FREE(*opv_desc_vector_p
, M_SYNTHFS
);
204 if (newvfsconf
) FREE (newvfsconf
, M_SYNTHFS
);
209 DBG_VOP(("load_synthfs: calling synthfs_init()...\n"));
210 synthfs_init(newvfsconf
);
218 int synthfs_unload(void) {
219 DBG_VOP(("synthfs: Entering synthfs_unload...\n"));
233 synthfs_mount_fs(struct mount
*mp
, char *path
, caddr_t data
, struct nameidata
*ndp
, struct proc
*p
)
235 struct synthfs_mntdata
*priv_mnt_data
;
239 DBG_VOP(("synthfs_mount_fs called.\n"));
240 MALLOC(priv_mnt_data
, struct synthfs_mntdata
*, sizeof(struct synthfs_mntdata
), M_SYNTHFS
, M_WAITOK
);
241 DBG_VOP(("MALLOC succeeded...\n"));
243 strncpy(mp
->mnt_stat
.f_fstypename
, synthfs_fs_name
, sizeof(mp
->mnt_stat
.f_fstypename
));
244 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, sizeof(mp
->mnt_stat
.f_mntonname
) - 1, &size
);
245 strncpy(mp
->mnt_stat
.f_mntfromname
, synthfs_fake_mntfromname
, sizeof(mp
->mnt_stat
.f_mntfromname
));
246 priv_mnt_data
->synthfs_mounteddev
= (dev_t
)0;
247 priv_mnt_data
->synthfs_nextid
= FIRST_SYNTHFS_ID
;
248 priv_mnt_data
->synthfs_filecount
= 0;
249 priv_mnt_data
->synthfs_dircount
= 0;
250 priv_mnt_data
->synthfs_encodingsused
= 0x00000001;
253 Set up the root vnode for fast reference in the future.
254 Note that synthfs_new_directory() returns the vnode with a refcount of +2.
255 The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount.
257 error
= synthfs_new_directory(mp
, NULL
, "", ROOT_DIRID
, (S_IRWXU
|S_IRWXG
|S_IROTH
|S_IXOTH
), p
, &priv_mnt_data
->synthfs_rootvp
);
259 DBG_VOP(("Attempt to create root directory failed with error %d.\n", error
));
262 priv_mnt_data
->synthfs_rootvp
->v_flag
|= VROOT
;
264 priv_mnt_data
->synthfs_mp
= mp
;
265 mp
->mnt_data
= (void *)priv_mnt_data
;
267 /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent
268 the vnode from beeing freed: */
269 vput(priv_mnt_data
->synthfs_rootvp
);
277 synthfs_mount(mp
, path
, data
, ndp
, p
)
278 register struct mount
*mp
;
281 struct nameidata
*ndp
;
286 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, sizeof(mp
->mnt_stat
.f_mntonname
) - 1, &size
);
287 return (synthfs_mount_fs(mp
, path
, data
, ndp
, p
));
296 * Initialize the filesystem
300 struct vfsconf
*vfsp
;
302 DBG_VOP(("synthfs_init called.\n"));
307 synthfs_start(mp
, flags
, p
)
312 DBG_VOP(("synthfs_start called.\n"));
317 * Return the root of a filesystem.
320 synthfs_root(mp
, vpp
)
324 unsigned long root_nodeid
= ROOT_DIRID
;
326 DBG_VOP(("synthfs_root called.\n"));
328 *vpp
= VFSTOSFS(mp
)->synthfs_rootvp
;
329 return vget(VFSTOSFS(mp
)->synthfs_rootvp
, LK_EXCLUSIVE
| LK_RETRY
, current_proc());
333 synthfs_quotactl(mp
, cmds
, uid
, arg
, p
)
340 DBG_VOP(("synthfs_quotactl called.\n"));
345 * unmount system call
348 synthfs_unmount(mp
, mntflags
, p
)
353 struct synthfs_mntdata
*synth
;
354 struct vnode
*root_vp
;
357 DBG_VOP(("synthfs_unmount called.\n"));
358 synth
= (struct synthfs_mntdata
*)mp
->mnt_data
;
360 root_vp
= synth
->synthfs_rootvp
;
361 retval
= vflush(mp
, root_vp
, (mntflags
& MNT_FORCE
) ? FORCECLOSE
: 0);
362 if (retval
&& ((mntflags
& MNT_FORCE
) == 0)) goto Err_Exit
;
364 /* Free the root vnode.
365 Note that there's no need to vget() or vref() it before locking it here:
366 the ref. count has been maintained at +1 ever since mount time. */
368 retval
= vn_lock(root_vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
369 if ((mntflags
& MNT_FORCE
) == 0) {
370 if (retval
) goto Err_Exit
;
372 if (root_vp
->v_usecount
> 1) {
373 DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp
, synth
->synthfs_rootvp
->v_usecount
));
374 VOP_UNLOCK(root_vp
, 0, p
);
380 synth
->synthfs_rootvp
= NULL
;
383 vput(root_vp
); /* This drops synthfs's own refcount */
388 /* All vnodes should be gone, and no errors, clean up the last */
391 FREE(synth
, M_SYNTHFS
);
395 if (mntflags
& MNT_FORCE
) retval
= 0;
401 * Get file system statistics.
404 synthfs_statfs(mp
, sbp
, p
)
406 register struct statfs
*sbp
;
409 DBG_VOP(("synthfs_statfs called.\n"));
413 sbp
->f_blocks
= 1024; // lies, darn lies and virtual file systems
414 sbp
->f_bfree
= 0; // Nope, can't write here!
416 sbp
->f_files
= VFSTOSFS(mp
)->synthfs_filecount
+ VFSTOSFS(mp
)->synthfs_dircount
;
418 strncpy(sbp
->f_mntonname
, mp
->mnt_stat
.f_mntonname
, sizeof(sbp
->f_mntonname
));
419 strncpy(sbp
->f_mntfromname
, mp
->mnt_stat
.f_mntfromname
, sizeof(sbp
->f_mntfromname
));
425 * synthfs doesn't have any data or backing store and you can't write into any of the synthfs
426 * structures, so don't do anything
429 synthfs_sync(mp
, waitfor
, cred
, p
)
435 // DBG_VOP(("synthfs_sync called\n"));
439 * Look up a synthfs node by node number.
442 synthfs_vget(mp
, ino
, vpp
)
449 // DBG_VOP(("synthfs_vget called\n"));
451 /* Check for unmount in progress */
452 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
458 simple_lock(&mntvnode_slock
);
459 LIST_FOREACH(vp
, &mp
->mnt_vnodelist
, v_mntvnodes
) {
460 if (VTOS(vp
)->s_nodeid
== *((unsigned long *)ino
)) {
461 if (vget(vp
, LK_EXCLUSIVE
, current_proc()) != 0) {
462 simple_unlock(&mntvnode_slock
);
465 simple_unlock(&mntvnode_slock
);
470 simple_unlock(&mntvnode_slock
);
476 * fast filesystem related variables.
479 synthfs_sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
, p
)
488 DBG_VOP(("synthfs_sysctl called.\n"));
493 * File handle to vnode
497 synthfs_fhtovp(mp
, fhp
, nam
, vpp
, exflagsp
, credanonp
)
498 register struct mount
*mp
;
503 struct ucred
**credanonp
;
505 DBG_VOP(("synthfs_fhtovp called.\n"));
510 * Vnode pointer to File handle
514 synthfs_vptofh(vp
, fhp
)
518 DBG_VOP(("synthfs_vptofh called.\n"));
528 vn_mkdir(struct proc
*p
, char *path
, int mode
) {
534 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE
, path
, p
);
535 if (error
= namei(&nd
)) {
536 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error
));
541 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
547 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
551 vattr
.va_type
= VDIR
;
552 vattr
.va_mode
= (mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
553 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
554 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
556 DBG_VOP(("vn_mkdir: error from VOP_MKDIR (%d).\n", error
));
566 vn_symlink(struct proc
*p
, char *path
, char *link
) {
571 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE
, link
, p
);
572 if (error
= namei(&nd
)) return error
;
575 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
576 if (nd
.ni_dvp
== nd
.ni_vp
)
584 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
585 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
586 return VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);