@@ -1409,6 +1409,7 @@ xfs_link(
xfs_trans_t *tp;
int error;
int resblks;
+ xfs_dir2_dataptr_t diroffset;
trace_xfs_link(tdp, target_name);
@@ -1436,8 +1437,8 @@ xfs_link(
xfs_lock_two_inodes(sip, XFS_ILOCK_EXCL, tdp, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
- xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
+ xfs_trans_ijoin(tp, sip, 0);
+ xfs_trans_ijoin(tp, tdp, 0);
/*
* If we are using project inheritance, we only allow hard link
@@ -1466,15 +1467,28 @@ xfs_link(
}
error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
- resblks, NULL);
+ resblks, &diroffset);
if (error)
- goto error_return;
+ goto out_defer_cancel;
xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
error = xfs_bumplink(tp, sip);
if (error)
- goto error_return;
+ goto out_defer_cancel;
+
+ /*
+ * If we have parent pointers, we now need to add the parent record to
+ * the attribute fork of the inode. If this is the initial parent
+ * attribute, we need to create it correctly, otherwise we can just add
+ * the parent to the inode.
+ */
+ if (xfs_sb_version_hasparent(&mp->m_sb)) {
+ error = xfs_parent_add_deferred(tdp, tp, sip, target_name,
+ diroffset);
+ if (error)
+ goto out_defer_cancel;
+ }
/*
* If this is a synchronous mount, make sure that the
@@ -1484,11 +1498,18 @@ xfs_link(
if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
xfs_trans_set_sync(tp);
- return xfs_trans_commit(tp);
+ error = xfs_trans_commit(tp);
+ xfs_iunlock(tdp, XFS_ILOCK_EXCL);
+ xfs_iunlock(sip, XFS_ILOCK_EXCL);
+ return error;
- error_return:
+out_defer_cancel:
+ xfs_defer_cancel(tp);
+error_return:
xfs_trans_cancel(tp);
- std_return:
+ xfs_iunlock(tdp, XFS_ILOCK_EXCL);
+ xfs_iunlock(sip, XFS_ILOCK_EXCL);
+std_return:
return error;
}