diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2020-09-21 19:15:09 +0300 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2020-09-23 18:58:51 +0300 |
commit | 93293bcbde93567efaf4e6bcd58cad270e1fcbf5 (patch) | |
tree | ce0c66955bfc654356af446cfbfcaa308037abd3 /fs/xfs/xfs_refcount_item.c | |
parent | e581c9397a25458c06b05f37efce2c480836ef4f (diff) | |
download | linux-93293bcbde93567efaf4e6bcd58cad270e1fcbf5.tar.xz |
xfs: log new intent items created as part of finishing recovered intent items
During a code inspection, I found a serious bug in the log intent item
recovery code when an intent item cannot complete all the work and
decides to requeue itself to get that done. When this happens, the
item recovery creates a new incore deferred op representing the
remaining work and attaches it to the transaction that it allocated. At
the end of _item_recover, it moves the entire chain of deferred ops to
the dummy parent_tp that xlog_recover_process_intents passed to it, but
fail to log a new intent item for the remaining work before committing
the transaction for the single unit of work.
xlog_finish_defer_ops logs those new intent items once recovery has
finished dealing with the intent items that it recovered, but this isn't
sufficient. If the log is forced to disk after a recovered log item
decides to requeue itself and the system goes down before we call
xlog_finish_defer_ops, the second log recovery will never see the new
intent item and therefore has no idea that there was more work to do.
It will finish recovery leaving the filesystem in a corrupted state.
The same logic applies to /any/ deferred ops added during intent item
recovery, not just the one handling the remaining work.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Diffstat (limited to 'fs/xfs/xfs_refcount_item.c')
-rw-r--r-- | fs/xfs/xfs_refcount_item.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/fs/xfs/xfs_refcount_item.c b/fs/xfs/xfs_refcount_item.c index ca93b6488377..492d80a0b406 100644 --- a/fs/xfs/xfs_refcount_item.c +++ b/fs/xfs/xfs_refcount_item.c @@ -555,7 +555,7 @@ xfs_cui_item_recover( } xfs_refcount_finish_one_cleanup(tp, rcur, error); - xfs_defer_move(parent_tp, tp); + xfs_defer_capture(parent_tp, tp); error = xfs_trans_commit(tp); return error; |