xfs: refactor xlog_recover_buffer_pass1

Split out a xlog_add_buffer_cancelled helper which does the low-level
manipulation of the buffer cancelation table, and in that helper call
xlog_find_buffer_cancelled instead of open coding it.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
Christoph Hellwig 2020-04-28 14:39:13 -07:00 committed by Darrick J. Wong
parent f15ab3f60e
commit 98b69b1285
1 changed files with 55 additions and 59 deletions

View File

@ -1913,65 +1913,6 @@ out:
return error;
}
/*
* Build up the table of buf cancel records so that we don't replay
* cancelled data in the second pass. For buffer records that are
* not cancel records, there is nothing to do here so we just return.
*
* If we get a cancel record which is already in the table, this indicates
* that the buffer was cancelled multiple times. In order to ensure
* that during pass 2 we keep the record in the table until we reach its
* last occurrence in the log, we keep a reference count in the cancel
* record in the table to tell us how many times we expect to see this
* record during the second pass.
*/
STATIC int
xlog_recover_buffer_pass1(
struct xlog *log,
struct xlog_recover_item *item)
{
xfs_buf_log_format_t *buf_f = item->ri_buf[0].i_addr;
struct list_head *bucket;
struct xfs_buf_cancel *bcp;
if (!xfs_buf_log_check_iovec(&item->ri_buf[0])) {
xfs_err(log->l_mp, "bad buffer log item size (%d)",
item->ri_buf[0].i_len);
return -EFSCORRUPTED;
}
/*
* If this isn't a cancel buffer item, then just return.
*/
if (!(buf_f->blf_flags & XFS_BLF_CANCEL)) {
trace_xfs_log_recover_buf_not_cancel(log, buf_f);
return 0;
}
/*
* Insert an xfs_buf_cancel record into the hash table of them.
* If there is already an identical record, bump its reference count.
*/
bucket = XLOG_BUF_CANCEL_BUCKET(log, buf_f->blf_blkno);
list_for_each_entry(bcp, bucket, bc_list) {
if (bcp->bc_blkno == buf_f->blf_blkno &&
bcp->bc_len == buf_f->blf_len) {
bcp->bc_refcount++;
trace_xfs_log_recover_buf_cancel_ref_inc(log, buf_f);
return 0;
}
}
bcp = kmem_alloc(sizeof(struct xfs_buf_cancel), 0);
bcp->bc_blkno = buf_f->blf_blkno;
bcp->bc_len = buf_f->blf_len;
bcp->bc_refcount = 1;
list_add_tail(&bcp->bc_list, bucket);
trace_xfs_log_recover_buf_cancel_add(log, buf_f);
return 0;
}
static struct xfs_buf_cancel *
xlog_find_buffer_cancelled(
struct xlog *log,
@ -1993,6 +1934,35 @@ xlog_find_buffer_cancelled(
return NULL;
}
static bool
xlog_add_buffer_cancelled(
struct xlog *log,
xfs_daddr_t blkno,
uint len)
{
struct xfs_buf_cancel *bcp;
/*
* If we find an existing cancel record, this indicates that the buffer
* was cancelled multiple times. To ensure that during pass 2 we keep
* the record in the table until we reach its last occurrence in the
* log, a reference count is kept to tell how many times we expect to
* see this record during the second pass.
*/
bcp = xlog_find_buffer_cancelled(log, blkno, len);
if (bcp) {
bcp->bc_refcount++;
return false;
}
bcp = kmem_alloc(sizeof(struct xfs_buf_cancel), 0);
bcp->bc_blkno = blkno;
bcp->bc_len = len;
bcp->bc_refcount = 1;
list_add_tail(&bcp->bc_list, XLOG_BUF_CANCEL_BUCKET(log, blkno));
return true;
}
/*
* Check if there is and entry for blkno, len in the buffer cancel record table.
*/
@ -2045,6 +2015,32 @@ xlog_buf_readahead(
xfs_buf_readahead(log->l_mp->m_ddev_targp, blkno, len, ops);
}
/*
* Build up the table of buf cancel records so that we don't replay cancelled
* data in the second pass.
*/
static int
xlog_recover_buffer_pass1(
struct xlog *log,
struct xlog_recover_item *item)
{
struct xfs_buf_log_format *bf = item->ri_buf[0].i_addr;
if (!xfs_buf_log_check_iovec(&item->ri_buf[0])) {
xfs_err(log->l_mp, "bad buffer log item size (%d)",
item->ri_buf[0].i_len);
return -EFSCORRUPTED;
}
if (!(bf->blf_flags & XFS_BLF_CANCEL))
trace_xfs_log_recover_buf_not_cancel(log, bf);
else if (xlog_add_buffer_cancelled(log, bf->blf_blkno, bf->blf_len))
trace_xfs_log_recover_buf_cancel_add(log, bf);
else
trace_xfs_log_recover_buf_cancel_ref_inc(log, bf);
return 0;
}
/*
* Perform recovery for a buffer full of inodes. In these buffers, the only
* data which should be recovered is that which corresponds to the