/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved.
- *
- * Modification History:
- *
- * 2/10/2000 Clark Warner Added copyfile
- * 5/24/1999 Don Brady Fixed security hole in get_fsvnode.
- * 11/18/1998 Don Brady Special case 2 to mean the root of a file system.
- * 9/28/1998 Umesh Vaishampayan Use the default vnode ops. Cleanup
- * header includes.
- * 11/12/1998 Scott Roberts validfsnode only checks to see if the volfs mount flag is set
- * 8/5/1998 Don Brady fix validfsnode logic to handle a "bad" VFS_GET
- * 7/5/1998 Don Brady In volfs_reclaim set vp->v_data to NULL after private data is free (VFS expects a NULL).
- * 4/5/1998 Don Brady Changed lockstatus calls to VOP_ISLOCKED (radar #2231108);
- * 3/25/1998 Pat Dirks Added include for sys/attr.h, which is no longer included indirectly.
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#include <mach/mach_types.h>
#include <sys/resourcevar.h>
#include <sys/kernel.h>
#include <sys/file.h>
+#include <sys/filedesc.h>
#include <sys/stat.h>
-#include <sys/buf.h>
-#include <sys/proc.h>
+#include <sys/proc_internal.h> /* for p_fd */
+#include <sys/kauth.h>
#include <sys/conf.h>
-#include <sys/mount.h>
-#include <sys/vnode.h>
+#include <sys/mount_internal.h>
+#include <sys/vnode_internal.h>
#include <sys/malloc.h>
#include <sys/dirent.h>
#include <sys/namei.h>
#include <sys/attr.h>
+#include <sys/kdebug.h>
+#include <sys/queue.h>
+#include <sys/uio_internal.h>
#include <sys/vm.h>
#include <sys/errno.h>
#include <vfs/vfs_support.h>
+#include <kern/locks.h>
+
#include "volfs.h"
/*
* a similar mechanism.
*/
+static int volfs_reclaim (struct vnop_reclaim_args*);
+static int volfs_getattr (struct vnop_getattr_args *);
+static int volfs_select (struct vnop_select_args *);
+static int volfs_rmdir (struct vnop_rmdir_args *);
+static int volfs_readdir (struct vnop_readdir_args *);
+static int volfs_pathconf (struct vnop_pathconf_args *);
+static int volfs_lookup (struct vnop_lookup_args *);
+
+static int volfs_readdir_callback(mount_t, void *);
+static int get_filevnode(struct mount *parent_fs, u_int id, vnode_t *ret_vnode, vfs_context_t context);
+static int get_fsvnode(struct mount *our_mount, int id, vnode_t *ret_vnode);
+
+/* for the call back function in volfs_readdir */
+struct volfs_rdstruct {
+ int validindex;
+ vnode_t vp;
+ int rec_offset;
+ struct uio * uio;
+};
+
#define VOPFUNC int (*)(void *)
/* Global vfs data structures for volfs. */
int (**volfs_vnodeop_p) (void *);
struct vnodeopv_entry_desc volfs_vnodeop_entries[] = {
- {&vop_default_desc, (VOPFUNC)vn_default_error},
- {&vop_strategy_desc, (VOPFUNC)err_strategy}, /* strategy */
- {&vop_bwrite_desc, (VOPFUNC)err_bwrite}, /* bwrite */
- {&vop_lookup_desc, (VOPFUNC)volfs_lookup}, /* lookup */
- {&vop_create_desc, (VOPFUNC)err_create}, /* create */
- {&vop_whiteout_desc, (VOPFUNC)err_whiteout}, /* whiteout */
- {&vop_mknod_desc, (VOPFUNC)err_mknod}, /* mknod */
- {&vop_mkcomplex_desc, (VOPFUNC)err_mkcomplex}, /* mkcomplex */
- {&vop_open_desc, (VOPFUNC)nop_open}, /* open */
- {&vop_close_desc, (VOPFUNC)nop_close}, /* close */
- {&vop_access_desc, (VOPFUNC)volfs_access}, /* access */
- {&vop_getattr_desc, (VOPFUNC)volfs_getattr}, /* getattr */
- {&vop_setattr_desc, (VOPFUNC)err_setattr}, /* setattr */
- {&vop_getattrlist_desc, (VOPFUNC)err_getattrlist}, /* getattrlist */
- {&vop_setattrlist_desc, (VOPFUNC)err_setattrlist}, /* setattrlist */
- {&vop_read_desc, (VOPFUNC)err_read}, /* read */
- {&vop_write_desc, (VOPFUNC)err_write}, /* write */
- {&vop_lease_desc, (VOPFUNC)err_lease}, /* lease */
- {&vop_ioctl_desc, (VOPFUNC)err_ioctl}, /* ioctl */
- {&vop_select_desc, (VOPFUNC)volfs_select}, /* select */
- {&vop_exchange_desc, (VOPFUNC)err_exchange}, /* exchange */
- {&vop_revoke_desc, (VOPFUNC)nop_revoke}, /* revoke */
- {&vop_mmap_desc, (VOPFUNC)err_mmap}, /* mmap */
- {&vop_fsync_desc, (VOPFUNC)err_fsync}, /* fsync */
- {&vop_seek_desc, (VOPFUNC)nop_seek}, /* seek */
- {&vop_remove_desc, (VOPFUNC)err_remove}, /* remove */
- {&vop_link_desc, (VOPFUNC)err_link}, /* link */
- {&vop_rename_desc, (VOPFUNC)err_rename}, /* rename */
- {&vop_mkdir_desc, (VOPFUNC)err_mkdir}, /* mkdir */
- {&vop_rmdir_desc, (VOPFUNC)volfs_rmdir}, /* rmdir */
- {&vop_symlink_desc, (VOPFUNC)err_symlink}, /* symlink */
- {&vop_readdir_desc, (VOPFUNC)volfs_readdir}, /* readdir */
- {&vop_readdirattr_desc, (VOPFUNC)err_readdirattr}, /* readdirattr */
- {&vop_readlink_desc, (VOPFUNC)err_readlink}, /* readlink */
- {&vop_abortop_desc, (VOPFUNC)err_abortop}, /* abortop */
- {&vop_inactive_desc, (VOPFUNC)err_inactive}, /* inactive */
- {&vop_reclaim_desc, (VOPFUNC)volfs_reclaim}, /* reclaim */
- {&vop_lock_desc, (VOPFUNC)volfs_lock}, /* lock */
- {&vop_unlock_desc, (VOPFUNC)volfs_unlock}, /* unlock */
- {&vop_bmap_desc, (VOPFUNC)err_bmap}, /* bmap */
- {&vop_print_desc, (VOPFUNC)err_print}, /* print */
- {&vop_islocked_desc, (VOPFUNC)volfs_islocked}, /* islocked */
- {&vop_pathconf_desc, (VOPFUNC)volfs_pathconf}, /* pathconf */
- {&vop_advlock_desc, (VOPFUNC)err_advlock}, /* advlock */
- {&vop_blkatoff_desc, (VOPFUNC)err_blkatoff}, /* blkatoff */
- {&vop_valloc_desc, (VOPFUNC)err_valloc}, /* valloc */
- {&vop_reallocblks_desc, (VOPFUNC)err_reallocblks}, /* reallocblks */
- {&vop_vfree_desc, (VOPFUNC)err_vfree}, /* vfree */
- {&vop_truncate_desc, (VOPFUNC)err_truncate}, /* truncate */
- {&vop_allocate_desc, (VOPFUNC)err_allocate}, /* allocate */
- {&vop_update_desc, (VOPFUNC)err_update}, /* update */
- {&vop_pgrd_desc, (VOPFUNC)err_pgrd}, /* pgrd */
- {&vop_pgwr_desc, (VOPFUNC)err_pgwr}, /* pgwr */
- {&vop_pagein_desc, (VOPFUNC)err_pagein}, /* pagein */
- {&vop_pageout_desc, (VOPFUNC)err_pageout}, /* pageout */
- {&vop_devblocksize_desc, (VOPFUNC)err_devblocksize}, /* devblocksize */
- {&vop_searchfs_desc, (VOPFUNC)err_searchfs}, /* searchfs */
- {&vop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */
- {&vop_blktooff_desc, (VOPFUNC)err_blktooff}, /* blktooff */
- {&vop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk */
- {&vop_cmap_desc, (VOPFUNC)err_cmap }, /* cmap */
+ {&vnop_default_desc, (VOPFUNC)vn_default_error},
+ {&vnop_strategy_desc, (VOPFUNC)err_strategy}, /* strategy */
+ {&vnop_bwrite_desc, (VOPFUNC)err_bwrite}, /* bwrite */
+ {&vnop_lookup_desc, (VOPFUNC)volfs_lookup}, /* lookup */
+ {&vnop_create_desc, (VOPFUNC)err_create}, /* create */
+ {&vnop_whiteout_desc, (VOPFUNC)err_whiteout}, /* whiteout */
+ {&vnop_mknod_desc, (VOPFUNC)err_mknod}, /* mknod */
+ {&vnop_open_desc, (VOPFUNC)nop_open}, /* open */
+ {&vnop_close_desc, (VOPFUNC)nop_close}, /* close */
+ {&vnop_getattr_desc, (VOPFUNC)volfs_getattr}, /* getattr */
+ {&vnop_setattr_desc, (VOPFUNC)err_setattr}, /* setattr */
+ {&vnop_getattrlist_desc, (VOPFUNC)err_getattrlist}, /* getattrlist */
+ {&vnop_setattrlist_desc, (VOPFUNC)err_setattrlist}, /* setattrlist */
+ {&vnop_read_desc, (VOPFUNC)err_read}, /* read */
+ {&vnop_write_desc, (VOPFUNC)err_write}, /* write */
+ {&vnop_ioctl_desc, (VOPFUNC)err_ioctl}, /* ioctl */
+ {&vnop_select_desc, (VOPFUNC)volfs_select}, /* select */
+ {&vnop_exchange_desc, (VOPFUNC)err_exchange}, /* exchange */
+ {&vnop_revoke_desc, (VOPFUNC)nop_revoke}, /* revoke */
+ {&vnop_mmap_desc, (VOPFUNC)err_mmap}, /* mmap */
+ {&vnop_fsync_desc, (VOPFUNC)err_fsync}, /* fsync */
+ {&vnop_remove_desc, (VOPFUNC)err_remove}, /* remove */
+ {&vnop_link_desc, (VOPFUNC)err_link}, /* link */
+ {&vnop_rename_desc, (VOPFUNC)err_rename}, /* rename */
+ {&vnop_mkdir_desc, (VOPFUNC)err_mkdir}, /* mkdir */
+ {&vnop_rmdir_desc, (VOPFUNC)volfs_rmdir}, /* rmdir */
+ {&vnop_symlink_desc, (VOPFUNC)err_symlink}, /* symlink */
+ {&vnop_readdir_desc, (VOPFUNC)volfs_readdir}, /* readdir */
+ {&vnop_readdirattr_desc, (VOPFUNC)err_readdirattr}, /* readdirattr */
+ {&vnop_readlink_desc, (VOPFUNC)err_readlink}, /* readlink */
+ {&vnop_inactive_desc, (VOPFUNC)err_inactive}, /* inactive */
+ {&vnop_reclaim_desc, (VOPFUNC)volfs_reclaim}, /* reclaim */
+ {&vnop_pathconf_desc, (VOPFUNC)volfs_pathconf}, /* pathconf */
+ {&vnop_advlock_desc, (VOPFUNC)err_advlock}, /* advlock */
+ {&vnop_allocate_desc, (VOPFUNC)err_allocate}, /* allocate */
+ {&vnop_pagein_desc, (VOPFUNC)err_pagein}, /* pagein */
+ {&vnop_pageout_desc, (VOPFUNC)err_pageout}, /* pageout */
+ {&vnop_devblocksize_desc, (VOPFUNC)err_devblocksize}, /* devblocksize */
+ {&vnop_searchfs_desc, (VOPFUNC)err_searchfs}, /* searchfs */
+ {&vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */
+ {&vnop_blktooff_desc, (VOPFUNC)err_blktooff}, /* blktooff */
+ {&vnop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk */
+ {&vnop_blockmap_desc, (VOPFUNC)err_blockmap }, /* blockmap */
{(struct vnodeop_desc *) NULL, (int (*) ()) NULL}
};
struct vnodeopv_desc volfs_vnodeop_opv_desc =
{&volfs_vnodeop_p, volfs_vnodeop_entries};
+static char gDotDot[] = "..";
-static int validfsnode(struct mount *fsnode);
+struct finfo {
+ fsobj_id_t parID;
+};
-#if DBG_VOP_TEST_LOCKS
-static void DbgVopTest (int max, int error, VopDbgStoreRec *VopDbgStore, char *funcname);
-#endif /* DBG_VOP_TEST_LOCKS */
+struct finfoattrbuf {
+ unsigned long length;
+ struct finfo fi;
+};
+
+
+static int volfs_getattr_callback(mount_t, void *);
/*
* volfs_reclaim - Reclaim a vnode so that it can be used for other purposes.
- *
- * Locking policy: ignored
*/
-int
+static int
volfs_reclaim(ap)
- struct vop_reclaim_args /* { struct vnode *a_vp; struct proc *a_p; } */ *ap;
+ struct vnop_reclaim_args /* { struct vnode *a_vp; vfs_context_t a_context; } */ *ap;
{
- struct vnode *vp = ap->a_vp;
- void *data = vp->v_data;
-
- DBG_FUNC_NAME("volfs_reclaim");
- DBG_VOP_LOCKS_DECL(1);
- DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
- DBG_VOP_LOCKS_INIT(0, vp, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
+ struct vnode *vp = ap->a_vp;
+ void *data = vp->v_data;
vp->v_data = NULL;
- FREE(data, M_VOLFSNODE);
+ FREE(data, M_VOLFSNODE);
- DBG_VOP_LOCKS_TEST(0);
- return (0);
+ return (0);
}
-/*
- * volfs_access - same access policy for all vnodes and all users (file/directory vnodes
- * for the actual file systems are handled by actual file system)
- *
- * Locking policy: a_vp locked on input and output
- */
-int
-volfs_access(ap)
- struct vop_access_args /* { struct vnode *a_vp; int a_mode; struct
- ucred *a_cred; struct proc *a_p; } */ *ap;
-{
- int ret_err;
- DBG_FUNC_NAME("volfs_access");
- DBG_VOP_LOCKS_DECL(1);
- DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
- DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
+struct volfsgetattr_struct{
+ int numMounts;
+ vnode_t a_vp;
+};
- /*
- * We don't need to check credentials! FS is read-only for everyone
- */
- if (ap->a_mode == VREAD || ap->a_mode == VEXEC)
- ret_err = 0;
- else
- ret_err = EACCES;
+static int
+volfs_getattr_callback(mount_t mp, void * arg)
+{
+ struct volfsgetattr_struct *vstrp = (struct volfsgetattr_struct *)arg;
- DBG_VOP_LOCKS_TEST(ret_err);
- return (ret_err);
+ if (mp != vnode_mount(vstrp->a_vp) && validfsnode(mp))
+ vstrp->numMounts++;
+ return(VFS_RETURNED);
}
/*
* volfs_getattr - fill in the attributes for this vnode
- *
- * Locking policy: don't change anything
*/
-int
+static int
volfs_getattr(ap)
- struct vop_getattr_args /* { struct vnode *a_vp; struct vattr *a_vap;
- struct ucred *a_cred; struct proc *a_p; } */ *ap;
+ struct vnop_getattr_args /* { struct vnode *a_vp; struct vnode_attr *a_vap;
+ vfs_context_t a_context; } */ *ap;
{
struct volfs_vndata *priv_data;
- struct vnode *a_vp;
- struct vattr *a_vap;
+ struct vnode *a_vp;
+ struct vnode_attr *a_vap;
int numMounts = 0;
- DBG_FUNC_NAME("volfs_getattr");
- DBG_VOP_LOCKS_DECL(1);
- DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
- DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS);
+ struct volfsgetattr_struct vstr;
+ struct timespec ts;
a_vp = ap->a_vp;
a_vap = ap->a_vap;
priv_data = a_vp->v_data;
- a_vap->va_type = VDIR;
- a_vap->va_mode = 0444; /* Yup, hard - coded to read - only */
- a_vap->va_nlink = 2;
- a_vap->va_uid = 0; /* Always owned by root */
- a_vap->va_gid = 0; /* Always part of group 0 */
- a_vap->va_fsid = (int) a_vp->v_mount->mnt_stat.f_fsid.val[0];
- a_vap->va_fileid = priv_data->nodeID;
+ VATTR_RETURN(a_vap, va_type, VDIR);
+ VATTR_RETURN(a_vap, va_mode, 0555);
+ VATTR_RETURN(a_vap, va_nlink, 2);
+ VATTR_RETURN(a_vap, va_uid, 0);
+ VATTR_RETURN(a_vap, va_gid, 0);
+ VATTR_RETURN(a_vap, va_fsid, (int) a_vp->v_mount->mnt_vfsstat.f_fsid.val[0]);
+ VATTR_RETURN(a_vap, va_fileid, (uint64_t)((u_long)priv_data->nodeID));
+ VATTR_RETURN(a_vap, va_acl, NULL);
/*
* If it's the root vnode calculate its size based on the number of eligible
* file systems
*/
- if (priv_data->vnode_type == VOLFS_ROOT)
- {
- register struct mount *mp, *nmp;
+ if (priv_data->vnode_type == VOLFS_ROOT) {
+ vstr.numMounts = 0;
+ vstr.a_vp = a_vp;
- simple_lock(&mountlist_slock);
- for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
- if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, ap->a_p)) {
- nmp = mp->mnt_list.cqe_next;
- continue;
- }
+ vfs_iterate(LK_NOWAIT, volfs_getattr_callback, (void *)&vstr);
- if (mp != a_vp->v_mount && validfsnode(mp))
- numMounts++;
+ numMounts = vstr.numMounts;
- simple_lock(&mountlist_slock);
- nmp = mp->mnt_list.cqe_next;
- vfs_unbusy(mp, ap->a_p);
- }
- simple_unlock(&mountlist_slock);
-
- DBG_VOP(("found %d file systems that volfs can support\n", numMounts));
- a_vap->va_size = (numMounts + 2) * VLFSDIRENTLEN;
- }
- else
- {
- a_vap->va_size = 2 * VLFSDIRENTLEN;
- }
- DBG_VOP(("va_size = %d, VLFSDIRENTLEN = %ld\n", (int) a_vap->va_size, VLFSDIRENTLEN));
- a_vap->va_blocksize = 512;
-
- a_vap->va_atime.tv_sec = boottime.tv_sec;
- a_vap->va_atime.tv_nsec = 0;
-
- a_vap->va_mtime.tv_sec = boottime.tv_sec;
- a_vap->va_mtime.tv_nsec = 0;
+ VATTR_RETURN(a_vap, va_data_size, (numMounts + 2) * VLFSDIRENTLEN);
+ } else {
+ VATTR_RETURN(a_vap, va_data_size, 2 * VLFSDIRENTLEN);
+ }
- a_vap->va_ctime.tv_sec = boottime.tv_sec;
- a_vap->va_ctime.tv_nsec = 0;
+ VATTR_RETURN(a_vap, va_iosize, 512);
+ ts.tv_sec = boottime_sec();
+ ts.tv_nsec = 0;
+ VATTR_RETURN(a_vap, va_access_time, ts);
+ VATTR_RETURN(a_vap, va_modify_time, ts);
+ VATTR_RETURN(a_vap, va_change_time, ts);
- a_vap->va_gen = 0;
- a_vap->va_flags = 0;
- a_vap->va_rdev = 0;
- a_vap->va_bytes = a_vap->va_size;
- a_vap->va_filerev = 0;
- a_vap->va_vaflags = 0;
+ VATTR_RETURN(a_vap, va_gen, 0);
+ VATTR_RETURN(a_vap, va_flags, 0);
+ VATTR_RETURN(a_vap, va_rdev, 0);
+ VATTR_RETURN(a_vap, va_filerev, 0);
- DBG_VOP_LOCKS_TEST(0);
return (0);
}
/*
* volfs_select - just say OK. Only possible op is readdir
- *
- * Locking policy: ignore
*/
-int
-volfs_select(ap)
- struct vop_select_args /* { struct vnode *a_vp; int a_which; int
- * a_fflags; struct ucred *a_cred; void * a_wql; struct
- proc *a_p; } */ *ap;
+static int
+volfs_select(__unused struct vnop_select_args *ap)
{
- DBG_VOP(("volfs_select called\n"));
-
- return (1);
+ return (1);
}
/*
* vofls_rmdir - not possible to remove directories in volfs
- *
- * Locking policy: a_dvp & a_vp - locked on entry, unlocked on exit
*/
-int
+static int
volfs_rmdir(ap)
- struct vop_rmdir_args /* { struct vnode *a_dvp; struct vnode *a_vp;
- struct componentname *a_cnp; } */ *ap;
+ struct vnop_rmdir_args /* { struct vnode *a_dvp; struct vnode *a_vp;
+ struct componentname *a_cnp; vfs_context_t a_context; } */ *ap;
{
- DBG_VOP(("volfs_rmdir called\n"));
if (ap->a_dvp == ap->a_vp) {
(void) nop_rmdir(ap);
return (EINVAL);
return (err_rmdir(ap));
}
+
+
+static int
+volfs_readdir_callback(mount_t mp, void * v)
+{
+ struct volfs_rdstruct * vcsp = (struct volfs_rdstruct *)v;
+ struct dirent local_dir;
+ int error;
+
+ if ((mp != vnode_mount(vcsp->vp)) && validfsnode(mp))
+ vcsp->validindex++;
+
+ if (vcsp->rec_offset == vcsp->validindex)
+ {
+ local_dir.d_fileno = mp->mnt_vfsstat.f_fsid.val[0];
+ local_dir.d_type = DT_DIR;
+ local_dir.d_reclen = VLFSDIRENTLEN;
+ local_dir.d_namlen = sprintf(&local_dir.d_name[0], "%d", mp->mnt_vfsstat.f_fsid.val[0]);
+ error = uiomove((char *) &local_dir, VLFSDIRENTLEN, vcsp->uio);
+ vcsp->rec_offset++;
+ }
+
+ return(VFS_RETURNED);
+}
+
/*
* volfs_readdir - Get directory entries
*
* equivalent of the f_fsid.val[0] from their mount structure (typically
* the device id of the volume). The maximum length for a name, then is
* 10 characters.
- *
- * Locking policy: a_vp locked on entry and exit
*/
-int
+static int
volfs_readdir(ap)
- struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio;
- * struct ucred *a_cred; int *a_eofflag; int
- *ncookies; u_long **a_cookies; } */ *ap;
+ struct vnop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio;
+ * int *a_eofflag; int
+ *ncookies; u_long **a_cookies; vfs_context_t a_context; } */ *ap;
{
struct volfs_vndata *priv_data;
register struct uio *uio = ap->a_uio;
int i;
int starting_resid;
off_t off;
- DBG_FUNC_NAME("volfs_readdir");
- DBG_VOP_LOCKS_DECL(1);
-
- DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS);
- DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
- DBG_VOP(("\tuio_offset = %d, uio_resid = %d\n", (int) uio->uio_offset, uio->uio_resid));
- /* We assume it's all one big buffer... */
- if (uio->uio_iovcnt > 1)
- DBG_VOP(("\tuio->uio_iovcnt = %d?\n", uio->uio_iovcnt));
-
+ struct volfs_rdstruct vcs;
+
off = uio->uio_offset;
priv_data = ap->a_vp->v_data;
- starting_resid = uio->uio_resid;
- count = uio->uio_resid;
+ // LP64todo - fix this!
+ starting_resid = count = uio_resid(uio);
/* Make sure we don't return partial entries. */
count -= (uio->uio_offset + count) & (VLFSDIRENTLEN - 1);
- if (count <= 0)
- {
- DBG_VOP(("volfs_readdir: Not enough buffer to read in entries\n"));
- DBG_VOP_LOCKS_TEST(EINVAL);
- return (EINVAL);
- }
+ if (count <= 0) {
+ return (EINVAL);
+ }
/*
* Make sure we're starting on a directory boundary
*/
- if (off & (VLFSDIRENTLEN - 1))
- {
- DBG_VOP_LOCKS_TEST(EINVAL);
- return (EINVAL);
- }
+ if (off & (VLFSDIRENTLEN - 1)) {
+ return (EINVAL);
+ }
rec_offset = off / VLFSDIRENTLEN;
- lost = uio->uio_resid - count;
- uio->uio_resid = count;
- uio->uio_iov->iov_len = count;
+ // LP64todo - fix this!
+ lost = uio_resid(uio) - count;
+ uio_setresid(uio, count);
+ uio_iov_len_set(uio, count);
+#if LP64_DEBUG
+ if (IS_VALID_UIO_SEGFLG(uio->uio_segflg) == 0) {
+ panic("%s :%d - invalid uio_segflg\n", __FILE__, __LINE__);
+ }
+#endif /* LP64_DEBUG */
local_dir.d_reclen = VLFSDIRENTLEN;
/*
* We must synthesize . and ..
*/
- DBG_VOP(("\tstarting ... uio_offset = %d, uio_resid = %d\n",
- (int) uio->uio_offset, uio->uio_resid));
+
if (rec_offset == 0)
{
- DBG_VOP(("\tAdding .\n"));
/*
* Synthesize .
*/
for (i = 1; i < MAXVLFSNAMLEN; i++)
local_dir.d_name[i] = 0;
error = uiomove((char *) &local_dir, VLFSDIRENTLEN, uio);
- DBG_VOP(("\t after adding ., uio_offset = %d, uio_resid = %d\n",
- (int) uio->uio_offset, uio->uio_resid));
rec_offset++;
}
if (rec_offset == 1)
{
- DBG_VOP(("\tAdding ..\n"));
/*
* Synthesize ..
* We only have two levels in the volfs hierarchy. Root's
local_dir.d_name[i] = 0;
error = uiomove((char *) &local_dir, VLFSDIRENTLEN, uio);
rec_offset++;
- DBG_VOP(("\t after adding .., uio_offset = %d, uio_resid = %d\n",
- (int) uio->uio_offset, uio->uio_resid));
}
/*
if (priv_data->vnode_type == VOLFS_FSNODE)
{
*ap->a_eofflag = 1; /* we got all the way to the end */
- DBG_VOP_LOCKS_TEST(error);
return (error);
}
if (rec_offset > 1) {
- register struct mount *mp, *nmp;
- int validnodeindex;
- struct proc *p = uio->uio_procp;
-
- validnodeindex = 1; /* we always have "." and ".." */
-
- simple_lock(&mountlist_slock);
- for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
- if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
- nmp = mp->mnt_list.cqe_next;
- continue;
- }
-
- if (mp != ap->a_vp->v_mount && validfsnode(mp))
- validnodeindex++;
-
- if (rec_offset == validnodeindex)
- {
- local_dir.d_fileno = mp->mnt_stat.f_fsid.val[0];
- local_dir.d_type = DT_DIR;
- local_dir.d_reclen = VLFSDIRENTLEN;
- DBG_VOP(("\tAdding dir entry %d for offset %d\n", mp->mnt_stat.f_fsid.val[0], rec_offset));
- local_dir.d_namlen = sprintf(&local_dir.d_name[0], "%d", mp->mnt_stat.f_fsid.val[0]);
- error = uiomove((char *) &local_dir, VLFSDIRENTLEN, uio);
- DBG_VOP(("\t after adding entry '%s', uio_offset = %d, uio_resid = %d\n",
- &local_dir.d_name[0], (int) uio->uio_offset, uio->uio_resid));
- rec_offset++;
- }
-
- simple_lock(&mountlist_slock);
- nmp = mp->mnt_list.cqe_next;
- vfs_unbusy(mp, p);
- }
- simple_unlock(&mountlist_slock);
+ vcs.validindex = 1; /* we always have "." and ".." */
+ vcs.rec_offset = rec_offset;
+ vcs.vp = ap->a_vp;
+ vcs.uio = uio;
+
+
+ vfs_iterate(0, volfs_readdir_callback, &vcs);
- if (mp == (void *) &mountlist)
+ //if (mp == (void *) &mountlist)
*ap->a_eofflag = 1; /* we got all the way to the end */
}
+ uio_setresid(uio, (uio_resid(uio) + lost));
- uio->uio_resid += lost;
- if (starting_resid == uio->uio_resid)
+ if (starting_resid == uio_resid(uio))
uio->uio_offset = 0;
- DBG_VOP(("\tExiting, uio_offset = %d, uio_resid = %d, ap->a_eofflag = %d\n",
- (int) uio->uio_offset, uio->uio_resid, *ap->a_eofflag));
-
- DBG_VOP_LOCKS_TEST(error);
return (error);
}
*
* This can cause context switching, so caller should be lock safe
*/
-static int
+int
validfsnode(struct mount *fsnode)
{
return 0;
}
-/*
- * volfs_lock - Lock an inode.
- * If its already locked, set the WANT bit and sleep.
- *
- * Locking policy: handled by lockmgr
- */
-int
-volfs_lock(ap)
- struct vop_lock_args /* { struct vnode *a_vp; int a_flags; struct
- proc *a_p; } */ *ap;
-{
- int retval;
- struct volfs_vndata *priv_data;
- DBG_FUNC_NAME("volfs_lock");
- DBG_VOP_LOCKS_DECL(1);
- DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
- DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO);
-
- priv_data = (struct volfs_vndata *) ap->a_vp->v_data;
- retval = lockmgr(&priv_data->lock, ap->a_flags, &ap->a_vp->v_interlock, ap->a_p);
- DBG_VOP_LOCKS_TEST(retval);
- return (retval);
-}
-
-/*
- * volfs_unlock - Unlock an inode.
- *
- * Locking policy: handled by lockmgr
- */
-int
-volfs_unlock(ap)
- struct vop_unlock_args /* { struct vnode *a_vp; int a_flags; struct
- proc *a_p; } */ *ap;
-{
- int retval;
- struct volfs_vndata *priv_data;
- DBG_FUNC_NAME("volfs_unlock");
- DBG_VOP_LOCKS_DECL(1);
- DBG_VOP_PRINT_FUNCNAME();DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n"));
-
- DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_ZERO);
-
- priv_data = (struct volfs_vndata *) ap->a_vp->v_data;
- retval = lockmgr(&priv_data->lock, ap->a_flags | LK_RELEASE,
- &ap->a_vp->v_interlock, ap->a_p);
-
- DBG_VOP_LOCKS_TEST(retval);
- return (retval);
-}
-
-/*
- * volfs_islocked - Check for a locked inode.
- *
- * Locking policy: ignore
- */
-int
-volfs_islocked(ap)
- struct vop_islocked_args /* { struct vnode *a_vp; } */ *ap;
-{
- int retval;
- struct volfs_vndata *priv_data;
-
- DBG_FUNC_NAME("volfs_islocked");
- DBG_VOP_LOCKS_DECL(1);
- //DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
-
- DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO);
- priv_data = (struct volfs_vndata *) ap->a_vp->v_data;
- retval = lockstatus(&priv_data->lock);
-
- DBG_VOP_LOCKS_TEST(retval);
- return (retval);
-}
-
/*
* volfs_pathconf - Return POSIX pathconf information applicable to ufs filesystems.
- *
- * Locking policy: a_vp locked on input and output
*/
-int
+static int
volfs_pathconf(ap)
- struct vop_pathconf_args /* { struct vnode *a_vp; int a_name; int
- *a_retval; } */ *ap;
+ struct vnop_pathconf_args /* { struct vnode *a_vp; int a_name; int
+ *a_retval; vfs_context_t a_context; } */ *ap;
{
- DBG_VOP(("volfs_pathconf called\n"));
-
switch (ap->a_name)
{
case _PC_LINK_MAX:
/* NOTREACHED */
}
+/*
+ * get_parentvp() - internal routine that tries to lookup the parent of vpp.
+ * On success, *vpp is the parent vp and is returned with a reference.
+ */
+static int
+get_parentvp(struct vnode **vpp, struct mount *mp, vfs_context_t context)
+{
+ int result;
+ struct vnode_attr va;
+ struct vnode *child_vp = *vpp;
+
+ VATTR_INIT(&va);
+ VATTR_WANTED(&va, va_parentid);
+ result = vnode_getattr(child_vp, &va, context);
+ if (result) {
+ return result;
+ }
+
+ /* Shift attention to the parent directory vnode: */
+ result = VFS_VGET(mp, (ino64_t)va.va_parentid, vpp, context);
+
+ if (result == 0 && child_vp->v_parent != *vpp) {
+ vnode_update_identity(child_vp, *vpp, NULL, 0, 0, VNODE_UPDATE_PARENT);
+ }
+
+ return result;
+}
+
+
+/*
+ * Look up the parent directory of a given vnode.
+ */
+static int
+lookup_parent(vnode_t child_vp, vnode_t *parent_vpp, int is_authorized, vfs_context_t context)
+{
+ struct componentname cn;
+ vnode_t new_vp;
+ int error;
+
+ *parent_vpp = NULLVP;
+
+ if (is_authorized == 0) {
+ error = vnode_authorize(child_vp, NULL, KAUTH_VNODE_SEARCH, context);
+ if (error != 0) {
+ return (error);
+ }
+ }
+ new_vp = child_vp->v_parent;
+
+ if (new_vp != NULLVP) {
+ if ( (error = vnode_getwithref(new_vp)) == 0 )
+ *parent_vpp = new_vp;
+ return (error);
+ }
+ bzero(&cn, sizeof(cn));
+ cn.cn_nameiop = LOOKUP;
+ cn.cn_context = context;
+ cn.cn_pnbuf = CAST_DOWN(caddr_t, &gDotDot);
+ cn.cn_pnlen = strlen(cn.cn_pnbuf);
+ cn.cn_nameptr = cn.cn_pnbuf;
+ cn.cn_namelen = cn.cn_pnlen;
+ cn.cn_flags = (FOLLOW | LOCKLEAF | ISLASTCN | ISDOTDOT);
+
+ error = VNOP_LOOKUP(child_vp, &new_vp, &cn, context);
+ if (error != 0) {
+ return(error);
+ }
+ if (new_vp == child_vp) {
+ vnode_put(new_vp);
+ return ELOOP;
+ }
+ if (child_vp->v_parent == NULLVP) {
+ vnode_update_identity(child_vp, new_vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
+ }
+ *parent_vpp = new_vp;
+ return 0;
+}
+
+
+/*
+ * verify_fullpathaccess(ret_vnode);
+ */
+
+static int
+verify_fullpathaccess(struct vnode *targetvp, vfs_context_t context)
+{
+ struct vnode *vp, *parent_vp;
+ struct mount *mp = targetvp->v_mount;
+ struct proc *p = vfs_context_proc(context);
+ int result;
+ int dp_authorized;
+ struct filedesc *fdp = p->p_fd; /* pointer to file descriptor state */
+
+ vp = targetvp;
+ dp_authorized = 0;
+
+ /* get the parent directory. */
+ if ((vp->v_flag & VROOT) == 0 && vp != fdp->fd_cdir && vp != fdp->fd_rdir) {
+ if (vp->v_parent == NULLVP || (vp->v_flag & VISHARDLINK) || (vnode_getwithref(vp->v_parent) != 0)) {
+ if (vp->v_type == VDIR) {
+ result = lookup_parent(vp, &parent_vp, dp_authorized, context);
+
+ /*
+ * If the lookup fails with EACCES and the vp is a directory,
+ * we should try again but bypass authorization check. Without this
+ * workaround directories that you can navigate to but not traverse will
+ * disappear when clicked in the Finder.
+ */
+ if (result == EACCES && (vp->v_flag & VROOT) == 0) {
+ dp_authorized = 1; /* bypass auth check */
+ if (lookup_parent(vp, &parent_vp, dp_authorized, context) == 0) {
+ result = 0;
+ }
+ dp_authorized = 0; /* force us to authorize */
+ }
+ vp = parent_vp;
+ }
+ else {
+ /*
+ * this is not a directory so we must get parent object ID
+ */
+ result = get_parentvp(&vp, mp, context);
+ parent_vp = vp;
+ }
+ if (result != 0)
+ goto err_exit;
+ }
+ else {
+ /*
+ * we where able to get a reference on v_parent
+ */
+ parent_vp = vp = vp->v_parent;
+ }
+ }
+
+ /*
+ * Keep going up until either the process's root or the process's working
+ * directory is hit, either one of which are potential valid starting points
+ * for a full pathname
+ */
+ while (vp != NULLVP) {
+
+ result = reverse_lookup(vp, &parent_vp, fdp, context, &dp_authorized);
+ if (result == 0) {
+ /*
+ * we're done and we have access
+ */
+ break;
+ }
+ if (vp != parent_vp) {
+ /*
+ * we where able to walk up the parent chain so now we don't need
+ * vp any longer
+ */
+ vnode_put(vp);
+ vp = parent_vp;
+ }
+ /*
+ * we have a referenced vp at this point... if dp_authorized == 1, than
+ * it's been authorized for search, but v_parent was NULL...
+ * if dp_authorized == 0, than we need to do the authorization check
+ * before looking up the parent
+ */
+ if ((vp->v_flag & VROOT) != 0 ||
+ vp == fdp->fd_cdir || vp == fdp->fd_rdir) {
+ /*
+ * we're already at the termination point, which implies that
+ * the authorization check in the cache failed (otherwise we
+ * would have returned 'done' from "reverse_lookup"... so,
+ * do the authorization and bail
+ */
+ result = vnode_authorize(vp, NULL, KAUTH_VNODE_SEARCH, context);
+ goto lookup_exit;
+ }
+ result = lookup_parent(vp, &parent_vp, dp_authorized, context);
+ if (result != 0) {
+ goto lookup_exit;
+ }
+ if (vp != parent_vp) {
+ /*
+ * got the parent so now we don't need vp any longer
+ */
+ vnode_put(vp);
+ vp = parent_vp;
+ }
+ } /* while loop */
+
+ /*
+ * Success: the caller has complete access to the initial vnode
+ */
+ result = 0;
+
+lookup_exit:
+ if (vp != NULLVP && vp != targetvp) {
+ vnode_put(vp);
+ }
+
+err_exit:
+ return result;
+};
+
+
/*
* get_fsvnode - internal routine to create a vnode for a file system. Called with mount pointer,
* id of filesystem to lookup and pointer to vnode pointer to fill in
*/
static int
-get_fsvnode(our_mount, id, ret_vnode)
- struct mount *our_mount;
- int id;
- struct vnode **ret_vnode;
+get_fsvnode(struct mount *our_mount, int id, vnode_t *ret_vnode)
{
- register struct mount *mp;
struct mount *cur_mount;
+ fsid_t cur_fsid;
struct vnode *cur_vnode;
struct volfs_vndata *cur_privdata;
int retval;
-
- //DBG_VOP(("volfs: get_fsvnode called\n"));
+ struct vnode_fsparam vfsp;
+ int vid = 0;
/*
* OK, first look up the matching mount on the list of mounted file systems
*/
- cur_mount = NULL;
- simple_lock(&mountlist_slock);
- for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = mp->mnt_list.cqe_next)
- {
- if (validfsnode(mp) && mp->mnt_stat.f_fsid.val[0] == id)
- {
- cur_mount = mp;
- break;
- }
- }
- simple_unlock(&mountlist_slock);
+ /* the following will return the mount point with vfs_busy held */
+ cur_mount = mount_lookupby_volfsid(id, 1);
if (cur_mount == NULL) {
/*
return ENOENT;
};
+ cur_fsid = cur_mount->mnt_vfsstat.f_fsid;
+
/*
* Now search the list attached to the mount structure to
* see if this vnode is already floating around
*/
search_vnodelist:
- cur_vnode = our_mount->mnt_vnodelist.lh_first;
- while (cur_vnode != NULL)
- {
+ mount_lock(our_mount);
+ TAILQ_FOREACH(cur_vnode, &our_mount->mnt_vnodelist, v_mntvnodes) {
cur_privdata = (struct volfs_vndata *) cur_vnode->v_data;
- if (cur_privdata->nodeID == id)
+ if (cur_privdata->nodeID == (unsigned int)id)
{
if (cur_privdata->fs_mount != cur_mount) {
- DBG_VOP(("volfs get_fsvnode: Updating fs_mount for vnode 0x%08lX (id = %d) from 0x%08lX to 0x%08lX...\n",
- (unsigned long)cur_vnode,
- cur_privdata->nodeID,
- (unsigned long)cur_privdata->fs_mount,
- (unsigned long)cur_mount));
cur_privdata->fs_mount = cur_mount;
+ cur_privdata->fs_fsid = cur_fsid;
};
break;
}
- cur_vnode = cur_vnode->v_mntvnodes.le_next;
- }
+ }
+ mount_unlock(our_mount);
- //DBG_VOP(("\tfinal cur_mount: 0x%x\n",cur_mount));
if (cur_vnode) {
- /* If vget returns an error, cur_vnode will not be what we think it is, try again */
- if (vget(cur_vnode, LK_EXCLUSIVE, current_proc()) != 0) {
+ vid = vnode_vid(cur_vnode);
+
+ /*
+ * use vnode_getwithvid since it will wait for a vnode currently being
+ * terminated... if it returns an error, cur_vnode will not be what we
+ * think it is, try again
+ */
+ if (vnode_getwithvid(cur_vnode, vid) != 0) {
goto search_vnodelist;
};
}
{
MALLOC(cur_privdata, struct volfs_vndata *,
sizeof(struct volfs_vndata), M_VOLFSNODE, M_WAITOK);
- retval = getnewvnode(VT_VOLFS, our_mount, volfs_vnodeop_p, &cur_vnode);
- if (retval != 0) {
- FREE(cur_privdata, M_VOLFSNODE);
- return retval;
- };
-
+
cur_privdata->vnode_type = VOLFS_FSNODE;
cur_privdata->nodeID = id;
cur_privdata->fs_mount = cur_mount;
- lockinit(&cur_privdata->lock, PINOD, "volfsnode", 0, 0);
- lockmgr(&cur_privdata->lock, LK_EXCLUSIVE, (struct slock *)0, current_proc());
- cur_vnode->v_data = cur_privdata;
- cur_vnode->v_type = VDIR;
- DBG_VOP(("get_fsvnode returned with new node of "));
- DBG_VOP_PRINT_VNODE_INFO(cur_vnode);DBG_VOP(("\n"));
+ cur_privdata->fs_fsid = cur_fsid;
+
+ vfsp.vnfs_mp = our_mount;
+ vfsp.vnfs_vtype = VDIR;
+ vfsp.vnfs_str = "volfs";
+ vfsp.vnfs_dvp = 0;
+ vfsp.vnfs_fsnode = cur_privdata;
+ vfsp.vnfs_cnp = 0;
+ vfsp.vnfs_vops = volfs_vnodeop_p;
+ vfsp.vnfs_rdev = 0;
+ vfsp.vnfs_filesize = 0;
+ vfsp.vnfs_flags = VNFS_NOCACHE | VNFS_CANTCACHE;
+ vfsp.vnfs_marksystem = 0;
+ vfsp.vnfs_markroot = 0;
+
+ retval = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &cur_vnode);
+ if (retval != 0) {
+ FREE(cur_privdata, M_VOLFSNODE);
+ goto out;
+ };
+ cur_vnode->v_tag = VT_VOLFS;
+
}
*ret_vnode = cur_vnode;
-
- return (0);
+ retval = 0;
+out:
+ vfs_unbusy(cur_mount);
+ return (retval);
}
* to a vnode pointer
*/
static int
-get_filevnode(parent_fs, id, ret_vnode)
- struct mount *parent_fs;
- u_int id;
- struct vnode **ret_vnode;
+get_filevnode(struct mount *parent_fs, u_int id, vnode_t *ret_vnode, vfs_context_t context)
{
int retval;
- DBG_VOP(("get_filevnode called for ID %d\n", id));
-
+again:
/*
* Special case 2 to mean the root of a file system
*/
if (id == 2)
- retval = VFS_ROOT(parent_fs, ret_vnode);
+ retval = VFS_ROOT(parent_fs, ret_vnode, context);
else
- retval = VFS_VGET(parent_fs, &id, ret_vnode);
+ retval = VFS_VGET(parent_fs, (ino64_t)id, ret_vnode, context);
+ if (retval) goto error;
+
+ retval = verify_fullpathaccess(*ret_vnode, context);
+ if (retval) {
+ /* An error was encountered verifying that the caller has,
+ in fact, got access all the way from "/" or their working
+ directory to the specified item...
+ */
+ vnode_put(*ret_vnode);
+ *ret_vnode = NULL;
+ /* vnode was recycled during access verification. */
+ if (retval == EAGAIN) {
+ goto again;
+ }
+ };
+error:
return (retval);
}
-int
-volfs_lookup(ap)
- struct vop_lookup_args /* { struct vnode *a_dvp; struct vnode
- **a_vpp; struct componentname *a_cnp; } */ *ap;
+static int
+volfs_lookup(struct vnop_lookup_args *ap)
{
- struct volfs_vndata *priv_data;
- char *cnp;
- long namelen;
- struct mount *parent_fs;
- int unlocked_parent = 0;
- int ret_err = ENOENT;
- DBG_FUNC_NAME("volfs_lookup");
- DBG_VOP_LOCKS_DECL(2);
-
- DBG_VOP(("volfs_lookup called, name = %s, namelen = %ld\n", ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen));
-
- DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS);
- DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS);
- DBG_VOP_PRINT_FUNCNAME();DBG_VOP(("\n"));
- DBG_VOP(("\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP(("\n"));
- if (ap->a_cnp->cn_flags & LOCKPARENT)
- DBG_VOP(("\tLOCKPARENT is set\n"));
- if (ap->a_cnp->cn_flags & ISLASTCN)
- {
- DBG_VOP(("\tISLASTCN is set\n"));
- if (ap->a_cnp->cn_nameiop == DELETE || ap->a_cnp->cn_nameiop == RENAME) /* XXX PPD Shouldn't we check for CREATE, too? */
- {
- ret_err = EROFS;
- goto Err_Exit;
- }
- }
+ struct volfs_vndata *priv_data;
+ char *nameptr;
+ long namelen;
+ struct mount *parent_fs;
+ vnode_t vp;
+ int isdot_or_dotdot = 0;
+ int ret_err = ENOENT;
+ char firstchar;
+ int ret_val;
+
+#if 0
+ KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 8)) | DBG_FUNC_START,
+ (unsigned int)ap->a_dvp, (unsigned int)ap->a_cnp, (unsigned int)p, 0, 0);
+#endif
priv_data = ap->a_dvp->v_data;
- cnp = ap->a_cnp->cn_nameptr;
+ nameptr = ap->a_cnp->cn_nameptr;
namelen = ap->a_cnp->cn_namelen;
-
-#if VOLFS_DEBUG
- switch (priv_data->vnode_type) {
- case VOLFS_ROOT:
- DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_ROOT.\n", (unsigned long)ap->a_dvp));
- break;
-
- case VOLFS_FSNODE:
- DBG_VOP(("\tparent directory (vnode 0x%08lX) vnode_type is VOLFS_FSNODE, nodeID = %d, fs_mount = 0x%08lX.\n",
- (unsigned long)ap->a_dvp,
- priv_data->nodeID,
- (unsigned long)priv_data->fs_mount));
+ firstchar = nameptr[0];
- default:
- DBG_VOP(("\tparent directory (vnode 0x%08lX) has unknown vnode_type (%d), nodeID = %d.\n",
- (unsigned long)ap->a_dvp,
- priv_data->vnode_type,
- priv_data->nodeID));
- };
-#endif /* VOLFS_DEBUG */
-
- /* first check for "." and ".." */
- if (cnp[0] == '.')
- {
- if (namelen == 1)
- {
+ /* First check for "." and ".." */
+ if (firstchar == '.') {
+ if (namelen == 1) {
/* "." requested */
- *ap->a_vpp = ap->a_dvp;
- VREF(*ap->a_vpp);
- DBG_VOP_LOCKS_TEST(0);
- return (0);
- }
- else if (cnp[1] == '.' && namelen == 2)
- {
+ isdot_or_dotdot = 1;
+ *ap->a_vpp = ap->a_dvp;
+ vnode_get(*ap->a_vpp);
+ ret_err = 0;
+ } else if (nameptr[1] == '.' && namelen == 2) {
/* ".." requested */
- ret_err = volfs_root(ap->a_dvp->v_mount, ap->a_vpp);
+ isdot_or_dotdot = 1;
+ ret_err = VFS_ROOT(ap->a_dvp->v_mount, ap->a_vpp, ap->a_context);
}
- }
-
- /* then look for special file system root symbol ('@') */
- else if (cnp[0] == '@')
- {
+ } else if (firstchar == '@') { /* '@' is alias for system root */
if ((namelen == 1) && (priv_data->vnode_type != VOLFS_ROOT)) {
- parent_fs = priv_data->fs_mount;
- if (!(ap->a_cnp->cn_flags & LOCKPARENT) || !(ap->a_cnp->cn_flags & ISLASTCN)) {
- VOP_UNLOCK(ap->a_dvp, 0, ap->a_cnp->cn_proc);
- unlocked_parent = 1;
- };
- ret_err = VFS_ROOT(parent_fs, ap->a_vpp);
- } else {
- DBG_VOP(("volfs_lookup: pathname = '@' but namelen = %ld and parent vnode_type = %d.\n", namelen, priv_data->vnode_type));
- *ap->a_vpp = NULL;
- ret_err = ENOENT;
- };
- }
-
- /* finally, just look for numeric ids... */
- else if (namelen <= 10 && cnp[0] > '0' && cnp[0] <= '9') /* 10 digits max lead digit must be 1 - 9 */
- {
+ /* the following returns with iteration count on mount point */
+ parent_fs = mount_list_lookupby_fsid(&priv_data->fs_fsid, 0, 1);
+ if (parent_fs) {
+ ret_val = vfs_busy(parent_fs, LK_NOWAIT);
+ mount_iterdrop(parent_fs);
+ if (ret_val !=0) {
+ *ap->a_vpp = NULL;
+ ret_err = ENOENT;
+ } else {
+ ret_err = VFS_ROOT(parent_fs, ap->a_vpp, ap->a_context);
+ vfs_unbusy(parent_fs);
+ }
+ } else {
+ *ap->a_vpp = NULL;
+ ret_err = ENOENT;
+ }
+ } else {
+ *ap->a_vpp = NULL;
+ ret_err = ENOENT;
+ }
+ } else if (namelen <= 10 && firstchar > '0' && firstchar <= '9') {
char *check_ptr;
u_long id;
- id = strtoul(cnp, &check_ptr, 10);
+ id = strtoul(nameptr, &check_ptr, 10);
- /*
+ /*
* strtol will leave us at the first non-numeric character.
* we've checked to make sure the component name does
* begin with a numeric so check_ptr must wind up on
* the terminating null or there was other junk following the
* number
*/
- if ((check_ptr - cnp) == namelen)
- {
- if (priv_data->vnode_type == VOLFS_ROOT)
+ if ((check_ptr - nameptr) == namelen) {
+ if (priv_data->vnode_type == VOLFS_ROOT) {
+ /*
+ * OPTIMIZATION
+ *
+ * Obtain the mountpoint and call VFS_VGET in
+ * one step (ie without creating a vnode for
+ * the mountpoint).
+ */
+ if (check_ptr[0] == '/' &&
+ check_ptr[1] > '0' && check_ptr[1] <= '9') {
+ struct mount *mp;
+ struct vnode *vp;
+ u_long id2;
+ char *endptr;
+
+ /* this call will return mount point with vfs_busy held */
+ mp = mount_lookupby_volfsid(id, 1);
+ if (mp == NULL) {
+ *ap->a_vpp = NULL;
+ return ENOENT;
+ }
+ id2 = strtoul(&check_ptr[1], &endptr, 10);
+ if ((endptr[0] == '/' || endptr[0] == '\0') &&
+ get_filevnode(mp, id2, &vp, ap->a_context) == 0) {
+ ap->a_cnp->cn_consume = endptr - check_ptr;
+ *ap->a_vpp = vp;
+ vfs_unbusy(mp);
+ return (0);
+ }
+ vfs_unbusy(mp);
+ }
+ /* Fall through to default behavior... */
+
ret_err = get_fsvnode(ap->a_dvp->v_mount, id, ap->a_vpp);
- else {
- parent_fs = priv_data->fs_mount;
- if (!(ap->a_cnp->cn_flags & LOCKPARENT) || !(ap->a_cnp->cn_flags & ISLASTCN)) {
- VOP_UNLOCK(ap->a_dvp, 0, ap->a_cnp->cn_proc);
- unlocked_parent = 1;
- };
- ret_err = get_filevnode(parent_fs, id, ap->a_vpp);
+
+ } else {
+ parent_fs = mount_list_lookupby_fsid(&priv_data->fs_fsid, 0, 1);
+ if (parent_fs) {
+ ret_val = vfs_busy(parent_fs, LK_NOWAIT);
+ mount_iterdrop(parent_fs);
+ if (ret_val !=0) {
+ *ap->a_vpp = NULL;
+ ret_err = ENOENT;
+ } else {
+ ret_err = get_filevnode(parent_fs, id, ap->a_vpp, ap->a_context);
+ vfs_unbusy(parent_fs);
+ }
+ } else {
+ *ap->a_vpp = NULL;
+ ret_err = ENOENT;
+ }
}
}
-
}
+ vp = *ap->a_vpp;
- if (!unlocked_parent && (!(ap->a_cnp->cn_flags & LOCKPARENT) || !(ap->a_cnp->cn_flags & ISLASTCN))) {
- VOP_UNLOCK(ap->a_dvp, 0, ap->a_cnp->cn_proc);
- };
-
- /* XXX PPD Should we do something special in case LOCKLEAF isn't set? */
-
-Err_Exit:
-
- DBG_VOP_UPDATE_VP(1, *ap->a_vpp);
- DBG_VOP_LOCKS_TEST(ret_err);
-
- return (ret_err);
-}
-
-#if DBG_VOP_TEST_LOCKS
+ if ( ret_err == 0 && !isdot_or_dotdot && (vp != NULLVP) && (vp->v_parent == NULLVP))
+ vnode_update_identity(vp, ap->a_dvp, NULL, 0, 0, VNODE_UPDATE_PARENT);
#if 0
-static void DbgLookupTest( char *funcname, struct componentname *cnp, struct vnode *dvp, struct vnode *vp)
-{
- int flags = cnp->cn_flags;
- int nameiop = cnp->cn_nameiop;
-
- DBG_VOP (("%s: Action:", funcname));
- switch (nameiop)
- {
- case LOOKUP:
- PRINTIT ("LOOKUP");
- break;
- case CREATE:
- PRINTIT ("CREATE");
- break;
- case DELETE:
- PRINTIT ("DELETE");
- break;
- case RENAME:
- PRINTIT ("RENAME");
- break;
- default:
- PRINTIT ("!!!UNKNOWN!!!!");
- break;
- }
- PRINTIT(" flags: 0x%x ",flags );
- if (flags & LOCKPARENT)
- PRINTIT (" Lock Parent");
- if (flags & ISLASTCN)
- PRINTIT (" Last Action");
- PRINTIT("\n");
-
- if (dvp)
- {
- PRINTIT ("%s: Parent vnode exited ", funcname);
- if (VOP_ISLOCKED(dvp))
- PRINTIT("LOCKED\n");
- else
- PRINTIT("UNLOCKED\n");
- }
- if (vp && vp==dvp)
- {
- PRINTIT ("%s: Found and Parent are the same\n", funcname);
- }
- else if (vp)
- {
- PRINTIT ("%s: Found vnode exited ", funcname);
- if (VOP_ISLOCKED(vp))
- PRINTIT("LOCKED\n");
- else
- PRINTIT("UNLOCKED\n");
- }
- else
- PRINTIT ("%s: Found vnode exited NULL\n", funcname);
-
-
-}
+ KERNEL_DEBUG((FSDBG_CODE(DBG_FSVN, 8)) | DBG_FUNC_START,
+ (unsigned int)ap->a_dvp, (unsigned int)ap->a_cnp, (unsigned int)p, ret_err, 0);
#endif
-
-static void DbgVopTest( int maxSlots,
- int retval,
- VopDbgStoreRec *VopDbgStore,
- char *funcname)
-{
- int index;
-
- for (index = 0; index < maxSlots; index++)
- {
- if (VopDbgStore[index].id != index) {
- PRINTIT("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname, VopDbgStore[index].id, index);
- return;
- };
-
- if ((VopDbgStore[index].vp != NULL) &&
- ((VopDbgStore[index].vp->v_data==NULL)))
- continue;
-
- switch (VopDbgStore[index].inState)
- {
- case VOPDBG_IGNORE:
- case VOPDBG_SAME:
- /* Do Nothing !!! */
- break;
- case VOPDBG_LOCKED:
- case VOPDBG_UNLOCKED:
- case VOPDBG_LOCKNOTNIL:
- {
- if (VopDbgStore[index].vp == NULL && (VopDbgStore[index].inState != VOPDBG_LOCKNOTNIL)) {
- PRINTIT ("%s: InState check: Null vnode ptr in entry #%d\n", funcname, index);
- } else if (VopDbgStore[index].vp != NULL) {
- switch (VopDbgStore[index].inState)
- {
- case VOPDBG_LOCKED:
- case VOPDBG_LOCKNOTNIL:
- if (VopDbgStore[index].inValue == 0)
- {
- PRINTIT ("%s: %d Entry: not LOCKED:", funcname, index); DBG_VOP(("\n"));
- }
- break;
- case VOPDBG_UNLOCKED:
- if (VopDbgStore[index].inValue != 0)
- {
- PRINTIT ("%s: %d Entry: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
- }
- break;
- }
- }
- break;
- }
- default:
- PRINTIT ("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname, VopDbgStore[index].errState);
- }
-
-
- if (retval != 0)
- {
- switch (VopDbgStore[index].errState)
- {
- case VOPDBG_IGNORE:
- /* Do Nothing !!! */
- break;
- case VOPDBG_LOCKED:
- case VOPDBG_UNLOCKED:
- case VOPDBG_SAME:
- {
- if (VopDbgStore[index].vp == NULL) {
- PRINTIT ("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname, index);
- } else {
- VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
- switch (VopDbgStore[index].errState)
- {
- case VOPDBG_LOCKED:
- if (VopDbgStore[index].outValue == 0)
- {
- PRINTIT ("%s: %d Error: not LOCKED:", funcname, index); DBG_VOP(("\n"));
- }
- break;
- case VOPDBG_UNLOCKED:
- if (VopDbgStore[index].outValue != 0)
- {
- PRINTIT ("%s: %d Error: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
- }
- break;
- case VOPDBG_SAME:
- if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
- PRINTIT ("%s: Error: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue);
- break;
- }
- }
- break;
- }
- case VOPDBG_LOCKNOTNIL:
- if (VopDbgStore[index].vp != NULL) {
- VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
- if (VopDbgStore[index].outValue == 0)
- PRINTIT ("%s: Error: %d Not LOCKED: 0x%x\n", funcname, index, (u_int)VopDbgStore[index].vp);
- }
- break;
- default:
- PRINTIT ("%s: Error: bad lock test value: %d\n", funcname, VopDbgStore[index].errState);
- }
- }
- else
- {
- switch (VopDbgStore[index].outState)
- {
- case VOPDBG_IGNORE:
- /* Do Nothing !!! */
- break;
- case VOPDBG_LOCKED:
- case VOPDBG_UNLOCKED:
- case VOPDBG_SAME:
- if (VopDbgStore[index].vp == NULL) {
- PRINTIT ("%s: OutState: Null vnode ptr in entry #%d\n", funcname, index);
- };
- if (VopDbgStore[index].vp != NULL)
- {
- VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
- switch (VopDbgStore[index].outState)
- {
- case VOPDBG_LOCKED:
- if (VopDbgStore[index].outValue == 0)
- {
- PRINTIT ("%s: %d Out: not LOCKED:", funcname, index); DBG_VOP(("\n"));
- }
- break;
- case VOPDBG_UNLOCKED:
- if (VopDbgStore[index].outValue != 0)
- {
- PRINTIT ("%s: %d Out: not UNLOCKED:", funcname, index); DBG_VOP(("\n"));
- }
- break;
- case VOPDBG_SAME:
- if (VopDbgStore[index].outValue != VopDbgStore[index].inValue)
- PRINTIT ("%s: Out: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue);
- break;
- }
- }
- break;
- case VOPDBG_LOCKNOTNIL:
- if (VopDbgStore[index].vp != NULL) {
- if (&((struct volfs_vndata *)(VopDbgStore[index].vp->v_data))->lock == NULL)
- PRINTIT ("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname, (u_int)VopDbgStore[index].vp);
- else {
- VopDbgStore[index].outValue = VOP_ISLOCKED(VopDbgStore[index].vp);
- if (VopDbgStore[index].outValue == 0)
- {
- PRINTIT ("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname); DBG_VOP(("\n"));
- }
- }
- }
- break;
- default:
- PRINTIT ("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname, VopDbgStore[index].outState);
- }
- }
-
- VopDbgStore[index].id = -1; /* Invalidate the entry to allow panic-free re-use */
- }
+ return (ret_err);
}
-#endif /* DBG_VOP_TEST_LOCKS */
-