/*
- * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <sys/systm.h>
#include <sys/namei.h>
#include <sys/filedesc.h>
-#include <sys/proc.h>
+#include <sys/proc_internal.h>
#include <sys/kernel.h>
#include <mach/machine/vm_types.h>
-#include <sys/vnode.h>
+#include <sys/vnode_internal.h>
#include <sys/socket.h>
-#include <sys/mount.h>
-#include <sys/buf.h>
+#include <sys/mount_internal.h>
#include <sys/mbuf.h>
#include <sys/file.h>
#include <sys/disk.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <sys/attr.h>
+#include <sys/uio_internal.h>
#include <miscfs/specfs/specdev.h>
synthfs_start,
synthfs_unmount,
synthfs_root,
- synthfs_quotactl,
- synthfs_statfs,
+ NULL, /* quotactl */
+ synthfs_vfs_getattr,
synthfs_sync,
synthfs_vget,
synthfs_fhtovp,
#define ROOTMPMODE 0755
#define ROOTPLACEHOLDERMODE 0700
-static char synthfs_fs_name[MFSNAMELEN] = "synthfs";
+static char synthfs_fs_name[MFSTYPENAMELEN] = "synthfs";
static char synthfs_fake_mntfromname[] = "<synthfs>";
#if LOADABLE_FS
void
synthfs_load(int loadArgument) {
- struct vfsconf *newvfsconf = NULL;
- int j;
- int (***opv_desc_vector_p)() = NULL;
- int (**opv_desc_vector)();
- struct vnodeopv_entry_desc *opve_descp;
- int error = 0;
-
-#pragma unused(loadArgument)
-
- /*
- * This routine is responsible for all the initialization that would
- * ordinarily be done as part of the system startup; it calls synthfs_init
- * to do the initialization that is strictly synthfs-specific.
- */
-
- DBG_VOP(("load_synthfs: starting ...\n"));
-
- MALLOC(newvfsconf, void *, sizeof(struct vfsconf), M_SYNTHFS, M_WAITOK);
- DBG_VOP(("load_synthfs: Allocated new vfsconf list entry, newvfsconf = 0x%08lx.\n", (unsigned long)newvfsconf));
- bzero(newvfsconf, sizeof(struct vfsconf));
-
- if (newvfsconf) {
- DBG_VOP(("load_synthfs: filling in newly allocated vfsconf entry at 0x%08lX.\n", (long)newvfsconf));
- newvfsconf->vfc_vfsops = &synthfs_vfsops;
- strncpy(&newvfsconf->vfc_name[0], synthfs_fs_name, MFSNAMELEN);
- newvfsconf->vfc_typenum = maxvfsconf++;
- newvfsconf->vfc_refcount = 0;
- newvfsconf->vfc_flags = 0;
- newvfsconf->vfc_mountroot = NULL; /* Can't mount root of file system [yet] */
-
- newvfsconf->vfc_next = NULL;
-
- /* Based on vfs_op_init and ... */
- opv_desc_vector_p = synthfs_vnodeop_opv_desc.opv_desc_vector_p;
-
- DBG_VOP(("load_synthfs: Allocating and initializing VNode ops vector...\n"));
-
- /*
- * Allocate and init the vector.
- * Also handle backwards compatibility.
- */
-
- MALLOC(*opv_desc_vector_p, PFI *, vfs_opv_numops*sizeof(PFI), M_SYNTHFS, M_WAITOK);
- bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI));
- opv_desc_vector = *opv_desc_vector_p;
- for (j=0; synthfs_vnodeop_opv_desc.opv_desc_ops[j].opve_op; j++) {
- opve_descp = &(synthfs_vnodeop_opv_desc.opv_desc_ops[j]);
-
- /*
- * Sanity check: is this operation listed
- * in the list of operations? We check this
- * by seeing if its offest is zero. Since
- * the default routine should always be listed
- * first, it should be the only one with a zero
- * offset. Any other operation with a zero
- * offset is probably not listed in
- * vfs_op_descs, and so is probably an error.
- *
- * A panic here means the layer programmer
- * has committed the all-too common bug
- * of adding a new operation to the layer's
- * list of vnode operations but
- * not adding the operation to the system-wide
- * list of supported operations.
- */
- if (opve_descp->opve_op->vdesc_offset == 0 &&
- opve_descp->opve_op->vdesc_offset != VOFFSET(vop_default)) {
- DBG_VOP(("load_synthfs: operation %s not listed in %s.\n",
- opve_descp->opve_op->vdesc_name,
- "vfs_op_descs"));
- panic ("load_synthfs: bad operation");
- }
- /*
- * Fill in this entry.
- */
- opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
- opve_descp->opve_impl;
- }
-
- /*
- * Finally, go back and replace unfilled routines
- * with their default. (Sigh, an O(n^3) algorithm. I
- * could make it better, but that'd be work, and n is small.)
- */
- opv_desc_vector_p = synthfs_vnodeop_opv_desc.opv_desc_vector_p;
-
- /*
- * Force every operations vector to have a default routine.
- */
- opv_desc_vector = *opv_desc_vector_p;
- if (opv_desc_vector[VOFFSET(vop_default)]==NULL) {
- panic("load_vp;fs: operation vector without default routine.");
- }
- for (j = 0;j<vfs_opv_numops; j++)
- if (opv_desc_vector[j] == NULL)
- opv_desc_vector[j] =
- opv_desc_vector[VOFFSET(vop_default)];
-
- if (error = vfsconf_add(newvfsconf)) {
- goto ErrExit;
- };
- goto InitFS;
-
-
-ErrExit: ;
- if (opv_desc_vector_p && *opv_desc_vector_p) FREE(*opv_desc_vector_p, M_SYNTHFS);
-
- if (newvfsconf) FREE (newvfsconf, M_SYNTHFS);
- goto StdExit;
-
-
-InitFS: ;
- DBG_VOP(("load_synthfs: calling synthfs_init()...\n"));
- synthfs_init(newvfsconf);
- };
-
-StdExit: ;
+ /* Should use vfs_fsadd kpi */
}
int synthfs_unload(void) {
- DBG_VOP(("synthfs: Entering synthfs_unload...\n"));
+ /* should use fs_fsremove kpi */
return 0;
}
#endif
* mount system call
*/
int
-synthfs_mount_fs(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p)
+synthfs_mount_fs(struct mount *mp, vnode_t devvp, __unused user_addr_t data, struct proc *p)
{
struct synthfs_mntdata *priv_mnt_data;
int error;
MALLOC(priv_mnt_data, struct synthfs_mntdata *, sizeof(struct synthfs_mntdata), M_SYNTHFS, M_WAITOK);
DBG_VOP(("MALLOC succeeded...\n"));
- strncpy(mp->mnt_stat.f_fstypename, synthfs_fs_name, sizeof(mp->mnt_stat.f_fstypename));
- (void) copyinstr(path, mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
- strncpy(mp->mnt_stat.f_mntfromname, synthfs_fake_mntfromname, sizeof(mp->mnt_stat.f_mntfromname));
+ strncpy(mp->mnt_vfsstat.f_fstypename, synthfs_fs_name, sizeof(mp->mnt_vfsstat.f_fstypename));
+ strncpy(mp->mnt_vfsstat.f_mntfromname, synthfs_fake_mntfromname, sizeof(mp->mnt_vfsstat.f_mntfromname));
priv_mnt_data->synthfs_mounteddev = (dev_t)0;
priv_mnt_data->synthfs_nextid = FIRST_SYNTHFS_ID;
priv_mnt_data->synthfs_filecount = 0;
/* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent
the vnode from beeing freed: */
- vput(priv_mnt_data->synthfs_rootvp);
+ vnode_put(priv_mnt_data->synthfs_rootvp);
return (0);
}
int
-synthfs_mount(mp, path, data, ndp, p)
+synthfs_mount(mp, devvp, data, context)
register struct mount *mp;
- char *path;
- caddr_t data;
- struct nameidata *ndp;
- struct proc *p;
+ vnode_t devvp;
+ user_addr_t data;
+ vfs_context_t context;
{
size_t size;
- (void) copyinstr(path, mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
- return (synthfs_mount_fs(mp, path, data, ndp, p));
+ return (synthfs_mount_fs(mp, devvp, data, vfs_context_proc(context)));
}
}
int
-synthfs_start(mp, flags, p)
+synthfs_start(mp, flags, context)
struct mount * mp;
int flags;
-struct proc * p;
+vfs_context_t context;
{
DBG_VOP(("synthfs_start called.\n"));
return 0;
* Return the root of a filesystem.
*/
int
-synthfs_root(mp, vpp)
+synthfs_root(mp, vpp, context)
struct mount *mp;
struct vnode **vpp;
+ vfs_context_t context;
{
unsigned long root_nodeid = ROOT_DIRID;
DBG_VOP(("synthfs_root called.\n"));
*vpp = VFSTOSFS(mp)->synthfs_rootvp;
- return vget(VFSTOSFS(mp)->synthfs_rootvp, LK_EXCLUSIVE | LK_RETRY, current_proc());
-}
-
-int
-synthfs_quotactl(mp, cmds, uid, arg, p)
-struct mount *mp;
-int cmds;
-uid_t uid;
-caddr_t arg;
-struct proc * p;
-{
- DBG_VOP(("synthfs_quotactl called.\n"));
- return (0);
+ return vnode_get(VFSTOSFS(mp)->synthfs_rootvp);
}
/*
* unmount system call
*/
int
-synthfs_unmount(mp, mntflags, p)
+synthfs_unmount(mp, mntflags, context)
struct mount *mp;
int mntflags;
- struct proc *p;
+ vfs_context_t context;
{
struct synthfs_mntdata *synth;
struct vnode *root_vp;
if (retval && ((mntflags & MNT_FORCE) == 0)) goto Err_Exit;
/* Free the root vnode.
- Note that there's no need to vget() or vref() it before locking it here:
the ref. count has been maintained at +1 ever since mount time. */
if (root_vp) {
- retval = vn_lock(root_vp, LK_EXCLUSIVE | LK_RETRY, p);
if ((mntflags & MNT_FORCE) == 0) {
if (retval) goto Err_Exit;
if (root_vp->v_usecount > 1) {
DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp, synth->synthfs_rootvp->v_usecount));
- VOP_UNLOCK(root_vp, 0, p);
retval = EBUSY;
goto Err_Exit;
};
synth->synthfs_rootvp = NULL;
if (retval == 0) {
- vput(root_vp); /* This drops synthfs's own refcount */
- vgone(root_vp);
+ vnode_get(root_vp);
+ vnode_rele(root_vp);
+ vnode_recycle(root_vp);
+ vnode_put(root_vp); /* This drops synthfs's own refcount */
};
};
* Get file system statistics.
*/
int
-synthfs_statfs(mp, sbp, p)
- struct mount *mp;
- register struct statfs *sbp;
- struct proc *p;
+synthfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context)
{
- DBG_VOP(("synthfs_statfs called.\n"));
-
- sbp->f_bsize = 512;
- sbp->f_iosize = 512;
- sbp->f_blocks = 1024; // lies, darn lies and virtual file systems
- sbp->f_bfree = 0; // Nope, can't write here!
- sbp->f_bavail = 0;
- sbp->f_files = VFSTOSFS(mp)->synthfs_filecount + VFSTOSFS(mp)->synthfs_dircount;
- sbp->f_ffree = 0;
- strncpy(sbp->f_mntonname, mp->mnt_stat.f_mntonname, sizeof(sbp->f_mntonname));
- strncpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname, sizeof(sbp->f_mntfromname));
-
- return (0);
+ struct synthfs_mntdata *synthfs_mp = VFSTOSFS(mp);
+ DBG_VOP(("synthfs_vfs_getattr called.\n"));
+
+ VFSATTR_RETURN(fsap, f_bsize, 512);
+ VFSATTR_RETURN(fsap, f_iosize, 512);
+ VFSATTR_RETURN(fsap, f_blocks, 1024);
+ VFSATTR_RETURN(fsap, f_bfree, 0);
+ VFSATTR_RETURN(fsap, f_bavail, 0);
+ VFSATTR_RETURN(fsap, f_bused, 1024);
+ VFSATTR_RETURN(fsap, f_files, synthfs_mp->synthfs_filecount + synthfs_mp->synthfs_dircount);
+ VFSATTR_RETURN(fsap, f_ffree, 0);
+ VFSATTR_RETURN(fsap, f_fssubtype, 0);
+
+ return 0;
}
/*
* structures, so don't do anything
*/
int
-synthfs_sync(mp, waitfor, cred, p)
+synthfs_sync(mp, waitfor, context)
struct mount *mp;
int waitfor;
- struct ucred *cred;
- struct proc *p;
+ vfs_context_t context;
{
// DBG_VOP(("synthfs_sync called\n"));
return 0;
* Look up a synthfs node by node number.
*/
int
-synthfs_vget(mp, ino, vpp)
+synthfs_vget(mp, ino, vpp, context)
struct mount *mp;
- void *ino;
+ ino64_t ino;
struct vnode **vpp;
+ vfs_context_t context;
{
struct vnode *vp;
+ int vid = 0;
// DBG_VOP(("synthfs_vget called\n"));
}
loop:
- simple_lock(&mntvnode_slock);
- LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
- if (VTOS(vp)->s_nodeid == *((unsigned long *)ino)) {
- if (vget(vp, LK_EXCLUSIVE, current_proc()) != 0) {
- simple_unlock(&mntvnode_slock);
- goto loop;
- };
- simple_unlock(&mntvnode_slock);
+ TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
+ if (VTOS(vp)->s_nodeid == (unsigned long)ino) {
+ /*
+ * doing a vnode_getwithvid isn't technically
+ * necessary since synthfs is an unsafe filesystem
+ * and we're running behind a funnel at this point
+ * however, vnode_get always succeeds, which isn't
+ * what we want if this vnode is in the process of
+ * being terminated
+ */
+ vid = vnode_vid(vp);
+
+ if (vnode_getwithvid(vp, vid) != 0) {
+ goto loop;
+ };
*vpp = vp;
return 0;
};
};
- simple_unlock(&mntvnode_slock);
*vpp = NULL;
return -1;
}
* fast filesystem related variables.
*/
int
-synthfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
- int *name;
- u_int namelen;
- void *oldp;
- size_t *oldlenp;
- void *newp;
- size_t newlen;
- struct proc *p;
+synthfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
+ user_addr_t newp, size_t newlen, vfs_context_t context)
{
DBG_VOP(("synthfs_sysctl called.\n"));
- return (EOPNOTSUPP);
+ return (ENOTSUP);
}
/*
*
*/
int
-synthfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
+synthfs_fhtovp(mp, fhlen, fhp, vpp, context)
register struct mount *mp;
- struct fid *fhp;
- struct mbuf *nam;
+ int fhlen;
+ unsigned char *fhp;
struct vnode **vpp;
- int *exflagsp;
- struct ucred **credanonp;
+ vfs_context_t context;
{
DBG_VOP(("synthfs_fhtovp called.\n"));
- return EOPNOTSUPP;
+ return ENOTSUP;
}
/*
*/
/* ARGSUSED */
int
-synthfs_vptofh(vp, fhp)
+synthfs_vptofh(vp, fhlenp, fhp, context)
struct vnode *vp;
- struct fid *fhp;
+ int *fhlenp;
+ unsigned char *fhp;
+ vfs_context_t context;
{
DBG_VOP(("synthfs_vptofh called.\n"));
- return EOPNOTSUPP;
+ return ENOTSUP;
}
int
-vn_mkdir(struct proc *p, char *path, int mode) {
+vn_mkdir(struct proc *p, char *path, int mode)
+{
struct nameidata nd;
struct vnode *vp;
- struct vattr vattr;
+ struct vnode_attr va;
+ struct vfs_context context;
int error;
- NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, path, p);
- if (error = namei(&nd)) {
+ context.vc_proc = p;
+ context.vc_ucred = proc_ucred(p); /* XXX kauth_cred_get() ??? proxy */
+
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(path), &context);
+ error = namei(&nd);
+ if (error) {
DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error));
return (error);
};
vp = nd.ni_vp;
- if (vp != NULL) {
- VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
- if (nd.ni_dvp == vp)
- vrele(nd.ni_dvp);
- else
- vput(nd.ni_dvp);
- vrele(vp);
+
+ if (vp == NULL) {
+ VATTR_INIT(&va);
+ VATTR_SET(&va, va_type, VDIR);
+ VATTR_SET(&va, va_mode, (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask);
+
+ error = vn_create(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, 0, &context);
+ if (error)
+ DBG_VOP(("vn_mkdir: error from vnop_mkdir (%d).\n", error));
+ } else {
DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
- return (EEXIST);
+ error = EEXIST;
}
- VATTR_NULL(&vattr);
- vattr.va_type = VDIR;
- vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
- VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
- error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
- if (error) {
- DBG_VOP(("vn_mkdir: error from VOP_MKDIR (%d).\n", error));
- } else {
- vput(nd.ni_vp);
- };
+ vnode_put(nd.ni_dvp);
+ if (nd.ni_vp)
+ vnode_put(nd.ni_vp);
+ nameidone(&nd);
+
return (error);
}
int
vn_symlink(struct proc *p, char *path, char *link) {
struct nameidata nd;
- struct vattr vattr;
+ struct vnode_attr va;
+ struct vfs_context context;
int error;
- NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, link, p);
- if (error = namei(&nd)) return error;
-
- if (nd.ni_vp) {
- VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
- if (nd.ni_dvp == nd.ni_vp)
- vrele(nd.ni_dvp);
- else
- vput(nd.ni_dvp);
- vrele(nd.ni_vp);
- return EEXIST;
- }
- VATTR_NULL(&vattr);
- vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
- VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
- return VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
+ context.vc_proc = p;
+ context.vc_ucred = proc_ucred(p); /* XXX kauth_cred_get() ??? proxy */
+
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(link), &context);
+ if ((error = namei(&nd))) return error;
+
+ if (nd.ni_vp == NULL) {
+ VATTR_INIT(&va);
+ VATTR_SET(&va, va_type, VLNK);
+ VATTR_SET(&va, va_mode, ACCESSPERMS &~ p->p_fd->fd_cmask);
+
+ error = VNOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, path, &context);
+ } else
+ error = EEXIST;
+
+ vnode_put(nd.ni_dvp);
+ if (nd.ni_vp)
+ vnode_put(nd.ni_vp);
+ nameidone(&nd);
+
+ return (error);
}