@@ -478,6 +478,7 @@ void __xfs_buf_mark_corrupt(struct xfs_buf *bp, xfs_failaddr_t fa);
__mode = __mode; /* no set-but-unused warning */ \
})
#define xfs_lock_two_inodes(ip0,mode0,ip1,mode1) ((void) 0)
+#define xfs_lock_inodes(ips,num_ips,mode) ((void) 0)
/* space allocation */
#define XFS_EXTENT_BUSY_DISCARDED 0x01 /* undergoing a discard op. */
@@ -815,13 +815,37 @@ xfs_defer_ops_continue(
struct xfs_trans *tp,
struct xfs_defer_resources *dres)
{
- unsigned int i;
+ unsigned int i, j;
+ struct xfs_inode *sips[XFS_DEFER_OPS_NR_INODES];
+ struct xfs_inode *temp;
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
ASSERT(!(tp->t_flags & XFS_TRANS_DIRTY));
/* Lock the captured resources to the new transaction. */
- if (dfc->dfc_held.dr_inos == 2)
+ if (dfc->dfc_held.dr_inos > 2) {
+ /*
+ * Renames with parent pointer updates can lock up to 5 inodes,
+ * sorted by their inode number. So we need to make sure they
+ * are relocked in the same way.
+ */
+ memset(sips, 0, sizeof(sips));
+ for (i = 0; i < dfc->dfc_held.dr_inos; i++)
+ sips[i] = dfc->dfc_held.dr_ip[i];
+
+ /* Bubble sort of at most 5 inodes */
+ for (i = 0; i < dfc->dfc_held.dr_inos; i++) {
+ for (j = 1; j < dfc->dfc_held.dr_inos; j++) {
+ if (sips[j]->i_ino < sips[j-1]->i_ino) {
+ temp = sips[j];
+ sips[j] = sips[j-1];
+ sips[j-1] = temp;
+ }
+ }
+ }
+
+ xfs_lock_inodes(sips, dfc->dfc_held.dr_inos, XFS_ILOCK_EXCL);
+ } else if (dfc->dfc_held.dr_inos == 2)
xfs_lock_two_inodes(dfc->dfc_held.dr_ip[0], XFS_ILOCK_EXCL,
dfc->dfc_held.dr_ip[1], XFS_ILOCK_EXCL);
else if (dfc->dfc_held.dr_inos == 1)
@@ -70,7 +70,13 @@ extern const struct xfs_defer_op_type xfs_attr_defer_type;
/*
* Deferred operation item relogging limits.
*/
-#define XFS_DEFER_OPS_NR_INODES 2 /* join up to two inodes */
+
+/*
+ * Rename w/ parent pointers can require up to 5 inodes with deferred ops to
+ * be joined to the transaction: src_dp, target_dp, src_ip, target_ip, and wip.
+ * These inodes are locked in sorted order by their inode numbers
+ */
+#define XFS_DEFER_OPS_NR_INODES 5
#define XFS_DEFER_OPS_NR_BUFS 2 /* join up to two buffers */
/* Resources that must be held across a transaction roll. */