]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vfs/vfs_syscalls.c
xnu-1228.9.59.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_syscalls.c
index c266535dcde05bb94af70bb0c1593e42dda1f8e8..be9bfe17a6c3fbd5aac65ca2c40b23d265b6115b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 1995-2008 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -95,6 +95,7 @@
 #include <sys/sysproto.h>
 #include <sys/xattr.h>
 #include <sys/ubc_internal.h>
+#include <sys/disk.h>
 #include <machine/cons.h>
 #include <machine/limits.h>
 #include <miscfs/specfs/specdev.h>
@@ -418,6 +419,7 @@ __mac_mount(struct proc *p, register struct __mac_mount_args *uap, __unused regi
        strncpy(mp->mnt_vfsstat.f_mntonname, nd.ni_cnd.cn_pnbuf, MAXPATHLEN);
        mp->mnt_vnodecovered = vp;
        mp->mnt_vfsstat.f_owner = kauth_cred_getuid(vfs_context_ucred(ctx));
+       mp->mnt_devbsdunit = LOWPRI_MAX_NUM_DEV - 1;
 
        /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
        vfs_setowner(mp, KAUTH_UID_NONE, KAUTH_GID_NONE);
@@ -590,6 +592,11 @@ update:
                        goto out3;
        }
 #endif
+       if (device_vnode != NULL) {
+               VNOP_IOCTL(device_vnode, DKIOCGETBSDUNIT, (caddr_t)&mp->mnt_devbsdunit, 0, NULL);
+               mp->mnt_devbsdunit %= LOWPRI_MAX_NUM_DEV;
+       }
+
        /*
         * Mount the filesystem.
         */
@@ -1020,6 +1027,7 @@ dounmount(struct mount *mp, int flags, int withref, vfs_context_t ctx)
        int needwakeup = 0;
        int forcedunmount = 0;
        int lflags = 0;
+       struct vnode *devvp = NULLVP;
 
        if (flags & MNT_FORCE)
                forcedunmount = 1;
@@ -1115,10 +1123,14 @@ dounmount(struct mount *mp, int flags, int withref, vfs_context_t ctx)
                OSAddAtomic(1, (SInt32 *)&vfs_nummntops);
 
        if ( mp->mnt_devvp && mp->mnt_vtable->vfc_vfsflags & VFC_VFSLOCALARGS) {
-               mp->mnt_devvp->v_specflags &= ~SI_MOUNTEDON;
-               VNOP_CLOSE(mp->mnt_devvp, mp->mnt_flag & MNT_RDONLY ? FREAD : FREAD|FWRITE,
+               /* hold an io reference and drop the usecount before close */
+               devvp = mp->mnt_devvp;
+               vnode_clearmountedon(devvp);
+               vnode_getalways(devvp);
+               vnode_rele(devvp);
+               VNOP_CLOSE(devvp, mp->mnt_flag & MNT_RDONLY ? FREAD : FREAD|FWRITE,
                        ctx);
-               vnode_rele(mp->mnt_devvp);
+               vnode_put(devvp);
        }
        lck_rw_done(&mp->mnt_rwlock);
        mount_list_remove(mp);
@@ -3493,6 +3505,10 @@ access(__unused proc_t p, struct access_args *uap, __unused register_t *retval)
        int niopts;
        struct vfs_context context;
 
+#if NAMEDRSRCFORK
+       int is_namedstream = 0;
+#endif
+
        /*
         * Access is defined as checking against the process'
         * real identity, even if operations are checking the
@@ -3517,8 +3533,27 @@ access(__unused proc_t p, struct access_args *uap, __unused register_t *retval)
        if (error)
                goto out;
 
+#if NAMEDRSRCFORK
+       /* Grab reference on the shadow stream file vnode to
+        * force an inactive on release which will mark it for
+        * recycle
+        */
+       if (vnode_isnamedstream(nd.ni_vp) &&
+                       (nd.ni_vp->v_parent != NULLVP) &&
+                       ((nd.ni_vp->v_parent->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0)) {
+               is_namedstream = 1;
+               vnode_ref(nd.ni_vp);
+       }
+#endif
+
        error = access1(nd.ni_vp, nd.ni_dvp, uap->flags, &context);
        
+#if NAMEDRSRCFORK
+       if (is_namedstream) {
+               vnode_rele(nd.ni_vp);
+       }
+#endif
+
        vnode_put(nd.ni_vp);
        if (uap->flags & _DELETE_OK)
                vnode_put(nd.ni_dvp);
@@ -3551,6 +3586,7 @@ stat2(vfs_context_t ctx, struct nameidata *ndp, user_addr_t ub, user_addr_t xsec
        void * statptr;
 
 #if NAMEDRSRCFORK
+       int is_namedstream = 0;
        /* stat calls are allowed for resource forks. */
        ndp->ni_cnd.cn_flags |= CN_ALLOWRSRCFORK;
 #endif
@@ -3562,16 +3598,28 @@ stat2(vfs_context_t ctx, struct nameidata *ndp, user_addr_t ub, user_addr_t xsec
                statptr  = (void *)&sb64;
        else
                statptr  = (void *)&sb;
+
+#if NAMEDRSRCFORK
+       /* Grab reference on the shadow stream file vnode to
+        * force an inactive on release which will mark it for
+        * recycle.
+        */
+       if (vnode_isnamedstream(ndp->ni_vp) &&
+                       (ndp->ni_vp->v_parent != NULLVP) &&
+                       ((ndp->ni_vp->v_parent->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0)) {
+               is_namedstream = 1;
+               vnode_ref (ndp->ni_vp);
+       }
+#endif
+
        error = vn_stat(ndp->ni_vp, statptr, (xsecurity != USER_ADDR_NULL ? &fsec : NULL), isstat64, ctx);
 
 #if NAMEDRSRCFORK
-       /* Clean up resource fork shadow file if needed. */
-       if ((ndp->ni_vp->v_flag & VISNAMEDSTREAM) && 
-           (ndp->ni_vp->v_parent != NULLVP) &&
-           !(ndp->ni_vp->v_parent->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS)) {
-               (void) vnode_relenamedstream(ndp->ni_vp->v_parent, ndp->ni_vp, ctx);
+       if (is_namedstream) {
+               vnode_rele (ndp->ni_vp);
        }
 #endif
+       
        vnode_put(ndp->ni_vp);
        nameidone(ndp);
 
@@ -4655,6 +4703,7 @@ rename(__unused proc_t p, struct rename_args *uap, __unused register_t *retval)
        struct nameidata fromnd, tond;
        vfs_context_t ctx = vfs_context_current();
        int error;
+       int do_retry;
        int mntrename;
        int need_event;
        const char *oname;
@@ -4666,6 +4715,7 @@ rename(__unused proc_t p, struct rename_args *uap, __unused register_t *retval)
        fse_info from_finfo, to_finfo;
        
        holding_mntlock = 0;
+    do_retry = 0;
 retry:
        fvp = tvp = NULL;
        fdvp = tdvp = NULL;
@@ -4780,8 +4830,17 @@ retry:
                        if ((error = vnode_authorize(((tvp != NULL) && vnode_isdir(tvp)) ? tvp : tdvp,
                                 NULL, 
                                 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
-                                ctx)) != 0)
+                                ctx)) != 0) {
+                /*
+                 * We could encounter a race where after doing the namei, tvp stops
+                 * being valid. If so, simply re-drive the rename call from the
+                 * top.
+                 */
+                 if (error == ENOENT) {
+                     do_retry = 1;
+                 }
                                goto auth_exit;
+                       }
                } else {
                        /* node staying in same directory, must be allowed to add new name */
                        if ((error = vnode_authorize(fdvp, NULL,
@@ -4790,8 +4849,17 @@ retry:
                }
                /* overwriting tvp */
                if ((tvp != NULL) && !vnode_isdir(tvp) &&
-                   ((error = vnode_authorize(tvp, tdvp, KAUTH_VNODE_DELETE, ctx)) != 0))
+                   ((error = vnode_authorize(tvp, tdvp, KAUTH_VNODE_DELETE, ctx)) != 0)) {
+            /*
+             * We could encounter a race where after doing the namei, tvp stops
+             * being valid. If so, simply re-drive the rename call from the
+             * top.
+             */
+            if (error == ENOENT) {
+                do_retry = 1;
+            }
                        goto auth_exit;
+               }
                    
                /* XXX more checks? */
 
@@ -5035,6 +5103,15 @@ auth_exit:
                holding_mntlock = 0;
        }
        if (error) {
+        /*
+         * We may encounter a race in the VNOP where the destination didn't 
+         * exist when we did the namei, but it does by the time we go and 
+         * try to create the entry. In this case, we should re-drive this rename
+         * call from the top again.
+         */
+        if (error == EEXIST) {
+            do_retry = 1;
+        }
 
                goto out1;
        } 
@@ -5122,14 +5199,18 @@ auth_exit:
                vnode_update_identity(fvp, tdvp, tond.ni_cnd.cn_nameptr, tond.ni_cnd.cn_namelen, tond.ni_cnd.cn_hash, update_flags);
        }
 out1:
-       if (to_name != NULL)
-               RELEASE_PATH(to_name);
-       if (from_name != NULL)
-               RELEASE_PATH(from_name);
-
+       if (to_name != NULL) {
+               RELEASE_PATH(to_name);
+               to_name = NULL;
+       }
+       if (from_name != NULL) {
+               RELEASE_PATH(from_name);
+               from_name = NULL;
+       }
        if (holding_mntlock) {
                mount_unlock_renames(locked_mp);
                mount_drop(locked_mp, 0);
+               holding_mntlock = 0;
        }
        if (tdvp) {
                /*
@@ -5153,6 +5234,16 @@ out1:
                        vnode_put(fvp);
                vnode_put(fdvp);
        }
+
+    /*
+     * If things changed after we did the namei, then we will re-drive
+     * this rename call from the top.
+     */
+       if(do_retry) {
+        do_retry = 0;
+               goto retry;
+       }
+
        return (error);
 }