]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/miscfs/union/union_vfsops.c
xnu-792.6.61.tar.gz
[apple/xnu.git] / bsd / miscfs / union / union_vfsops.c
index 06578a15a849c7199469f6ded35686e33bc3bf0f..959c201d247939c7b884f5a38c16b42e067f8a78 100644 (file)
@@ -1,24 +1,21 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 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. 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
+ * This 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
 #include <sys/systm.h>
 #include <sys/time.h>
 #include <sys/types.h>
-#include <sys/proc.h>
-#include <sys/vnode.h>
-#include <sys/mount.h>
+#include <sys/proc_internal.h>
+#include <sys/kauth.h>
+#include <sys/vnode_internal.h>
+#include <sys/mount_internal.h>
 #include <sys/namei.h>
 #include <sys/malloc.h>
 #include <sys/filedesc.h>
 #include <sys/queue.h>
 #include <miscfs/union/union.h>
 
+static int union_itercallback(__unused vnode_t, void *);
+
 /*
  * Mount union filesystem
  */
 int
-union_mount(mp, path, data, ndp, p)
-       struct mount *mp;
-       char *path;
-       caddr_t data;
-       struct nameidata *ndp;
-       struct proc *p;
+union_mount(mount_t mp, __unused vnode_t devvp, user_addr_t data, vfs_context_t context)
 {
+       proc_t p = vfs_context_proc(context);
        int error = 0;
-       struct union_args args;
+       struct user_union_args args;
        struct vnode *lowerrootvp = NULLVP;
        struct vnode *upperrootvp = NULLVP;
        struct union_mount *um = 0;
-       struct ucred *cred = 0;
-       struct ucred *scred;
-       struct vattr va;
+       kauth_cred_t cred = NOCRED;
        char *cp;
        int len;
        u_int size;
-
+       struct nameidata nd;
+       
 #ifdef UNION_DIAGNOSTIC
        printf("union_mount(mp = %x)\n", mp);
 #endif
@@ -115,31 +110,42 @@ union_mount(mp, path, data, ndp, p)
                 * 1. a way to convert between rdonly and rdwr mounts.
                 * 2. support for nfs exports.
                 */
-               error = EOPNOTSUPP;
+               error = ENOTSUP;
                goto bad;
        }
 
        /*
         * Get argument
         */
-       if (error = copyin(data, (caddr_t)&args, sizeof(struct union_args)))
+       if (vfs_context_is64bit(context)) {
+               error = copyin(data, (caddr_t)&args, sizeof(args));
+       }
+       else {
+               struct union_args temp;
+               error = copyin(data, (caddr_t)&temp, sizeof (temp));
+               args.target = CAST_USER_ADDR_T(temp.target);
+               args.mntflags = temp.mntflags;
+       }
+       if (error)
                goto bad;
 
        lowerrootvp = mp->mnt_vnodecovered;
-       VREF(lowerrootvp);
+       vnode_get(lowerrootvp);
 
        /*
         * Find upper node.
         */
-       NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
-              UIO_USERSPACE, args.target, p);
+       NDINIT(&nd, LOOKUP, FOLLOW|WANTPARENT,
+              (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), 
+              args.target, context);
 
-       if (error = namei(ndp))
+       if ((error = namei(&nd)))
                goto bad;
 
-       upperrootvp = ndp->ni_vp;
-       vrele(ndp->ni_dvp);
-       ndp->ni_dvp = NULL;
+       nameidone(&nd);
+       upperrootvp = nd.ni_vp;
+       vnode_put(nd.ni_dvp);
+       nd.ni_dvp = NULL;
 
        if (upperrootvp->v_type != VDIR) {
                error = EINVAL;
@@ -153,7 +159,7 @@ union_mount(mp, path, data, ndp, p)
 
        /*
         * Keep a held reference to the target vnodes.
-        * They are vrele'd in union_unmount.
+        * They are vnode_put'd in union_unmount.
         *
         * Depending on the _BELOW flag, the filesystems are
         * viewed in a different order.  In effect, this is the
@@ -173,7 +179,7 @@ union_mount(mp, path, data, ndp, p)
                break;
 
        case UNMNT_REPLACE:
-               vrele(lowerrootvp);
+               vnode_put(lowerrootvp);
                lowerrootvp = NULLVP;
                um->um_uppervp = upperrootvp;
                um->um_lowervp = lowerrootvp;
@@ -189,13 +195,13 @@ union_mount(mp, path, data, ndp, p)
         * supports whiteout operations
         */
        if ((mp->mnt_flag & MNT_RDONLY) == 0) {
-               error = VOP_WHITEOUT(um->um_uppervp, (struct componentname *) 0, LOOKUP);
+               error = VNOP_WHITEOUT(um->um_uppervp, (struct componentname *) 0,
+                                     LOOKUP, context);
                if (error)
                        goto bad;
        }
 
-       um->um_cred = p->p_ucred;
-       crhold(um->um_cred);
+       um->um_cred = kauth_cred_get_with_ref();
        um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask;
 
        /*
@@ -226,8 +232,6 @@ union_mount(mp, path, data, ndp, p)
        mp->mnt_data = (qaddr_t) um;
        vfs_getnewfsid(mp);
 
-       (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
-       bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
 
        switch (um->um_op) {
        case UNMNT_ABOVE:
@@ -241,17 +245,17 @@ union_mount(mp, path, data, ndp, p)
                break;
        }
        len = strlen(cp);
-       bcopy(cp, mp->mnt_stat.f_mntfromname, len);
+       bcopy(cp, mp->mnt_vfsstat.f_mntfromname, len);
 
-       cp = mp->mnt_stat.f_mntfromname + len;
+       cp = mp->mnt_vfsstat.f_mntfromname + len;
        len = MNAMELEN - len;
 
-       (void) copyinstr(args.target, cp, len - 1, &size);
+       (void) copyinstr(args.target, cp, len - 1, (size_t *)&size);
        bzero(cp + size, len - size);
 
 #ifdef UNION_DIAGNOSTIC
        printf("union_mount: from %s, on %s\n",
-               mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
+               mp->mnt_vfsstat.f_mntfromname, mp->mnt_vfsstat.f_mntonname);
 #endif
        return (0);
 
@@ -259,11 +263,11 @@ bad:
        if (um)
                _FREE(um, M_UFSMNT);
        if (cred != NOCRED)
-               crfree(cred);
+               kauth_cred_rele(cred);
        if (upperrootvp)
-               vrele(upperrootvp);
+               vnode_put(upperrootvp);
        if (lowerrootvp)
-               vrele(lowerrootvp);
+               vnode_put(lowerrootvp);
        return (error);
 }
 
@@ -273,30 +277,35 @@ bad:
  * when that filesystem was mounted.
  */
 int
-union_start(mp, flags, p)
-       struct mount *mp;
-       int flags;
-       struct proc *p;
+union_start(__unused struct mount *mp, __unused int flags, __unused vfs_context_t context)
 {
 
        return (0);
 }
 
+static int
+union_itercallback(__unused vnode_t vp, void *args)
+{
+       int  num = *(int *)args;
+       
+       *(int *)args = num + 1;
+       return(VNODE_RETURNED);
+}
+
+
+
 /*
  * Free reference to union layer
  */
 int
-union_unmount(mp, mntflags, p)
-       struct mount *mp;
-       int mntflags;
-       struct proc *p;
+union_unmount(mount_t mp, int mntflags, __unused vfs_context_t context)
 {
        struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
        struct vnode *um_rootvp;
        int error;
        int freeing;
        int flags = 0;
-       struct ucred *cred;
+       kauth_cred_t cred;
 
 #ifdef UNION_DIAGNOSTIC
        printf("union_unmount(mp = %x)\n", mp);
@@ -305,7 +314,7 @@ union_unmount(mp, mntflags, p)
        if (mntflags & MNT_FORCE)
                flags |= FORCECLOSE;
 
-       if (error = union_root(mp, &um_rootvp))
+       if ((error = union_root(mp, &um_rootvp)))
                return (error);
 
        /*
@@ -318,14 +327,9 @@ union_unmount(mp, mntflags, p)
         * in the filesystem.
         */
        for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) {
-               struct vnode *vp;
-               int n;
+               int n = 0;
 
-               /* count #vnodes held on mount list */
-               for (n = 0, vp = mp->mnt_vnodelist.lh_first;
-                               vp != NULLVP;
-                               vp = vp->v_mntvnodes.le_next)
-                       n++;
+               vnode_iterate(mp, VNODE_NOLOCK_INTERNAL, union_itercallback, &n);
 
                /* if this is unchanged then stop */
                if (n == freeing)
@@ -336,8 +340,8 @@ union_unmount(mp, mntflags, p)
        }
 
        /* At this point the root vnode should have a single reference */
-       if (um_rootvp->v_usecount > 1) {
-               vput(um_rootvp);
+       if (vnode_isinuse(um_rootvp, 0)) {
+               vnode_put(um_rootvp);
                return (EBUSY);
        }
 
@@ -348,21 +352,21 @@ union_unmount(mp, mntflags, p)
         * Discard references to upper and lower target vnodes.
         */
        if (um->um_lowervp)
-               vrele(um->um_lowervp);
-       vrele(um->um_uppervp);
+               vnode_put(um->um_lowervp);
+       vnode_put(um->um_uppervp);
        cred = um->um_cred;
        if (cred != NOCRED) {
                um->um_cred = NOCRED;
-               crfree(cred);
+               kauth_cred_rele(cred);
        }
        /*
         * Release reference on underlying root vnode
         */
-       vput(um_rootvp);
+       vnode_put(um_rootvp);
        /*
         * And blow it away for future re-use
         */
-       vgone(um_rootvp);
+       vnode_reclaim(um_rootvp);
        /*
         * Finally, throw away the union_mount structure
         */
@@ -372,28 +376,17 @@ union_unmount(mp, mntflags, p)
 }
 
 int
-union_root(mp, vpp)
-       struct mount *mp;
-       struct vnode **vpp;
+union_root(mount_t mp, vnode_t *vpp, __unused vfs_context_t context)
 {
-       struct proc *p = current_proc();        /* XXX */
        struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
        int error;
-       int loselock;
 
        /*
         * Return locked reference to root.
         */
-       VREF(um->um_uppervp);
-       if ((um->um_op == UNMNT_BELOW) &&
-            VOP_ISLOCKED(um->um_uppervp)) {
-               loselock = 1;
-       } else {
-               vn_lock(um->um_uppervp, LK_EXCLUSIVE | LK_RETRY, p);
-               loselock = 0;
-       }
+       vnode_get(um->um_uppervp);
        if (um->um_lowervp)
-               VREF(um->um_lowervp);
+               vnode_get(um->um_lowervp);
        error = union_allocvp(vpp, mp,
                              (struct vnode *) 0,
                              (struct vnode *) 0,
@@ -403,75 +396,85 @@ union_root(mp, vpp)
                              1);
 
        if (error) {
-               if (loselock)
-                       vrele(um->um_uppervp);
-               else
-                       vput(um->um_uppervp);
+               vnode_put(um->um_uppervp);
                if (um->um_lowervp)
-                       vrele(um->um_lowervp);
-       } else {
-               if (loselock)
-                       VTOUNION(*vpp)->un_flags &= ~UN_ULOCK;
-       }
+                       vnode_put(um->um_lowervp);
+       } 
 
        return (error);
 }
 
-int
-union_statfs(mp, sbp, p)
-       struct mount *mp;
-       struct statfs *sbp;
-       struct proc *p;
+static int
+union_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context)
 {
        int error;
        struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
-       struct statfs mstat;
-       int lbsize;
+       struct vfs_attr attr;
+       uint32_t lbsize = 0;
 
 #ifdef UNION_DIAGNOSTIC
-       printf("union_statfs(mp = %x, lvp = %x, uvp = %x)\n", mp,
+       printf("union_vfs_getattr(mp = %x, lvp = %x, uvp = %x)\n", mp,
                        um->um_lowervp,
                        um->um_uppervp);
 #endif
 
-       bzero(&mstat, sizeof(mstat));
-
+       /* Get values from lower file system (if any) */
        if (um->um_lowervp) {
-               error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p);
+               VFSATTR_INIT(&attr);
+               VFSATTR_WANTED(&attr, f_bsize);
+               VFSATTR_WANTED(&attr, f_blocks);
+               VFSATTR_WANTED(&attr, f_bused);
+               VFSATTR_WANTED(&attr, f_files);
+               error = vfs_getattr(um->um_lowervp->v_mount, &attr, context);
                if (error)
                        return (error);
+
+               /* now copy across the "interesting" information and fake the rest */
+               if (VFSATTR_IS_SUPPORTED(&attr, f_bsize))
+                       lbsize = attr.f_bsize;
+               else
+                       lbsize = um->um_lowervp->v_mount->mnt_devblocksize;
+               fsap->f_blocks = VFSATTR_IS_SUPPORTED(&attr, f_blocks) ? attr.f_blocks : 0;
+               fsap->f_bused  = VFSATTR_IS_SUPPORTED(&attr, f_bused)  ? attr.f_bused  : 0;
+               fsap->f_files  = VFSATTR_IS_SUPPORTED(&attr, f_files)  ? attr.f_files  : 0;
+       } else {
+               fsap->f_blocks = 0;
+               fsap->f_bused = 0;
+               fsap->f_files = 0;
        }
 
-       /* now copy across the "interesting" information and fake the rest */
-#if 0
-       sbp->f_type = mstat.f_type;
-       sbp->f_flags = mstat.f_flags;
-       sbp->f_bsize = mstat.f_bsize;
-       sbp->f_iosize = mstat.f_iosize;
-#endif
-       lbsize = mstat.f_bsize;
-       sbp->f_blocks = mstat.f_blocks;
-       sbp->f_bfree = mstat.f_bfree;
-       sbp->f_bavail = mstat.f_bavail;
-       sbp->f_files = mstat.f_files;
-       sbp->f_ffree = mstat.f_ffree;
-
-       error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p);
+       VFSATTR_INIT(&attr);
+       VFSATTR_WANTED(&attr, f_bsize);
+       VFSATTR_WANTED(&attr, f_blocks);
+       VFSATTR_WANTED(&attr, f_bfree);
+       VFSATTR_WANTED(&attr, f_bavail);
+       VFSATTR_WANTED(&attr, f_files);
+       VFSATTR_WANTED(&attr, f_ffree);
+       error = vfs_getattr(um->um_uppervp->v_mount, &attr, context);
        if (error)
                return (error);
 
-       sbp->f_flags = mstat.f_flags;
-       sbp->f_bsize = mstat.f_bsize;
-       sbp->f_iosize = mstat.f_iosize;
+       if (VFSATTR_IS_SUPPORTED(&attr, f_bsize)) {
+               fsap->f_bsize = attr.f_bsize;
+               VFSATTR_SET_SUPPORTED(fsap, f_bsize);
+       }
+       if (VFSATTR_IS_SUPPORTED(&attr, f_iosize)) {
+               fsap->f_iosize = attr.f_iosize;
+               VFSATTR_SET_SUPPORTED(fsap, f_iosize);
+       }
 
        /*
         * if the lower and upper blocksizes differ, then frig the
         * block counts so that the sizes reported by df make some
         * kind of sense.  none of this makes sense though.
         */
-
-       if (mstat.f_bsize != lbsize)
-               sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize;
+       if (VFSATTR_IS_SUPPORTED(&attr, f_bsize))
+               fsap->f_bsize = attr.f_bsize;
+       else
+               fsap->f_bsize =  um->um_uppervp->v_mount->mnt_devblocksize;
+       VFSATTR_RETURN(fsap, f_bsize, attr.f_bsize);
+       if (fsap->f_bsize != lbsize)
+               fsap->f_blocks = fsap->f_blocks * lbsize / attr.f_bsize;
 
        /*
         * The "total" fields count total resources in all layers,
@@ -479,49 +482,52 @@ union_statfs(mp, sbp, p)
         * free in the upper layer (since only the upper layer
         * is writeable).
         */
-       sbp->f_blocks += mstat.f_blocks;
-       sbp->f_bfree = mstat.f_bfree;
-       sbp->f_bavail = mstat.f_bavail;
-       sbp->f_files += mstat.f_files;
-       sbp->f_ffree = mstat.f_ffree;
-
-       if (sbp != &mp->mnt_stat) {
-               sbp->f_type = mp->mnt_vfc->vfc_typenum;
-               bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
-               bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
-               bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
-       }
+       if (VFSATTR_IS_SUPPORTED(&attr, f_blocks))
+               fsap->f_blocks += attr.f_blocks;
+       if (VFSATTR_IS_SUPPORTED(&attr, f_bfree))
+               fsap->f_bfree = attr.f_bfree;
+       if (VFSATTR_IS_SUPPORTED(&attr, f_bavail))
+               fsap->f_bavail = attr.f_bavail;
+       if (VFSATTR_IS_SUPPORTED(&attr, f_bused))
+               fsap->f_bused += attr.f_bused;
+       if (VFSATTR_IS_SUPPORTED(&attr, f_files))
+               fsap->f_files += attr.f_files;
+       if (VFSATTR_IS_SUPPORTED(&attr, f_ffree))
+               fsap->f_ffree = attr.f_ffree;
+
+       VFSATTR_SET_SUPPORTED(fsap, f_bsize);
+       VFSATTR_SET_SUPPORTED(fsap, f_blocks);
+       VFSATTR_SET_SUPPORTED(fsap, f_bfree);
+       VFSATTR_SET_SUPPORTED(fsap, f_bavail);
+       VFSATTR_SET_SUPPORTED(fsap, f_bused);
+       VFSATTR_SET_SUPPORTED(fsap, f_files);
+       VFSATTR_SET_SUPPORTED(fsap, f_ffree);
+
        return (0);
 }
 
 /*
  * XXX - Assumes no data cached at union layer.
  */
-#define union_sync ((int (*) __P((struct mount *, int, struct ucred *, \
-           struct proc *)))nullop)
-
-#define union_fhtovp ((int (*) __P((struct mount *, struct fid *, \
-           struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
-int union_init __P((struct vfsconf *));
-#define union_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
-           struct proc *)))eopnotsupp)
-#define union_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
-           size_t, struct proc *)))eopnotsupp)
-#define union_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
-           eopnotsupp)
-#define union_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
+#define union_sync (int (*) (mount_t, int, ucred_t, vfs_context_t))nullop
+
+#define union_fhtovp (int (*) (mount_t, int, unsigned char *, vnode_t *, vfs_context_t))eopnotsupp
+int union_init (struct vfsconf *);
+#define union_sysctl (int (*) (int *, u_int, user_addr_t, size_t *, user_addr_t, size_t, vfs_context_t))eopnotsupp
+#define union_vget (int (*) (mount_t, ino64_t, vnode_t *, vfs_context_t))eopnotsupp
+#define union_vptofh (int (*) (vnode_t, int *, unsigned char *, vfs_context_t))eopnotsupp
 
 struct vfsops union_vfsops = {
        union_mount,
        union_start,
        union_unmount,
        union_root,
-       union_quotactl,
-       union_statfs,
+       NULL,                   /* quotactl */
+       union_vfs_getattr,
        union_sync,
        union_vget,
        union_fhtovp,
        union_vptofh,
        union_init,
-       union_sysctl,
+       union_sysctl
 };