2 * Copyright (c) 2000-2001 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 <sys/vnode.h>
38 #include <sys/socket.h>
39 #include <sys/mount.h>
44 #include <sys/ioctl.h>
45 #include <sys/errno.h>
46 #include <sys/malloc.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
[MFSNAMELEN
] = "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 struct vfsconf
*newvfsconf
= NULL
;
96 int (***opv_desc_vector_p
)() = NULL
;
97 int (**opv_desc_vector
)();
98 struct vnodeopv_entry_desc
*opve_descp
;
101 #pragma unused(loadArgument)
104 * This routine is responsible for all the initialization that would
105 * ordinarily be done as part of the system startup; it calls synthfs_init
106 * to do the initialization that is strictly synthfs-specific.
109 DBG_VOP(("load_synthfs: starting ...\n"));
111 MALLOC(newvfsconf
, void *, sizeof(struct vfsconf
), M_SYNTHFS
, M_WAITOK
);
112 DBG_VOP(("load_synthfs: Allocated new vfsconf list entry, newvfsconf = 0x%08lx.\n", (unsigned long)newvfsconf
));
113 bzero(newvfsconf
, sizeof(struct vfsconf
));
116 DBG_VOP(("load_synthfs: filling in newly allocated vfsconf entry at 0x%08lX.\n", (long)newvfsconf
));
117 newvfsconf
->vfc_vfsops
= &synthfs_vfsops
;
118 strncpy(&newvfsconf
->vfc_name
[0], synthfs_fs_name
, MFSNAMELEN
);
119 newvfsconf
->vfc_typenum
= maxvfsconf
++;
120 newvfsconf
->vfc_refcount
= 0;
121 newvfsconf
->vfc_flags
= 0;
122 newvfsconf
->vfc_mountroot
= NULL
; /* Can't mount root of file system [yet] */
124 newvfsconf
->vfc_next
= NULL
;
126 /* Based on vfs_op_init and ... */
127 opv_desc_vector_p
= synthfs_vnodeop_opv_desc
.opv_desc_vector_p
;
129 DBG_VOP(("load_synthfs: Allocating and initializing VNode ops vector...\n"));
132 * Allocate and init the vector.
133 * Also handle backwards compatibility.
136 MALLOC(*opv_desc_vector_p
, PFI
*, vfs_opv_numops
*sizeof(PFI
), M_SYNTHFS
, M_WAITOK
);
137 bzero (*opv_desc_vector_p
, vfs_opv_numops
*sizeof(PFI
));
138 opv_desc_vector
= *opv_desc_vector_p
;
139 for (j
=0; synthfs_vnodeop_opv_desc
.opv_desc_ops
[j
].opve_op
; j
++) {
140 opve_descp
= &(synthfs_vnodeop_opv_desc
.opv_desc_ops
[j
]);
143 * Sanity check: is this operation listed
144 * in the list of operations? We check this
145 * by seeing if its offest is zero. Since
146 * the default routine should always be listed
147 * first, it should be the only one with a zero
148 * offset. Any other operation with a zero
149 * offset is probably not listed in
150 * vfs_op_descs, and so is probably an error.
152 * A panic here means the layer programmer
153 * has committed the all-too common bug
154 * of adding a new operation to the layer's
155 * list of vnode operations but
156 * not adding the operation to the system-wide
157 * list of supported operations.
159 if (opve_descp
->opve_op
->vdesc_offset
== 0 &&
160 opve_descp
->opve_op
->vdesc_offset
!= VOFFSET(vop_default
)) {
161 DBG_VOP(("load_synthfs: operation %s not listed in %s.\n",
162 opve_descp
->opve_op
->vdesc_name
,
164 panic ("load_synthfs: bad operation");
167 * Fill in this entry.
169 opv_desc_vector
[opve_descp
->opve_op
->vdesc_offset
] =
170 opve_descp
->opve_impl
;
174 * Finally, go back and replace unfilled routines
175 * with their default. (Sigh, an O(n^3) algorithm. I
176 * could make it better, but that'd be work, and n is small.)
178 opv_desc_vector_p
= synthfs_vnodeop_opv_desc
.opv_desc_vector_p
;
181 * Force every operations vector to have a default routine.
183 opv_desc_vector
= *opv_desc_vector_p
;
184 if (opv_desc_vector
[VOFFSET(vop_default
)]==NULL
) {
185 panic("load_vp;fs: operation vector without default routine.");
187 for (j
= 0;j
<vfs_opv_numops
; j
++)
188 if (opv_desc_vector
[j
] == NULL
)
190 opv_desc_vector
[VOFFSET(vop_default
)];
192 if (error
= vfsconf_add(newvfsconf
)) {
199 if (opv_desc_vector_p
&& *opv_desc_vector_p
) FREE(*opv_desc_vector_p
, M_SYNTHFS
);
201 if (newvfsconf
) FREE (newvfsconf
, M_SYNTHFS
);
206 DBG_VOP(("load_synthfs: calling synthfs_init()...\n"));
207 synthfs_init(newvfsconf
);
215 int synthfs_unload(void) {
216 DBG_VOP(("synthfs: Entering synthfs_unload...\n"));
230 synthfs_mount_fs(struct mount
*mp
, char *path
, caddr_t data
, struct nameidata
*ndp
, struct proc
*p
)
232 struct synthfs_mntdata
*priv_mnt_data
;
236 DBG_VOP(("synthfs_mount_fs called.\n"));
237 MALLOC(priv_mnt_data
, struct synthfs_mntdata
*, sizeof(struct synthfs_mntdata
), M_SYNTHFS
, M_WAITOK
);
238 DBG_VOP(("MALLOC succeeded...\n"));
240 strncpy(mp
->mnt_stat
.f_fstypename
, synthfs_fs_name
, sizeof(mp
->mnt_stat
.f_fstypename
));
241 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, sizeof(mp
->mnt_stat
.f_mntonname
) - 1, &size
);
242 strncpy(mp
->mnt_stat
.f_mntfromname
, synthfs_fake_mntfromname
, sizeof(mp
->mnt_stat
.f_mntfromname
));
243 priv_mnt_data
->synthfs_mounteddev
= (dev_t
)0;
244 priv_mnt_data
->synthfs_nextid
= FIRST_SYNTHFS_ID
;
245 priv_mnt_data
->synthfs_filecount
= 0;
246 priv_mnt_data
->synthfs_dircount
= 0;
247 priv_mnt_data
->synthfs_encodingsused
= 0x00000001;
250 Set up the root vnode for fast reference in the future.
251 Note that synthfs_new_directory() returns the vnode with a refcount of +2.
252 The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount.
254 error
= synthfs_new_directory(mp
, NULL
, "", ROOT_DIRID
, (S_IRWXU
|S_IRWXG
|S_IROTH
|S_IXOTH
), p
, &priv_mnt_data
->synthfs_rootvp
);
256 DBG_VOP(("Attempt to create root directory failed with error %d.\n", error
));
259 priv_mnt_data
->synthfs_rootvp
->v_flag
|= VROOT
;
261 priv_mnt_data
->synthfs_mp
= mp
;
262 mp
->mnt_data
= (void *)priv_mnt_data
;
264 /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent
265 the vnode from beeing freed: */
266 vput(priv_mnt_data
->synthfs_rootvp
);
274 synthfs_mount(mp
, path
, data
, ndp
, p
)
275 register struct mount
*mp
;
278 struct nameidata
*ndp
;
283 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, sizeof(mp
->mnt_stat
.f_mntonname
) - 1, &size
);
284 synthfs_mount_fs(mp
, path
, data
, ndp
, p
);
293 * Initialize the filesystem
297 struct vfsconf
*vfsp
;
299 DBG_VOP(("synthfs_init called.\n"));
304 synthfs_start(mp
, flags
, p
)
309 DBG_VOP(("synthfs_start called.\n"));
314 * Return the root of a filesystem.
317 synthfs_root(mp
, vpp
)
321 unsigned long root_nodeid
= ROOT_DIRID
;
323 DBG_VOP(("synthfs_root called.\n"));
325 *vpp
= VFSTOSFS(mp
)->synthfs_rootvp
;
326 return vget(VFSTOSFS(mp
)->synthfs_rootvp
, LK_EXCLUSIVE
| LK_RETRY
, current_proc());
330 synthfs_quotactl(mp
, cmds
, uid
, arg
, p
)
337 DBG_VOP(("synthfs_quotactl called.\n"));
342 * unmount system call
345 synthfs_unmount(mp
, mntflags
, p
)
350 struct synthfs_mntdata
*synth
;
351 struct vnode
*root_vp
;
354 DBG_VOP(("synthfs_unmount called.\n"));
355 synth
= (struct synthfs_mntdata
*)mp
->mnt_data
;
357 root_vp
= synth
->synthfs_rootvp
;
358 retval
= vflush(mp
, root_vp
, (mntflags
& MNT_FORCE
) ? FORCECLOSE
: 0);
359 if (retval
&& ((mntflags
& MNT_FORCE
) == 0)) goto Err_Exit
;
361 /* Free the root vnode.
362 Note that there's no need to vget() or vref() it before locking it here:
363 the ref. count has been maintained at +1 ever since mount time. */
365 retval
= vn_lock(root_vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
366 if ((mntflags
& MNT_FORCE
) == 0) {
367 if (retval
) goto Err_Exit
;
369 if (root_vp
->v_usecount
> 1) {
370 DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp
, synth
->synthfs_rootvp
->v_usecount
));
371 VOP_UNLOCK(root_vp
, 0, p
);
377 synth
->synthfs_rootvp
= NULL
;
380 vput(root_vp
); /* This drops synthfs's own refcount */
385 /* All vnodes should be gone, and no errors, clean up the last */
388 FREE(synth
, M_SYNTHFS
);
392 if (mntflags
& MNT_FORCE
) retval
= 0;
398 * Get file system statistics.
401 synthfs_statfs(mp
, sbp
, p
)
403 register struct statfs
*sbp
;
406 DBG_VOP(("synthfs_statfs called.\n"));
410 sbp
->f_blocks
= 1024; // lies, darn lies and virtual file systems
411 sbp
->f_bfree
= 0; // Nope, can't write here!
413 sbp
->f_files
= VFSTOSFS(mp
)->synthfs_filecount
+ VFSTOSFS(mp
)->synthfs_dircount
;
415 strncpy(sbp
->f_mntonname
, mp
->mnt_stat
.f_mntonname
, sizeof(sbp
->f_mntonname
));
416 strncpy(sbp
->f_mntfromname
, mp
->mnt_stat
.f_mntfromname
, sizeof(sbp
->f_mntfromname
));
422 * synthfs doesn't have any data or backing store and you can't write into any of the synthfs
423 * structures, so don't do anything
426 synthfs_sync(mp
, waitfor
, cred
, p
)
432 // DBG_VOP(("synthfs_sync called\n"));
436 * Look up a synthfs node by node number.
439 synthfs_vget(mp
, ino
, vpp
)
446 // DBG_VOP(("synthfs_vget called\n"));
448 /* Check for unmount in progress */
449 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
455 simple_lock(&mntvnode_slock
);
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) {
459 simple_unlock(&mntvnode_slock
);
462 simple_unlock(&mntvnode_slock
);
467 simple_unlock(&mntvnode_slock
);
473 * fast filesystem related variables.
476 synthfs_sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
, p
)
485 DBG_VOP(("synthfs_sysctl called.\n"));
490 * File handle to vnode
494 synthfs_fhtovp(mp
, fhp
, nam
, vpp
, exflagsp
, credanonp
)
495 register struct mount
*mp
;
500 struct ucred
**credanonp
;
502 DBG_VOP(("synthfs_fhtovp called.\n"));
507 * Vnode pointer to File handle
511 synthfs_vptofh(vp
, fhp
)
515 DBG_VOP(("synthfs_vptofh called.\n"));
525 vn_mkdir(struct proc
*p
, char *path
, int mode
) {
531 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE
, path
, p
);
532 if (error
= namei(&nd
)) {
533 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error
));
538 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
544 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
548 vattr
.va_type
= VDIR
;
549 vattr
.va_mode
= (mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
550 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
551 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
553 DBG_VOP(("vn_mkdir: error from VOP_MKDIR (%d).\n", error
));
563 vn_symlink(struct proc
*p
, char *path
, char *link
) {
568 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_SYSSPACE
, link
, p
);
569 if (error
= namei(&nd
)) return error
;
572 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
573 if (nd
.ni_dvp
== nd
.ni_vp
)
581 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
582 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
583 return VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);