2 * Copyright (c) 2000 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>
35 #include <sys/kernel.h>
36 #include <mach/machine/vm_types.h>
37 //#include <mach/mach_init.h>
38 #include <sys/vnode.h>
39 #include <sys/socket.h>
40 #include <sys/mount.h>
45 #include <sys/ioctl.h>
46 #include <sys/errno.h>
47 #include <sys/malloc.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
[MFSNAMELEN
] = "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 struct vfsconf
*newvfsconf
= NULL
;
97 int (***opv_desc_vector_p
)() = NULL
;
98 int (**opv_desc_vector
)();
99 struct vnodeopv_entry_desc
*opve_descp
;
102 #pragma unused(loadArgument)
105 * This routine is responsible for all the initialization that would
106 * ordinarily be done as part of the system startup; it calls synthfs_init
107 * to do the initialization that is strictly synthfs-specific.
110 DBG_VOP(("load_synthfs: starting ...\n"));
112 MALLOC(newvfsconf
, void *, sizeof(struct vfsconf
), M_SYNTHFS
, M_WAITOK
);
113 DBG_VOP(("load_synthfs: Allocated new vfsconf list entry, newvfsconf = 0x%08lx.\n", (unsigned long)newvfsconf
));
114 bzero(newvfsconf
, sizeof(struct vfsconf
));
117 DBG_VOP(("load_synthfs: filling in newly allocated vfsconf entry at 0x%08lX.\n", (long)newvfsconf
));
118 newvfsconf
->vfc_vfsops
= &synthfs_vfsops
;
119 strncpy(&newvfsconf
->vfc_name
[0], synthfs_fs_name
, MFSNAMELEN
);
120 newvfsconf
->vfc_typenum
= maxvfsconf
++;
121 newvfsconf
->vfc_refcount
= 0;
122 newvfsconf
->vfc_flags
= 0;
123 newvfsconf
->vfc_mountroot
= NULL
; /* Can't mount root of file system [yet] */
125 newvfsconf
->vfc_next
= NULL
;
127 /* Based on vfs_op_init and ... */
128 opv_desc_vector_p
= synthfs_vnodeop_opv_desc
.opv_desc_vector_p
;
130 DBG_VOP(("load_synthfs: Allocating and initializing VNode ops vector...\n"));
133 * Allocate and init the vector.
134 * Also handle backwards compatibility.
137 MALLOC(*opv_desc_vector_p
, PFI
*, vfs_opv_numops
*sizeof(PFI
), M_SYNTHFS
, M_WAITOK
);
138 bzero (*opv_desc_vector_p
, vfs_opv_numops
*sizeof(PFI
));
139 opv_desc_vector
= *opv_desc_vector_p
;
140 for (j
=0; synthfs_vnodeop_opv_desc
.opv_desc_ops
[j
].opve_op
; j
++) {
141 opve_descp
= &(synthfs_vnodeop_opv_desc
.opv_desc_ops
[j
]);
144 * Sanity check: is this operation listed
145 * in the list of operations? We check this
146 * by seeing if its offest is zero. Since
147 * the default routine should always be listed
148 * first, it should be the only one with a zero
149 * offset. Any other operation with a zero
150 * offset is probably not listed in
151 * vfs_op_descs, and so is probably an error.
153 * A panic here means the layer programmer
154 * has committed the all-too common bug
155 * of adding a new operation to the layer's
156 * list of vnode operations but
157 * not adding the operation to the system-wide
158 * list of supported operations.
160 if (opve_descp
->opve_op
->vdesc_offset
== 0 &&
161 opve_descp
->opve_op
->vdesc_offset
!= VOFFSET(vop_default
)) {
162 DBG_VOP(("load_synthfs: operation %s not listed in %s.\n",
163 opve_descp
->opve_op
->vdesc_name
,
165 panic ("load_synthfs: bad operation");
168 * Fill in this entry.
170 opv_desc_vector
[opve_descp
->opve_op
->vdesc_offset
] =
171 opve_descp
->opve_impl
;
175 * Finally, go back and replace unfilled routines
176 * with their default. (Sigh, an O(n^3) algorithm. I
177 * could make it better, but that'd be work, and n is small.)
179 opv_desc_vector_p
= synthfs_vnodeop_opv_desc
.opv_desc_vector_p
;
182 * Force every operations vector to have a default routine.
184 opv_desc_vector
= *opv_desc_vector_p
;
185 if (opv_desc_vector
[VOFFSET(vop_default
)]==NULL
) {
186 panic("load_vp;fs: operation vector without default routine.");
188 for (j
= 0;j
<vfs_opv_numops
; j
++)
189 if (opv_desc_vector
[j
] == NULL
)
191 opv_desc_vector
[VOFFSET(vop_default
)];
193 if (error
= vfsconf_add(newvfsconf
)) {
200 if (opv_desc_vector_p
&& *opv_desc_vector_p
) FREE(*opv_desc_vector_p
, M_SYNTHFS
);
202 if (newvfsconf
) FREE (newvfsconf
, M_SYNTHFS
);
207 DBG_VOP(("load_synthfs: calling synthfs_init()...\n"));
208 synthfs_init(newvfsconf
);
216 int synthfs_unload(void) {
217 DBG_VOP(("synthfs: Entering synthfs_unload...\n"));
231 synthfs_mount_fs(struct mount
*mp
, char *path
, caddr_t data
, struct nameidata
*ndp
, struct proc
*p
)
233 struct synthfs_mntdata
*priv_mnt_data
;
237 DBG_VOP(("synthfs_mount_fs called.\n"));
238 MALLOC(priv_mnt_data
, struct synthfs_mntdata
*, sizeof(struct synthfs_mntdata
), M_SYNTHFS
, M_WAITOK
);
239 DBG_VOP(("MALLOC succeeded...\n"));
241 strncpy(mp
->mnt_stat
.f_fstypename
, synthfs_fs_name
, sizeof(mp
->mnt_stat
.f_fstypename
));
242 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, sizeof(mp
->mnt_stat
.f_mntonname
) - 1, &size
);
243 strncpy(mp
->mnt_stat
.f_mntfromname
, synthfs_fake_mntfromname
, sizeof(mp
->mnt_stat
.f_mntfromname
));
244 priv_mnt_data
->synthfs_mounteddev
= (dev_t
)0;
245 priv_mnt_data
->synthfs_nextid
= FIRST_SYNTHFS_ID
;
246 priv_mnt_data
->synthfs_filecount
= 0;
247 priv_mnt_data
->synthfs_dircount
= 0;
248 priv_mnt_data
->synthfs_encodingsused
= 0x00000001;
251 Set up the root vnode for fast reference in the future.
252 Note that synthfs_new_directory() returns the vnode with a refcount of +2.
253 The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount.
255 error
= synthfs_new_directory(mp
, NULL
, "", ROOT_DIRID
, (S_IRWXU
|S_IRWXG
|S_IROTH
|S_IXOTH
), p
, &priv_mnt_data
->synthfs_rootvp
);
257 DBG_VOP(("Attempt to create root directory failed with error %d.\n", error
));
260 priv_mnt_data
->synthfs_rootvp
->v_flag
|= VROOT
;
262 priv_mnt_data
->synthfs_mp
= mp
;
263 mp
->mnt_data
= (void *)priv_mnt_data
;
265 /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent
266 the vnode from beeing freed: */
267 vput(priv_mnt_data
->synthfs_rootvp
);
275 synthfs_mount(mp
, path
, data
, ndp
, p
)
276 register struct mount
*mp
;
279 struct nameidata
*ndp
;
284 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, sizeof(mp
->mnt_stat
.f_mntonname
) - 1, &size
);
285 synthfs_mount_fs(mp
, path
, data
, ndp
, p
);
294 * Initialize the filesystem
298 struct vfsconf
*vfsp
;
300 DBG_VOP(("synthfs_init called.\n"));
305 synthfs_start(mp
, flags
, p
)
310 DBG_VOP(("synthfs_start called.\n"));
315 * Return the root of a filesystem.
318 synthfs_root(mp
, vpp
)
322 unsigned long root_nodeid
= ROOT_DIRID
;
324 DBG_VOP(("synthfs_root called.\n"));
326 *vpp
= VFSTOSFS(mp
)->synthfs_rootvp
;
327 return vget(VFSTOSFS(mp
)->synthfs_rootvp
, LK_EXCLUSIVE
| LK_RETRY
, current_proc());
331 synthfs_quotactl(mp
, cmds
, uid
, arg
, p
)
338 DBG_VOP(("synthfs_quotactl called.\n"));
343 * unmount system call
346 synthfs_unmount(mp
, mntflags
, p
)
351 struct synthfs_mntdata
*synth
;
352 struct vnode
*root_vp
;
355 DBG_VOP(("synthfs_unmount called.\n"));
356 synth
= (struct synthfs_mntdata
*)mp
->mnt_data
;
358 root_vp
= synth
->synthfs_rootvp
;
359 retval
= vflush(mp
, root_vp
, (mntflags
& MNT_FORCE
) ? FORCECLOSE
: 0);
360 if (retval
&& ((mntflags
& MNT_FORCE
) == 0)) goto Err_Exit
;
362 /* Free the root vnode.
363 Note that there's no need to vget() or vref() it before locking it here:
364 the ref. count has been maintained at +1 ever since mount time. */
366 retval
= vn_lock(root_vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
367 if ((mntflags
& MNT_FORCE
) == 0) {
368 if (retval
) goto Err_Exit
;
370 if (root_vp
->v_usecount
> 1) {
371 DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp
, synth
->synthfs_rootvp
->v_usecount
));
372 VOP_UNLOCK(root_vp
, 0, p
);
378 synth
->synthfs_rootvp
= NULL
;
381 vput(root_vp
); /* This drops synthfs's own refcount */
386 /* All vnodes should be gone, and no errors, clean up the last */
389 FREE(synth
, M_SYNTHFS
);
393 if (mntflags
& MNT_FORCE
) retval
= 0;
399 * Get file system statistics.
402 synthfs_statfs(mp
, sbp
, p
)
404 register struct statfs
*sbp
;
407 DBG_VOP(("synthfs_statfs called.\n"));
411 sbp
->f_blocks
= 1024; // lies, darn lies and virtual file systems
412 sbp
->f_bfree
= 0; // Nope, can't write here!
414 sbp
->f_files
= VFSTOSFS(mp
)->synthfs_filecount
+ VFSTOSFS(mp
)->synthfs_dircount
;
416 strncpy(sbp
->f_mntonname
, mp
->mnt_stat
.f_mntonname
, sizeof(sbp
->f_mntonname
));
417 strncpy(sbp
->f_mntfromname
, mp
->mnt_stat
.f_mntfromname
, sizeof(sbp
->f_mntfromname
));
423 * synthfs doesn't have any data or backing store and you can't write into any of the synthfs
424 * structures, so don't do anything
427 synthfs_sync(mp
, waitfor
, cred
, p
)
433 // DBG_VOP(("synthfs_sync called\n"));
437 * Look up a synthfs node by node number.
440 synthfs_vget(mp
, ino
, vpp
)
447 // DBG_VOP(("synthfs_vget called\n"));
449 /* Check for unmount in progress */
450 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
456 LIST_FOREACH(vp
, &mp
->mnt_vnodelist
, v_mntvnodes
) {
457 if (VTOS(vp
)->s_nodeid
== *((unsigned long *)ino
)) {
458 if (vget(vp
, LK_EXCLUSIVE
, current_proc()) != 0) {
470 * fast filesystem related variables.
473 synthfs_sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
, p
)
482 DBG_VOP(("synthfs_sysctl called.\n"));
487 * File handle to vnode
491 synthfs_fhtovp(mp
, fhp
, nam
, vpp
, exflagsp
, credanonp
)
492 register struct mount
*mp
;
497 struct ucred
**credanonp
;
499 DBG_VOP(("synthfs_fhtovp called.\n"));
504 * Vnode pointer to File handle
508 synthfs_vptofh(vp
, fhp
)
512 DBG_VOP(("synthfs_vptofh called.\n"));
522 vn_mkdir(struct proc
*p
, char *path
, int mode
) {
528 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE
, path
, p
);
529 if (error
= namei(&nd
)) {
530 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error
));
535 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
541 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
545 vattr
.va_type
= VDIR
;
546 vattr
.va_mode
= (mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
547 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
548 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
550 DBG_VOP(("vn_mkdir: error from VOP_MKDIR (%d).\n", error
));
560 vn_symlink(struct proc
*p
, char *path
, char *link
) {
565 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE
, link
, p
);
566 if (error
= namei(&nd
)) return error
;
569 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
570 if (nd
.ni_dvp
== nd
.ni_vp
)
578 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
579 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
580 return VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);