]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_vnops.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_vnops.c
index eef6b5e9660486b10484d49bd60c81c25a9bcf21..6d8d6ad33d8f9c5f9039c1a02e64eabd19c91136 100644 (file)
@@ -367,6 +367,11 @@ hfs_vnop_close(ap)
        }
        
        hfs_unlock(cp);
+
+       if (ap->a_fflag & FWASWRITTEN) {
+               hfs_sync_ejectable(hfsmp);
+       }
+
        return (0);
 }
 
@@ -2304,8 +2309,32 @@ hfs_vnop_rename(ap)
        error = hfs_lockfour(VTOC(fdvp), VTOC(fvp), VTOC(tdvp), tvp ? VTOC(tvp) : NULL,
                             HFS_EXCLUSIVE_LOCK);
        if (error) {
-               if (took_trunc_lock)
+               if (took_trunc_lock) {
                        hfs_unlock_truncate(VTOC(tvp), TRUE);   
+                       took_trunc_lock = 0;
+               }
+        /* 
+         * tvp might no longer exist. if we get ENOENT, re-check the
+         * C_NOEXISTS flag  on tvp to find out whether it's still in the
+         * namespace.
+         */
+        if (error == ENOENT && tvp) {
+            /* 
+             * It's okay to just check C_NOEXISTS without having a lock,
+             * because we have an iocount on it from the vfs layer so it can't
+             * have disappeared.
+             */
+            if (VTOC(tvp)->c_flag & C_NOEXISTS) {
+                /*
+                 * tvp is no longer in the namespace. Try again with NULL
+                 * tvp/tcp (NULLing these out is fine because the vfs syscall
+                 * will vnode_put the vnodes).
+                 */
+                tcp = NULL;
+                tvp = NULL;
+                goto retry;
+            }
+        }
                return (error);
        }
 
@@ -2595,6 +2624,16 @@ hfs_vnop_rename(ap)
 skip_rm:
        /*
         * All done with tvp and fvp
+        *
+        * We also jump to this point if there was no destination observed during lookup and namei.
+        * However, because only iocounts are held at the VFS layer, there is nothing preventing a 
+        * competing thread from racing us and creating a file or dir at the destination of this rename 
+        * operation.  If this occurs, it may cause us to get a spurious EEXIST out of the cat_rename 
+        * call below.  To preserve rename's atomicity, we need to signal VFS to re-drive the 
+        * namei/lookup and restart the rename operation.  EEXIST is an allowable errno to be bubbled 
+        * out of the rename syscall, but not for this reason, since it is a synonym errno for ENOTEMPTY.
+        * To signal VFS, we return ERECYCLE (which is also used for lookup restarts). This errno
+        * will be swallowed and it will restart the operation.
         */
 
        lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
@@ -2602,6 +2641,9 @@ skip_rm:
        hfs_systemfile_unlock(hfsmp, lockflags);
 
        if (error) {
+               if (error == EEXIST) {
+                       error = ERECYCLE;
+               }
                goto out;
        }
 
@@ -2815,7 +2857,7 @@ hfs_vnop_symlink(struct vnop_symlink_args *ap)
        }
 
        /* Write the link to disk */
-       bp = buf_getblk(vp, (daddr64_t)0, roundup((int)fp->ff_size, VTOHFS(vp)->hfs_phys_block_size),
+       bp = buf_getblk(vp, (daddr64_t)0, roundup((int)fp->ff_size, hfsmp->hfs_physical_block_size),
                        0, 0, BLK_META);
        if (hfsmp->jnl) {
                journal_modify_block_start(hfsmp->jnl, bp);
@@ -3185,8 +3227,7 @@ hfs_vnop_readlink(ap)
 
                MALLOC(fp->ff_symlinkptr, char *, fp->ff_size, M_TEMP, M_WAITOK);
                error = (int)buf_meta_bread(vp, (daddr64_t)0,
-                                           roundup((int)fp->ff_size,
-                                           VTOHFS(vp)->hfs_phys_block_size),
+                                           roundup((int)fp->ff_size, VTOHFS(vp)->hfs_physical_block_size),
                                            vfs_context_ucred(ap->a_context), &bp);
                if (error) {
                        if (bp)