Last active
February 14, 2018 08:58
-
-
Save lundman/a26310e58cfba1a2dd7a38526104631a to your computer and use it in GitHub Desktop.
hardlink corrective
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/module/zfs/zfs_vnops_osx.c b/module/zfs/zfs_vnops_osx.c | |
index 9b7ee25..0faba36 100644 | |
--- a/module/zfs/zfs_vnops_osx.c | |
+++ b/module/zfs/zfs_vnops_osx.c | |
@@ -1190,6 +1190,80 @@ zfs_vnop_lookup(struct vnop_lookup_args *ap) | |
exit: | |
+ // hardlinks can be left "orphaned", ie with an invalid parentid, | |
+ // so we can detect that here. Also called for positive vnode cache lookup | |
+ if (error == 0) { | |
+ znode_t *zp = VTOZ(*ap->a_vpp); | |
+ znode_t *dzp = VTOZ(ap->a_dvp); | |
+ zfsvfs_t *zfsvfs = zp->z_zfsvfs; | |
+ uint64_t parentid; | |
+ dmu_buf_t *db; | |
+ | |
+ if (!vfs_isrdonly(zfsvfs->z_vfs) && | |
+ vnode_isreg(*ap->a_vpp) && | |
+ (sa_lookup(zp->z_sa_hdl, SA_ZPL_PARENT(zfsvfs), | |
+ &parentid, sizeof (parentid)) == 0)) { | |
+ | |
+ /* If parent does not match here, and links==1 we | |
+ * fix it. If links>1 then check if target is invalid | |
+ * as we don't care which parent it points to, as long | |
+ * as it is valid. | |
+ */ | |
+ if (parentid != dzp->z_id) { | |
+ int update = 0; | |
+ | |
+ if (zp->z_links == 1) { | |
+ update = 1; | |
+ } else { | |
+ // Check dir exists | |
+ ZFS_OBJ_HOLD_ENTER(zfsvfs, parentid); | |
+ error = sa_buf_hold(zfsvfs->z_os, parentid, NULL, &db); | |
+ if (error == 0) | |
+ sa_buf_rele(db, NULL); | |
+ ZFS_OBJ_HOLD_EXIT(zfsvfs, parentid); | |
+ printf("Checking if parent %llu exists: %d\n", | |
+ parentid, error); | |
+ if (error) | |
+ update = 1; | |
+ error = 0; | |
+ } | |
+ | |
+ printf("%s: orphaned file '%s' %llu != %llu (links %llu)\n", | |
+ __func__, filename ? filename : cnp->cn_nameptr, | |
+ parentid, dzp->z_id, zp->z_links); | |
+ | |
+ if (update) { | |
+ boolean_t waited = B_FALSE; | |
+ dmu_tx_t *tx; | |
+ | |
+ top: | |
+ tx = dmu_tx_create(zfsvfs->z_os); | |
+ dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE); | |
+ zfs_sa_upgrade_txholds(tx, zp); | |
+ error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT); | |
+ if (error) { | |
+ if (error == ERESTART) { | |
+ waited = B_TRUE; | |
+ dmu_tx_wait(tx); | |
+ dmu_tx_abort(tx); | |
+ goto top; | |
+ } | |
+ dmu_tx_abort(tx); | |
+ ZFS_EXIT(zfsvfs); | |
+ } else { // error == 0 | |
+ (void )sa_update(zp->z_sa_hdl, | |
+ SA_ZPL_PARENT(zp->z_zfsvfs), (void *)&dzp->z_id, | |
+ sizeof (uint64_t), tx); | |
+ dmu_tx_commit(tx); | |
+ printf("%s: orphaned file '%s' corrected.\n", | |
+ __func__, filename ? filename : cnp->cn_nameptr); | |
+ } //error | |
+ error = 0; // dont return error to vnop_lookup | |
+ } // update | |
+ } // parentid != z_id | |
+ } // sa_lookup(parentid) | |
+ } // error == 0 | |
+ | |
#ifdef __APPLE__ | |
if (!error) | |
zfs_cache_name(*ap->a_vpp, ap->a_dvp, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Wondering how we would handle the following case :
And then the above fix kicks in and finds that f1 has SA_ZPL_PARENT pointing to dir2
and dir2 is present. Would it wrongly assume that dir2 has a valid hardlink dentry pointing to f1 ?