|
@@ -24,6 +24,7 @@
|
|
|
#include "xfs_bit.h"
|
|
|
#include "xfs_sb.h"
|
|
|
#include "xfs_mount.h"
|
|
|
+#include "xfs_defer.h"
|
|
|
#include "xfs_da_format.h"
|
|
|
#include "xfs_da_btree.h"
|
|
|
#include "xfs_inode.h"
|
|
@@ -4716,7 +4717,8 @@ STATIC int
|
|
|
xlog_recover_process_cui(
|
|
|
struct xfs_mount *mp,
|
|
|
struct xfs_ail *ailp,
|
|
|
- struct xfs_log_item *lip)
|
|
|
+ struct xfs_log_item *lip,
|
|
|
+ struct xfs_defer_ops *dfops)
|
|
|
{
|
|
|
struct xfs_cui_log_item *cuip;
|
|
|
int error;
|
|
@@ -4729,7 +4731,7 @@ xlog_recover_process_cui(
|
|
|
return 0;
|
|
|
|
|
|
spin_unlock(&ailp->xa_lock);
|
|
|
- error = xfs_cui_recover(mp, cuip);
|
|
|
+ error = xfs_cui_recover(mp, cuip, dfops);
|
|
|
spin_lock(&ailp->xa_lock);
|
|
|
|
|
|
return error;
|
|
@@ -4756,7 +4758,8 @@ STATIC int
|
|
|
xlog_recover_process_bui(
|
|
|
struct xfs_mount *mp,
|
|
|
struct xfs_ail *ailp,
|
|
|
- struct xfs_log_item *lip)
|
|
|
+ struct xfs_log_item *lip,
|
|
|
+ struct xfs_defer_ops *dfops)
|
|
|
{
|
|
|
struct xfs_bui_log_item *buip;
|
|
|
int error;
|
|
@@ -4769,7 +4772,7 @@ xlog_recover_process_bui(
|
|
|
return 0;
|
|
|
|
|
|
spin_unlock(&ailp->xa_lock);
|
|
|
- error = xfs_bui_recover(mp, buip);
|
|
|
+ error = xfs_bui_recover(mp, buip, dfops);
|
|
|
spin_lock(&ailp->xa_lock);
|
|
|
|
|
|
return error;
|
|
@@ -4805,6 +4808,46 @@ static inline bool xlog_item_is_intent(struct xfs_log_item *lip)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* Take all the collected deferred ops and finish them in order. */
|
|
|
+static int
|
|
|
+xlog_finish_defer_ops(
|
|
|
+ struct xfs_mount *mp,
|
|
|
+ struct xfs_defer_ops *dfops)
|
|
|
+{
|
|
|
+ struct xfs_trans *tp;
|
|
|
+ int64_t freeblks;
|
|
|
+ uint resblks;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We're finishing the defer_ops that accumulated as a result of
|
|
|
+ * recovering unfinished intent items during log recovery. We
|
|
|
+ * reserve an itruncate transaction because it is the largest
|
|
|
+ * permanent transaction type. Since we're the only user of the fs
|
|
|
+ * right now, take 93% (15/16) of the available free blocks. Use
|
|
|
+ * weird math to avoid a 64-bit division.
|
|
|
+ */
|
|
|
+ freeblks = percpu_counter_sum(&mp->m_fdblocks);
|
|
|
+ if (freeblks <= 0)
|
|
|
+ return -ENOSPC;
|
|
|
+ resblks = min_t(int64_t, UINT_MAX, freeblks);
|
|
|
+ resblks = (resblks * 15) >> 4;
|
|
|
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, resblks,
|
|
|
+ 0, XFS_TRANS_RESERVE, &tp);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+
|
|
|
+ error = xfs_defer_finish(&tp, dfops);
|
|
|
+ if (error)
|
|
|
+ goto out_cancel;
|
|
|
+
|
|
|
+ return xfs_trans_commit(tp);
|
|
|
+
|
|
|
+out_cancel:
|
|
|
+ xfs_trans_cancel(tp);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* When this is called, all of the log intent items which did not have
|
|
|
* corresponding log done items should be in the AIL. What we do now
|
|
@@ -4825,10 +4868,12 @@ STATIC int
|
|
|
xlog_recover_process_intents(
|
|
|
struct xlog *log)
|
|
|
{
|
|
|
- struct xfs_log_item *lip;
|
|
|
- int error = 0;
|
|
|
+ struct xfs_defer_ops dfops;
|
|
|
struct xfs_ail_cursor cur;
|
|
|
+ struct xfs_log_item *lip;
|
|
|
struct xfs_ail *ailp;
|
|
|
+ xfs_fsblock_t firstfsb;
|
|
|
+ int error = 0;
|
|
|
#if defined(DEBUG) || defined(XFS_WARN)
|
|
|
xfs_lsn_t last_lsn;
|
|
|
#endif
|
|
@@ -4839,6 +4884,7 @@ xlog_recover_process_intents(
|
|
|
#if defined(DEBUG) || defined(XFS_WARN)
|
|
|
last_lsn = xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block);
|
|
|
#endif
|
|
|
+ xfs_defer_init(&dfops, &firstfsb);
|
|
|
while (lip != NULL) {
|
|
|
/*
|
|
|
* We're done when we see something other than an intent.
|
|
@@ -4859,6 +4905,12 @@ xlog_recover_process_intents(
|
|
|
*/
|
|
|
ASSERT(XFS_LSN_CMP(last_lsn, lip->li_lsn) >= 0);
|
|
|
|
|
|
+ /*
|
|
|
+ * NOTE: If your intent processing routine can create more
|
|
|
+ * deferred ops, you /must/ attach them to the dfops in this
|
|
|
+ * routine or else those subsequent intents will get
|
|
|
+ * replayed in the wrong order!
|
|
|
+ */
|
|
|
switch (lip->li_type) {
|
|
|
case XFS_LI_EFI:
|
|
|
error = xlog_recover_process_efi(log->l_mp, ailp, lip);
|
|
@@ -4867,10 +4919,12 @@ xlog_recover_process_intents(
|
|
|
error = xlog_recover_process_rui(log->l_mp, ailp, lip);
|
|
|
break;
|
|
|
case XFS_LI_CUI:
|
|
|
- error = xlog_recover_process_cui(log->l_mp, ailp, lip);
|
|
|
+ error = xlog_recover_process_cui(log->l_mp, ailp, lip,
|
|
|
+ &dfops);
|
|
|
break;
|
|
|
case XFS_LI_BUI:
|
|
|
- error = xlog_recover_process_bui(log->l_mp, ailp, lip);
|
|
|
+ error = xlog_recover_process_bui(log->l_mp, ailp, lip,
|
|
|
+ &dfops);
|
|
|
break;
|
|
|
}
|
|
|
if (error)
|
|
@@ -4880,6 +4934,11 @@ xlog_recover_process_intents(
|
|
|
out:
|
|
|
xfs_trans_ail_cursor_done(&cur);
|
|
|
spin_unlock(&ailp->xa_lock);
|
|
|
+ if (error)
|
|
|
+ xfs_defer_cancel(&dfops);
|
|
|
+ else
|
|
|
+ error = xlog_finish_defer_ops(log->l_mp, &dfops);
|
|
|
+
|
|
|
return error;
|
|
|
}
|
|
|
|