ASSERT(iip->ili_lock_flags == 0);
        iip->ili_lock_flags = lock_flags;
+       ASSERT(!xfs_iflags_test(ip, XFS_ISTALE));
 
        /*
         * Get a log_item_desc to point at the new item.
 
        ASSERT(ip->i_itemp != NULL);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+       ASSERT(!xfs_iflags_test(ip, XFS_ISTALE));
 
        /*
         * Don't bother with i_lock for the I_DIRTY_TIME check here, as races
 
                        goto out_ifunlock;
                xfs_iunpin_wait(ip);
        }
-       if (xfs_iflags_test(ip, XFS_ISTALE) || xfs_inode_clean(ip)) {
+       if (xfs_inode_clean(ip)) {
                xfs_ifunlock(ip);
                goto reclaim;
        }
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        xfs_qm_dqdetach(ip);
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       ASSERT(xfs_inode_clean(ip));
 
        __xfs_inode_free(ip);
        return error;
 
                return error;
        }
 
+       /*
+        * We do not hold the inode locked across the entire rolling transaction
+        * here. We only need to hold it for the first transaction that
+        * xfs_ifree() builds, which may mark the inode XFS_ISTALE if the
+        * underlying cluster buffer is freed. Relogging an XFS_ISTALE inode
+        * here breaks the relationship between cluster buffer invalidation and
+        * stale inode invalidation on cluster buffer item journal commit
+        * completion, and can result in leaving dirty stale inodes hanging
+        * around in memory.
+        *
+        * We have no need for serialising this inode operation against other
+        * operations - we freed the inode and hence reallocation is required
+        * and that will serialise on reallocating the space the deferops need
+        * to free. Hence we can unlock the inode on the first commit of
+        * the transaction rather than roll it right through the deferops. This
+        * avoids relogging the XFS_ISTALE inode.
+        *
+        * We check that xfs_ifree() hasn't grown an internal transaction roll
+        * by asserting that the inode is still locked when it returns.
+        */
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, 0);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
        error = xfs_ifree(tp, ip);
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
        if (error) {
                /*
                 * If we fail to free the inode, shut down.  The cancel
                        xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
                }
                xfs_trans_cancel(tp);
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
                return error;
        }
 
                xfs_notice(mp, "%s: xfs_trans_commit returned error %d",
                        __func__, error);
 
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
        return 0;
 }