}
hfs_unlock(cp);
+
+ if (ap->a_fflag & FWASWRITTEN) {
+ hfs_sync_ejectable(hfsmp);
+ }
+
return (0);
}
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);
}
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);
hfs_systemfile_unlock(hfsmp, lockflags);
if (error) {
+ if (error == EEXIST) {
+ error = ERECYCLE;
+ }
goto out;
}
}
/* 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);
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)